
Из студентов в инженеры: как перестать бояться и полюбить системную верификацию

Михаил Степанов и Роман Казаченко из группы функциональной верификации YADRO рассказали о своем пути от участников хакатона SoC Design Challenge до сотрудников компании. Ребята объяснили на примере заданий, что такое системная верификация, и дали полезные советы, как подготовиться к этому испытанию.
Если вы не планируете участвовать в хакатоне, но вам интересно, как инженеры тестируют системы на кристалле перед запуском в производство, эта статья тоже будет вам полезна. Разберетесь, что такое системная верификация, из каких блоков состоят СнК и какие инструменты используются для их тестирования.

- что такое системная верификация систем на кристалле
- как подготовиться к хакатону SoC Design Challenge 2025
- какие инструменты стоит изучить: примеры с кодом
- как грамотно организовать работу команды
Как попасть на хакатон
В прошлом году мы были студентами выпускного курса «Информатика и вычислительная техника» в ИТМО и решили испытать себя на хакатоне SoC Design Challenge. Тогда у нас было немного опыта в разработке системного ПО, поэтому мы выбрали трек «Системное программирование». В этом году его переименовали в «Системную верификацию СнК», что точнее отражает суть задания.
Путь истового инженера начинается с несложного отборочного теста. Обычно, чтобы его успешно пройти, достаточно знаний на уровне второго и третьего курсов. Самое главное — успеть ответить на все вопросы за отведенные четверть часа. В интернете искать ответы можно, но мы не рекомендуем — можете впустую потратить драгоценные минуты.
Лучше сразу оценить, сколько времени вы сможете потратить на каждый вопрос. Если над каким-то из них нужно поломать голову, лучше его пропустить и попробовать сделать следующее задание. Так вы успеете больше за отведенное время и не потеряете потенциальные баллы.

Если вы пройдете отбор, то вас пригласят на основной этап в Зеленоград и поселят в классном отеле с трехразовым питанием. На решение кейса у вашей команды будет три дня. Первые два дня работать придется с утра до вечера, можете ориентироваться на восемь часов в день. В последний день времени будет меньше из-за подведения итогов. Рекомендуем быть готовыми трудиться над заданием по вечерам, но не в ущерб сну. Отдых — залог эффективной работы и вашей победы.
На SoC Design Challenge 2025 несколько треков с соответствующими заданиями: «Топологическое проектирование», «UVM-верификация», «Системная верификация СнК» и «RTL-проектирование». Описания заданий с прошлогоднего хакатона можно посмотреть в анонсе хакатона на Хабре. В этой статье мы делимся опытом нашей команды в треке по системной верификации и даю подробные советы по работе с инструментами, которые пригодятся вам в этом году. Также, как участники процесса подготовки заданий, рассказываю об изменениях по сравнению с прошлым годом.
Про задание трека «Системная верификация СнК»
Нам нужно было провести верификацию аппаратного блока в косимуляционном окружении. Давайте разберемся, что это значит.
Системы на кристалле состоят из логических и функциональных блоков. Такое деление позволяет независимо разрабатывать разные части системы, а затем модульно отлаживать их в изолированном окружении. Функциональная верификация — это процесс тестирования таких блоков по спецификации. Она проводится перед отправкой чипа на завод и называется pre-silicon стадией. Без этой процедуры велик шанс получить нерабочий чип, причем в объемах всей произведенной партии.
Проводить такие тесты можно при помощи таких инструментов, как:
- Функциональные симуляторы (например, QEMU) — работают очень быстро, но в отличие от других инструментов не предоставляют достоверной информации о работе устройства. Зато QEMU может почти молниеносно осуществить подачу требуемых данных и выдать результат в виде «прошел» или «не прошел», а также некоторые логи.
- Потактовые симуляторы (например, VCS) — у них есть внутренняя система планирования времени, но скорость работы низкая. Они нужны для сбора трассировочных файлов, по которым можно восстановить состояние любого регистра и провода в любой момент.
- ПЛИС — специальные вычислительные платформы, на которые можно загрузить и запустить «образ» своей микросхемы, будто это уже готовое физическое устройство. ПЛИС значительно быстрее потактовых симуляторов, но при этом дает представление о реальном поведении системы на кристалле.
У каждого решения есть плюсы и минусы, и не всегда очевидно, какое лучше подходит для решения конкретной задачи. Именно поэтому придумали концепцию косимуляции, при которой микросхема делится на небольшие логические части, каждая из которых запускается в отдельном окружении. Наша задача как инженеров верификации — настроить бесшовное соединение этих частей. Так мы заметно ускоряем работу потактового симулятора, потому что распределяем его нагрузку на другие элементы системы.
На хакатоне участникам предложили поработать с небольшим DUT-устройством (Device Under Test): UART 16650. Нам нужно было найти спецификацию блока, внимательно ее изучить и составить тестовый план, который покрывает все основные главы спецификации. После составления тестового плана и написания тестов нужно прогнать их в двух разных конфигурациях интерфейса:
- c обратной петлей — UART соединен сам с собой,
- с подключением к термодатчику — интерфейс подключен к устройству, взаимодействие с которым также можно протестировать.
Успеть за три дня
Задание сначала может показаться сложным и не очень понятным. Но если грамотно разбить его на подзадачи, а затем постепенно двигаться к решению, то вам вполне хватит трех дней на успешную реализацию.
В первый день мы решили засесть за изучение материалов и спецификаций, а не бросаться судорожно писать тесты. Самой большой проблемой для нас тогда был страх перед непонятным и незнакомым заданием. Но он быстро прошел — заботливые инженеры YADRO снабдили нас исчерпывающей документацией. В ней описано, что и как устроено, а также в каком порядке выполнять работу.
В общем, не старайтесь в первый день стать самыми быстрыми системными программистами на хакатоне. Как показала практика — медленный, но осознанный подход приводит к лучшим результатам в ограниченное время. Так проще выходить из тупиков, в которых вы наверняка окажитесь, а их может быть много.

