Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как ускорить компиляцию проекта на квартусе
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
iiv
Всем привет,

есть незадачка - мой системверилог проект очень долго компилится (2-5 часов) и не всегда его fmax бывает приемлим.

Сам проект - всего-то около 600 строк без ниоса и наворотов, используется только мегафункции памяти (M9K, M144), altpll и altmult_add.

В самом проекте есть два параметра, назову из K и M, где K - это объем кольцевого буффера памяти, M - число использующихся умножителей.

Если K примерно 70% от всей доступной памяти, M - 10% от всех доступных умножителей, fmax на основной клок получается хороший (490МГц). Компилится все около часу на хорошем i5.

Если
1) K примерно 10-20% от всей доступной памяти, M - любое, или
2) K и M примерно по 30%,
fmax получается еще приемлимый, окло 400МГц (мне не меньше надо) но компилится уже около 2-5 часов.

Если я пытаюсь задействовать почти все умножители и хотя бы 70% памяти, то обычно квартус через 1-2 часа падает со своей какой-то внутренней ошибкой или через 5-7 часов все-таки заканчивает работу, но fmax получается очень маленьким - около 300МГц.

Алгоритмически все упирается в одну простую конструкцию:
Код
...
parameter   N=42;
input                   Clk;
input       [13:0]      In[0:2];
...

reg  signed [13:0]      D[0:2][0:1];
reg  signed [13:0]      Data[0:2][0:N];
wire signed [31:0]      ScalY[0:8][0:N-1];

...

// Generating modules

generate
genvar i, j, k;
for(i=0; i<N; i+=2) begin : aaa
   for(j=0; j<3; j++) begin : bbb
     for(k=0; k<3; k++) begin : ccc
       MultOne MultOne_Module(Clk, D[j][0], D[j][1], Data[k][i], Data[k][i+1], Clk2, ScalY[j+3*k][i], ScalY[j+3*k][i+1]);
end end end
endgenerate

...


module MultOne(Clk, A1, A2, B1, B2, Clk2, Res1, Res2);
parameter SHR=18;
input Clk, Clk2;
input signed [13:0] A1, A2, B1, B2;
output reg signed [31:0] Res1, Res2;

reg signed [13:0] P1, P2, Q1, Q2;
reg signed [28:0] Sum;
reg signed [28:0] SumR0, SumR1, SumR2, SumDM0, SumDM1;
reg signed [28+SHR:0] ScalX1, ScalX2;
reg signed [31:0] Z_Res1, Z_Res2;

//   Sum<=P1*Q1+P2*Q2;
my_madd my_madd_module(Clk, P1, Q1, P2, Q2, Sum);

always @(posedge Clk)
begin
   P1<=A1;
   P2<=A2;
   Q1<=B1;
   Q2<=B2;
   SumR0<=Sum;
   SumR1<=SumR0;
   SumR2<=SumR1;
end

always @(posedge Clk2) // этот клок в два раза медленнее Clk
begin
   SumDM0<=SumR1;
   SumDM1<=SumR2;
   ScalX1<=ScalX1+SumDM0-(ScalX1>>>SHR);
   ScalX2<=ScalX2+SumDM1-(ScalX2>>>SHR);
   Z_Res1<=ScalX1[28+SHR:SHR-3];
   Z_Res2<=ScalX2[28+SHR:SHR-3];
   Res1<=Z_Res1;
   Res2<=Z_Res2;
end
endmodule


Как я понимаю, основная загвоздка у Квартуса возникает тогда, когда я пытаюсь поместить сотни дублей моего MultOne модуля (в мой кристал влазит 384) мне очень хочется вычислять при N=42, то есть когда задействовано 378 умножителей.

Теперь мой вопрос... Могу ли я как-то помочь квартусу, чтобы он стал быстрее компилировать, например, можно ли скомпилить сколько-то этих модулей и физически куда-то в кристалле разместить? Шаманил вокруг LogicLock Regions and Design Partitions Window, но, кажется так запутался, что ничего не могу поделать сам, поэтому прошу помощи у Вас!

Пожалуйста, посоветуйте, что мне сделать, чтобы увеличить fmax и не ждать по 5 часов на компиляцию этих нескольких строк кода!

ЗЫ: при компиляции в квартусе стоят все опции, которые ускоряют fmaxна основе адвизора! Если их отключать, компиляция конечно за пол часа заканчивается но и fmax даже до 200МГц не дотягивает!

Спасибо

И
Shtirlits
Ключевое слово верное - logic lock.

