Привет! Меня зовут Михаил, я руковожу отделом верификации в YADRO. В этом посте я поделюсь нашим опытом верификации и рассмотрю организацию этой работы на разных уровнях. Останавливаться на всех технических подробностях не планирую, но постараюсь осветить все важные моменты, чтобы по итогам поста у вас сложилась цельная картина.

Общие проблемы верификации в ASIC и FPGA

Все сложные дизайны содержат баги. Что не проверено — то не работает. Отсюда следует вывод: сложность вашего дизайна ограничена сложностью верификации, которую вы можете себе позволить. Собственно, мне и пришлось перейти из разработчиков RTL в верификаторы именно из-за того, что рабочие процессы стали упираться именно в верификацию.

В функциональной верификации стоит помнить: мы можем доказать наличие багов, но не их отсутствие. Решение второй проблемы — это уже задача верификации формальной, со своими нюансами и проблемами. Они остаются за скобками, а я остановлюсь именно на функциональной верификации и ее вызовах:

  • возрастающая сложность дизайнов и протоколов,

  • ограниченное время на создание продукта (time to market),

  • ограниченные человеческие и вычислительные ресурсы,

  • увеличение стоимости ошибки на каждом этапе проектирования SoC.

Говорят, что верификация проще в FPGA, так как FPGA можно перепрошить. Взглянем на исследование Wilsom Research Group. Каждые два года они сводят данные компаний в сфере FPGA- и ASIC-разработки: число проектов, сколько из них укладывается в расписание, сколько было перезапусков, по каким причинам и т. д.

Основные причины перезапусков проектов и в FPGA, и в ASIC — это логические ошибки в дизайне.

Расписание проектов выдерживается хорошо если в 25% случаев.

Верификация занимает более половины времени всего дизайна, и у FPGA здесь среднее значение лишь немного ниже. Таким образом, для верификации FPGA подойдут такие же жесткие маршруты, как приняты в ASIC.

Вопросам верификации посвящена немалая часть грядущей конференции FPGA-Systems. 29 ноября, Москва. Два потока и 14 докладов. Регистрируйтесь на онлайн или офлайн.

Что вообще такое верификация

По моему опыту, эта информация есть во всех базовых учебниках, но в самый неподходящий момент ее часто забывают. Верификация — это в первую очередь проверка преобразования из одной точки в другую — то есть кода RTL, под FPGA либо ASIC, на соответствие спецификации.

Выделю здесь два важных момента. Первый: для верификации обязательно нужна спецификация. Иначе вы будете изобретать непонятно что, постоянно меняя дизайн, и это невозможно будет проверифицировать. Второй момент: верификация дизайна подтверждает его соответствие вашей интерпретации спецификации, а не самой спецификации. Если вы верифицируете свой код, то будете воспроизводить те же ошибки, которые допустили при интерпретации спецификации. По этой причине компании стараются разработку и верификацию разделять.

Вторая причина — все возрастающая техническая сложность как разработки, так и верификации. Точка входа — это спецификация. Ее оценивают RTL-разработчик и верификатор, затем один пишет код, другой — верификационное окружение и тесты.

Когда-то верификаторы писали множество направленных тестов, содержавших подачу входных стимулов, чекеры, проверки. По этим тестам оценивалось покрытие. Со временем тестов становилось все больше и было уже непонятно, как их поддерживать, что они проверяют, а что нет. В длительных проектах это становилось большой проблемой.

Сегодня все уже перешли на coverage-driven верификацию — то есть верификацию, управляемую покрытием. Здесь мониторы отделены от тестов. Тесты — это наборы входных воздействий, которые генерируются по constraint’ам. Монитор же контролирует корректность и выполнение этих тестов, собирает статистику по их покрытию. С таким подходом к верификации можно запускать больше тестов со случайной генерацией, покрывать больше состояний дизайна и автоматизировать процессы.

При coverage-driven подходе задача верификатора уже не столько в написании ручных тестов, сколько в определении состояния дизайна, которое нужно достичь и проверить, в написании constraint’ов для тестов, чтобы достичь этого состояния.

