реклама на сайте
подробности

 
 
> Как в одном клок-домейне сказать Квартусу, что де инструкция может выполняться несколько тактов?
iiv
сообщение Aug 2 2013, 19:23
Сообщение #1


вопрошающий
*****

Группа: Свой
Сообщений: 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
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
yes
сообщение Aug 5 2013, 13:37
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 198
Регистрация: 23-12-04
Пользователь №: 1 640



ну все равно мультиплексор параллельный, то есть сделайте

always @(posedge Clk)
...
tmp1<=In1Reg*In2Reg;
tmp2<=In1Reg+In2Reg;

always @*
case
3'b000: OutReg<=tmp1
....

и законстрейните мультицайклы с end в tmp1, tmp2 соответственно

Go to the top of the page
 
+Quote Post
Fat Robot
сообщение Aug 5 2013, 15:11
Сообщение #3


ʕʘ̅͜ʘ̅ʔ
*****

Группа: Свой
Сообщений: 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, и используйте его для выборки след. команды.
Go to the top of the page
 
+Quote Post
Fat Robot
сообщение Aug 5 2013, 18:16
Сообщение #4


ʕʘ̅͜ʘ̅ʔ
*****

Группа: Свой
Сообщений: 1 008
Регистрация: 3-05-05
Пользователь №: 4 691



ах, да..

Лучше всего о Synopsys Design Constraints рассказывет, как это ни странно, первоисточник: Synopsys Timing Constraints and Optimization User Guide из SOLD.

Все остальное - эпигонство, на которое не надо тратить время.
Go to the top of the page
 
+Quote Post
iiv
сообщение Aug 6 2013, 19:46
Сообщение #5


вопрошающий
*****

Группа: Свой
Сообщений: 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[*]}]]



вдруг кто-то сможет меня на путь истинный наставить, помогите, пожалуйста, советом!

Спасибо!

ИИВ
Go to the top of the page
 
+Quote Post
Timmy
сообщение Aug 7 2013, 16:18
Сообщение #6


Знающий
****

Группа: Участник
Сообщений: 835
Регистрация: 9-08-08
Из: Санкт-Петербург
Пользователь №: 39 515



Цитата(iiv @ Aug 6 2013, 23:46) *
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\[*\]}]][/code]

Здесь ошибка в синтаксисе TCL. Во-первых, строка из фигурных скобочек передаётся в команду list, которая снова заворачивает эту строку в фигурные скобочки, создавая список в списке, и передаёт дальше в get_registers, которая резонно возвращает пустую коллекцию, так как ожидает увидеть список имён, не завёрнутый в скобочки. Во-вторых, внутри фигурных скобочек никакие подстановки не производятся, поэтому ставить обратные слэши перед квадратными скобками в этом случае не нужно. Тут надо либо убрать [list] и бэкслэши, либо убрать фигурные скобки. В среде Timequest можно посмотреть список всех активированных констрейнов с их параметрами, а также, если в TCL-консоли ввести команду puts c какой-нибудь строкой, можно посмотреть, во что эта строка на самом деле превращается. И лучше изучить TCL поближе, там есть много всего интересного.
Кроме того, полезно включить в имена всех мультицикловых сигналов общие суффиксы, уникальные для каждого варианта задержки(на 2,3,4 цикла и т.д), которые и использовать в шаблоне при задании констрейнов.
Go to the top of the page
 
+Quote Post
iiv
сообщение Aug 13 2013, 08:52
Сообщение #7


вопрошающий
*****

Группа: Свой
Сообщений: 1 726
Регистрация: 24-01-11
Пользователь №: 62 436



Уважаемые друзья,

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

Действительно было несколько багов - как заметил Timmy - баг в тикле, и баг в том, что мегафункцию я собрал с конвейером, но комментарий Fat Robotа
Цитата
т.е. внутри блока ваш путь будет пролегать от выхода регистра через определенное облако комбинаторной логики к входу следующего регистра.

помог мне над этим задуматься.

Исправив эти мои ошибки мультицикл у меня успешно заработал.

Поигравшись с этим заметил одну неприятную вещь - если имеется мегафункция не только на комбинаторной логике, но и с конвейером, то поместить вызов ее в мультицикл не получается - это вроде теперь понятно, так как путь должен идти от одного регистра до другого, то есть надо использовать опции -throu. Но, чтобы ее использовать, надо знать названия промежуточных регистров. А как их узнать, если мегафункция не в сорсах, или есть более элегантный метод помещения в мультицикл конвейерной мегафункции, вдруг кто знает, скажите, пожалуйста!

Спасибо

ИИВ
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- 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
|- - Fat Robot   По сути сообщение о том, что квартус не может найт...   Aug 7 2013, 09:59
||- - iiv   Уважаемые Fat Robot и Yes, очень Вам благодарен, ...   Aug 7 2013, 12:21
||- - Fat Robot   -from {port | pin | clock | instance} Selects all ...   Aug 7 2013, 12:36
||- - iiv   Цитата(Fat Robot @ Aug 7 2013, 17:36) -fr...   Aug 7 2013, 12:44
|- - Fat Robot   Еще раз: -through {port |pin | instance | net} Se...   Aug 13 2013, 10:05
- - yes   советую констрейны (то есть то, что патерн со * чт...   Aug 7 2013, 11:17


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 00:31
Рейтинг@Mail.ru


Страница сгенерированна за 0.01453 секунд с 7
ELECTRONIX ©2004-2016