С квартусом лет 6 подробно не работал, но когда-то надо было отдельно синтезировать netlist,
потом один экземпляр разместить и развести, сохранить файлы и потом в основном дизайне все экземпляры расставить указывая либо все три файла, либо netlist и placement, либо только netlist.
Могут быть трудности с copy-paste-ом, так как микросхема не однородна и может понадобиться не один "штамп".
Во-первых, это позволяет зафиксировать fmax.
Во-вторых, радикально уменьшает время разработки, даже с учетом нескольких дней на чтение документации и игры с logic lock и virtual pins, так как не только ускоряет разводку, но и уменьшает количество ненужных итераций.
des00
помочь можно только в том случае, если будет видно модуль умножения сложения. И надо понимать что на таких проекта трассы перевешивают все, поэтому регистры, регистры и еще раз регистры. На входе умножителя регистр, внутри умножителя все регистры, на выходе регистр, тоже самое с памятью и т.д.
iiv
Цитата(des00 @ Mar 19 2011, 07:56) *
помочь можно только в том случае, если будет видно модуль умножения сложения. И надо понимать что на таких проекта трассы перевешивают все, поэтому регистры, регистры и еще раз регистры. На входе умножителя регистр, внутри умножителя все регистры, на выходе регистр, тоже самое с памятью и т.д.

С Вашим советом я полностью согласен, но, и модуль два умножения плюс сложение - это системная процедура altmult_add, и на входе по два регистра, и на выходе по два... Проверял - больше двух - уже не помогает. Это я уже прошел. Иначе 490МГц я бы не получал!!!

И даже если у меня только умножительный модуль, но забитый под 70-80%, то я тоже получаю необходимые мне 400МГц, и ОТДЕЛЬНО, модуль с памятью, тоже нормально работает. Кстати, у меня память работает только на 1/6 от основного клока, то есть мне достаточно клока в 66МГц на запись, а на чтение и того меньше - всего-то 15МГц.

Основная проблема возникает только при объединении двух модулей - такое чувство, что квартус не в сосотянии решить такую сложную задачу по размещению - фиттер висит по 5 часов а иногда падает с системной ошибкой.

Как Вы думаете, на что еще кроме логик лок стоит обратить внимание (я уже начал разбираться с логик лок, но пока не помогает...)

Спасибо

И

Цитата(Shtirlits @ Mar 19 2011, 01:26) *
Ключевое слово верное - logic lock.

Спасибо Вам большое, разбираюсь в этом направлении, надеюсь поможет!
jojo
Цитата(iiv @ Mar 19 2011, 12:12) *
Основная проблема возникает только при объединении двух модулей - такое чувство, что квартус не в сосотянии решить такую сложную задачу по размещению - фиттер висит по 5 часов а иногда падает с системной ошибкой.



Можно попробовать Design Space Explorer, или как он сейчас называется в Altera.
В Xilinx ISE нарвался на аналогичную проблему: на одних настройках (таблицах) MAP проект в итоге трассируется, на других - нет.
Причём при минимальных правках нужно искать новую "счастливую таблицу" из 100*5 возможных.
Проблема появилась при большом количестве плотных макросов с размещением (RPM) и большом количестве блоков ОЗУ.

Для получения fmax пришлось навтыкать "ненужные" регистры с запасом, хотя при малом тираже макросов доп. регистры не требовались.
iiv
Цитата(jojo @ Mar 19 2011, 14:49) *
Для получения fmax пришлось навтыкать "ненужные" регистры с запасом, хотя при малом тираже макросов доп. регистры не требовались.


один в один как у меня было, пока я в проект памяти не напихал, а сейчас и это не помогает.
Shtirlits
Logic lock не такой уж и сложный механизм!
Попробуйте на небольшой кошке.
jojo
Да, и частоту в констрейнах можно уменьшить, чтобы понапрасну не ждать.

После трассировки для неправильно размещаемых элементов можно задавать (уточнять) области, где им положено быть. Это если элементы в макрос не входят.
iiv
Благодарю Вас за ответы и советы!

Цитата(jojo @ Mar 19 2011, 17:05) *
Да, и частоту в констрейнах можно уменьшить, чтобы понапрасну не ждать.

и так по минимуму sm.gif


Цитата(jojo @ Mar 19 2011, 17:05) *
После трассировки для неправильно размещаемых элементов можно задавать (уточнять) области, где им положено быть. Это если элементы в макрос не входят.

Будьте любезны, разъясните, пожалуйста, как это делается. Вот получил я, например, fmax=330MHz вместо ожидаемых 400МГц. И как я это исправлю, куда смотреть?

Спасибо
jojo
Цитата(iiv @ Mar 19 2011, 17:21) *
Будьте любезны, разъясните, пожалуйста, как это делается. Вот получил я, например, fmax=330MHz вместо ожидаемых 400МГц. И как я это исправлю, куда смотреть?


Нужно сопоставлять отчёт анализатора задержек (Timequest др.) и вид проблемного пути на кристалле (FloorPlan Editor и т.п.).

Проблемный триггер или блок памяти может быть расположен в "левом" месте на кристалле, вдали от разумного, желаемого положения.
Поскольку таких элементов может быть много, их положение можно оптом законстрейнить.