SystemVerilog for Verification, Chris Spear. Writing Testbenches using SystemVerilog, Janick Bergeron
SystemVerilog for Verification, Chris Spear. Writing Testbenches using SystemVerilog, Janick Bergeron

По примерам из литературы и собственному опыту мы знаем, что при случайной генерации тестов стопроцентное покрытие достигается гораздо быстрее, чем при направленной. Если есть обратная связь от модели покрытия — когда при генерации новых тестов вы опираетесь на достигнутые результаты — то верификацию можно ускорить еще больше.

Описанная концепция может быть реализована многими инструментами и языками, но в подавляющем большинстве случаев используется SystemVerilog и UVM. Сейчас UVM — это стандарт де-факто, поскольку он решил фундаментальные проблемы верификации сложных цифровых систем: обеспечил стандартизацию, что позволило создать совместимую экосистему инструментов и компонентов, а также сделал многократное использование основным принципом, что радикально повысило производительность и качество труда инженеров-верификаторов. Несмотря на некоторые недостатки — например, оверхед для простых блоков и достаточно высокий порог входа — преимущества UVM для современных проектов неоспоримы.

Что подготовить для верификации

C точки зрения фреймворка все понятно: можете и умеете — используйте UVM, нет — кастомное ООП-окружение. По самому же процессу проведения верификации общего подхода нет. Далее я опишу наш подход.

Если кратко, то работа по верификации разделена на несколько очевидных этапов: план, разработка окружения, разработка тестов, разработка модели покрытия, сведение покрытия. Для каждого этапа есть собственные планы, которые я тоже кратко описал ниже.

Для декомпозиции задач верификации нужно подготовить ряд артефактов. В зависимости от команды, их сбором может заниматься один инженер или разные:

  • План тестирования (верификационный план). Что, где, как и в какие моменты проверять, как контролировать процесс.

  • Система сборки проекта. Как запускать проект на моделирование, получить и воспроизвести результаты.

  • Верификационное окружение. Что будет подавать тестовые воздействия и смотреть за ответами системы.

  • Тесты. Что, собственно, будет запускаться.

  • Инструменты отладки. Механизм воспроизведения ошибок и отладки.

  • Механизм контроля и измерения прогресса. Модель покрытия, его сборки и анализа.

Для каждого из этих документов разработаны шаблоны, составляющие в сумме стратегию верификации. Далее я опишу их по отдельности

Что содержит план тестирования?

  • Входные данные для верификации (документация и DUT, design under test): что дано в качестве входа с версиями (git hash).

  • Подход к разработке тестового окружения: разработка scoreboard или референс-модели, распределение работы между командами.

  • Объем верификации: connectivity, тесты регистров, функциональные тесты, негативное тестирование, тестирование производительности, тестирование энергопотребления, GLS (gate-level simulation).

  • Сценарии верификации.

  • Требования к тестовому окружению.

  • Описание модели покрытия.

Что входит в сценарии верификации:

  • Список проверяемых характеристик.

  • Описание охвата сценариев — точнее, того, что сценарии не охватывают.

  • Сами сценарии, где каждый состоит из описания того, что он должен делать, последовательности действий для разработки тестов, описания платформ для запуска (симуляция, netlist, FPGA и т. п.), условий прохождения и распределения работы между командами.

Для всех проектов обычно используем одну систему сборки, которую постепенно развиваем. Для конкретных же проектов возможны свои индивидуальные настройки, параметры и особенности использования. Это обязательно должно быть описано, чтобы в будущем было проще использовать окружение и подключать к проекту новых инженеров.

Другой документ, которым многие пренебрегают, не менее — описание верификационного окружение, не уступающее по важности спецификации для RTL. Вот что входит в описание:

  • используемые инструменты и методологии;

  • структура тестового окружения: статические интерфейсы и подключение UVM-компонентов к DUT, компоненты для преобразования транзакций, для сбора покрытия, чекеры, внешние источники данных или генераторы воздействий;

  • подключение компонентов окружения через TLM-порты;

  • места вывоза uvm_callbacks;

  • функциональная модель (scoreboard);

  • структура и иерархия sequence (в том числе библиотек HAL);

  • модель покрытия;

  • запуск тестов,

  • контроль корректности завершения тестов.