Если на какую-то подзадачу вы безрезультатно потратили много времени, то попросите помощи у менторов. Штрафные баллы за это не начислят, а вы быстрее выйдите из сложной ситуации.
Отметим, что задание и исходный код могут быть неидеальны. Мы, например, нашли несоответствие спецификации RTL-коду. Но не стоит сразу же писать об этом во всех чатах хакатона — лучше несколько раз проверить найденную ошибку и записать ее в отчет по верификации.
Поспешайте медленно
Правильно презентовать результаты перед жюри так же важно, как и решить саму задачу. В некоторых заданиях нужно предоставить результат в конкретном формате, например:
- корректно сформировать план тестирования,
- прогнать все тесты через CI,
- нарисовать все нужные схемы и таблицы,
- добавить текстовое пояснение к каждому тесту.
Не рекомендуем гнаться за объемом написанного кода и количеством тестов — можете не успеть привести код в порядок и потерять заветные баллы.
Распределите роли в команде, а работу разбейте на микроспринты. Задач и аспектов много, их надо учитывать на каждом этапе выполнения: поработали, обменялись кодом, провели кросс-ревью, позапускали на регрессе, записали проблемы и баги, задали вопросы ментору, повторили.

Залог вашего успеха — баланс скорости и осознанности. Если наброситься на выполнение заданий, то можно упустить важные моменты и прийти к финишу в аутсайдерах после спринтерского старта. Однако излишняя медлительность может заставить вас потратить время на задачи, которые для победы попросту не нужны.
На этом мы заканчиваем с вьетнамскими флешбэками нашим опытом на SoC Design Challenge 2024 и переходим к хакатону этого года, но уже с другой стороны — специалистов, которые помогают организаторам. Спойлеров не будет, а вот о критериях оценки ваших работ и инструментах с конкретными примерами кода с удовольствием расскажем.
Что будет на SoC Design Challenge 2025
Расскажем, что ждет участников трека «Системная верификация СнК» в апреле. Вы снова будете работать с DUT, для которого нужно провести верификацию. Но на этот раз не UART. А что именно — узнаете на самом хакатоне, всех секретов раскрывать не будем. Для DUT нужно будет разработать тестовый план и сами тесты.
В чем отличия от задания прошлого года:
- Участникам больше не придется копаться в самом RTL-коде. Мы решили, что концепция «черного ящика» лучше подходит под формат проведения. К тому же не все участники в прошлом году были хорошо знакомы с SystemVerilog, что стало для них дополнительной сложностью.
- Само задание не будет запускаться с целью проверки, что все работает. Мы планируем намеренно добавить некоторое количество неисправностей, чтобы участники выявили ситуации, в которых эта неисправность проявляется, и описали ее.
- Зафиксированных тестовых данных не будет. Участники должны сами разобраться в том, как лучше представить входные данные и подготовить несколько шаблонов.
Надеемся, что изменения сделают хакатон еще более привлекательным для молодых специалистов.
Как подготовиться к хакатону
Далее поделимся критериями оценки работ участников, а также подробно разберем инструменты QEMU и Verilator, без которых на хакатоне не обойтись. Устраивайтесь поудобнее, будет много кода.
На что обращают внимание судьи
Как судьи выбирают победителей — наверное, самая важная информация. Поделимся основными критериями оценки:
- Качество кода. Здесь будут приветствоваться проверка с помощью статических анализаторов, логичные и понятные названия переменных и функций, лаконичность самого кода и интересные входные данные.
- Тестовое покрытие. Судьи соберут процент покрытых строчек кода с DUT и узнают, насколько хорошо вы справились с написанием тестов.
- Количество найденных ошибок. Как уже говорилось, мы намеренно добавим несколько ошибок. Чем больше ошибок вы найдете, тем больше баллов получите.
- Тестовый план. Он должен быть подробным и понятным.
Мы также решили немного изменить нашу систему косимуляции. В распоряжении участников будет два инструмента: QEMU и Verilator. Займемся разработкой небольшой библиотеки rtl-bridge для Verilator — она будет отвечать за коммуникацию двух частей системы. Давайте разберемся, что это за инструменты.
Обзор инструментов с примерами кода: QEMU и Verilator
QEMU
В косимуляции QEMU в основном нужен для управления тестом: передавать и считывать данные, а также проверять результаты на корректность.
Компания Xilinx уже задумывалась о создании подобных систем косимуляции, поэтому они разработали Remote Port — протокол передачи данных через сокеты. Чтобы этот протокол работал в реальных условиях, Xilinx создала свою версию QEMU и устройство с поддержкой взаимодействия по Remote-Port. Именно ее мы возьмем для небольшого примера.
Для начала надо скачать и собрать QEMU из официального репозитория. Процесс описан в файле README, поэтому подробно разбирать его не будем. Отметим, что не обязательно собирать все таргеты QEMU. Для это во время конфигурирования замените команду на такую:
configure --target-list=riscv32-softmmu, riscv64-softmmu
Рекомендуем использовать версию g++ 11.4.0, так как на более старых версиях могут возникнуть проблемы со сборкой.
Выбираем машину для запуска будущего теста с помощью команды:
qemu-system-riscv32 --machine ?
Получаем такой список:

Напишем простой тест, чтобы отправить строчку «Hello world!» на сторону RTL-кода. Мы планируем писать bare metal-тест, который запускается на «голом железе», то есть без операционной системы. Поэтому нужно узнать регистры и области памяти, в которые будет записываться информация.
Сначала нам нужны регистры UART, чтобы тест мог вывести информацию в консоль QEMU. Открываем файл /hw/riscv/virt.c и находим таблицу virt_memmap. В ней указаны адреса, по которым находятся виртуальные устройства:

UART находится по адресу 0×10000000. Затем ищем вхождение строки «UART» в файле и находим следующий блок кода. Он показывает, что это устройство соответствует спецификации ns16650a:

Документацию к устройству можно прочитать самостоятельно, поэтому привожу уже готовый код:
Функция uart_putc нужна для вывода в консоль одного символа, а uart_puts — для вывода строки.
Теперь пишем тело теста. Для этого выясним, по каким адресам расположено косимуляционное устройство. В таблице virt_memmap указано, что устройство находится по адресу 0×28000000. Тело нашего теста выглядит так:
Отметим три важных момента:
- Мы добавили шаблонные функции для записи в память. Формально это не обязательно, но позволяет отделить использование обычной памяти от обращения к устройствам.
- В конце присутствует бесконечный цикл, чтобы машина QEMU не завершала свое выполнение на некотором адресе — это может привести в непредвиденной ошибке. При желании вы можете организовать штатное завершение выполнения.
- Перед бесконечным циклом мы пишем в адрес, отличный от адреса для записи строки. Эта условность нужна, чтобы мы могли завершить симуляцию.
Для сборки нам нужные специальные компиляторы, которые умеют собирать код под платформу RISC-V. Рекомендую использовать инструменты Syntacore.
Перед сборкой лучше написать код на ассемблере, чтобы установить корректный указатель на стек и линковочный файл для правильного расположения секций:
Пришло время заняться сборкой с помощью инструментов от Syntacore. Makefile будет состоять из четырех этапов:
- Сборка кода на C.
- Сборка ассемблера.
- Компоновка всего этого добра в elf-файл.
- Запуск самого QEMU.
Разберемся, как запустить QEMU:
- Укажем cosim-машину, чтобы создалось устройство cosim.
- В качестве используемого сокета укажем UNIX-сокет по пути /tmp/cosim.sock.
- Укажем директорию для создания записей о работе машины.
- Выключим графику.
- Передадим elf-файл под видом BIOS.
Поясним последний пункт: в линковочном файле указан 0×80000000 — это стандартный адрес расположения BIOS. Поэтому мы передаем elf-файл под видом BIOS. Если мы захотим запустить программу на другом адресе, сначала запустится OpenSBI, который проверит подключенные устройства и передаст управление прикладной функции. Тогда нужно указать другой адрес и запускать QEMU с параметром loader.
Verilator
Приступаем к созданию второй части системы. Для этого устанавливаем Verilator версии 5 и выше. Это потактовый симулятор для языка Verilog, которым можно управлять при помощи программы на C++.
Чтобы разобраться, как работает система Verilator, напишем такую программу:
В программе создаем экземпляр класса, который отвечает за логику нашего Verilog-кода. Пока симуляция не закончится, в цикле производим подсчет новых значений регистров и проводов, а также двигаем время симуляции. Можно считать, что top->eval () передает управление коду на verilog, а contextp->time (top->nextTimeSlot ()) изменяет значение clk.
Для написания testbench нужно понять концепцию DPI-функций. Фактически это функции, которые позволяют передавать данные и поток управления между кодом на C++ и кодом на Verilog. Такой подход позволит выполнять логику RTL-кода и при этом предоставлять интерфейс для Remote-Port.
Для косимуляции нам понадобится несколько функций, которые передают управление из C++ кода и обратно:
- sv_write — функция из C++ сообщает Verilog, что пришла транзакция на запись,
- c_write_resp — Verilog сообщает C++, что транзакцию обработали,
- accept_transaction — Verilog опрашивает код на C++ на предмет пришедших транзакций,
- sv_finish — функция из C++ завершает симуляцию.
Схема вызовов Verilog из кода C++ и обратно:

Теперь напишем Testbench (пока только базовую часть) и объявим все необходимые функции. Про особенности объявления DPI-функций можете почитать на официальном сайте Verilator.
Допишем часть опроса на наличие транзакций и сами DPI-функции:
Теперь нужно обеспечить работу всех вызовов на стороне C++. Для этого создадим структуру, которая будет хранить данные о пришедшей транзакции, и напишем функции подключения и отключения сокета:
В нашем случае readSerializer — это поток, который все время читает сокет и сохраняет полученные пакеты Remote-Port. Код этой функции выглядит так:
Для обработки транзакций напишем функцию handleRequest. Рекомендуем почитать документацию к протоколу Remote-Port, чтобы разобраться с кодом.
Обратите внимание, что все данные приходят в обратной последовательности байт, поэтому необходимо использовать функцию be32toh. Она возвращает байтам правильную последовательность. Также научимся обрабатывать sync-пакеты для корректной работы с QEMU.
Пример кода, который обрабатывает sync-, write- и read-пакеты:
Осталось написать функцию опроса из Verilog, она совсем простая:
Доработаем main, чтобы он создавал сокет:
Теперь можно запускать тест в косимуляции. Приведу пример своего Makefile:
Открываем две консоли и видим долгожданный «Hello World!». Если вы работаете через WSL, то рекомендуем использовать Windows Terminal. Его можно скачать в магазине Microsoft.
В окне с QEMU:

В окне с Verilator:

Общая схема полученной системы:

Ждем на хакатоне
Еще есть время разобраться с инструментами и поработать с исходниками, которые мы упомянули в статье. Всех студентов, которым интересно проверить свои силы и пообщаться с профессионалами рынка системного программирования, ждем на инженерном хакатоне SoC Design Challenge 2025. Главное — верить в свои силы и не пасовать перед вызовами. Желаем удачи!