|
Особенности логики, Вопросы по проектированию RTL |
|
|
|
Dec 17 2015, 08:15
|
Частый гость
 
Группа: Свой
Сообщений: 108
Регистрация: 2-02-11
Пользователь №: 62 650

|
Добрый день. Пытаюсь адаптировать свой verilog, проверенный на fpga, для реализации в кремнии. Периодически возникают те или иные вопросы, ответ на которые хочется найти тут, у спецов. Первый вопрос: Представим 8-разрядный счетчик, считающий по клоку. По достижению им числа 100 нужно переключиться в режим 1, по достижению 200 - в режим 2 и остаться в нем до сброса. Раньше, в ПЛИС (в связи с избыточностью ячеек), я бы сделал так: Код reg [7:0]cnt; always @(posedge clk, negedge nrst) begin if (~nrst) cnt <= 0; else begin if(cnt<200) cnt <=cnt + 1'b1; end end
always @* begin if(cnt<100) mode <= 0; else if(cnt <200) mode <= 1; else mode <= 2; end Теперь, представляю, во что выльется этот код: синтезатор реализует 3 компаратора (причем для определения диапазона) из простых элементов для декодирования значения счетчика. Думаю, как упростить схему. Рождается код: Код reg [7:0]cnt; always @(posedge clk, negedge nrst) begin if (~nrst) begin cnt <= 0; mode <= 0; end else begin cnt <= cnt+1; if(cnt==100 || cnt==200) mode <= mode+1; end end Тут уже компарирование не диапазона, а конкретных значений, зато логика mode становится синхронной. Проверил в DC - действительно, экономия по площади и кол-ву ячеек - почти в 2 раза. Не имеет ли второй вариант каких-то подводных камней?
Сообщение отредактировал drozel - Dec 17 2015, 11:51
|
|
|
|
|
Dec 17 2015, 11:53
|
Частый гость
 
Группа: Свой
Сообщений: 108
Регистрация: 2-02-11
Пользователь №: 62 650

|
Цитата(masics @ Dec 17 2015, 17:32)  1. Словестное описание не соответствует verilog'у. 2. Во втором варианте нет прибавления к счетчику. 3. Во втором случае mode будет меняться на 1 клок позже. (возможно, нужно будет сравнивать с 99 и 199) 1. Сорри, делал второпях, не суть, просто пример. Поправил. 2. Опять же недоглядел. Поправил. 3. Опять суть в константах, не критично. Спасибо, из вашего ответа следует "и так и так можно делать, т.к. второй вариант более экономичен, можно и нужно делать по второму варианту"?
|
|
|
|
|
Dec 17 2015, 13:02
|
Частый гость
 
Группа: Свой
Сообщений: 108
Регистрация: 2-02-11
Пользователь №: 62 650

|
Цитата(iosifk @ Dec 17 2015, 18:51)  Вот первый вариант - асинхронный. И он-то как раз "имеет", потому как "cnt" переключается далеко не одновременно. Да и еще компаратор свое добавит. А потому "mode" может переключаться как угодно из-за гонки фронтов... В зависимости от погоды и настроения... Хорошее замечание, спасибо. Кстати, отловил еще одно отличие: в синхронном примере нет насыщения счетчика. После того, как добавил, площадь второго варианта стала почти в 1.5 раза больше. Т.е. синхронный более накладный. Видимо, все таки синтезер очень сильно упрощает логику сравнения, даже если речь идет о диапазонах. Еще, в синхронном отстал один critical path.
|
|
|
|
|
Dec 17 2015, 13:05
|
Местный
  
Группа: Свой
Сообщений: 399
Регистрация: 21-02-05
Из: Melbourne, Australia
Пользователь №: 2 779

|
Цитата(drozel @ Dec 18 2015, 00:02)  Хорошее замечание, спасибо. Кстати, отловил еще одно отличие: в синхронном примере нет насыщения счетчика. После того, как добавил, площадь второго варианта стала почти в 1.5 раза больше. Т.е. синхронный более накладный. Видимо, все таки синтезер очень сильно упрощает логику сравнения, даже если речь идет о диапазонах. Еще, в синхронном отстал один critical path. 1. дайте посмотреть на код. 2. что значит "отстал один critical path"?
|
|
|
|
|
Dec 17 2015, 13:09
|
Частый гость
 
Группа: Свой
Сообщений: 108
Регистрация: 2-02-11
Пользователь №: 62 650

|
Цитата(masics @ Dec 17 2015, 19:05)  1. дайте посмотреть на код. 2. что значит "отстал один critical path"? Код module top ( input clk, input nrst, output reg [1:0]mode );
reg [7:0]cnt; always @(posedge clk, negedge nrst) begin if (~nrst) begin cnt <= 0; mode <= 0; end else begin if(cnt<200) cnt <= cnt + 1; if(cnt==99 || cnt==199) mode <= mode+1; end end
endmodule Вы говорили про тайминги. Я не до конца понял, что Вы имели ввиду, посмотрел отчет по slack. У варианта 2 они чуть лучше, кроме одного пути: младший бит cnt - сумматор - старший бит через логику. К слову про глитчи: предположим, что на выходе mode еще одна защелка, которая защелкивает по окончанию счета. Вариант 2:
Вариант 1:
Сообщение отредактировал drozel - Dec 17 2015, 13:13
|
|
|
|
|
Dec 17 2015, 13:13
|
Гуру
     
Группа: Модераторы
Сообщений: 4 011
Регистрация: 8-09-05
Из: спб
Пользователь №: 8 369

|
Цитата(drozel @ Dec 17 2015, 16:02)  Хорошее замечание, спасибо. Кстати, отловил еще одно отличие: в синхронном примере нет насыщения счетчика. После того, как добавил, площадь второго варианта стала почти в 1.5 раза больше. Т.е. синхронный более накладный. Видимо, все таки синтезер очень сильно упрощает логику сравнения, даже если речь идет о диапазонах. На самом деле не все так однозначно... Вы пишите (cnt<100)... А что будет, если не 100, а 127? И не 200, а 255? Тогда компараторы могут просто сравнивать только старшие разряды и логика значительно сократится... Т.е. если старший разряд 0, то mode = 0, если 1, то и mode = 1, а если два старших разряда 1, то mode = 2...
--------------------
www.iosifk.narod.ru
|
|
|
|
|
Dec 17 2015, 13:17
|
Местный
  
Группа: Свой
Сообщений: 399
Регистрация: 21-02-05
Из: Melbourne, Australia
Пользователь №: 2 779

|
1. А если поменять "if(cnt<200) cnt <= cnt + 1;" на "if(mode != 2) cnt <= cnt + 1'b1;"? 2. Для такого маленького дизайна не стоит обращать на critical path. В любом случае, это всё поменяется при placement. Цитата(iosifk @ Dec 18 2015, 00:13)  На самом деле не все так однозначно... Вы пишите (cnt<100)... А что будет, если не 100, а 127? И не 200, а 255? Тогда компараторы могут просто сравнивать только старшие разряды и логика значительно сократится... Т.е. если старший разряд 0, то mode = 0, если 1, то и mode = 1, а если два старших разряда 1, то mode = 2... Ага, давайте сделаем 128 итераций вместо 100. Какая разница? Ну результат шифрования будет неверный, зато гейты съэкономили.
|
|
|
|
|
Dec 17 2015, 15:05
|

Знающий
   
Группа: Свой
Сообщений: 680
Регистрация: 11-02-08
Из: Msk
Пользователь №: 34 950