Вот пример описания структуры нашего верификационного окружения — чтобы проиллюстрировать, с какой степенью детализации стоит проводить эту работу:

Следующий документ — описание функционального покрытия для последующего переноса в код на SystemVerilog.

  • Кодовое покрытие: блоки с метриками, интерфейсы.

  • Функциональное покрытие: метрики и их атрибуты (собираемые значения, место сбора и момент сбора).

  • Формальные утверждения (assertions): описания утверждений со ссылкой на документацию.

  • Направленные тесты. Покрытие может содержать просто список направленных тестов, но, по сути, это тоже контракт и одновременно ТЗ для разработчика функционального покрытия.

В конце верификации готовится отчет о верификации (verification report) c описанием, что и как было сделано.

  • Входные данные для верификации. Что дано в качестве входа с версиями (git hash): архитектурная спецификация, DUT, описания тестового окружения и сценариев.

  • Выходные данные: что получено в качестве результата с версиями (git hash).

  • Реализованные тесты: список, параметры, строки запуска.

  • Отчет о покрытии.

  • Статистика по результатам проведенной работы: количество найденных ошибок в дизайне и время, потраченное на разработку.

  • Изменения относительно исходных планов.

К verification report мы в YADRO прикладываем еще один отчет по результатам работы — с зафиксированными в Jira багами в дизайне и тестбенче, с затраченным временем. Это помогает проводить ретроспективу и улучшать работу команды от проекта к проекту. Например, множество багов в верификационном окружении показывает либо неопытность верификатора, либо проблемы с документацией. В последнем случае разработчик при виде каждого бага будет утверждать, что верификатор не понял спеку и надо описать ее дополнительно. Тогда это системная проблема, которую надо решать по-другому.

Работа по верификационному плану

С верификационным планом связано немало важных вопросов. Как понять, что план полный? Что план написан правильно, измеримо? Как переиспользовать план от проекта к проекту? От блока к системе?

План верификации должен определять конкретно измеримые цели, которые можно охватить точками кодового или функционального покрытия. План должен описывать, что вы будете проверять, а не как проверять — ведь это верификационный план, а не реализация тестов. Наконец, план должен быть разработан так, чтобы прогресс выполнения могли отслеживать в том числе и сторонние люди: те, кто не разбирается в синтаксисе SystemVerilog, но должны понимать, как продвигается проект — проджект-менеджеры, архитекторы и другие специалисты.

Самый популярный метод для составления плана — это брейншторм с участием всех заинтересованных лиц.

В верификационный план включают:

  • Направленные тесты — список тестов, которые команды придумали на основе сценариев.

  • Кодовое покрытие, которое легко получается при симуляции (line coverage, condition coverage, FSM).

  • Покрытие функциональной спецификации — в плане важно отразить все указанные режимы работы.

  • Если используются коммерческие verification IP (VIP), в план могут войти верификационные планы для проверки протоколов, которые можно переиспользовать для экономии времени. Иногда они бывают очень детализированы, особенно для конфигурируемых IP.

  • Список атрибутов с указанием места и момента их сбора — информацию берут из документации.

С этими артефактами уже можно кодировать функциональное покрытие: писать coverage groups и брать точки из VIP. В результате должна получиться такая логика.

  • Функциональная спецификация трансформируется в план верификации.

  • План верификации определяет coverage-метрики.

  • Вы кодируете coverage-метрики в дизайне.

  • Coverage-метрики определяют, какие фичи верификационного плана были покрыты после запуска некоторого количества тестов.

  • Coverage-метрики определяют, что из описанного в спецификации было покрыто тестами.

Следование маршруту от спецификации к функциональным метрикам и обратно позволит точно сказать: «Я запустил столько-то тестов и покрыл столько-то фич, которые написал дизайнер. А вот эти фичи не покрыты, и мне нужно дописать тесты для них».

