# Контроль прошивок ПЛИС: Xilinx ISE, Vivado и Altera Quartus Для ISE: запустите `INSTALL_ISE.bat`, укажите `.xise`, затем используйте созданный в проекте `build_firmware.bat`. [Краткая инструкция](ISE_PORTING.md). Шаблон подключает к существующему проекту ПЛИС общий механизм [`firmware-info`](../../../c/firmware-info/README.md): сохраняемый итератор 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 добавьте экземпляр: ```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: ```vhdl 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:** ```bat 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:** ```bat 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:** ```bat 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: ```bat 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. Результаты и проверка ```text 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 относится к файлу программатора целиком и хранится снаружи образа. Проверить сохранённый файл можно общим инструментом: ```bat 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`; номер версии при этом не меняется: ```bat 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, графическое окно не открывается. ```bat rem Запускает проверки адаптера и управляющих сценариев без лицензии САПР. python -m unittest discover -s tools/firmware-build/fpga/tests -v ``` Шаблон пока не подключён к конкретной плате. Полный синтез и чтение паспорта на железе требуют установленной САПР, проекта и платы; хостовые тесты эти проверки не заменяют. Команды сверены с руководствами производителей: [ISE Command Line Tools UG628](https://docs.amd.com/v/u/en-US/devref), [Vivado: запуск синтеза и реализации UG939](https://docs.amd.com/r/2023.1-English/ug939-vivado-designing-with-ip-tutorial/Step-8-Launch-Synthesis-and-Implementation), [Quartus: полный Tcl flow](https://www.intel.com/content/www/us/en/docs/programmable/683432/22-1/the-tcl-shell-in-interactive-mode-example.html).