Ресурсы ПЛИС расположены немонотонно, например, узкими колонками, простым констрейном размещения дело может не обойтись. В этом случае добавляем в конвейер пустые регистры, которые по алгоритму вроде не нужны, но задержку сокращают.

Покажите, если можете, аналогичную картинку своего проекта с подсвечиванием сбойных путей.
iiv
Уважаемый jojo,

очень Вам благодарен за классные советы и разъяснения.

Я, к сожалению, новичек в квартусе (только один год опыта) и, некоторые вещи пока еще не знаю.

Цитата(jojo @ Mar 19 2011, 19:33) *
Покажите, если можете, аналогичную картинку своего проекта с подсвечиванием сбойных путей.


вот как это сделать, не понимаю. Допустим у меня есть собранный проект.
; Logic utilization ; 50 % ;
; Combinational ALUTs ; 23,937 / 113,600 ( 21 % ) ;
; Memory ALUTs ; 84 / 56,800 ( < 1 % ) ;
; Dedicated logic registers ; 60,800 / 113,600 ( 54 % ) ;
; Total registers ; 60800 ;
; Total block memory bits ; 4,131,624 / 5,630,976 ( 73 % ) ;
; DSP block 18-bit elements ; 210 / 384 ( 55 % ) ;

Это последний из максимальных, который у меня собирается, но его fmax=398MHz (85С) и 420МГц (0С), то есть чуть-чуть меньше, чем надо. Я кстати заметил, что хоть кристалл и до 60С разогревается во время работы, но данные бывают битые, если fmax меньше 420МГц, хотя у меня клок системы через плл из плиски задается и составляет ровно 400МГц. Возможно где-то нестабильность имеется, ну да ладно, главное я знаю на какую частоту мне все затачивать.

По спидгрейдам кристалла, умножители могут работать до 490МГц, все остальное - совсем простое - суммы примерно 40 битных чисел, работающие на полуклоке, то есть на 200МГц от основного клока.

Вот получил я Technology Map Viewver на 615 страницах sm.gif или Resource Property Editor с огромным числом информации, большая часть которой мне не понятна, или получил картинку от Chip Planner, красивая конечно, но что мне с ней делать, можно по разному ее покрасить, но путей там не видно... Если FanIn кнопку нажимаю, получается сначала какое-то мессиво, а потом квартус зависает с полной загрузкой компьютера. Это здесь именно я должен был увидеть картинку сбойных путей, подскажите, мне, если Вас не затруднит, пожалуйтса!

ЗЫ: вроде и компьютер не совсем тормознутый, 2*2.2ГГц с 8 ГБ оперативки.

Спасибо

И
jojo
Возможно, из-за дрожания тактового сигнала данные сбиваются.

Я сейчас больше с Xilinx работаю. По памяти, вроде надо в Timequest провести анализ путей на Fmax, потом построить список путей в отчёте, потом нажать на сбойный путь и сделать Locate in Chip Planner. Там подсветятся ресурсы сбойного пути. Наверное, можно прямее сделать это же.

В том же отчёте TimeQuest можно увидеть, из чего складывается задержка. Нажмите на сбойный путь и Locate in Technology Map Viewer.

Что-то в документации должно быть на эту тему.

Надо либо законстрейнить положение, либо добавить регистры, либо перестроить сбойный путь.
bogaev_roman
Цитата(iiv @ Mar 19 2011, 22:47) *
Если FanIn кнопку нажимаю, получается сначала какое-то мессиво, а потом квартус зависает с полной загрузкой компьютера. Это здесь именно я должен был увидеть картинку сбойных путей

Что именно мешает посмотреть все критические пути на timequest анализатор? Там все расписано подробно - посмотрите примерно в каких пропорциях задержки критичекого пути распределены - если большие задержки на IC (т.е. от элемента до элемента) то советую идти по пути partition и logic lock, то что Shtirlits советовал. Если основные задержки на самих элементах - то только переделка самого алгоритма.
slawikg
Цитата
По спидгрейдам кристалла, умножители могут работать до 490МГц, все остальное - совсем простое - суммы примерно 40 битных чисел, работающие на полуклоке, то есть на 200МГц от основного клока.

Непонятно как у вас законстрейнена времянка, цепи из цитаты должны быть ослабланы мультициклами.
bogaev_roman
Цитата(iiv @ Mar 19 2011, 22:47) *
По спидгрейдам кристалла, умножители могут работать до 490МГц, все остальное - совсем простое - суммы примерно 40 битных чисел, работающие на полуклоке, то есть на 200МГц от основного клока.

Да, кстати, вот это очень интересное место. Еще не понятно как раскидал фиттер эту сумму. Ну и как у Вас чатоты в проекте соотносятся или Вы работаете на основной частоте, а 200МГц получаете используя разрешающий сигнал на триггер?
iiv
Уважаемые друзья, Jojo, Slawikg, Bogaev_Roman и все, кто помогает мне советами!