Получается следующий цикл разработки:

  1. На основе спеки разрабатывают план, готовят environment с рандомными тестами на UVM.

  2. Параллельно тесты массированно запускают на симуляцию.

  3. Получается покрытие для анализа — скорее всего, недостаточное — и начинается новый круг.

Параллельно с этим мы уточняем верификационный план, обновляем его и дописываем тесты. Эта работа завершается, когда покрытие нас наконец-то удовлетворяет.

Критерии достаточного покрытия

Существует два типа покрытия: кодовое и функциональное. В начале верификации процент и кодового, и функционального покрытия низкий. В ходе нормальной работы кодовое покрытие растет быстрее функционального. Постепенно вы приходите к тому, что высоких значений достигают оба: >97% для кодового и 100% для функционального покрытия.

Чтобы добиться такого успеха, верификацию надо строить с модульного уровня и потом подниматься в систему. Прямо в системе такой высокий процент кодового покрытия для мелких блоков получить не удастся. Если, например, у вас самописный UART, то его надо описывать и верифицировать модульно.

В описании покрытия допустимы исключения. Например, вы можете заявить, что не будете учитывать некоторые фичи, которые не охвачены функциональным покрытием. Возможно, вы просто не успеваете поработать с ними, или возникли другие проблемы. Главное — для каждой фичи в списке исключений указать, планируете ли вы все-таки охватить ее в будущем.

Возможны ситуации, когда кодовое покрытие низкое, а функциональное — высокое. Так быть не должно: скорее всего, вы плохо подошли к проработке именно функционального покрытия, и оно получилось маленьким само по себе. В таком случае нужно планировать его заново. Кодовое покрытие без функционального не может гарантировать, что дизайн проверифицирован.

Выше я перечислил множество документов, важных для верификации. Может показаться, что это по большей части пустая трата времени, но для компаний, которые нацелены на длительную работу с большими дизайнами, это хорошая схема планирования. Так у вас точно будет вся информация по работе над дизайном, вы будете понимать распределение, график, прогресс работ, и верификация в целом станет более предсказуемой.

Переиспользуемое окружение

Как организовать верификационное окружение, которое можно будет использовать повторно? Главное — это сделать модель многоуровневой. Модель должна включать сценарный, сигнальный, командный, функциональный уровни вне зависимости от того, используете ли вы UVM или пишете окружение сами. В противном случае справиться со сложностью не получится.

Другие советы по созданию переиспользуемого окружения можно свести в два списка. Вот «зеленые флаги»:

  • Разделяйте scoreboard и активные компоненты. Подключайте scoreboard’ы только к пассивным компонентам.

  • Проводите функциональные проверки в пассивных компонентах.

  • Собирайте функциональное покрытие только в пассивных компонентах.

  • Объявляйте предупреждения только от пассивных компонентов.

  • Не используйте end-of тест от пассивных компонентов.

  • Обновляйте конфигурацию только от пассивных компонентов.

  • Разрешите disable-проверки.

«Красные флаги»:

  • Активные драйверы передают данные напрямую в scoreboard.

  • Имеются чекеры в активных компонентах: драйверах, секвенсорах и т. п.

  • Покрытие определено в активных компонентах.

  • Приходят важные сообщения от драйверов.

  • Конфигурация обновляется из активных компонентов.

  • Драйверы проводят проверки функционального таймаута.

  • Неконтролируемые проверки end-of тест со стороны scoreboard.

Если эти требования не соблюдены в вашем проекте, лучше потратить дополнительное время на разработку необходимых компонентов. На этот счет у меня есть еще один список — во что стоит вкладываться, если вы планируете работать «вдолгую»:

  • Пассивный и активный режим для всех компонентов.

  • Унификация окружений: структура, сообщения, конфигурация и т. д.

  • Общая кодовая база: базовые классы, оболочки, библиотеки утилит и т. д.

  • Рекомендации по стилю кодирования.

  • Автогенерация окружения на основе единого шаблона.

  • Собственная библиотека UVC (Universal Verification Component).

  • «Песочница» — небольшой тестовый дизайн с полным верификационным окружением.

Все это требует дополнительных ресурсов, но зато вам не придется выкидывать старые наработки перед новыми проектами, что в долгосрочной перспективе будет очень выгодно. Теперь — об инструментах, которые помогают верификаторам в нашей команде. 

