|
Как в одном клок-домейне сказать Квартусу, что де инструкция может выполняться несколько тактов? |
|
|
|
Aug 2 2013, 19:23
|
вопрошающий
    
Группа: Свой
Сообщений: 1 726
Регистрация: 24-01-11
Пользователь №: 62 436

|
Всем привет, есть что-то типа примитивного софт-процессора - CmdAddr - номер выполняемого оператора, Cmd - код оператора, и с десяток различных инструкций. Если оставить все инструкции и собрать проект, то клок можно выставить только в 50МГц (есть долгие инструкции, в качестве примера, я написал инструкцию деления). Если закомментировать несколько "долгих инструкций", то проект можно собрать с клоком в 200МГц. Реально я понимаю, что, если я для самого себя условлюсь, что после некоторых инструкций я поставлю 1-2-3 такта пустые инструкции, а длительность выполнения этих инструкций будет не один клок, а 2-3-4, то все будет работать, но вот как это объяснить квартусу? Заводить кучу клоков, синхронизировать данные между ними - получается очень заумно и неудобно. Может есть какой-то простой способ как сказать, что де инструкция Номер 1 и 2 может работать два такта, инструкция Номер 3 может работать 3 такта, инструкия Номер 4 - может работать 4 такта и пусть квартус не парится и не доводит тайминг этих долгих инструкций до высокой частоты? Научите, пожалуйста, меня, кто знает, как это сделать! Спасибо ИИВ Код reg Clk; // клок reg [31:0] In1Reg; reg [31:0] In2Reg; reg [31:0] OutReg; reg [8:0] CmdAddr; reg [17:0] CmdA[0:511]; // список команд-операций как-то где-то инициализируемый reg [17:0] Cmd;
always @(posedge Clk) begin Cmd<=CmdA[CmdAddr+1]; if(Cmd[17]) CmdAddr<=Cmd[8:0]; else begin CmdAddr<=CmdAddr+1; case(Cmd[16:14]) 3'b000: OutReg<=In1Reg+In2Reg; // было бы классно выполнять ее 2 такта 3'b001: OutReg<=In1Reg-In2Reg; // было бы классно выполнять ее 2 такта 3'b010: OutReg<=In1Reg*In2Reg; // было бы классно выполнять ее 3 такта 3'b011: OutReg<=In1Reg/In2Reg; // было бы классно выполнять ее 4 такта 3'b100: OutReg<=In1Reg&In2Reg; // должна выполниться за такт 3'b101: OutReg<=In1Reg^In2Reg; // должна выполниться за такт 3'b110: OutReg<=In1Reg|In2Reg; // должна выполниться за такт 3'b111: // пустой оператор endcase end end
|
|
|
|
|
 |
Ответов
|
Aug 5 2013, 15:11
|
ʕʘ̅͜ʘ̅ʔ
    
Группа: Свой
Сообщений: 1 008
Регистрация: 3-05-05
Пользователь №: 4 691