Огромное вам за советы человеческое СПАСИБО!

С Логиклоком я сейчас разбираюсь, и начал на мелкой кошке тренироваться.

По последним Вашим замечаниям мне показалось, что я могу что-то еще не учесть.

Вдруг вас не затруднит, пробегитесь, пожалуйста по тексту моего проекта, вдруг Вы сразу заметите что-то, что я делаю криво. Буду Вам очень-очень благодарен!

Урезал проект до минимума, оставив только самый сложный кусок, который и тормозит ужастно и должен на большой частоте работать.

Код
module ...

wire [13:0]  MidData[0:2]; // приходят из еще одного модуля (выход от ФИФО на МЛАБах) и синхронизованы с Clk
wire [31:0]  CommonTimers[0:54]; // приходят из еще одного модуля (каунтеры 55 ножек), тоже синхронизованы с Clk
wire         Clk;

...

DATA_Aq DATA_Aq_module(Clk, MidData, GPIO1_D[25], GPIO1_D[24], GPIO1_D[23], GPIO1_D[29], GPIO1_D[28],
CommonTimers);

my_pll my_pll_module1(OSC1_50, Clk); // 8-ми кратный умножитель частоты, на выходе должно быть 400МГц
endmodule


module DATA_Aq(Clk, In, ClkOut, OutOn, Out, SP1, SP2, InputCounters);
parameter   N=42;
parameter   M=100;
parameter   LSSH=3;
parameter   MAXLOCBUF=(56>N*9+5)?56:N*9+5;
parameter   IMPULSEBITS=14;
parameter   IMPULSELEN=16*1024;
input                   Clk, ClkOut, OutOn, SP1, SP2;
input       [13:0]      In[0:2];
input       [31:0]      InputCounters[0:54];
output reg              Out;

// Memory ////////////////////////////

reg  signed [13:0]      D[0:2][0:1];
reg  signed [13:0]      Data[0:2][0:M-1];
wire signed [31:0]      ScalY[0:8][0:N-1];
reg  signed [31:0]      MiddleSum[0:2];
reg         [31:0]      LocBuf[0:MAXLOCBUF];
wire signed [31:0]      ShortSumY[0:8][0:N-1];

reg  signed [31+LSSH:0] LevelSumY[0:5];
reg  signed [31:0]      LevelSum[0:5], ShortSum[0:5];
reg         [5:0]       cmpres;
reg         [2:0]       cmpton;
reg                     cmpon;
reg                     InDataSW;
reg         [255:0]     OutData;
reg         [7:0]       OutDataLen;
reg [IMPULSEBITS-1:0]   PosIn, PosOut;
reg         [31:0]      OutCounter;
reg         [63:0]      CurTimer, ImpulseTime, ReadImpulseTime;
reg         [17:0]      NewStatus;
reg         [7:0]       BlockLen;
reg         [31:0]      Counters[0:54];
reg         [2:0]       MemCounter;
reg                     MemClk;

wire        [251:0]     OutDataMem;
wire        [251:0]     InDataMem;

assign InDataMem[251:238]=Data[0][M-1];
assign InDataMem[237:224]=Data[1][M-1];
assign InDataMem[223:210]=Data[2][M-1];

assign InDataMem[209:196]=Data[0][M-2];
assign InDataMem[195:182]=Data[1][M-2];
assign InDataMem[181:168]=Data[2][M-2];

assign InDataMem[167:154]=Data[0][M-3];
assign InDataMem[153:140]=Data[1][M-3];
assign InDataMem[139:126]=Data[2][M-3];

assign InDataMem[125:112]=Data[0][M-4];
assign InDataMem[111: 98]=Data[1][M-4];
assign InDataMem[ 97: 84]=Data[2][M-4];

assign InDataMem[ 83: 70]=Data[0][M-5];
assign InDataMem[ 69: 56]=Data[1][M-5];
assign InDataMem[ 55: 42]=Data[2][M-5];

assign InDataMem[ 41: 28]=Data[0][M-6];
assign InDataMem[ 27: 14]=Data[1][M-6];
assign InDataMem[ 13:  0]=Data[2][M-6];

my_lmem  my_lmem_module1(InDataMem[143:  0], PosIn, InDataSW, PosOut, ClkOut, 1, OutDataMem[143:  0]); // 16*M144
my_lmem2 my_lmem_module2(InDataMem[251:144], PosIn, InDataSW, PosOut, ClkOut, 1, OutDataMem[251:144]); // 216*M9K

// Generating modules

generate
genvar i, j, k;
for(i=0; i<N; i+=2) begin : aaa
   for(j=0; j<3; j++) begin : bbb
     for(k=0; k<3; k++) begin : ccc
       MultOne MultOne_Module(Clk, D[j][0], D[j][1], Data[k][i], Data[k][i+1], InDataSW,
                              ScalY    [j+3*k][i], ScalY    [j+3*k][i+1],
                              ShortSumY[j+3*k][i], ShortSumY[j+3*k][i+1]);
