В предыдущей статье я поделился опытом работы с ПЛИС фирмы Lattice через инструменты с открытым исходным кодом Yosys и NextPNR. Как я отмечал, освоить их меня заставило не столько любопытство, сколько требования Заказчика. В том проекте у меня просто не было выбора. И та статья, скорее, была написана в помощь для быстрого старта тем, кого тоже заставят. А можно ли использовать эту сцепку для дома, для семьи? Для этого она должна быть удобной.
Как мы обсудили в комментариях к прошлой статье, в минусы этой сцепке можно записать отсутствие такого полезного инструмента, как SignalTap (Altera) или ChipScope (Xilinx). Замену этой парочке пока что удалось найти только в виде физического анализатора. Так себе замена, но хоть что-то.
Более серьёзная трудность заключалась в том, что все примеры, которые я находил, были реализованы на чистом Верилоге. А я уже не могу писать автоматы, не используя такой механизм, как enum. Меня каждый раз злит необходимость перенумеровывать состояния, если я правлю автомат по ходу разработки. Но чтобы был enum, надо пользоваться более прогрессивным стандартом языка, который уже называется SystemVerilog.
На странице Yosys YosysHQ/yosys: Yosys Open SYnthesis Suite (github.com) описано, что данный язык ограниченно поддерживается синтезатором, и даже указана опция для его использования. А именно сказано, что команде read_verilog надо добавить ключ –sv. Но попытки найти в сети готовую инструкцию для новичков, как её активировать, я не нашёл, потому что если кто-то и пользуется этой командой, то для одного файла, а не для списка.
Наконец, я разобрался, поэтому делаю такую инструкцию, чтобы любой желающий смог быстро найти готовое решение.
Немного теории
В прошлой статье я ссылался на пример makefile, из которого Yosys запускается так:
yosys -p "synth_ecp5 -top $(FPGA_TOP) -json $@ -abc2" $(SYN_FILES_REL)
То есть, сначала задаётся имя файла (yosys), затем идёт ключ –p и очень длинный аргумент в кавычках. После закрывающих кавычек идёт список обрабатываемых файлов.
В свою очередь, аргумент –p говорит, что там будет идти строка скрипта. И все ключи –top, -json и –abc2 относятся уже не к ключам запуска программы, а к ключам команды скрипта, которая называется synth_ecp5. Хитро? Точно! Но погодите, это только начало! Правда, это надо понять, но запоминать не надо. Но чтобы понять, продолжаем углубляться в теорию.
Гугль подсказал мне, что перечень доступных команд скрипта можно найти вот тут: Yosys Open SYnthesis Suite :: Documentation (clairexen.net)
Вот кусочек этого перечня:
И тут мы выясняем, что synth_ecp5 – это всего лишь макрокоманда, которая распадается на множество других команд. Теоретически, она даже может быть заменена скриптом из них, только надо брать актуальную расшифровку не из этой документации, а из реальных исходников. Но то в теории. На практике – просто глянем на начало раскрытия этого макроса и задумчиво почешем голову:
Что мы сейчас выяснили? Для достижения нашей цели, мы не можем ограничиться одной строкой скрипта. Нам надо как-то сделать скрипт с командами read_verilog, часть из которых будет иметь ключ –sv.
Кстати, если внимательно порыться по документации, можно найти вот такую команду:
Я пробовал применить её, чтобы задать опцию –sv по умолчанию. Не помогло. Так что вроде скрипт делать надо! Но как?
Где черпаем вдохновение
Решение я нашёл вот в этом проекте ghent360/riscvOnColorlight-5A-75B: RISC-V soft core running on Colorlight 5B-74B. (github.com). Чтобы его собрать, надо установить среду Litex. Коротко я про неё уже рассказывал в прошлой статье. Возможно (если интерес к теме не угаснет) я посвящу этой среде одну-две отдельных статьи. Там есть, что рассказать. В частности, указанный проект под Windows не соберётся. Надо будет поправить совсем чуть-чуть в штатных скриптах… Но чтобы не отвлекаться от темы SystemVerilog, мы просто соберём проект строго в Линуксе. И наконец получим эталонный пакетный файл, содержащий вот такую строку для запуска Yosys:
yosys -l colorlight_5a_75b.rpt colorlight_5a_75b.ys
В отличие от того, что я показывал выше, здесь нет никакого ключа –p. Ключ –l задаёт файл лога, куда будут сохранены все тексты, выведенные на экран. И дальше идёт аргумент colorlight_5a_75b.ys. А это – имя файла скрипта. Прекрасно! Заглянем в него!
verilog_defaults -push
verilog_defaults -add –defer
read_verilog VexRiscv_Linux.v
read_verilog gateware/colorlight_5a_75b.v
verilog_defaults -pop
attrmap -tocase keep -imap keep="true" keep=1 -imap keep="false" keep=0 -remove keep=0
synth_ecp5 -json colorlight_5a_75b.json -top colorlight_5a_75b
Мне кажется, что первые две строки задают очень полезную вещь. Можно ли без них – я точно не знаю. Я просто пользуюсь этой «рыбой». Но возможно, именно они позволяют загрузить не один, а несколько файлов. Поэтому дальше идут две строки с двумя файлами. Целевая платформа и процессор с архитектурой RISC-V. То есть, у нас имеется пример скрипта, содержащего не одну, а целых две команды read_verilog! Это – то, что я так долго искал и до сих пор не мог найти средствами Гугля!
Потом идёт строка, комплементарная к первой. Суть предпоследней строки мне пока что неведома. И, наконец, последняя очень похожа на ту, которую вызывал makefile из предыдущего раздела.
Собственно решение
Ну, собственно, и всё. На радостях, я написал вот такой скрипт (часть несущественных строк выкинута):
То же самое текстом.
verilog_defaults -push
verilog_defaults -add -defer
read_verilog -sv ../rtl/fpga.v
read_verilog ../rtl/fpga_core.v
read_verilog ../rtl/rst_gen.v
read_verilog ../rtl/lfsr_yosys.v
read_verilog -sv ../rtl/sdram.sv
read_verilog ../lib/eth/rtl/iddr.v
read_verilog ../lib/eth/rtl/oddr.v
read_verilog ../lib/eth/rtl/ssio_ddr_in.v
…
read_verilog ../lib/eth/lib/axis/rtl/axis_fifo.v
read_verilog ../lib/eth/lib/axis/rtl/sync_reset.v
verilog_defaults -pop
attrmap -tocase keep -imap keep="true" keep=1 -imap keep="false" keep=0 -remove keep=0
synth_ecp5 -top fpga -json fpga.json –abc2
Как видим, у двух строк есть ключи –sv. И в тех файлах имеется SystemVerilog код. Файл sdram я просто взял из проекта эмулятора БК, как пример среднестатистического SystemVerilog кода. Он не выдаёт ошибок! В файл fpga я вставлял свой код. К сожалению, там работает не всё, к чему я привык в Квартусе. Вот такая строка приведёт к ошибке
enum {red,redyellow,green,yellow,black} state = red;
Но если убрать начальное присвоение – всё заработает.
enum {red,redyellow,green,yellow,black} state;
А чтобы начальное присвоение заработало – надо применять tyedef. Всяк лучше, чем ничего! И, в конце концов, лучше присваивать начальное значение в обработчике сигнала reset.
Немного прикладного перфекционизма
Когда я показал идею коллегам, мне объяснили, что я не совсем прав. Я вызываю этот скрипт из makefile вот так:
yosys ../common/colorlight_5a_75b.ys
А список файлов, как я отметил, заранее помещён мною в тело скрипта. Мне объяснили, что ценность makefile в том, что он не вызывает средство сборки, если исходные тексты не изменялись, а для этого список должен формироваться внутри него. Для остальных случаев необходимо и достаточно использовать не makefile, а простой пакетный файл. Но зная текущую теорию, можно найти и пример в тему. Вот так каждый раз формирует скрипт makefile из примера от платы Orange Crab:
orangecrab-examples/Makefile at main · orangecrab-fpga/orangecrab-examples · GitHub
Все желающие сделать красиво, могут воспользоваться им и сформулировать правила для добавления файлов с расширениями *.v и *.sv. Первые будут добавляться без ключа, вторые – с ним. К целям статьи это уже не относится. Целью статьи было показать реально работающий пример скрипта, понимающего исходные тексты на языке SystemVerilog. Когда идея ясна – дальше каждый уже сможет сделать собственные решения в силу своего понимания красоты.