Files
templates/tools/firmware-build/fpga/README.md
T
Andrey 62c0492bfd feat(firmware-build): Добавь сборку и паспорта проектов ПЛИС
Подключи ISE, Vivado и Quartus к общему итератору версии и HDL-паспорту. Проверяй новый bit/sof до создания manifest, SHA-256 и архива выпуска.

Добавь установку локальных команд ISE, инструкции переноса и регрессионные проверки успешных и прерванных сборок.
2026-10-23 14:16:21 +03:00

17 KiB
Raw Blame History

Контроль прошивок ПЛИС: Xilinx ISE, Vivado и Altera Quartus

Для ISE: запустите INSTALL_ISE.bat, укажите .xise, затем используйте созданный в проекте build_firmware.bat. Краткая инструкция.

Шаблон подключает к существующему проекту ПЛИС общий механизм firmware-info: сохраняемый итератор SemVer, время сборки в UTC, Git build ID, manifest, SHA-256 и архив выпуска. Параметры кристалла, выводы, частоты, ограничения и транспорт чтения регистров задаёт проект платы.

Цепочка: проект → Tcl своей САПР → identity.py из этого каталога → общий c/firmware-info/tools/identity.py. Итератор, правила Git и архивирования используются те же, что для CCS и Keil.

Файлы и зависимости

Файл Назначение Зависимости
firmware_identity.example.json Начальная конфигурация изделия и счётчика Копируется в проект
INSTALL_ISE.bat, ise_project.py Автоматическая установка локальных BAT, JSON, HDL и памятки из .xise Windows, Python 3.9+
ise-build.bat, ise_bootstrap.py, ise-project.md Шаблоны локальной команды сборки и памятки Копируются установщиком в проект
identity.py Генерация Verilog-2001/VHDL-93 и контроль готового файла Python 3.9+, stdlib, общий identity.py из templates
common.tcl Пути, язык, вызовы Python, обработка отказов Tcl 8.5+ в САПР
ise.tcl Полная сборка .xise до .bit Xilinx ISE / xtclsh
vivado.tcl Полная сборка .xpr до .bit Vivado Project Mode
quartus.tcl Полная сборка .qpf до .sof Altera/Intel Quartus II или Prime / quartus_sh

Python 3 должен быть доступен как python из окружения САПР. Если ISE или Quartus подставляет старый Python, передайте путь к python.exe шестым аргументом. Git в PATH нужен для хешей; при недоступном Git получается явный NOGIT000, локальная сборка продолжается.

1. Конфигурация проекта

Скопируйте firmware_identity.example.json рядом с .xise, .xpr или .qpf под именем firmware_identity.json. Пример намеренно требует заменить имя кристалла; задайте своё изделие и точный part number.

Поле Смысл
product Имя изделия, например MY_FPGA_BOARD
target Точное обозначение кристалла; информационное поле, настройки part в проекте не меняет
version Последний занятый номер [major, minor, patch]; в примере [0, 1, 0]
increment_version true включает общий сохраняемый итератор; false оставляет ручную версию

Первая подготовка примера выдаёт 0.1.1. Следующий pre-build выдаёт 0.1.2, включая попытки после ошибки синтеза. Переносы: 0.1.999 → 0.2.0, 0.255.999 → 1.0.0. После 255.255.999 сборка останавливается. Post-build номер не увеличивает. Clean не сбрасывает конфигурацию.

Храните этот JSON в Git. Каталог build/ добавьте в .gitignore проекта; файлы результатов САПР также должны игнорироваться, иначе они пометят сборку как dirty. Одна конфигурация JSON обслуживает только одну сборку одновременно. Для независимых ревизий платы используйте отдельные JSON и выходные каталоги.

2. Подключение паспорта к логике

Генератор создаёт generated/firmware_identity.v и generated/firmware_identity.vhd. Tcl добавляет в проект только выбранный язык. Паспорт — комбинационный ROM из 12 слов по 16 бит:

Относительный адрес слова Значение
0 Версия контракта: 1
1, 2, 3 Major, minor, patch
4 Год, 2000..2199
5 Месяц в битах 15..8, день в 7..0
6 Час UTC в битах 15..8, минута в 7..0
7 Секунда UTC
8..11 Восемь ASCII-символов build ID, первый символ пары в старшем октете
12..15 Ноль

