iiv 18 20 марта, 2011 Опубликовано 20 марта, 2011 (изменено) · Жалоба Уважаемые друзья, 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]}] Спасибо! ЗЫ несколько редактирований этого сообщения были вызваны глюком при набивке сообщения и желанием откоментарить текст для удобства восприятия Изменено 20 марта, 2011 пользователем iiv Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bogaev_roman 0 20 марта, 2011 Опубликовано 20 марта, 2011 (изменено) · Жалоба Было бы гораздо удобней разбираться, если б Вы привели отчет временного анализатора: 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} Изменено 20 марта, 2011 пользователем bogaev_roman Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iiv 18 20 марта, 2011 Опубликовано 20 марта, 2011 (изменено) · Жалоба Уважаемый Роман, огромное спасибо Вам за советы и помощь! Косяк с 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? ЗЫ с одним вопросом про разрешающие сигналы - разобрался, поэтому поправил свой ответ Изменено 20 марта, 2011 пользователем iiv Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bogaev_roman 0 21 марта, 2011 Опубликовано 21 марта, 2011 · Жалоба По поводу правильного использования 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 18 3 апреля, 2011 Опубликовано 3 апреля, 2011 · Жалоба Добрый день, Роман, огромное Вам спасибо за советы и ссылки про таймквест и логиклок - сильно помогло. Поставил все клоки через ПЛЛ, стало проще и нагляднее. Есть один момент, даже не знаю как правильно объяснить, помогите, пожалуйста, советом, как правильно. Основной клок у меня 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 0 4 апреля, 2011 Опубликовано 4 апреля, 2011 (изменено) · Жалоба три клока генерятся одним ПЛЛ и имеют четко прописанные частоты 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 Изменено 4 апреля, 2011 пользователем bogaev_roman Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться