Постановка задачи
Для чего нам нужна система сборки?
Для автоматической сборки проектов, которая легко запускается и нивелирует возможные ошибки разработчика (очень обидно под конец текущей сборки вспомнить, что забыл обновить память процессора новой программой, а проект ПЛИС ведь долго собирается!).
На выходе хотелось бы получить образ конфигурирующей ПЛИС флешки (прошивку).
Система должна быть максимально гибкой, чтобы ее можно было использовать для разных проектов, и легко масштабируемой для ее последующего развития.
Каким образом можно собирать отдельные компоненты проекта?
Через 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" :
{
"type" : "qsys",
"file" : "ip\\nios_system\\nios_system.qsys",
"output_directory" : "ip\\nios_system"
},
"cyc_v_pll" :
{
"type" : "hdl",
"file" : "ip\\cyc_v_pll\\cyc_v_pll.v"
}
}
Здесь описаны два ядра − 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-файла, который нужен для преобразования битстрима в образ флешки.
На этом настройка сборки на локальной машине завершается и уже можно что-нибудь сделать. Например,
make sw
соберет программный проект, выбранный по умолчанию, а также создаст необходимый образ памяти программы и mem_init файл.
make sw SW_APP='another_app' SW_BSP='another_bsp'
сделает то же самое, но для другого программного проекта. Для упрощения сборки нескольких программных проектов в makefile была добавлена цель sw_all
, в которой можно собрать все необходимые проекты, что удобно, когда используется несколько микропроцессорных систем Nios II.
Разумеется, присутствует цель all
, которая полностью соберет Quartus-проект для выбранной ревизии.
Перейдем к гвоздю программы, а именно к сборке проекта на удаленном сервере.
Continuous Integration
Конвейер сборки нашего тестового проекта выглядит следующим образом:
Уже по этой картинке, а также по YAML-файлу, описывающему CI, видно, что сборка происходит в четыре этапа:
IP generate;
Software build;
Bitstream build;
Flash build.
IP generate
Генерация IP-ядер согласно списку, который хранится в JSON-файле.
Артефакты задания − файлы ядер, которые передаются на следующие этапы и живут короткий промежуток времени.
Software build
Сборка программных проектов.
В данном конвейере собирается один проект, но ничего не мешает собирать их несколько под один Nios II или под разные Nios II.
Артефакты задания − ELF-файл и содержимое папки mem_init
, которая хранит образ памяти и QIP-файл, нужный Quartus'у для нахождения этого образа.
Bitstream build
На данном этапе сборки происходит несколько операций:
Удаление из QSF-файла упоминаний файлов
mem_init.qip
, которые были в нем на момент коммита.Добавление выбранных пользователем
mem_init.qip
(считай, программных проектов).Данную операцию можно проводить несколько раз, для разных проектов, когда в дизайне используются несколько процессоров Nios II.
Синтез дизайна.
Имплементация дизайна.
Генерация битстрима (SOF-файла).
Проверка плохих таймингов в Timing Analyzer.
Тайминги проверяются для обеих моделей (slow/fast) и для разных температур (min/max, в проекте это 0/85°C).
В тестовом проекте собираются битстримы для двух разных ревизий (для двух разных отладочных плат).
Артефакты задания − битстрим и файлы репортов.
Flash build
Генерация образа флешки из битстрима согласно COF-файлу.
Артефакт задания − образ флешки (JIC-файл).
Заключение
Репозиторий проекта со скриптами, CI и тестовым дизайном для сборки располагается здесь.
Надеемся, наш подход вам пригодится. Лично нам CI здорово упростил жизнь при создании релизных прошивок для множества ревизий проекта, а ведь еще можно добавить в него верификацию и тогда дизайн будет тестироваться каждый раз при пуше!
Комментарии и обсуждение приветствуются.
Raccoon Security – специальная команда экспертов НТЦ «Вулкан» в области практической информационной безопасности, криптографии, схемотехники, обратной разработки и создания низкоуровневого программного обеспечения.