Для чего нам нужна система сборки? Для автоматической сборки проектов, которая легко запускается и нивелирует возможные ошибки разработчика (очень обидно под конец текущей сборки вспомнить, что забыл обновить память процессора новой программой, а проект ПЛИС ведь долго собирается!). На выходе хотелось бы получить образ конфигурирующей ПЛИС флешки (прошивку). Система должна быть максимально гибкой, чтобы ее можно было использовать для разных проектов, и легко масштабируемой для ее последующего развития. Каким образом можно собирать отдельные компоненты проекта? Через TCL-скрипты (а TCL глубоко интегрирован в Quartus) или через запуск отдельных утилит в консольном режиме. Требования по гибкости и масштабируемости намекают на использование модульной архитектуры, а значит лучше всего разбросать функционал по отдельным TCL-скриптам. Система сборки призвана не заменить обычный flow разработки в Quartus, но дополнить ее − она позволит удобно получать релизные прошивки. Получившуюся систему можно глянуть здесь, а мы перейдем к описанию ее возможностей. Перечислим возможности системы: генерация IP-ядер (как HDL, так и Qsys); сборка программных проектов для Nios II; сборка дизайна (синтез, имплементация) и получение битстрима; проверка таймингов на Failing Paths; генерация образа флешки. Запуск этих операций проводится через старый добрый make, который в свою очередь запускает необходимые TCL-скрипты через интерпретатор Quartus. Проверенные версии Quartus – 15.1 и 18.1. Что с версиями поновее? Начиная с версии 19.1, Intel заменила утилиты для программной сборки Cygwin на WSL. При проверке Quartus 20.1 программный проект для Nios II ожидаемо не собрался, но остальной функционал работал.  В данный момент система сборки поддерживает только Windows. Теперь поговорим о необходимой настройке компьютера для работы сборки. Во-первых, необходимо добавить в переменную PATH пути до bin-папки ваших Quartus (их может быть несколько). Пример: C:\altera\15.1\quartus\bin64   C:\intelFPGA\18.1\quartus\bin64  Во-вторых, нужно установить утилиту make. Мы пользуемся этой из набора MinGW-w64. Не забываем указать путь к make в PATH. В-третьих, следует разрешить выполнение скриптов Powershell, так как в состав системы сборки входит скрипт, который анализирует по QPF-файлу используемую версию Quartus и сортирует PATH в рамках текущей сессии (глобально PATH не меняется). Во время изучения возможности автоматической генерации IP-ядер мы столкнулись со следующей проблемой: Quartus не умеет самостоятельно их генерировать во время сборки дизайна, всегда необходимо самому заходить в MegaWizard для генерации обычных HDL-ядер и в Platform Designer (Qsys) для генерации Qsys-компонентов. К слову, Xilinx Vivado не имеет с этим проблем и спокойно собирает свои ядра во время сборки дизайна или отдельной TCL-командой. Мы решили описывать все используемые ядра в отдельном файле и «скармливать» его системе сборки. Вся остальная настройка проекта будет происходить в makefile, но о нем чуть попозже. Заполняется информация в файле в JSON-формате. Пример: Здесь описаны два ядра − nios_system и cyc_v_pll, как раз достаточных для примера, так как типов ядер тоже два − Qsys и HDL. Ключи-строчки nios_system и cyc_v_pll − просто названия ядер. Для каждого ядра необходимо определить тип ("type") и указать относительный путь до файла ("file"). Если ядро реализовано MegaWizard'ом на VHDL или Verilog, то указываем тип "hdl", если ядро является Qsys-компонентом − "qsys". Путь до файла относителен директории проекта (там, где лежит QPF-файл). В случае описания Qsys-ядра необходимо также указать "output_directory" − директорию, где сохраняется результат генерации ядра. Она должна совпадать с той, на которую настроен Platform Designer при обычной генерации через GUI. Теперь можно поговорить про настройку makefile для проекта. Вот предлагаемый пример. Как можно заметить, в makefile есть блок переменных editable parameters, который предлагается настраивать для каждого проекта: REPO_DIR − путь до репозитория относительно директории с makefile; SCRIPTS_DIR − путь до скриптов, которые и выполняют основную работу.Скрипты не обязательно должны лежать в этом же репозитории, также их можно подключить как submodule; REVISION − ревизия Quartus-проекта по умолчанию.При необходимости собирать другую ревизию, следует передать другое значение переменной во время вызова make и тем самым перебить ревизию по умолчанию − этим удобно пользоваться на CI; IP_JSON_PATH − путь до файла, описывающего ядра, о котором мы недавно говорили; WORKSPACE − путь до программного workspace; SW_APP − программный проект по умолчанию; SW_BSP − BSP для проекта SW_APP; COF_PATH − путь до COF-файла, который нужен для преобразования битстрима в образ флешки. На этом настройка сборки на локальной машине завершается и уже можно что-нибудь сделать. Например, соберет программный проект, выбранный по умолчанию, а также создаст необходимый образ памяти программы и mem_init файл. сделает то же самое, но для другого программного проекта. Для упрощения сборки нескольких программных проектов в makefile была добавлена цель sw_all, в которой можно собрать все необходимые проекты, что удобно, когда используется несколько микропроцессорных систем Nios II. Разумеется, присутствует цель all, которая полностью соберет Quartus-проект для выбранной ревизии. Перейдем к гвоздю программы, а именно к сборке проекта на удаленном сервере. Конвейер сборки нашего тестового проекта выглядит следующим образом: Уже по этой картинке, а также по YAML-файлу, описывающему CI, видно, что сборка происходит в четыре этапа: IP generate; Software build; Bitstream build; Flash build. Генерация IP-ядер согласно списку, который хранится в JSON-файле. Артефакты задания − файлы ядер, которые передаются на следующие этапы и живут короткий промежуток времени. Сборка программных проектов. В данном конвейере собирается один проект, но ничего не мешает собирать их несколько под один Nios II или под разные Nios II. Артефакты задания − ELF-файл и содержимое папки mem_init, которая хранит образ памяти и QIP-файл, нужный Quartus'у для нахождения этого образа.  На данном этапе сборки происходит несколько операций: Удаление из QSF-файла упоминаний файлов mem_init.qip, которые были в нем на момент коммита. Добавление выбранных пользователем mem_init.qip (считай, программных проектов). Данную операцию можно проводить несколько раз, для разных проектов, когда в дизайне используются несколько процессоров Nios II. Синтез дизайна. Имплементация дизайна. Генерация битстрима (SOF-файла). Проверка плохих таймингов в Timing Analyzer.Тайминги проверяются для обеих моделей (slow/fast) и для разных температур (min/max, в проекте это 0/85°C). В тестовом проекте собираются битстримы для двух разных ревизий (для двух разных отладочных плат). Артефакты задания − битстрим и файлы репортов. Генерация образа флешки из битстрима согласно COF-файлу. Артефакт задания − образ флешки (JIC-файл). Репозиторий проекта со скриптами, CI и тестовым дизайном для сборки располагается здесь. Надеемся, наш подход вам пригодится. Лично нам CI здорово упростил жизнь при создании релизных прошивок для множества ревизий проекта, а ведь еще можно добавить в него верификацию и тогда дизайн будет тестироваться каждый раз при пуше! Комментарии и обсуждение приветствуются. Raccoon Security – специальная команда экспертов НТЦ «Вулкан» в области практической информационной безопасности, криптографии, схемотехники, обратной разработки и создания низкоуровневого программного обеспечения.