Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Особенности логики
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Разработка цифровых, аналоговых, аналого-цифровых ИС
drozel
Добрый день. Пытаюсь адаптировать свой 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 раза.
Не имеет ли второй вариант каких-то подводных камней?
masics
1. Словестное описание не соответствует verilog'у.
2. Во втором варианте нет прибавления к счетчику.
3. Во втором случае mode будет меняться на 1 клок позже. (возможно, нужно будет сравнивать с 99 и 199)
drozel
Цитата(masics @ Dec 17 2015, 17:32) *
1. Словестное описание не соответствует verilog'у.
2. Во втором варианте нет прибавления к счетчику.
3. Во втором случае mode будет меняться на 1 клок позже. (возможно, нужно будет сравнивать с 99 и 199)

1. Сорри, делал второпях, не суть, просто пример. Поправил.
2. Опять же недоглядел. Поправил.
3. Опять суть в константах, не критично.

Спасибо, из вашего ответа следует "и так и так можно делать, т.к. второй вариант более экономичен, можно и нужно делать по второму варианту"?
masics
Да. Так лучше со всех сторон. Включая timing.
iosifk
Цитата(drozel @ Dec 17 2015, 11:15) *
always @*
begin
if(cnt<100) mode <= 0;
else if(cnt <200) mode <= 1;
else mode <= 2;
end[/code]



Не имеет ли второй вариант каких-то подводных камней?

Вот первый вариант - асинхронный. И он-то как раз "имеет", потому как "cnt" переключается далеко не одновременно. Да и еще компаратор свое добавит. А потому "mode" может переключаться как угодно из-за гонки фронтов... В зависимости от погоды и настроения...
drozel
Цитата(iosifk @ Dec 17 2015, 18:51) *
Вот первый вариант - асинхронный. И он-то как раз "имеет", потому как "cnt" переключается далеко не одновременно. Да и еще компаратор свое добавит. А потому "mode" может переключаться как угодно из-за гонки фронтов... В зависимости от погоды и настроения...

Хорошее замечание, спасибо.
Кстати, отловил еще одно отличие: в синхронном примере нет насыщения счетчика. После того, как добавил, площадь второго варианта стала почти в 1.5 раза больше. Т.е. синхронный более накладный. Видимо, все таки синтезер очень сильно упрощает логику сравнения, даже если речь идет о диапазонах.
Еще, в синхронном отстал один critical path.
masics
Цитата(drozel @ Dec 18 2015, 00:02) *
Хорошее замечание, спасибо.
Кстати, отловил еще одно отличие: в синхронном примере нет насыщения счетчика. После того, как добавил, площадь второго варианта стала почти в 1.5 раза больше. Т.е. синхронный более накладный. Видимо, все таки синтезер очень сильно упрощает логику сравнения, даже если речь идет о диапазонах.
Еще, в синхронном отстал один critical path.

1. дайте посмотреть на код.
2. что значит "отстал один critical path"?
drozel
Цитата(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:
Нажмите для просмотра прикрепленного файла
iosifk
Цитата(drozel @ Dec 17 2015, 16:02) *
Хорошее замечание, спасибо.
Кстати, отловил еще одно отличие: в синхронном примере нет насыщения счетчика. После того, как добавил, площадь второго варианта стала почти в 1.5 раза больше. Т.е. синхронный более накладный. Видимо, все таки синтезер очень сильно упрощает логику сравнения, даже если речь идет о диапазонах.

На самом деле не все так однозначно... Вы пишите (cnt<100)... А что будет, если не 100, а 127? И не 200, а 255? Тогда компараторы могут просто сравнивать только старшие разряды и логика значительно сократится... Т.е. если старший разряд 0, то mode = 0, если 1, то и mode = 1, а если два старших разряда 1, то mode = 2...
masics
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. Какая разница? Ну результат шифрования будет неверный, зато гейты съэкономили.

Shivers
Я бы еще посоветовал всегда полностью прописывать разрядности шин. Потому как то, что Вы не указали явно, синтезатору приходится додумывать. А чем больше он додумывает, тем больше шанс, что сделает неверно

Код
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
Цитата(masics @ Dec 17 2015, 16:17) *
Ага, давайте сделаем 128 итераций вместо 100. Какая разница? Ну результат шифрования будет неверный, зато гейты съэкономили.

никто не заставляет считать с нуля. после 128 счетчик может сразу внезапно стать 28. и тогда останутся прежние 100 шагов, а компаратор упростится =)
masics
Цитата(ZASADA @ Dec 18 2015, 05:20) *
никто не заставляет считать с нуля. после 128 счетчик может сразу внезапно стать 28. и тогда останутся прежние 100 шагов, а компаратор упростится =)

внезапно = дополнительные гейты и не факт что их будет меньше.

Цитата(Shivers @ Dec 18 2015, 02:05) *
Я бы еще посоветовал всегда полностью прописывать разрядности шин. Потому как то, что Вы не указали явно, синтезатору приходится додумывать. А чем больше он додумывает, тем больше шанс, что сделает неверно

А я бы такого не делал. Будет очень сложно потом увеличить разрядность или что-то поменять. Синтесайзер достаточно умный чтобы такие вещи понимать.
drozel
Цитата(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 подключил к этому блоку.
masics
Цитата(drozel @ Dec 18 2015, 15:29) *
а a,b,c - не объявлены заранее. Синтезатор создает их сам, только все шириной 1 бит. Потом только в RTL или в симуляции докапываешься, в чем дело.

Есть замечательная директива
Код
`implicit_nettype none

drozel
Цитата(masics @ Dec 18 2015, 10:34) *
Есть замечательная директива
Код
`implicit_nettype none

Жаль, тут нет репутации пользователей, как на ixbt или 4pda. Очень полезная вещь.
Спасибо rolleyes.gif
Shivers
Цитата(masics @ Dec 18 2015, 05:34) *
А я бы такого не делал. Будет очень сложно потом увеличить разрядность или что-то поменять. Синтесайзер достаточно умный чтобы такие вещи понимать.

1. Сложности нет, для "увеличить разрядность" существуют параметры.
2. На мой вкус, постоянный контроль за разрядностью позволяет лучше чувствовать код, держать все в голове. Так легче не-накосячить.
3. И главный аргумент: на конструкции вида cnt <= cnt + 1; синтезатор будет ругаться, что не равны разрядности операндов.
masics
Цитата(Shivers @ Dec 18 2015, 17:36) *
1. Сложности нет, для "увеличить разрядность" существуют параметры.
2. На мой вкус, постоянный контроль за разрядностью позволяет лучше чувствовать код, держать все в голове. Так легче не-накосячить.
3. И главный аргумент: на конструкции вида cnt <= cnt + 1; синтезатор будет ругаться, что не равны разрядности операндов.

1. Слишком много параметров загрязняет код. Так же как и явное указание размерности.
2. Позволю не согласиться.
3. Именно поэтому я и написал: cnt <= cnt + 1'b1;
Torpeda
1) результат синтеза во многом зависит от: SDC, Fmax, включенных опций оптимизации, флурплана и.т.д
Бится за буквы в Verilog - не совсем благодарное дело в этом случае...
2) а чё это Вы не верите в способности современных супер синтезаторов-оптимизаторов?
lexx
Цитата(Shivers @ Dec 18 2015, 10:36) *
1. Сложности нет, для "увеличить разрядность" существуют параметры.
2. На мой вкус, постоянный контроль за разрядностью позволяет лучше чувствовать код, держать все в голове. Так легче не-накосячить.
3. И главный аргумент: на конструкции вида cnt <= cnt + 1; синтезатор будет ругаться, что не равны разрядности операндов.


Если брать айсики и DC, то он не ругается на такие конструкции. Линт будет ругаться на это, но в принципе можно игнорить, но посмотреть и проверить не мешает.
В любом случае (айсики) все равно потом EC прокатывать, так что можно спокойно игнорить.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.