|
1. Нужно немного переделать модуль: - сделать промежуточные результаты tmp_add, tmp_sub, tmp_mul, tmp_div, etc комбинаторным присвоением - указать оптимизатору, чтоб он не выбрасывал эти промежуточные результаты. Можно использовать директиву // synopsys keep (altera поддерживала, кажется). Можно сделать отдельные модули, которые будут вычислять эти промежуточные результаты, и запретить синтезатору их разгруппировку (я бы сделал так) - в мультиплексоре в регистр записывать эти промежуточные результаты. - в sdc что-то в таком духе (пути только правильно укажите):
set path_stp 3 # например set path_hld [expr ${path_stp} - 1]
set_multicycle_path ${path_stp} -setup -end -through [get_net [list {tmp_xx\[*\]}]] -to [get_cells [list {OutReg_reg\[*\]}]] set_multicycle_path ${path_hld} -hold -end -through [get_net [list {tmp_xx\[*\]}]] -to [get_cells [list {OutReg_reg\[*\]}]]
или -through [get_pins [list ... если делать отдельные модули для результатов
2. формально у Вас In1Reg, In2Reg и управляющий вход мультиплексора меняются каждый такт. Те несколько тактов, которые вы закладываете на вчисление результата, эти цепи не должны меняться. Вам это придется как-то учитывать за пределами области видимости RTL (например, как Вы верно отметили, в микрокоде).
3. CmdA[CmdAddr+1] - это, конечно, "сильно" в плане временных ограничений, учитывая, что CmdAddr вычисляется на предыдущем такте. Сделайте CmdAddr_plus_one, обновляемый вместе с CmdAddr, и используйте его для выборки след. команды.
|
|
|
|
|
Aug 6 2013, 19:46
|
вопрошающий
    
Группа: Свой
Сообщений: 1 726
Регистрация: 24-01-11
Пользователь №: 62 436

|
Огромное спасибо всем отвечавшим и сочувствовавшим, понял примерно как сделать, также сразу, на основе Ваших советов, придумал как улучшить. Сейчас немного уперся в то, что не сильно понимаю, почему у меня не работает команда с мультициклом. Так как мне нужна фактически стейт-машина с микрокодом, а не процессор, поле деятельности как это все модифицировать большое, поэтому я все переписал так, что есть некоторые регистры (я их обозвал GPIO0, GPIO1, ..., GPIO9), которые я как-то инициализирую на каждый такт, и есть несколько результатов операций, которые каждый или почти каждый такт выполняются. Код module main(...)
my_cpu my_cpu_module(...);
endmodule
module my_cpu(...) ... reg signed [REG_LEN-1:0] GPIO0; reg signed [REG_LEN-1:0] GPIO1; reg signed [REG_LEN-1:0] GPIO2; reg signed [REG_LEN-1:0] GPIO3; reg signed [REG_LEN-1:0] GPIO4; reg signed [REG_LEN-1:0] GPIO5; reg signed [REG_LEN-1:0] GPIO6; reg signed [REG_LEN-1:0] GPIO7; reg signed [REG_LEN-1:0] GPIO8; reg signed [REG_LEN-1:0] GPIO9;
// 14 registers reg signed [REG_LEN-1:0] RegRes0; reg signed [REG_LEN-1:0] RegRes1; reg signed [REG_LEN-1:0] RegRes2; reg signed [REG_LEN-1:0] RegRes3; reg signed [REG_LEN-1:0] RegRes4; reg signed [REG_LEN-1:0] RegRes5; reg signed [REG_LEN-1:0] RegRes6; reg signed [REG_LEN-1:0] RegRes7; reg signed [REG_LEN-1:0] RegRes8; reg signed [REG_LEN-1:0] RegRes9; reg signed [REG_LEN-1:0] RegRes10; reg signed [REG_LEN-1:0] RegRes11; reg signed [REG_LEN-1:0] RegRes12;
my_div my_dive_module(.clock(Clk), .denom(GPIO6), .numer(GPIO9), .quotient(RegRes9), .remain(RegRes10)); // должно вычисляться за 8 тактов my_mult my_mult_module(.clock(Clk), .dataa(GPIO5), .datab(GPIO8), .result(RegRes8)); // должно вычисляться за два такта my_sub my_sub_module(.clock(Clk), .dataa(GPIO1), .datab(GPIO7), .result(RegRes7)); // должно вычисляться за один такт my_add my_add_module(.clock(Clk), .dataa(GPIO1), .datab(GPIO7), .result(RegRes6)); // должно вычисляться за один такт my_compare my_compare_module(.clock(Clk), .dataa(GPIO0), .datab(GPIO2), .aeb(CmpFlag[0]), .agb(CmpFlag[1]), .alb(CmpFlag[2])); // должно вычисляться за один такт
always @(posedge Clk) begin RegRes0 <=GPIO0&GPIO2; RegRes1 <=GPIO0|GPIO2; RegRes2 <=GPIO0^GPIO2; RegRes3 <=GPIO3>>1; RegRes4 <=GPIO3<<1; RegRes5 <=~GPIO4; // ... и еще всякие операции по перетаскиванию значений из одного регистра в другой на основе микрокода end endmodule При написании констрейна он не признает его, и я все никак не могу понять почему, констрейн написал вроде бы как все здесь советовали, но, провидимому, так до сих пор что-то до конца не понял. Код set_multicycle_path 8 -setup -end -from [get_registers [list \ {my_cpu_module|GPIO0\[*\] my_cpu_module|GPIO1\[*\] my_cpu_module|GPIO2\[*\] \ my_cpu_module|GPIO3\[*\] my_cpu_module|GPIO4\[*\] my_cpu_module|GPIO5\[*\] \ my_cpu_module|GPIO6\[*\] my_cpu_module|GPIO7\[*\] my_cpu_module|GPIO8\[*\] \ my_cpu_module|GPIO9\[*\] }]] \ -to [get_registers [list {my_cpu_module|RegRes9\[*\] my_cpu_module|RegRes10\[*\]}]]
set_multicycle_path 7 -hold -end -from [get_registers [list \ {my_cpu_module|GPIO0\[*\] my_cpu_module|GPIO1\[*\] my_cpu_module|GPIO2\[*\] \ my_cpu_module|GPIO3\[*\] my_cpu_module|GPIO4\[*\] my_cpu_module|GPIO5\[*\] \ my_cpu_module|GPIO6\[*\] my_cpu_module|GPIO7\[*\] my_cpu_module|GPIO8\[*\] \ my_cpu_module|GPIO9\[*\] }]] \ -to [get_registers [list {my_cpu_module|RegRes9\[*\] my_cpu_module|RegRes10\[*\]}]] Квартус ругается, что де Warning: Ignored set_multicycle_path at DE0_PWM.SDC(141): Argument <from> is an empty collection Info: set_multicycle_path 8 -setup -end -from [get_registers [list \ {my_cpu_module|GPIO0[*] my_cpu_module|GPIO1[*] my_cpu_module|GPIO2[*] \ my_cpu_module|GPIO3[*] my_cpu_module|GPIO4[*] my_cpu_module|GPIO5[*] \ my_cpu_module|GPIO6[*] my_cpu_module|GPIO7[*] my_cpu_module|GPIO8[*] \ my_cpu_module|GPIO9[*] }]] \ -to [get_registers [list {my_cpu_module|RegRes9[*] my_cpu_module|RegRes10[*]}]] вдруг кто-то сможет меня на путь истинный наставить, помогите, пожалуйста, советом! Спасибо! ИИВ
|
|
|
|
|
Aug 7 2013, 09:59
|
ʕʘ̅͜ʘ̅ʔ
    
Группа: Свой
Сообщений: 1 008
Регистрация: 3-05-05
Пользователь №: 4 691

|
По сути сообщение о том, что квартус не может найти начальные узлы для описания ограничения. Сразу оговорюсь: я не великий специалист в квартусе, но вот что я вижу: 1. Директивы get_registers в оригинальном sdc нет. Пути тоже смешно обозначены вертикальной чертой. Подозреваю что это что-то самобытное от альтеры (но в сравнении с ucf от x. это все равно прекрасно) 2. Синтезаторы, с которыми мне приходится иметь дело, поступают так: если на этапе elaboration они видят ff, то они добавляют к имени _reg и помещают объект в структуру проекта. Возможно, квартус делает похожие изменения. Попробуйте после синтеза отыскать ваши регистры, набрав в командной строке вариации на тему get_registers [list {my_cpu_module|GPIO0\[*\]}] и get_registers [list {my_cpu_module|GPIO0_reg\[*\]}], или сохранить post-synthesys netlist и посмотреть, как регистры стали называться после синтеза. Цитата(iiv @ Aug 6 2013, 23:46)  Warning: Ignored set_multicycle_path at DE0_PWM.SDC(141): Argument <from> is an empty collection Info: set_multicycle_path 8 -setup -end -from [get_registers [list \ {my_cpu_module|GPIO0[*] my_cpu_module|GPIO1[*] my_cpu_module|GPIO2[*] \ my_cpu_module|GPIO3[*] my_cpu_module|GPIO4[*] my_cpu_module|GPIO5[*] \ my_cpu_module|GPIO6[*] my_cpu_module|GPIO7[*] my_cpu_module|GPIO8[*] \ my_cpu_module|GPIO9[*] }]] \ -to [get_registers [list {my_cpu_module|RegRes9[*] my_cpu_module|RegRes10[*]}]] Я еще не очень понимаю, как можно в регистр передать прямо из выходного порта модуля. reg signed [REG_LEN-1:0] RegRes9; .quotient(RegRes9) Но, видимо, сказываются мои ограниченные знания языка.
|
|
|
|
|
Aug 7 2013, 12:21
|
вопрошающий
    
Группа: Свой
Сообщений: 1 726
Регистрация: 24-01-11
Пользователь №: 62 436

|
Уважаемые Fat Robot и Yes, очень Вам благодарен, что помогаете и не оставляете меня наедине с моей незадачкой! Цитата(Fat Robot @ Aug 7 2013, 14:59)  reg signed [REG_LEN-1:0] RegRes9;
.quotient(RegRes9) прошляпил, так как переписывал с обычного синтаксиса (RegRes9<=GPIO6/GPIO9;) в мегафункцию, спасибо, что увидели и подсказали!!! С констрейнами, похоже я что-то глобально не понимаю. Пытался в таймквесте явно задать, получается, что в "-from" у меня возникает очень длинный список, но все равно не работает. Понятно, что команда типа set_multicycle_path 9 -setup -end -from [get_registers *] -to [get_registers *] set_multicycle_path 8 -hold -end -from [get_registers *] -to [get_registers *] слаки изгоняет, но это не то, что мне надо  То есть я, на сколько смог поразобравшись, понимаю, что во "-from" надо написать что-то типа: [get_registers [list {my_cpu:my_cpu_module|GPIO6[*] my_cpu:my_cpu_module|GPIO6[*]}]] а вот для "-to" - что-то связанное с моими выходными проводами (wire). Причем даже "-from" у меня все еще не до конца правилен, так как если взять то, что у меня во "-from" и в "-to" поставить все возможные регистры -to [get_registers *] - то слаки не исчезают  Гуру Квартуса, пожалуйста, помогите! Спасибо! ИИВ
|
|
|
|
|
Aug 7 2013, 12:36
|
ʕʘ̅͜ʘ̅ʔ
    
Группа: Свой
Сообщений: 1 008
Регистрация: 3-05-05
Пользователь №: 4 691

|
-from {port | pin | clock | instance} Selects all paths that start from the specified start points. The start points can be input ports of your design, clock pins of flip-flops, clock objects, instances, or a combination of these. Specify a Tcl list. -through {port |pin | instance | net} Selects all paths that traverse through the specified points. The points to traverse can be ports of your design, hierarchical pins, pins on a sequential/mapped combinational cells, or sequential/mapped combinational instances or nets. Specify a Tcl list of start points. -to {port | pin | clock | instance} Selects all paths that end at the specified end points. The end points can be output ports of your design, clock pins of flip-flops, clock objects, instances, or a combination of these. Specify a Tcl list of end points. Наверное не стоит пытаться красиво сделать все сразу. Разберитесь сначала с одной операцией, одной парой операндов и одиним результатом. Например, деление: из GPIO6 и GPIO9 через my_dive_module/quotient (я подразумеваю, что делитель у Вас чисто комбинаторный) в RegRes9 или что там будет правильное т.е. внутри блока ваш путь будет пролегать от выхода регистра через определенное облако комбинаторной логики к входу следующего регистра. Подробнее здесь: http://acms.ucsd.edu/_files/tcoug.pdfУспехов
|
|
|
|
|
Aug 7 2013, 12:44
|
вопрошающий
    
Группа: Свой
Сообщений: 1 726
Регистрация: 24-01-11
Пользователь №: 62 436

|
Цитата(Fat Robot @ Aug 7 2013, 17:36)  -from {port | pin | clock | instance} ... -through {port |pin | instance | net} ... -to {port | pin | clock | instance} ... да, правильно, я это в доках уже много раз видел, и вроде синтаксис тикла тоже минимально мне знаком - я даже когда-то на нем оболочки рисовал, но, тут упорно не понимаю, почему написав туда имя регистра, квартус на синтаксис не ругается, но зависимость с этого регистра не мультициклит.
|
|
|
|
Сообщений в этой теме
iiv Как в одном клок-домейне сказать Квартусу, что де инструкция может выполняться несколько тактов? Aug 2 2013, 19:23 Tiro Цитата(iiv @ Aug 2 2013, 22:23) Реально я... Aug 2 2013, 22:49 Джеймс Цитата(iiv @ Aug 2 2013, 23:23) Реально я... Aug 3 2013, 06:13 iosifk Цитата(Джеймс @ Aug 3 2013, 10:13) В Ваш... Aug 3 2013, 07:48    Timmy Цитата(iiv @ Aug 6 2013, 23:46) set_multi... Aug 7 2013, 16:18     iiv Уважаемые друзья,
огромное Вам спасибо за помощь... Aug 13 2013, 08:52      Fat Robot Еще раз:
-through {port |pin | instance | net}
Se... Aug 13 2013, 10:05 yes советую констрейны (то есть то, что патерн со * чт... Aug 7 2013, 11:17
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|