Comments 39
UFO just landed and posted this here
UFO just landed and posted this here
А вас не удивляет, что в комбинационной логике присвоение происходит переменной, объявленной как регистр?
Компилятор не по этим признакам определит что ему использовать: триггер или LUT. Для него важнее список чувствительности always.
Компилятор не по этим признакам определит что ему использовать: триггер или LUT. Для него важнее список чувствительности always.
0
UFO just landed and posted this here
Даже если поставить <= синтезатор будет использовать LUT, если список чувствительности включает все сигналы, например так:
Если сигнал в списке чувствительности указан явно и не используется в качестве информационного в потоке, то он будет воспринят как clk или асинхронный сброс/установка. В этом случаи будет использован триггер.
Когда пишешь код для синтеза нужно знать не только особенность стандарта Verilog, но и архитектуру аппаратной платформы, как минимум, устройство логического элемента — что допустимо для Стратикса, пойдет на Циклоне со скрипом.
always @*
. Если вы собираетесь делать именно комбинационное устройство, то все входные сигналы должны быть в списке чувствительности, а все мультиплексоры (операторы if, case, ?:) должны иметь явную ветвь default. Если сигнал в списке чувствительности указан явно и не используется в качестве информационного в потоке, то он будет воспринят как clk или асинхронный сброс/установка. В этом случаи будет использован триггер.
Когда пишешь код для синтеза нужно знать не только особенность стандарта Verilog, но и архитектуру аппаратной платформы, как минимум, устройство логического элемента — что допустимо для Стратикса, пойдет на Циклоне со скрипом.
0
UFO just landed and posted this here
Я тут мимо проходил, и на верилоге почти не пишу, поэтому не могу сказать, где код ужасен, а где нет, но хотел бы научиться отличаться ужасный код от нормального и толковые комментарии от профессионалов могли бы в этом помочь. Вместо них у вас тут «и так понятно».
Посмотрите для примера на комментарии тов. khim, он тоже не терпит говнокода, но при этом не ленится пояснять почему конкретный код — говно и что с этим можно сделать. В итоге в выигрыше все, и автор, и комментатор, и читатели.
TL;DR: Критикуешь — предлагай.
Посмотрите для примера на комментарии тов. khim, он тоже не терпит говнокода, но при этом не ленится пояснять почему конкретный код — говно и что с этим можно сделать. В итоге в выигрыше все, и автор, и комментатор, и читатели.
TL;DR: Критикуешь — предлагай.
+2
Как говорится, я, конечно, не гинеколог, но посмотреть могу… Я не профессионал, но могу пару общих правил привести, по возможности, с примером ошибки из кода:
1. Необходимо чётко знать, какой тип схемы должен получиться из куска кода: синхронная, защёлка или комбинационная. Для каждого типа есть свои правила написания кода, их я ниже изложу
2. В синхронной схеме нужно использовать только неблокирующие присваивания, т.е. <=
В приведённом коде этот кусок с ошибкой
…
always @(negedge clock)
begin
if(PS2_CLK_in == 1)
count_clk = count_clk + 1;
else
…
3. В комбинационной только блокирующие =
В приведённом коде этот кусок с ошибкой
…
always @*
begin
visible <= hvisible & vvisible;
end
…
4. Все возможные ветви комбинационного кода должны быть описаны, иначе получится защёлка. Например, если у вас кейс по 4х-битной переменной, нужно либо описать все 16 ветвей либо добавить ветку default для всех неописанных.
Если получилась где-то защёлка, где вы не собирались её создавать (вы это увидите в варнингах), то скорее всего, код косячный.
Ещё по коду увидел такую вещь: синхронизация дисплея берётся с выхода комбинационной схемы
…
wire w_hsync = (pixel_count < h_sync);
…
Выход комбинационной схемы может давать иголки из-за неодновременного переключения составляющих логических элементов, поэтому их всегда надо пропускать через синхронизатор, прежде чем заводить куда-то дальше в синхронных схемах
1. Необходимо чётко знать, какой тип схемы должен получиться из куска кода: синхронная, защёлка или комбинационная. Для каждого типа есть свои правила написания кода, их я ниже изложу
2. В синхронной схеме нужно использовать только неблокирующие присваивания, т.е. <=
В приведённом коде этот кусок с ошибкой
…
always @(negedge clock)
begin
if(PS2_CLK_in == 1)
count_clk = count_clk + 1;
else
…
3. В комбинационной только блокирующие =
В приведённом коде этот кусок с ошибкой
…
always @*
begin
visible <= hvisible & vvisible;
end
…
4. Все возможные ветви комбинационного кода должны быть описаны, иначе получится защёлка. Например, если у вас кейс по 4х-битной переменной, нужно либо описать все 16 ветвей либо добавить ветку default для всех неописанных.
Если получилась где-то защёлка, где вы не собирались её создавать (вы это увидите в варнингах), то скорее всего, код косячный.
Ещё по коду увидел такую вещь: синхронизация дисплея берётся с выхода комбинационной схемы
…
wire w_hsync = (pixel_count < h_sync);
…
Выход комбинационной схемы может давать иголки из-за неодновременного переключения составляющих логических элементов, поэтому их всегда надо пропускать через синхронизатор, прежде чем заводить куда-то дальше в синхронных схемах
+7
Большое спасибо. Плюсанул бы вам в карму с удовольствием, но у вас статей нет. Напишите что-нибудь о верилоге и FPGA, если найдете время.
0
При всем уважении, почему в комбинационном только блокирующие?
В моей практике часто бывает, когда комбинационную схему приходится делать регистровой, например, если по времянке не проходит, то добавляю еще одно звено конвейера. В этом случае просто редактируется список чувствительности
Лично я стараюсь использую везде неблокирующие присваивания, и только там, где это действительно нужно использую блокирующие, причем это бывает и в синхронных схемах. Другим так делать не рекомендую, потому как не уверен в своей правоте.
В моей практике часто бывает, когда комбинационную схему приходится делать регистровой, например, если по времянке не проходит, то добавляю еще одно звено конвейера. В этом случае просто редактируется список чувствительности
always
, но если там везде блокирующие присваивания, то придется менять и их. А потом удалось оптимизировать где-то еще, и захотелось вернуться к комбинационной схеме… Вероятность допустить ошибку повышается. Лично я стараюсь использую везде неблокирующие присваивания, и только там, где это действительно нужно использую блокирующие, причем это бывает и в синхронных схемах. Другим так делать не рекомендую, потому как не уверен в своей правоте.
0
Я сразу указал, что я не профессионал, поэтому не могу ответить на это) читал в книгах и слышал от разбирающихся людей, что в комб. логике не следует использовать неблокирующие присваивания.
Я пишу на SystemVerilog, там можно явно указать, какая логика требуется: флип-флопы, защёлки или комбинационная ( always_ff, always_latch, always_comb) соответственно. У 2 и 3 списка чувствительности нет в принципе.
Я пишу на SystemVerilog, там можно явно указать, какая логика требуется: флип-флопы, защёлки или комбинационная ( always_ff, always_latch, always_comb) соответственно. У 2 и 3 списка чувствительности нет в принципе.
0
UFO just landed and posted this here
Я думал это написать, но не смог внятно сформулировать) Насколько я понял, при использовании блокирующих присваиваний важен порядок строк в коде, и тогда если написать
b = c;
a = b;
то для компилятора переменная b уже будет как бы «определена», а её значение равно c. И он подставит c вместо b во всех строках, идущих после.
b = c;
a = b;
то для компилятора переменная b уже будет как бы «определена», а её значение равно c. И он подставит c вместо b во всех строках, идущих после.
0
Пару замечаний.
>1. Необходимо чётко знать, какой тип схемы должен получиться из куска кода: синхронная, защёлка или комбинационная.
Согласен, кроме того, что защелок следует избегать.
>2. В синхронной схеме нужно использовать только неблокирующие присваивания, т.е.
>1. Необходимо чётко знать, какой тип схемы должен получиться из куска кода: синхронная, защёлка или комбинационная.
Согласен, кроме того, что защелок следует избегать.
>2. В синхронной схеме нужно использовать только неблокирующие присваивания, т.е.
0
Я не автор, но спрошу — какие в этом проблемы? Я в HDL языках нуб полнейший, не понял, чему вы так ужасаетесь.
0
отличное упражнение написать игру пинг понг на любом языке программирования. В один тред. С AI на генеративных функциях (иногда ошибается) и с Command pattern'ом.
Хорошая задача, нормальный студент должен суметь кое-как написать.
Вот тут ныли-ныли, что они не хотят быть «мясом» и писать на го. А вот идите ка на своей скале напишите хоть пинг-понг. И покажите и поговорим тогда.
Хорошая задача, нормальный студент должен суметь кое-как написать.
Вот тут ныли-ныли, что они не хотят быть «мясом» и писать на го. А вот идите ка на своей скале напишите хоть пинг-понг. И покажите и поговорим тогда.
-7
За тематику плюсую. Но к оформлению проекта и кода есть много вопросов. Какая религия не позволила сделать проект полностью на HDL, зачем Top Level в Schematic? Зачем в тексте кода так много Magic number? Но не оставляет ощущение, что вы до сих пор пишете на Си: много begin-end, сложные логические конструкции. Множество приоритетных мультиплексоров на if с неявными else. Вам компилятор про Latch предупреждение не выдавал?
P.S.: Недостаток запятых в тексте делает чтение не комфортным.
P.S.: Недостаток запятых в тексте делает чтение не комфортным.
+2
Привет! Отличная статья, хорошая мотивация для новичков, в т.ч. и меня.
Попробуйте в тестбенчах для генерации клока такую конструкцию:
initial begin
#0 clock_r = 1;
//…
end
always begin
#x clock_r
Попробуйте в тестбенчах для генерации клока такую конструкцию:
initial begin
#0 clock_r = 1;
//…
end
always begin
#x clock_r
0
Не уловил смысл, того что предлагаете сделать.
0
Красивая девушка.
0
Не требовалось ли в рамках этого конкурса использовать процессор MIPSfpga для решения задачи?
Коли спрашиваете, даю советы:
YuriPanchul, вы как-то модерируете (ревьюите) проекты (и исходные коды), которые потом попадают к вам на гитхаб?
PS: в мир FPGA вошел недавно, очень извиняюсь перед более опытными людьми которым мой код выжег глаза. Прошу понять, простить, помочь советом.
Коли спрашиваете, даю советы:
- Прочитать «Совершенный код» Макконнелла.
- Найти в интернете или взять какой-то готовый coding-style по Verilog'у. На правах рекламы показываю тот, которым руководствуюсь я. (Версия не самая полная, я еще кое-чего там буду дописывать).
- Не путать блокирующие и неблокирующие присваивания.
- Разобраться, какие файлы надо класть в систему контроля версий, а какие нет. Невооруженным взглядом видно, что много мусорных файлов (например, директория db) лежит в проекте.
- Для описания констрейнов (например, значений частот у клоков в системе) не использовался sdc-файл. По отчету project_1.sta.rpt видно, что клоки clk:inst4|clock_out[17] и PS2_CLK взяты с частотой 1 ГГц, что на самом деле, конечно не так.
YuriPanchul, вы как-то модерируете (ревьюите) проекты (и исходные коды), которые потом попадают к вам на гитхаб?
+1
Спасибо за coding-style. А на какой-либо площадке предполагается обсуждение и вопросы? Может статью на Хабр заделаете?
Мне кое-что не ясно, есть спорные моменты. Например, чем не угодил вам TAB? Много где встречаю, что вместо него пробелами ровняют, но почему? Переносимость между редакторами?
Мне кое-что не ясно, есть спорные моменты. Например, чем не угодил вам TAB? Много где встречаю, что вместо него пробелами ровняют, но почему? Переносимость между редакторами?
0
Кодинг стайл состоит из двух вещей: субъективной (расстановка скобок, пробелов, выравнивание, конвенция о наименовании переменных) и объективной (к примеру, корректное использование присваиваний).
ИМХО, большая часть кодинг стайла — субъективная, и обсуждать её я не вижу особого смысла.
Два примера с if:
Кому-то больше нравится первый вариант, вариант кому-то второй. Это абсолютно нормально: и я не вижу смысла тратить время на холивары.
Пробелы гарантируют одинаковое отображение исходного кода везде (при использовании monospace шрифта, разумеется), а табы — в зависимости от настроек, но это не значит, что табы должны быть запрещены: в linux kernel их используют, и я не имею права за это в них кинуть камень. У них есть свой CodingStyle, где это явно прописано.
Тот кодинг стайл, что я скинул, это компиляция опыта (~5-7 лет коммерческой разработки) и предпочтений небольшой команды FPGA-разработчиков. Этот стиль позволял быстро (за предсказуемое время), качественно разрабатывать новые модули (сам себя не похвалишь — никто не похвалит) и осуществлять дальнейшую поддержку и багфикс кода. Версия не самая полная, потому что оригинал находится в формате wiki/html, и я постепенно переношу это в markdown, причёсывая его структуру.
Я всегда рад услышать вопросы, замечания, предложения, но скатываться в холивар я не буду. Это является оффтопом к теме с созданием игры, поэтому можно писать мне в личку.
ИМХО, большая часть кодинг стайла — субъективная, и обсуждать её я не вижу особого смысла.
Два примера с if:
1. if( a > b )
2. if (a > b)
Кому-то больше нравится первый вариант, вариант кому-то второй. Это абсолютно нормально: и я не вижу смысла тратить время на холивары.
Пробелы гарантируют одинаковое отображение исходного кода везде (при использовании monospace шрифта, разумеется), а табы — в зависимости от настроек, но это не значит, что табы должны быть запрещены: в linux kernel их используют, и я не имею права за это в них кинуть камень. У них есть свой CodingStyle, где это явно прописано.
Тот кодинг стайл, что я скинул, это компиляция опыта (~5-7 лет коммерческой разработки) и предпочтений небольшой команды FPGA-разработчиков. Этот стиль позволял быстро (за предсказуемое время), качественно разрабатывать новые модули (сам себя не похвалишь — никто не похвалит) и осуществлять дальнейшую поддержку и багфикс кода. Версия не самая полная, потому что оригинал находится в формате wiki/html, и я постепенно переношу это в markdown, причёсывая его структуру.
Я всегда рад услышать вопросы, замечания, предложения, но скатываться в холивар я не буду. Это является оффтопом к теме с созданием игры, поэтому можно писать мне в личку.
0
ishevchuk в данном случае я не модерировал, рассматривая это как упражнение для Бориса, которого все равно раскритикуют. Когда он собрался публиковать, я ему сказал про проблемы с стилем (см. описание ниже) и предложил либо их исправить, либо опубликовать как есть, с идеей, что на Хабре его все равно раскритикуют.
Раз уж тут пошла критика, прибавляю своей:
Борис, я рекомендую перед публикацией привести стиль вашего кода к некоторым принятым в индустрии традициям, которые были сформулированы в районе 2000-го года (т.е. вы можете найти много старого верилога, который этому не следует, но лучше чтобы следовало). В принципе, можно публиковать и так, но вас тогда раскритикуют на Хабре (это может быть полезно, так как там много людей, и они сделают критику быстрее чем я, потому что я связан другими делами).
Но как минимум стоит избавиться от блокирующих присваиваний внутри последовательностных always-блоков. С ними можно нарваться на гонки, race-condition, когда результат симуляции может не совпасть с результатом работы платы после синтеза. Например см. мой коммент в обсуждении на https://habrahabr.ru/post/278005/
Простейший пример race condition:
А вот если делать так, то все будет однозначно:
Также использование генерируемого сигнала в качестве clock-а – это не очень хорошо:
Если вам нужно такое сгенерить, то лучше делать чего-нибудь типа (хоть это и выглядит громоздко):
Кроме этого, код типа
лучше заменить на
Наконец, есть более компактные способы записи кода в testbench:
Вместо:
Можно написать что-нибудь типа:
Но опять же: вы можете выложить as-is и посмотреть, как народ на Хабре будет реагировать (так как вы начинающий, то вашу репутацию это не испортит).
Кроме этого я рекомендую выложить ваш код на GitHub (например поместить проект в https://github.com/MIPSfpga/pre-mipsfpga ) чтобы ссылаться на ваш код из поста.
Это мои первые мысли – завтра я посмотрю ваш код более внимательно.
Спасибо,
Юрий Панчул
Раз уж тут пошла критика, прибавляю своей:
Борис, я рекомендую перед публикацией привести стиль вашего кода к некоторым принятым в индустрии традициям, которые были сформулированы в районе 2000-го года (т.е. вы можете найти много старого верилога, который этому не следует, но лучше чтобы следовало). В принципе, можно публиковать и так, но вас тогда раскритикуют на Хабре (это может быть полезно, так как там много людей, и они сделают критику быстрее чем я, потому что я связан другими делами).
Но как минимум стоит избавиться от блокирующих присваиваний внутри последовательностных always-блоков. С ними можно нарваться на гонки, race-condition, когда результат симуляции может не совпасть с результатом работы платы после синтеза. Например см. мой коммент в обсуждении на https://habrahabr.ru/post/278005/
Простейший пример race condition:
module dut ( input clk, input [7:0] d, output logic [7:0] q ); logic [7:0] r; always @(posedge clk) // ПЛОХО! Результат симуляции зависит от того, какой блок симулируется раньше в event queue – первый или второй r = d; always @(posedge clk) q = r; endmodule
А вот если делать так, то все будет однозначно:
module dut ( input clk, input [7:0] d, output logic [7:0] q ); logic [7:0] r; always @(posedge clk) r <= d; always @(posedge clk) q <= r; endmodule
Также использование генерируемого сигнала в качестве clock-а – это не очень хорошо:
always @ (posedge pixel_clock) begin hsync <= (pixel_count < h_sync); …. always @ (posedge hsync) …
Если вам нужно такое сгенерить, то лучше делать чего-нибудь типа (хоть это и выглядит громоздко):
wire hsync <= (pixel_count < h_sync); reg prev_hsync; always @ (posedge clk) prev_hsync <= hsync; … wire pos_hsync = hsync & ~ prev_hsync; …. always @ (posedge clk) if(reset) … else if (pos_hsync)
Кроме этого, код типа
if(goal == 0) begin HEX_1 = 7'b1000000; end if(goal == 1) begin HEX_1 = 7'b1111001; end if(goal == 2) begin HEX_1 = 7'b0100100; end
лучше заменить на
case (goal) 0: HEX_1 = 7'b1000000; 1: HEX_1 = 7'b1111001; 2: HEX_1 = 7'b0100100; . . . . default: HEX_1 = 7’b1111111; endcase
Наконец, есть более компактные способы записи кода в testbench:
Вместо:
#50 PS2_CLK_r = 0; //start #50 PS2_CLK_r = 0; //0 #50 PS2_CLK_r = 1; //1 #50 PS2_CLK_r = 1; //2 #50 PS2_CLK_r = 0; //3 #50 PS2_CLK_r = 1; //4 #50 PS2_CLK_r = 0; //5 #50 PS2_CLK_r = 1; //6 #50 PS2_CLK_r = 1; //7 #50 PS2_CLK_r = 1; //parity bit #50 PS2_CLK_r = 0; //stop #50 PS2_CLK_r = 1; //s #50 PS2_CLK_r = 1; //s
Можно написать что-нибудь типа:
reg [511:0] test_bits; integer i; initial begin … test_bits = 512’b01010111000110010101; for (i = 0; i < 512; i = i + 1) #50 PS2_CLK_r = test_bits [i];
Но опять же: вы можете выложить as-is и посмотреть, как народ на Хабре будет реагировать (так как вы начинающий, то вашу репутацию это не испортит).
Кроме этого я рекомендую выложить ваш код на GitHub (например поместить проект в https://github.com/MIPSfpga/pre-mipsfpga ) чтобы ссылаться на ваш код из поста.
Это мои первые мысли – завтра я посмотрю ваш код более внимательно.
Спасибо,
Юрий Панчул
+2
Спасибо за подробный ответ.
Жаль, что изначальная предпосылка такая:
Жаль, что изначальная предпосылка такая:
рассматривая это как упражнение для Бориса, которого все равно раскритикуют. Когда он собрался публиковать, я ему сказал про проблемы с стилем (см. описание ниже) и предложил либо их исправить, либо опубликовать как есть, с идеей, что на Хабре его все равно раскритикуют.
0
Коллеги, будьте объективны. Человек написал первый в жизни простенький проектик. Несмотря на объективные проблемы с кодом, довел его до работоспособного состояния (по крайней мере в данных конкретных условиях, хе-хе). Зачем же сразу зло клевать, ласковее надо… Другое дело, для чего его выкладывать сразу на общее обозрение… Я вот прошлую неделю впервые на жабаскрипте писал, но показывать код, пока, пожалуй никому не буду. Пусть лучше потом следственный комитет разбирается, отчего ракета упала.
PS Блокирующие и не блокирующие назначение при синтезе дают одит и тот же [правильный] результат в массе своей, так что проблемы только в моделировании можно заметить.
PS Блокирующие и не блокирующие назначение при синтезе дают одит и тот же [правильный] результат в массе своей, так что проблемы только в моделировании можно заметить.
+2
[quote]PS Блокирующие и не блокирующие назначение при синтезе дают один и тот же [правильный] результат в массе своей, так что проблемы только в моделировании можно заметить.[/quote]
Не совсем так.
Если под рукой есть синтезатор, тот же квартус, попробуйте написать такой код ( SystemVerilog ):
module top (
input logic rst_i,
input logic clk_i,
input logic data_i,
output logic data_o
);
logic data_between;
always_ff @( posedge clk_i or posedge rst_i ) begin
if ( rst_i ) begin
data_o <= 0;
data_between <= 0;
end else begin
data_between <= data_i;
data_o <= data_between;
end
end
endmodule
Просинтезируйте и посмотрите RTL модель, затем поменяйте неблокирующие присваивания на блокирующие, просинтезируйте и посмотрите, что будет. А будет следующее: цепочка из 2х триггеров будет «оптимизирована» и один из триггеров будет выкинут просто-напросто
Не совсем так.
Если под рукой есть синтезатор, тот же квартус, попробуйте написать такой код ( SystemVerilog ):
module top (
input logic rst_i,
input logic clk_i,
input logic data_i,
output logic data_o
);
logic data_between;
always_ff @( posedge clk_i or posedge rst_i ) begin
if ( rst_i ) begin
data_o <= 0;
data_between <= 0;
end else begin
data_between <= data_i;
data_o <= data_between;
end
end
endmodule
Просинтезируйте и посмотрите RTL модель, затем поменяйте неблокирующие присваивания на блокирующие, просинтезируйте и посмотрите, что будет. А будет следующее: цепочка из 2х триггеров будет «оптимизирована» и один из триггеров будет выкинут просто-напросто
0
Ну да, в этом-то случае естественно, когда есть прямая последовательность назначений в одном процессе.
0
Причём если поменять местами 2 строчки и написать так:
data_o <= data_between;
data_between <= data_i;
То никакой оптимизации не произойдёт)) У меня нещадно бомбило однажды от такого поведения кода
data_o <= data_between;
data_between <= data_i;
То никакой оптимизации не произойдёт)) У меня нещадно бомбило однажды от такого поведения кода
-1
Бесплатный совет всем, у кого не хватило денег на Spyglass. Используйте Verilator в Lint-режиме.
0
Sign up to leave a comment.
Создание простой игры на базе FPGA