drozel 0 17 декабря, 2015 Опубликовано 17 декабря, 2015 (изменено) · Жалоба Добрый день. Пытаюсь адаптировать свой 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 раза. Не имеет ли второй вариант каких-то подводных камней? Изменено 17 декабря, 2015 пользователем drozel Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
masics 0 17 декабря, 2015 Опубликовано 17 декабря, 2015 · Жалоба 1. Словестное описание не соответствует verilog'у. 2. Во втором варианте нет прибавления к счетчику. 3. Во втором случае mode будет меняться на 1 клок позже. (возможно, нужно будет сравнивать с 99 и 199) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
drozel 0 17 декабря, 2015 Опубликовано 17 декабря, 2015 · Жалоба 1. Словестное описание не соответствует verilog'у. 2. Во втором варианте нет прибавления к счетчику. 3. Во втором случае mode будет меняться на 1 клок позже. (возможно, нужно будет сравнивать с 99 и 199) 1. Сорри, делал второпях, не суть, просто пример. Поправил. 2. Опять же недоглядел. Поправил. 3. Опять суть в константах, не критично. Спасибо, из вашего ответа следует "и так и так можно делать, т.к. второй вариант более экономичен, можно и нужно делать по второму варианту"? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
masics 0 17 декабря, 2015 Опубликовано 17 декабря, 2015 · Жалоба Да. Так лучше со всех сторон. Включая timing. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iosifk 3 17 декабря, 2015 Опубликовано 17 декабря, 2015 · Жалоба always @* begin if(cnt<100) mode <= 0; else if(cnt <200) mode <= 1; else mode <= 2; end[/code] Не имеет ли второй вариант каких-то подводных камней? Вот первый вариант - асинхронный. И он-то как раз "имеет", потому как "cnt" переключается далеко не одновременно. Да и еще компаратор свое добавит. А потому "mode" может переключаться как угодно из-за гонки фронтов... В зависимости от погоды и настроения... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
drozel 0 17 декабря, 2015 Опубликовано 17 декабря, 2015 · Жалоба Вот первый вариант - асинхронный. И он-то как раз "имеет", потому как "cnt" переключается далеко не одновременно. Да и еще компаратор свое добавит. А потому "mode" может переключаться как угодно из-за гонки фронтов... В зависимости от погоды и настроения... Хорошее замечание, спасибо. Кстати, отловил еще одно отличие: в синхронном примере нет насыщения счетчика. После того, как добавил, площадь второго варианта стала почти в 1.5 раза больше. Т.е. синхронный более накладный. Видимо, все таки синтезер очень сильно упрощает логику сравнения, даже если речь идет о диапазонах. Еще, в синхронном отстал один critical path. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
masics 0 17 декабря, 2015 Опубликовано 17 декабря, 2015 · Жалоба Хорошее замечание, спасибо. Кстати, отловил еще одно отличие: в синхронном примере нет насыщения счетчика. После того, как добавил, площадь второго варианта стала почти в 1.5 раза больше. Т.е. синхронный более накладный. Видимо, все таки синтезер очень сильно упрощает логику сравнения, даже если речь идет о диапазонах. Еще, в синхронном отстал один critical path. 1. дайте посмотреть на код. 2. что значит "отстал один critical path"? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
drozel 0 17 декабря, 2015 Опубликовано 17 декабря, 2015 (изменено) · Жалоба 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: Изменено 17 декабря, 2015 пользователем drozel Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iosifk 3 17 декабря, 2015 Опубликовано 17 декабря, 2015 · Жалоба Хорошее замечание, спасибо. Кстати, отловил еще одно отличие: в синхронном примере нет насыщения счетчика. После того, как добавил, площадь второго варианта стала почти в 1.5 раза больше. Т.е. синхронный более накладный. Видимо, все таки синтезер очень сильно упрощает логику сравнения, даже если речь идет о диапазонах. На самом деле не все так однозначно... Вы пишите (cnt<100)... А что будет, если не 100, а 127? И не 200, а 255? Тогда компараторы могут просто сравнивать только старшие разряды и логика значительно сократится... Т.е. если старший разряд 0, то mode = 0, если 1, то и mode = 1, а если два старших разряда 1, то mode = 2... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
masics 0 17 декабря, 2015 Опубликовано 17 декабря, 2015 · Жалоба 1. А если поменять "if(cnt<200) cnt <= cnt + 1;" на "if(mode != 2) cnt <= cnt + 1'b1;"? 2. Для такого маленького дизайна не стоит обращать на critical path. В любом случае, это всё поменяется при placement. На самом деле не все так однозначно... Вы пишите (cnt<100)... А что будет, если не 100, а 127? И не 200, а 255? Тогда компараторы могут просто сравнивать только старшие разряды и логика значительно сократится... Т.е. если старший разряд 0, то mode = 0, если 1, то и mode = 1, а если два старших разряда 1, то mode = 2... Ага, давайте сделаем 128 итераций вместо 100. Какая разница? Ну результат шифрования будет неверный, зато гейты съэкономили. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Shivers 0 17 декабря, 2015 Опубликовано 17 декабря, 2015 · Жалоба Я бы еще посоветовал всегда полностью прописывать разрядности шин. Потому как то, что Вы не указали явно, синтезатору приходится додумывать. А чем больше он додумывает, тем больше шанс, что сделает неверно 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. ну и т.д. Виртуозы верилога меня наверняка запинают ногами, но такой кандовый стиль выверен временем, и позволяет впоследствии сэкономить много сил на дебаге. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ZASADA 0 17 декабря, 2015 Опубликовано 17 декабря, 2015 · Жалоба Ага, давайте сделаем 128 итераций вместо 100. Какая разница? Ну результат шифрования будет неверный, зато гейты съэкономили. никто не заставляет считать с нуля. после 128 счетчик может сразу внезапно стать 28. и тогда останутся прежние 100 шагов, а компаратор упростится =) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
masics 0 18 декабря, 2015 Опубликовано 18 декабря, 2015 · Жалоба никто не заставляет считать с нуля. после 128 счетчик может сразу внезапно стать 28. и тогда останутся прежние 100 шагов, а компаратор упростится =) внезапно = дополнительные гейты и не факт что их будет меньше. Я бы еще посоветовал всегда полностью прописывать разрядности шин. Потому как то, что Вы не указали явно, синтезатору приходится додумывать. А чем больше он додумывает, тем больше шанс, что сделает неверно А я бы такого не делал. Будет очень сложно потом увеличить разрядность или что-то поменять. Синтесайзер достаточно умный чтобы такие вещи понимать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
drozel 0 18 декабря, 2015 Опубликовано 18 декабря, 2015 · Жалоба 1. А если поменять "if(cnt<200) cnt <= cnt + 1;" на "if(mode != 2) cnt <= cnt + 1'b1;"? Попробовал. Ожидаемо уменьшилось кол-во гейтов: теперь на входе каждого регистра-счетчика - по мультиплексору 2 в 1. На вход управления приходит mode[1]. Т.е. по сравнению с предыдущим вариантом просто упростилась логика определения условия остановки. Спасибо за идею. Я бы еще посоветовал всегда полностью прописывать разрядности шин. Потому как то, что Вы не указали явно, синтезатору приходится додумывать. А чем больше он додумывает, тем больше шанс, что сделает неверно Я на 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 подключил к этому блоку. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
masics 0 18 декабря, 2015 Опубликовано 18 декабря, 2015 · Жалоба а a,b,c - не объявлены заранее. Синтезатор создает их сам, только все шириной 1 бит. Потом только в RTL или в симуляции докапываешься, в чем дело. Есть замечательная директива `implicit_nettype none Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться