Гаражный движ 👩🔧
По вопросам рекламы и сотрудничества - [email protected]
РКН: https://vk.cc/cHx9JD
Last updated 2 months, 1 week ago
По просьбе коллеги добавил в бенчмарк симуляторов запуск Квесты с параметром "-O5" и без параметра "+acc". Прирост скорости составил ровно 10 раз, но есть мнение, что могут быть проблемы с доступом к внутренним сигналам (через VPI/DPI или даже из верилога). Сам не проверял.
Ещё добавил запуск VCS (честно взятый "во временное пользование" на всем известном ftp) на своём компе и перезапустил все тесты. Можно заметить, что скорость работы большинства симуляторов значительно возросла - это от того, что я выключил HyperThreading. А ещё верилятор стал заметно быстрее компилировать, особенно для многопоточного варианта симуляции.
Нашел забавную ошибку в Вериляторе. При иерархической передаче строки в параметре модуля через два и более модуля строка может не дойти до конечного потребителя. Зависит это от того, указан ли, и где конкретно, тип параметра. Если во всей цепочке тип параметра отсутствует (выводится из дефолтного значения), то строка проходит. Если тип везде указан, то тоже проходит. А если во втором модуле тип не указать, то туда приходит строка той же длины, только заполненная пробелами. Причём, если её передать дальше, то она совсем обнулится.
Вот пример кода с багом:
```
module string_param_0 #(parameter S = "");
initial $display("S = '%s'", S);
endmodule
module string_param_1 #(parameter string S = "");
string_param_0 #(.S(S)) u_sp0();
endmodule
module test;
string_param_1 #(.S("Greetings from the old shoes")) u_sp1();
initial \#1 $finish;
endmodule
```
Вывод такой:
S = ' '
Если добавить тип параметра в первый модуль или убрать тип из второго, то вывод будет корректным:
S = 'Greetings from the old shoes'
Немного поигравшись с Veryl пишу отзыв. Если кратко: потенциал есть, но пока не готов.
Не буду лить воду, пойду по фактам. Плюсы языка:
➡️Полярность сброса и клока можно выбрать при сборке. Очень полезная фича, но есть некоторые проблемы с передачей этих знаний в подключаемые модули на верилоге. Есть автоматическая инверсия сброса, если в вериложном модуле сброс не той полярности. Но пока нет инверсии клока и никак не передать информацию о типе сброса - синхронный он или асинхронный.
➡️Фигурные скобки в качестве операторных скобок конечно выглядят гораздо приятней многословных begin/end
и module/endmodule
.
➡️Нет разделения на блокирующее и неблокирующее присваивание. Язык предназначен для написания только синтезируемого кода, по этому синхронные присваивания - неблокирующие, асинхронные - блокирующие.
➡️if/else
как выражение (expression). Как бы реверанс в сторону функциональных языков, но по сути синтаксический сахар над тернарным оператором.
➡️Дженерики! Наконец-то шаг в сторону метапрограммирования. Шаг скромный, но в верилоге этого очень не хватает.
➡️Есть поддержка аннотации CDC. Если вдруг вы небезопасно передаёте данные из домена в домен, транслятор даст вам по рукам.
➡️Какая-никакая стандартная библиотека с FIFO и некоторыми полезными модулями (кое кто из чата FPGA Systemc был бы очень рад).
Теперь минусы:
➡️Нет приведения ширины. Есть приведение к типу, и как бы можно объявить новый тип с нужной шириной и к нему приводить. Но это лишняя писанина, и результирующий верилог не поддерживается парсером Yosys'а. Такая вот шляпа.
➡️В конструкции вида a = {b, '1}
единица не расширяется до размера a
, и код в неизменном виде попадает в верилог. Т.е. это ошибка и в верилоге и в вериле, что несколько расстраивает. Выражение как бы очевидное, но авторы решили сохранить совместимость с верилогом. А ещё линтер на это не ругается (а Верилятор ругается).
➡️Нельзя объявить несколько переменных одного типа с одной декларации. Для каждой переменной надо писать var бла_бла: тип;
.
➡️Невозможно задать начальное значение регистру или памяти. ROM в принципе можно описать в виде const
(которое транслируется в localparam
), но RAM только через readmem. Авторы говорят, что для асиков это не нужно, а проблемы плисоводов их не волнуют. Конструкция initial
поддерживает только вывод сообщений.
По инфраструктуре. В отличие от верилога, у которого только стандарт, Veryl "из коробки" имеет форматтер, линтер и language server. Это очень удобно. Например, на добавление полноценной поддержки языка с в Emacs у меня ушли сутки. А это форматирование с отступами, подсветка синтаксиса, подсветка ошибок в реальном времени, автодополнение, хождение по коду и попапы.
Кроме перечисленного, в комплекте с транслятором есть система документирования с поддержкой markdown и wavedrom, система юнит-тестирования с интегрированными тестбенчами на верилоге, и система сборки, которая умеет подгружать зависимости.
Есть и недостатки:
➡️Нет настроек форматирования, есть только настройка длины таба.
➡️У линтера есть только настройки стиля, языковых настроек нет. Например, нет предупреждения о неявном приведении ширины.
➡️При касте сброса транслятор может менять имя сигнала, добавляя к нему префикс или суффикс (настраиваемо). При этом он это делает и для портов вериложных модулей. По этому, если включена эта опция, при имплементации вериложного модуля к именам портов клока и сброса надо прибавлять префикс r\#
. Но это скорее ошибка, которую нужно исправлять.
➡️Часто неправильно указывает положение ошибки, особенно если забыли или лишняя точка с запятой.
В общем, впечатления от языка двойственные. С одной стороны линтер, language server и дженерики. С другой - ощущение, что пишешь на верилоге с новым синтаксисом и старыми проблемами. А зачем мне старые проблемы? Мне нужны новые ?
PS: Дописывая пост заглянул в репозиторий. Две недели назад вышла новая версия, в которой добавили приведение ширины. Вот так может и допишут до продакшена.
Хорошее замечание и ещё один аргумент в ~~срачах~~ спорах про сбросы. Получается (без учёта других аргументов), что тотальный сброс можно делать любым - синхронным или асинхронным, а частичный (только control path, например) лучше синхронным, чтобы в случае чего синтезатор смог сымитировать его на логике.
В комментах товарищ @Xtyll спросил, не упала ли скорость симуляции в Вериляторе после добавления событийного шедулинга. Сообщаю: не упала.
Добавил тест Верилятора 4-й версии в свой бенчмарк - разница в результатах с версией 5 на уровне погрешности. Для надежности сделал ещё тест на реальном проекте. Там тоже разницы нет. Вот как-то так.
Про асинхронный сброс и Verilator.
Вот типичный код асинхронного сброса:
always\_ff @(posedge clk or negedge rst\_n) begin
if (!rst\_n) ...
else ...
end
Обычно, код работает так же, как в железе. Однако, если в начале симуляции нет клока, то сброс может не сработать. Так выйдет, если rst_n
присвоить 0 в нулевом времени через инициализацию в объявлении. Как можно догадаться, в этом случае события negedge rst_n
не случится, т.к. по стандарту присвоение в объявлении выполняется раньше присвоения в процессах.
Очевидное решение - в объявлении rst_n
присвоить 1 (или вообще ничего не присваивать, X->0 тоже считается за negedge
), а в initial
- 0:
logic rst\_n = 1'b1;
initial rst\_n = 1'b0;
Или так:
logic rst\_n;
initial begin
rst\_n = 1'b1;
rst\_n = 1'b0;
end
Однако, и здесь есть нюанс: Verilator не захотел регистрировать это событие, и не выполнил код процесса. Раньше такого в Вериляторе быть не могло, потому что до недавнего времени он был чисто clock-accurate симулятором. А раз клок всегда был, то события negedge rst_n
можно было не дожидаться, процесс вызвался бы при первом posedge clk
. Но сейчас он стал фактически полноценным event-driven, по этому наверное дожен справляться с такими вещами.
В связи со всем вышесказанным думаю самым правильным решением было бы присвоение rst_n
единицы, а как минимум в следующем цикле симуляции сбрасывать его в ноль:
logic rst\_n = 1'b1;
initial \#1 rst\_n = 1'b0;
Запилил issue
Вы наверное знаете, что в стандарте верилога есть ключевое слово macromodule
, которое ничем не отличается от module
, за исключением того, что "An implementation may choose to treat module definitions beginning with the macromodule keyword differently". Интересно, откуда растут ноги у этого macromodule
и используется ли где нибудь возможность интерпретировать его отлично от module
?
Я нашел документ, в котором сказано, что в macromodule
можно описывать только wire
и операции с ними. Никаких переменных/регистров и процедурных присваиваний, только assign
. Интересно, откуда эта информация, если в стандарте об этом ни слова?
Гаражный движ 👩🔧
По вопросам рекламы и сотрудничества - [email protected]
РКН: https://vk.cc/cHx9JD
Last updated 2 months, 1 week ago