end end end
endgenerate

// Initialization of variables

initial
begin
   MemCounter=0;
   MemClk=0;
   cmpres=0;
   InDataSW=0;
   ImpulseTime=0;
   ReadImpulseTime=0;
   OutData=0;
   OutDataLen=0;
   PosIn=0;
   PosOut=0;
   NewStatus=0;
   BlockLen=0;
   CurTimer=0;
   OutCounter=0;
end

// Reading Data from Channels ///////

always @(posedge Clk) // клок на 400МГц
begin
   for(int i=0; i<2; i++)
     for(int j=0; j<3; j++)
       D[j][i]<=Data[j][i+InDataSW];
   for(int j=0; j<3; j++)
     Data[j][0]<=In[j];
   for(int i=0; i<M-1; i++)
     for(int j=0; j<3; j++)
       Data[j][i+1]<=Data[j][i];
   InDataSW<=~InDataSW;
end


always @(posedge MemClk)  // программный делитель на 3 от клока на 200МГц, то есть 66.6666МГц
begin
   CurTimer<=CurTimer+1;
   if(PosIn)
     PosIn<=PosIn+1;
   else if(ReadImpulseTime==ImpulseTime && cmpon)
   begin
     ImpulseTime<=CurTimer;
     PosIn<=PosIn+1;
     for(int i=0; i<55; i++)
       Counters[i]<=InputCounters[i];
   end
end


always @(posedge InDataSW)  // программный делитель на 2 от клока на 400МГц, то есть 200МГц
begin
   for(int i=0; i<3; i++)
   begin
     ShortSum[i*2]<=ShortSumY[i][0];
     ShortSum[i*2+1]<=ShortSumY[i][0]-ShortSumY[i][1];
     MiddleSum[i]<=MiddleSum[i]+D[i][0]+D[i][1]-(MiddleSum[i]>>>17);
   end