|
Я бы еще посоветовал всегда полностью прописывать разрядности шин. Потому как то, что Вы не указали явно, синтезатору приходится додумывать. А чем больше он додумывает, тем больше шанс, что сделает неверно Код begin if (~nrst) begin cnt[7:0] <= 8'h0; mode[1:0] <= 2'h0; end else begin if(cnt[7:0]<200) cnt[7:0] <= cnt[7:0] + 8'h1; if(cnt[7:0]==99 || cnt[7:0]==199) mode[1:0] <= mode[1:0]+2'h1; end end На мой взгляд, особенность кода для эсика в том, чтобы не возникло разночтений с точки зрения восприятия кода синтезатором. Поэтому писать желательно кандово, используя стандартные конструкции. Еще один пример кандовости - если у вас always со сбросом, то в нем должны быть только регистры со сбросом. И если понадобится регистр без сброса, то его желательно выделить в отдельный always. ну и т.д. Виртуозы верилога меня наверняка запинают ногами, но такой кандовый стиль выверен временем, и позволяет впоследствии сэкономить много сил на дебаге.
|
|
|
|
|
Dec 18 2015, 02:34
|
Местный
  
Группа: Свой
Сообщений: 399
Регистрация: 21-02-05
Из: Melbourne, Australia
Пользователь №: 2 779

|
Цитата(ZASADA @ Dec 18 2015, 05:20)  никто не заставляет считать с нуля. после 128 счетчик может сразу внезапно стать 28. и тогда останутся прежние 100 шагов, а компаратор упростится =) внезапно = дополнительные гейты и не факт что их будет меньше. Цитата(Shivers @ Dec 18 2015, 02:05)  Я бы еще посоветовал всегда полностью прописывать разрядности шин. Потому как то, что Вы не указали явно, синтезатору приходится додумывать. А чем больше он додумывает, тем больше шанс, что сделает неверно А я бы такого не делал. Будет очень сложно потом увеличить разрядность или что-то поменять. Синтесайзер достаточно умный чтобы такие вещи понимать.
|
|
|
|
|
Dec 18 2015, 04:29
|
Частый гость
 
Группа: Свой
Сообщений: 108
Регистрация: 2-02-11
Пользователь №: 62 650

|
Цитата(masics @ Dec 17 2015, 19:17)  1. А если поменять "if(cnt<200) cnt <= cnt + 1;" на "if(mode != 2) cnt <= cnt + 1'b1;"? Попробовал. Ожидаемо уменьшилось кол-во гейтов: теперь на входе каждого регистра-счетчика - по мультиплексору 2 в 1. На вход управления приходит mode[1]. Т.е. по сравнению с предыдущим вариантом просто упростилась логика определения условия остановки. Спасибо за идею. Цитата(Shivers @ Dec 17 2015, 21:05)  Я бы еще посоветовал всегда полностью прописывать разрядности шин. Потому как то, что Вы не указали явно, синтезатору приходится додумывать. А чем больше он додумывает, тем больше шанс, что сделает неверно Я на FPGA частенько напарывался на такую глупую ошибку: есть готовый модуль с шиной на выходе Код module mod1( input [7:0]a, output c, output [7:0]b); используешь его в проекте, пишешь Код mod1 mod( .a(a), .c(c), .b(b); а a,b,c - не объявлены заранее. Синтезатор создает их сам, только все шириной 1 бит. Потом только в RTL или в симуляции докапываешься, в чем дело. Тогда я принял за правило писать .b(b[7:0]) - так, если она не объявлена, синтезатор хотя бы ругнется. Потом пришел более опытный товарищ (гораздо более опытный) и сказал, что такое написание бъет по глазам - будто бы я только часть шины b подключил к этому блоку.
|
|
|
|
|
Dec 18 2015, 04:34
|
Местный
  
Группа: Свой
Сообщений: 399
Регистрация: 21-02-05
Из: Melbourne, Australia
Пользователь №: 2 779

|
Цитата(drozel @ Dec 18 2015, 15:29)  а a,b,c - не объявлены заранее. Синтезатор создает их сам, только все шириной 1 бит. Потом только в RTL или в симуляции докапываешься, в чем дело. Есть замечательная директива Код `implicit_nettype none
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|