Memory Mapped Interface

В тестовой среде SoC подключены Verification IP (VIP), которые представляют собой конечные устройства, генерируют трафик на контроллеры. Нам нужно иметь возможность запустить в нужный момент трафик, внести ошибки внутрь дизайна в память, управлять сигналами внутри памяти. Для этого мы сделали специальный механизм — memory mapped interface.

В памяти выделяется область, куда программа, выполняемая на модели процессора, пишет определенные команды. За этой областью памяти следит тестовое окружение (environment). Для упрощения работы реализован отдельный UVM environment, позволяющий централизованно регистрировать executor (функцию, выполняющую определенные действия) и привязывать ее к коду команды, получаемой монитором с шины.

В зависимости от команд environment запускает секвенции, производит действия. Самые простые — это печать чисел и строк, остановка теста. Более сложные — подача ресетов, запуск секвенсов на VIP и т. д.

DPI — универсальный SystemVerilog API

Универсальные компоненты по DPI позволяют подключить модель либо запущенную на x86-хосте, либо подключенную на внешних симуляторах. Представим, что мы хотим работать с неким устройством, а программа, которая хочет это устройство сконфигурировать, запущена и симулируется на модели процессорного кластера. Так симуляция занимает в лучшем случае долгие часы, а иногда и дни.

Самая затратная часть здесь — это моделирование CPU-кластера. Поэтому через DPI-бридж его модель выносится на софтверный стек — например, в QEMU. Там работает программа, а в симуляцию подаются команды чтения и записи по интерфейсу.

Далее возможны проблемы с моделированием памяти, поскольку это второй по затратам времени этап. Причина здесь в том, что «внешний программный стек» ходит с инструкциями в память, которая симулируется — в DDR и/или SRAM, где лежат данные. Поэтому память тоже выносится тоже на сторону хоста, в косимуляцию. Подключаются уже слоевые DPI-бриджи, и контроллеры через интерконнект могут ходить в память, которая моделируется снаружи. Третий компонент, который необходимо реализовать в такой схеме, — прерывания. Для них есть дополнительные функции, позволяющие передать прерывание в программный симулятор и получить подтверждение о завершении его обработки (это сделано специально). 

Тот же самый подход используется для модульной верификации: DUT обвязывается только DPI. Есть управляющий интерфейс, есть AXI и AXI-Slave для модульного блока. Чтобы софтверный стек, запущенный на QEMU, и симуляция какого-либо контроллера работали параллельно и независимо, существует бридж с очередями, который «развязывает» два потока управления.

Как строится тестовое окружение

Дам пару рекомендаций о создании модульного тестового окружения, которое упростит работу. Scoreboard подключаем по TLM. Если в качестве модели сравнения используется DPI, то он подключается ровно на то же место, на тот же scoreboard. Так получится нормальный модульный дизайн — не надо пытаться сэкономить и сразу из монитора что-то кидать в DPI.

Для упрощения структуры coverage collector выносится отдельно. Так же как и чекеры, что позволяет нескольким инженерам работать параллельно.

Python для верификации

Верификаторы нужны многим, но UVM и SystemVerilog имеют довольно высокий порог входа. Поэтому для верификации сегодня пытаются использовать Python. Библиотека Cocotb позволяет проводить симуляцию, подавать тестовое воздействие со стороны Python. Для создания тестового окружения на Cocotb по методологии UVM предназначена надстройка PyUVM. В открытом доступе есть библиотеки VIP для шин AMBA и части низкоскоростных контроллеров. Минусом этих компонентов является отсутствие какой-либо стандартизации кода. Но этот подход в любом случае позволяет разработчикам быстро писать собственные окружения и тесты.

В отличие от SystemVerilog, на Python нет конструкции языка, которая делает рандомизацию типов, и нет механизмов для сбора функционального покрытия. Эти недостатки решаются двумя библиотеками — pyvsc и cocotb-coverage соответственно. Для эксперимента мы проводили модульную верификацию одного и того же небольшого блока на UVM SystemVerilog и Cocotb + Python. Вторая связка в нашем случае оказалась медленнее примерно на 30%. Чем меньше блок, тем меньше эта разница, поскольку можно запустить несколько задач в параллель.