Адреса относительные, без привязки к CPU, AXI, Avalon, SPI, Modbus или SETCAN. Базовый адрес в системе назначает проект. Это тот же порядок слов, что в firmware_info_to_registers(). Порядок байтов на конкретной шине задаёт адаптер проекта.

В верхний модуль Verilog добавьте экземпляр:

wire [15:0] identity_data; // 16-битное слово паспорта для мультиплексора чтения шины проекта.
firmware_identity u_identity ( // Экземпляр генерируемого до синтеза паспорта текущей сборки.
    .word_addr(identity_word_offset), // Четыре младших бита относительного адреса слова в выделенном окне регистров.
    .word_data(identity_data) // Выход должен участвовать в ответе шины, чтобы синтезатор сохранил паспорт.
); // Выбор окна и тактовое согласование выполняет логика проекта.

Для VHDL объявите component в declarative part архитектуры и подключите его в теле архитектуры; component не требует заранее анализировать generated entity:

component firmware_identity is -- Объявление размещается до begin архитектуры верхнего уровня.
    port ( -- Интерфейс совпадает с генерируемой entity firmware_identity.
        word_addr : in std_logic_vector(3 downto 0); -- Относительный адрес одного из 12 слов паспорта.
        word_data : out std_logic_vector(15 downto 0) -- Данные для ответа шины проекта.
    ); -- Закрывает список портов компонента.
end component; -- Привязка к entity из work выполняется при elaboration.
signal identity_data : std_logic_vector(15 downto 0); -- Объявляется до begin и подключается к чтению регистров.
-- Следующий экземпляр размещается после begin архитектуры верхнего уровня.
u_identity : firmware_identity -- Создаёт экземпляр паспорта без примитивов производителя.
    port map ( -- Согласует имена сигналов проекта с интерфейсом компонента.
        word_addr => identity_word_offset, -- Четырёхбитный сигнал относительного адреса слова задаёт проект.
        word_data => identity_data -- Выход включается в мультиплексор ответа хосту.
    ); -- Завершает подключение экземпляра.

identity_word_offset, декодер окна и ответ шины реализуйте в проекте. Паспорт не имеет clock/reset, чтение комбинационное; при необходимости зарегистрируйте ответ в тактовом домене шины. Без подключения выхода синтезатор удалит паспорт. Смена языка существующего проекта требует удалить прежний generated-файл из списка исходников, чтобы не получить два одноимённых модуля.

3. Полная сборка

Команды запускаются из корня проекта в командной строке с настроенным окружением соответствующей САПР. В примерах templates подключён как lib/templates. Проект должен уже содержать свой top, part и UCF/XDC/QSF. Сценарии регистрируют generated-исходник в существующем проекте и выполняют полную цепочку до файла программирования.

Аргументы общие: project config output image verilog|vhdl [python]. Пути разрешаются относительно начального рабочего каталога. image — точный путь результата вашей САПР, а output — отдельный каталог паспорта и архивов; передача output не меняет настройки выходного каталога САПР.

ISE:

rem Собирает существующий ISE-проект, в котором BitGen создаёт top.bit рядом с .xise.
xtclsh "lib/templates/tools/firmware-build/fpga/ise.tcl" "board.xise" "firmware_identity.json" "build/ise" "top.bit" verilog

Используется Generate Programming File -force rerun_all: XST, реализация и BitGen выполняются заново. Логический false от процесса считается ошибкой.

Vivado:

rem Замените board.runs/impl_1/top.bit реальным путём .bit выбранного implementation run.
vivado -mode batch -source "lib/templates/tools/firmware-build/fpga/vivado.tcl" -tclargs "board.xpr" "firmware_identity.json" "build/vivado" "board.runs/impl_1/top.bit" verilog

Берётся активный implementation run и его родительский synthesis run; нестандартные имена runs поддерживаются. Оба запуска сбрасываются, затем выполняются синтез и реализация до write_bitstream. После wait_on_run отдельно проверяется PROGRESS, поэтому завершение с ошибкой не вызывает упаковку.

Altera / Intel Quartus:

rem Собирает текущую revision из .qpf; image должен совпадать с результатом Assembler.
quartus_sh -t "lib/templates/tools/firmware-build/fpga/quartus.tcl" "board.qpf" "firmware_identity.json" "build/quartus" "output_files/board.sof" vhdl

execute_flow -compile запускает полную компиляцию с Assembler. Для другой revision передайте седьмой аргумент после пути к Python:

rem Укажите реальный Python 3 и отдельный JSON счётчика ревизии B.
quartus_sh -t "lib/templates/tools/firmware-build/fpga/quartus.tcl" "board.qpf" "identity_B.json" "build/quartus_B" "output_files/board_B.sof" vhdl "C:/Python313/python.exe" "board_B"

Не добавляйте второе увеличение версии в существующие pre-flow/pre-synthesis hooks. Эти Tcl-файлы предназначены для запуска полной сборки из командной строки; их нельзя подключать как вложенные hooks этапов синтеза. Для выпуска через данную схему запускайте указанный сценарий, в том числе после работы в GUI.

4. Результаты и проверка

build/vivado/
  generated/
    firmware_identity.h
    firmware_identity.v
    firmware_identity.vhd
    firmware_identity.json
  firmware/
    HASH_YYYY-MM-DD_HH-MM-SS_UTC+3/
      top.bit
      top.bit.manifest.json
      top.bit.sha256
      firmware_identity.v
      firmware_identity.json

Для VHDL архив содержит выбранный .vhd, для Quartus — .sof вместо .bit. Manifest и .sha256 также создаются рядом с исходным файлом программирования. Хеш и дата архивной папки берутся из pre-build, дата имени переводится в UTC+3; в самом паспорте остаётся UTC. Знак + у build ID означает изменённые исходники или templates. firmware_identity.h — сопутствующий результат общего генератора; FPGA-сценарии используют HDL.

Упаковка отклоняет отсутствующий, пустой или не обновившийся после prepare файл. Проверяется содержимое и время записи: повторная запись тех же байтов допускается. Это защита от старого результата; она не проверяет наличие паспорта внутри vendor bitstream. Правильность подключения подтверждается чтением всех 12 регистров с работающей ПЛИС и сравнением с fpga.register_words в manifest. SHA-256 относится к файлу программатора целиком и хранится снаружи образа.

Проверить сохранённый файл можно общим инструментом:

rem Проверяет размер и SHA-256 указанного файла по созданному рядом manifest.
python "lib/templates/c/firmware-info/tools/identity.py" verify --image "board.runs/impl_1/top.bit" --manifest "board.runs/impl_1/top.bit.manifest.json"

Для локального экспорта папки выпуска повторите только finish с --export; номер версии при этом не меняется:

rem Копирует текущую архивную папку и проверяет SHA-256 экспортной копии.
python "lib/templates/tools/firmware-build/fpga/identity.py" finish --metadata "build/vivado/generated/firmware_identity.json" --output "build/vivado/firmware" --export "D:/Firmware/FPGA"

Шаблон выпускает .bit и .sof. Преобразование в .mcs, .bin, .pof или .rbf, загрузка на плату и публикация в сетевую базу требуют отдельного проектного этапа. Контрольная сумма нативного образа не переносится на преобразованный файл: для него создайте отдельные seal/verify общим инструментом.

Проверки и состояние

Хостовые тесты проверяют эталон всех 12 слов, совпадение Verilog/VHDL, итератор, свежесть результата, повреждение SHA-256, архив и экспорт. Реальные Tcl-сценарии исполняются в Tcl из Python tkinter с заменой API производителей; Python-генератор и упаковка выполняются полностью. Нужен Python с tkinter/Tcl, графическое окно не открывается.

rem Запускает проверки адаптера и управляющих сценариев без лицензии САПР.
python -m unittest discover -s tools/firmware-build/fpga/tests -v

Шаблон пока не подключён к конкретной плате. Полный синтез и чтение паспорта на железе требуют установленной САПР, проекта и платы; хостовые тесты эти проверки не заменяют.

Команды сверены с руководствами производителей: ISE Command Line Tools UG628, Vivado: запуск синтеза и реализации UG939, Quartus: полный Tcl flow.