Перейти к содержанию
    

Как ускорить компиляцию проекта на квартусе

Уважаемые друзья, 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]}]

 

 

Спасибо!

 

ЗЫ несколько редактирований этого сообщения были вызваны глюком при набивке сообщения и желанием откоментарить текст для удобства восприятия

Изменено пользователем iiv

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Было бы гораздо удобней разбираться, если б Вы привели отчет временного анализатора:

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}
Изменено пользователем bogaev_roman

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Уважаемый Роман,

 

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

 

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

 

У меня к Вам два вопроса, я, к сожалению, не все до конца с понимаю с Квартусом и с терминологией, помогите, пожалуйста:

Было бы гораздо удобней разбираться, если б Вы привели отчет временного анализатора:

Timequest timing analyzer там report top failing paths и критичные пути.

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

 

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?

 

ЗЫ с одним вопросом про разрешающие сигналы - разобрался, поэтому поправил свой ответ

Изменено пользователем iiv

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По поводу правильного использования 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, Вам эта запись вообще не понадобиться.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добрый день, Роман,

 

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

 

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

 

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

 

Основной клок у меня 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)МГц и данные между этими домейнами постоянно гуляют туда и обратно. Правильно ли я понимаю, что их как раз ни как не надо описывать?

 

Спасибо

 

И

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

три клока генерятся одним ПЛЛ и имеют четко прописанные частоты 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

Изменено пользователем bogaev_roman

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...