Что кардинально замедляет верификацию, так это библиотека для сбора покрытия: снижение производительности даже более существенное, чем на SystemVerilog. Поэтому у нас предусмотрены две опции регресса — просто для проверки работоспособности (daily regress) и отдельно для сбора покрытия (weekly coverage regress). 

В результате нашего опыта мы не стали продолжать использовать Python в рабочих задачах. Основные причины — недостаточное количество и качество доступных VIP для cocotb/PyUVM (даже в сравнении с коммерческими VIP от ведущих вендоров) и невозможность переиспользования окружений на системном уровне.

Вопросам верификации посвящена немалая часть грядущей конференции FPGA-Systems. 29 ноября, Москва. Два потока и 14 докладов. Регистрируйтесь на онлайн или офлайн.

Комментарии (7)


  1. Lampus
    17.10.2025 15:24

    Скажу пару слов про cocotb.
    Тоже пытались использовать для небольшого блока.
    RAL там появился относительно недавно. Реализацией соответствующей подсистемы в PyUVM занимался какой-то человек из Qualcomm, но почему-то он это делал местами без оглядки на API описанном в IEEE 1800.2.
    С Verification IP там совсем всё грустно. Чаще всего их просто нет, а если что-то есть, то под старую версию. В том же cocotbext-ahb нашли парочку существенных багов.
    cocotbext-apb тоже пришлось немного пропатчить.
    pyvsc на свежий Python 3.13 не встаёт, приходится отдельно ставить версию 3.12.

    Ну и про более низкий порог входа утверждение спорное, т.к. с cocotb+PyUVM надо быть готовым к тому что ты впорешься в какой-то не совсем очевидный баг либо extension-а, либо самого PyUVM, а дальше надо суметь это раздебажить. Не каждый новичок готов к таким приключениям, мягко скажем.


  1. mozg37
    17.10.2025 15:24

    Вот прочитал и ничего не понял. Не увидел ни одного инструмента, который действительно применяю при отладке - на железе. Не могли бы вы подробно расписать процесс верификации какого нибудь простого блока - к примеру, уарт с фифо.


  1. AlexanderS
    17.10.2025 15:24

    Расписание проектов выдерживается хорошо если в 25% случаев.

    Это ж получается какая-то тотальная профнепригодность, когда раз от раза менеджмент "промазывает" со сроками! Со временем же опыт оценки должен накапливаться и ошибки планирования минимизироваться.


  1. Lerk
    17.10.2025 15:24

    Вот за что мне нравятся отечественные статьи про микроэлектронику - так за то, что люди бесплатно делятся годами опыта, сотнями бессонных ночей, потраченными нервами просто так. В этой статье - лет десять опыта системной верификации. Новички, вероятно, поймут далеко не все. Опытные люди укажут что ещё очень много всего не описано. Тем не менее статья - супер.

    В принципе, по стилю похоже на статьи от консультантов McKinsey - указано что делать, не указано как ;)


    1. mozg37
      17.10.2025 15:24

      Но не могут/не хотят набросать простенький тест простенькой задачи - ну чтоб понятно было для более широкого круга читателей. Ведь статья для читателей, а не для выполнения плана по статьям. Чтоб, например, были ясны преимущества данного подхода.


      1. Lerk
        17.10.2025 15:24

        На мой взгляд статья подана соответствующее должности автора. Будущие или нынешние менеджеры отделов верификации больших чипов будут благодарны. Примеры с кодом требуются для линейных работников, и в данном случае разворачивание статьи детально с примерами выльется в книгу страниц на 200 а то и больше. В таком случае не дурно и классику почитать - Chris Spear, для начала.

        На всякий случай - я автора не знаю, и к ядру отношения не имею :)


        1. mozg37
          17.10.2025 15:24

          Хм. Для тестирования уарта потребуется написать книгу на 200стр? Пожалуй поищу другую технологию верификации.