//
   for(int i=0; i<6; i++)
     cmpres[i]<=((ShortSum[i]>=LevelSum[i])?1:0);
   cmpton<=(cmpres==6'h3f && BlockLen!=0)?{cmpton[1:0], 1'b1}:{cmpton[1:0], 1'b0};
//
   if(MemCounter==2)
   begin
     MemCounter<=0;
     MemClk<=1;
     cmpon<=(cmpton==7)?1:0;
   end
   else
   begin
     MemCounter<=MemCounter+1;
     MemClk<=0;
   end
//
   if(cmpres==6'h3f)
   begin
     for(int i=0; i<6; i++)
     begin
       LevelSumY[i]<=LevelSumY[i]-(LevelSumY[i]>>>LSSH)+ShortSum[i];
       LevelSum[i]<=LevelSumY[i]>>>LSSH;
     end
   end
end


always @(posedge SP1)
begin
   NewStatus<={NewStatus[16:0], SP2};
   if(NewStatus[17:13]==5'b01010 && NewStatus[4:0]==5'b01010)
     BlockLen<=NewStatus[12:5];
end


always @(posedge ClkOut) // медленный клок 15МГц для сбора данных с плиски, никак не синхронизован с теми клоками, которые выше, блок написан абы как, так как при этой скорости выжимать производительность не имеет смысла
begin
   if(OutOn==0)
   begin
     begin
       {OutData[254:0], Out}<=OutData;
       if(OutDataLen>0) OutDataLen<=OutDataLen-1;
       else
       begin
////////////////////////////////
         if(OutCounter==0)
         begin
           OutDataLen<=63;
           if(ImpulseTime>ReadImpulseTime)
           begin
             OutCounter<=64-57;
             OutData<={32'h0000ffff, 32'h0000ffff};
             LocBuf[0]<=ImpulseTime[63:32];
             LocBuf[1]<=ImpulseTime[31:0];
             for(int i=0; i<55; i++)
               LocBuf[i+2]<=Counters[i];
           end
           else
           begin
             OutCounter<=512-N*9-5;
             OutData<={32'h0000ffff, 32'h0000aaaa};
             LocBuf[0]<=CurTimer[63:32];
             LocBuf[1]<=CurTimer[31:0];
             for(int i=0; i<N*9; i++)
               LocBuf[i+2]<=ScalY[i%9][i/9];
             for(int i=0; i<3; i++)
               LocBuf[i+N*9+2]<=MiddleSum[i];
           end
         end
////////////////////////////////
         else if(OutCounter==63)
         begin
           OutCounter<=512;
           OutData<=LocBuf[0];
         end
////////////////////////////////
         else if(OutCounter==511)
         begin
           OutCounter<=0;
           OutData<=LocBuf[0];
         end
////////////////////////////////
         else if(OutCounter<511)
         begin
           OutDataLen<=31;
           OutCounter<=OutCounter+1;
           OutData<=LocBuf[0];
           for(int i=1; i<MAXLOCBUF; i++)
             LocBuf[i-1]<=LocBuf[i];
         end
////////////////////////////////
         else if(OutCounter<64*BlockLen+511)
         begin
           PosOut<=PosOut+1;
           OutCounter<=OutCounter+1;
           OutDataLen<=251;
           OutData<=OutDataMem;
         end
         else
////////////////////////////////
         begin
           PosOut<=0;
           OutCounter<=0;
           OutDataLen<=251;
           OutData<=OutDataMem;
           ReadImpulseTime=ImpulseTime;
         end
       end
     end
   end
end
endmodule


module MultOne(Clk, A1, A2, B1, B2, SW, Res1, Res2, PRes1, PRes2);
parameter SHR=18;
parameter RSH=5;
input Clk, SW;
input signed [13:0] A1, A2, B1, B2;
output reg signed [31:0] Res1, Res2;
output reg signed [31:0] PRes1, PRes2;

reg signed [13:0] P1, P2, Q1, Q2;
reg signed [28:0] Sum;
reg signed [28:0] SumR0, SumR1, SumR2, SumDM0, SumDM1;

// reg signed [31:0] Mul1, Mul2;
reg signed [28+SHR:0] ScalX1, ScalX2;
reg signed [28+RSH:0] ScalZ1, ScalZ2;

reg signed [31:0] Z_Res1, Z_Res2;
reg signed [31:0] Z_PRes1, Z_PRes2;

my_madd my_madd_module(Clk, P1, Q1, P2, Q2, Sum); // мегафункция altmult_add

always @(posedge Clk) // частота 400МГц
begin
   P1<=A1;
   P2<=A2;
   Q1<=B1;
   Q2<=B2;
//   Mul1<=P1*Q1; Mul2<=P2*Q2; Sum<=Mul1+Mul2;
   SumR0<=Sum;
   SumR1<=SumR0;
   SumR2<=SumR1;
end

always @(posedge SW) // половина частоты Clk
begin
   SumDM0<=SumR1;
   SumDM1<=SumR2;
//
   ScalX1<=ScalX1+SumDM0-(ScalX1>>>SHR);
   ScalX2<=ScalX2+SumDM1-(ScalX2>>>SHR);
   Z_Res1<=ScalX1[28+SHR:SHR-3];
   Z_Res2<=ScalX2[28+SHR:SHR-3];
   Res1<=Z_Res1;
   Res2<=Z_Res2;
//
   ScalZ1<=ScalZ1+SumDM0-(ScalZ1>>>RSH);
   ScalZ2<=ScalZ2+SumDM1-(ScalZ2>>>RSH);
   Z_PRes1<=ScalZ1[28+RSH:RSH-3];
   Z_PRes2<=ScalZ2[28+RSH:RSH-3];
   PRes1<=Z_PRes1;
   PRes2<=Z_PRes2;
end
endmodule


а констрейны написаны в файле так:

Код
set_time_format -unit ns -decimal_places 3

#**************************************************************
# Create Clock
#**************************************************************

derive_clocks -period "1.0"
create_clock -name {GPIO1_D[29]} -period 1000. -waveform {0.0 500.} [get_ports {GPIO1_D[29]}]
create_clock -name {GPIO1_D[25]} -period 60. -waveform {0.0 30.} [get_ports {GPIO1_D[25]}]

########################

create_clock "DATA_Aq:DATA_Aq_module|InDataSW" -name {DATA_Aq:DATA_Aq_module|InDataSW} -period 4.8 -waveform {0.0 2.4}
create_clock "DATA_Aq:DATA_Aq_module|MemClk" -name {DATA_Aq:DATA_Aq_module|MemClk} -period 28.8 -waveform {0.0 14.4}

########################

derive_pll_clocks

#**************************************************************
# Create Clock
#**************************************************************

create_clock "OSC2_50" -name "CLK" -period 20

#**************************************************************
# Create Generated Clock
#**************************************************************

create_generated_clock -master_clock 20. -source "OSC1_50" -name "CLK_OUT" -multiply_by 8 -divide_by 1
create_generated_clock -master_clock 20. -source "OSC1_50" -name "Clk" -multiply_by 8 -divide_by 1 [get_ports {my_pll_module1|altpll_component|auto_generated|pll1|clk[0]}]



Спасибо!

ЗЫ несколько редактирований этого сообщения были вызваны глюком при набивке сообщения и желанием откоментарить текст для удобства восприятия
bogaev_roman
Было бы гораздо удобней разбираться, если б Вы привели отчет временного анализатора:
Timequest timing analyzer там report top failing paths и критичные пути.
Мне лично не нравится запись:
Код
MiddleSum[i]<=MiddleSum[i]+D[i][0]+D[i][1]-(MiddleSum[i]>>>17);

Сколько здесь будет последовательных сумматоров/вычитателей - 2 или 3? Как quartus их раскидает непонятно.
D у Вас работает на частоте CLK, MiddleSum на частоте InDataSW - которая вообще есть выход триггера (пойдет по шине тактовых частот?). Здесь я так понимаю и есть косяк уж точно. Может переписать и работать так:
Код
always @(posedge CLK)  //здесь основная чатсота
if (InDataSW) //здесь разрешающий вход для триггеров
begin
   for(int i=0; i<3; i++)
   begin
     ShortSum[i*2]<=ShortSumY[i][0];
     ShortSum[i*2+1]<=ShortSumY[i][0]-ShortSumY[i][1];
     MiddleSum[i]<=(MiddleSum[i]+D[i][0])+(D[i][1]-(MiddleSum[i]>>>17));//Здесь в явном виде, чтоб было наверняка 2 последовательных сумматора/вычитателя
   end

PS/ У Вас очень много частот и нет вообще уверенности, чтоб Вы их правильно использовали и они шли именно по сетке частот. Получайте их на PLL если есть возможность или/и используйте если они кратные разрешающие сигналы на триггерах - по частоте точно уж не проиграете, а вот разводится будет быстрее гораздо.
PS2/ Частота clk - 400МГц (период 2,5ns), по коду InDataSW получается в два раза меньше
Цитата
always @(posedge Clk)
InDataSW<=~InDataSW
, а в ограничениях
Цитата
InDataSW" -name {DATA_Aq:DATA_Aq_module|InDataSW} -period 4.8 -waveform {0.0 2.4}
iiv
Уважаемый Роман,

огромное спасибо Вам за советы и помощь!

Косяк с MiddleSum - действительно мой косяк, правда который совсем, как оказалось, не влияет на получаемый результат, приходящий сигнал имеет постоянное значение, и это кривое усреднение не сказывается на получаемом результате. Уже придумал как переписать это все правильно и для работы с одним клоком.

У меня к Вам два вопроса, я, к сожалению, не все до конца с понимаю с Квартусом и с терминологией, помогите, пожалуйста:
Цитата(bogaev_roman @ Mar 20 2011, 19:48) *
Было бы гораздо удобней разбираться, если б Вы привели отчет временного анализатора:
Timequest timing analyzer там report top failing paths и критичные пути.

Вот Timequest timing analyzer я в репорте имею, а вот где в нем можно найти этот report top failing paths, тыкните, пожалуйста, моим носом в точное место и простите великодушно за такой мой глупый вопрос!

Цитата(bogaev_roman @ Mar 20 2011, 19:48) *
PS/ У Вас очень много частот и нет вообще уверенности, чтоб Вы их правильно использовали и они шли именно по сетке частот. Получайте их на PLL если есть возможность или/и используйте если они кратные разрешающие сигналы на триггерах - по частоте точно уж не проиграете, а вот разводится будет быстрее гораздо.

Правильно ли я понимаю, что если я буду использовать разрешающие сигналы на тригеррах, то этот кусок кода все еще должен констрейниться на высокой частоте. То есть если есть конструкция
Код
always @(posedge CLK)  //здесь основная чатсота 400МГц
if (InDataSW) //здесь разрешающий вход для триггеров
begin
   .... // вот здесь могу ли я выполнять операции, которые длятся 5нс (200МГц) или все-таки только 2.5нс?
   end

Если так, то мне подойдет решение только на ПЛЛ...


Спасибо, и простите за глупые вопросы, я, пока еще только разбираюсь!

Вот тут запутался в Вашем ответе, пожалуйста, помогите!

Мне нужен один клок Clk для умножителей 400МГц и половинный клок InDataSW (200МГц) для сумм. Я не могу понять, что же я не правильно сделал:

PS2/ Частота clk - 400МГц (период 2,5ns), по коду InDataSW получается в два раза меньше
Цитата
always @(posedge Clk)
InDataSW<=~InDataSW, а в ограничениях
Цитата
InDataSW" -name {DATA_Aq:DATA_Aq_module|InDataSW} -period 4.8 -waveform {0.0 2.4}

разве я не законстрейнил InDataSW на частоту 1000/4.8=208MHz?

ЗЫ с одним вопросом про разрешающие сигналы - разобрался, поэтому поправил свой ответ
bogaev_roman
По поводу правильного использования timequest для начала советую посмотреть блог des00 http://embedders.org/blog/des00 - очень хорошо и понятно написано
Для правильного использования инкрементальной компиляции, создание partition и logic lock - перевод документации от naliwator http://www.naliwator.narod.ru/
Цитата
Вот Timequest timing analyzer я в репорте имею, а вот где в нем можно найти этот report top failing paths, тыкните, пожалуйста, моим носом в точное место и простите великодушно за такой мой глупый вопрос!

Да не надо отчета. Все просто - окно в квартусе task, далее timequest timing analysis, вкладкой timequest timing analyzer запускаете анализатор. В анализаторе окно tasks выбираете вкладку reports->macros и два раза ЛК на report top failing paths. В окне report увидите все критические пути по частотам, которые не проходят ограничения. Далее выбирайте каждый путь и смотрите для него все задержки. Картинки, к сожалению, привести нет возможности...
Цитата
Правильно ли я понимаю, что если я буду использовать разрешающие сигналы на тригеррах, то этот кусок кода все еще должен констрейниться на высокой частоте.

Вы должны будете только констрейнить основную тактовую частоту. Фактически будете работать именно на ней. Кстати в чем проблема на одной PLL получить частоту и 200 и 400 МГц, они же кратные?
Цитата
Мне нужен один клок Clk для умножителей 400МГц и половинный клок InDataSW (200МГц) для сумм. Я не могу понять, что же я не правильно сделал:
На так в ограничениях Вы указываете не 200МГц, а 208. Ну и чего у Вас будет в момент их "перекрывания", т.е. когда фронты будут примерно "совпадать" - лажа будет. Мне казалось, что так должно быть:
Код
InDataSW" -name {DATA_Aq:DATA_Aq_module|InDataSW} -period 5.0 -waveform {0.0 2.5}

И, используя pll, Вам эта запись вообще не понадобиться.
iiv
Добрый день, Роман,

огромное Вам спасибо за советы и ссылки про таймквест и логиклок - сильно помогло.

Поставил все клоки через ПЛЛ, стало проще и нагляднее.

Есть один момент, даже не знаю как правильно объяснить, помогите, пожалуйста, советом, как правильно.

Основной клок у меня 400МГц, я его получаю из ПЛЛ на основе входной 50МГц частоты. Если у меня получаются фмакс(85С)=390-410, фмакс(0С)=400-420, то на практике имеются ошибки. Похоже где-то у меня не устойчиво частота получается. Я для этого хочу в ПЛЛ указать частоту 400МГц, а Квартус заставить компилиться на 420МГц. Этим вызвано то, что я указывал большие частоты в SDC файле. Скажите, пожалуйста, есть ли какой-то более правильный подход?

И еще сразу вопрос... Читал про таймквест, но, до конца не понял, вдруг не сложно будет, посоветуйте, пожалуйста.

Сейчас у меня есть 15 клоков. Все кроме 3-х из них - это асинхронные вводы-выводы, данные между которыми ходят через FIFO. Правильно ли я понимаю, что для всех этих клоков я должен написать в SDC такую инструкцию:

set_clock_groups -exclusive -group {GPIO1_D[29]}

А вот три клока генерятся одним ПЛЛ и имеют четко прописанные частоты 400МГц, 200МГц и 66.(6)МГц и данные между этими домейнами постоянно гуляют туда и обратно. Правильно ли я понимаю, что их как раз ни как не надо описывать?

Спасибо

И
bogaev_roman
Цитата
три клока генерятся одним ПЛЛ и имеют четко прописанные частоты 400МГц, 200МГц и 66.(6)МГц и данные между этими домейнами постоянно гуляют туда и обратно. Правильно ли я понимаю, что их как раз ни как не надо описывать?

Входная частота у Вас 50МГц, вот ее и объявляете в качестве входной, а далее просто derive_pll_clock. Timequest сам определит для них частоту и соотношения между ними, согласно установкам мегафункции pll. Для них вроде бы больше ничего и неда объявлять.
Цитата
Сейчас у меня есть 15 клоков. Все кроме 3-х из них - это асинхронные вводы-выводы, данные между которыми ходят через FIFO.

Если эти сигналы никак не связаны с логикой, которая работает на 3 остальных частотах, то вроде бы ничего не требуется.
Цитата
Основной клок у меня 400МГц, я его получаю из ПЛЛ на основе входной 50МГц частоты. Если у меня получаются фмакс(85С)=390-410, фмакс(0С)=400-420, то на практике имеются ошибки. Похоже где-то у меня не устойчиво частота получается. Я для этого хочу в ПЛЛ указать частоту 400МГц, а Квартус заставить компилиться на 420МГц.

На какой практике? Возможно два варианта:
1) Заданы не все ограничения - что-то не учли, может проблем с времянкой нет от триггера до триггера, есть проблемы с ограничениями на вход/выход.
2) Идет граничная ситуация и Fmax все-таки меньше заданной, читайте внимательно отчет timequest и выведете все сигналы, непроходящие по частоте - report top failing patch.
Поднять частоту на 10% можно с помощью настроек синтезатора/фиттера, если оптимизация кода не спасает и не хочется липить лишних partition, но это последнее дело. Настройки сильно зависят от проекта и все-таки замедляют скорость компиляции. Для себя выделил основные настройки следующие:
физический синтез - extra, дублирование регистров
analisys & synthesys - отключить удаление регистров дубликатов, оптимизация по скорости
фиттер - стандарт, уровень оптимизации роутера - максимальный
Может помочь и банальное изменение начальной точки разводки - seed
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.