Open Source VHDL Verification Methodology/Better Coverage in VHDL/ru
- Верификация в VHDL
- Презентация (eng)
- Better Coverage in VHDL (eng)
Введение
Почему тесбенчей (testbenches) не достаточно
Testbench vs. Coverage
- Для небольших проектов или небольших блоков больших проектов, можно создать тестбенч, который будет:
- давать правильные результаты моделирования
- осуществлять все режимы работы устройства
- В случае больших современных проектов со сложной функциональностью, даже самый знающий разработчик может пропустить некоторые режимы работы при создании тестбенча.
- Поэтому необходимо подтверждение того, что:
- в тестбенче проверяются все режимы работы устройства,
- поведение устройства является ожидаемым.
Необходимо проверка покрытия (Coverage)!
Что такое покрытие (Coverage)?
- Покрытие является крайне неоднозначным термином, когда используется сам по себе.
Можно сказать, что (в электронике):
![]() |
Покрытие (Coverage) является одной из разновидностей метрик проекта, которая сообщает, если определённые аспекты проекта были правильно выполнены во время процедуры тестирования. |
- Обычно уточняют термин покрытия, говоря какой аспект был протестирован:
- Тестирование качества кода — покрытие кода (code coverage)
- проверка свойств/утверждений — покрытие свойств/утверждений (property coverage)
- Сбор значений переменных проекта — функциональное покрытие (functional coverage).
Structure vs. Functionality
- при моделировании HDL-кода проекта с включенной опцией покрытие кода (code coverage), можно контролировать, все ли элементы структуры кода (code structure) были выполнены. Если они все выполнены, то принято считать, что качество проекта высокое.
- Полностью протестированный HDL-код может по прежнему не соответствовать спецификации проекта: отсутствие ошибок означает то, что фактическая, а не требуемая функциональность кода была протестирована...
- Функциональное тестирование (представленное покрытием свойств/утверждений и функциональным покрытием) дает больше информации, чем тестирование структуры кода.
Являются ли структурные и функциональные тесты взаимоисключающими или же они перекрывают друг друга?
Качество кода vs. функциональность (функционирование)
В чем проблема?
- Можно согласиться, что необходимо иметь хороший код проекта. Плохой код может иногда удивлять правильным функционированием, но это не управляемый процесс.
- Необходима проверка покрытия кода!
- Известно, что хороший код может представлять плохую функциональность.
- Можно моделировать много, чтобы убедиться, что он действительно представляет собой желаемое поведение проекта.
- Проведение покрытия свойств/утверждений и функциональное покрытие может сделать это быстрее и лучше!
- Рассмотрим каковы преимущества и недостатки всех трех видов покрытия ...
Разновидности покрытия кода (Code Coverage)
Когда и как их использовать?
Основы покрытия кода
- Покрытие кода было изобретено, чтобы улучшить качество программ, написанных на «обычных» языках программирования (например, C).
- По своей природе, покрытие кода анализирует структурную корректность кода, а не функциональную корректность! Структурно неправильный код обычно работает неправильно, поэтому исправление плохого кода обычно корректирует функциональные ошибки.
- Покрытие кода превратилось в широкое разнообразие разновидностей для решения очевидных и хорошо скрытых проблем, которые могут проникнуть в код.
Основные разновидности кодового покрытия
- Основными разновидностями покрытия кода являются:
- Покрытие операторов (Statement Coverage) – проверка все ли операторы в коде были выполнены хотя бы один раз,
- Покрытие ветвей (переходов) (Branch Coverage) – проверка все ли ветви условных операторов (if, case и др.) были пройдены.
- Покрытие операторов очень схоже с покрытием строк (Line Coverage), результаты которых будут отличаться, если только программист записывает больше одного оператора в одной строке (что является плохой практикой).
- Результаты покрытия ветвей могут быть извлечены из результатов покрытия состояний (утверждений), но в больших проектах это очень трудоёмкая задача...
Дополнительные разновидности покрытия кода
- Покрытие операторов и ветвей может давать ложные положительные результаты, когда имеют места необычные выражения:
-
Trig := SensA or SensB;
-
- Есть 4 различных комбинации значений SensA и SensB, но покрытие операторов будет полным уже после всего одного выполнения данного оператора.
В таких случаях необходимо выполнять покрытие выражений (Expression Coverage). |
---|
-
if Load='1' and Enable='1' then ...
-
- Покрытие ветвей только сообщит о том, что ветвь не была пройдена, без указания из-за какого сигнала (Load или Enable, или обоих) ветка не выполнилась.
В таких случаях требуется проводить покрытие состояний (Condition Coverage). |
---|
Специальные разновидности покрытия
|
|
HDL аспекты покрытия кода ???
- Исходное покрытие кода было создано для последовательного кода и игнорирует параллелизм и модульность языка VHDL.
- Проблема модульности может быть решена путем сбора данных по каждому экземпляру/элементу (per instance) в дополнение к сбору данных на компонент (per unit):
- Если у вас есть компоненты D-триггеров используемые 4 раза и включен сбор данных по компоненту, то выполнение одного экземпляра/элемента означает полное покрытие.
- Если вы включите сбор данных по каждому экземпляру/элементу в том же проекте, то все 4 элемента должны быть выполнены, чтобы выполнить полное покрытие.
- Нет никаких способов проверки (с покрытием кода) одновременного выполнение двух процессов, размещённых в одном компоненте (блоке) ...
Покрытие кода в программах САПР
- Покрытие кода не является особенностью (функцией) языка — это функция программы САПР...
- Как таковая, она обычно требует более продвинутой версии симулятора или дополнительной лицензии.
- Всегда проверяйте какие разновидности покрытия кода поддерживаются программами моделирования.
- Все программы САПР должны генерировать текстовые отчеты о покрытии (coverage reports);
- Ищите дополнительные просмоторщики покрытия (coverage viewers), которые делают анализ результатов покрытия кода проще.
- Не включайте все разновидности покрытия одновременно;
- Это будет замедлять работу моделирования и обычно не даёт значительно лучших результатов ...
Выводы
- Покрытие кода проверяет структурную целостность кода непосредственно и только косвенно свидетельствует о функциональной корректности.
- Покрытие кода позволяет улучшить качество процесса верификации.
- 100% покрытие кода никогда не дает гарантии, что проект функционирует правильно.
- Покрытие кода менее 100% является сильным признаком, что есть также проблемы функционирования в проекте.
- Покрытие кода не будет проверять параллелизм и временные ограничения!
Покрытие свойств/утверждений (Property Coverage)
Close Relative of Assertions
Основные термины
- Булева логика (Boolean logic) тестирует основные утверждения (statements) о проекте.
- Временная логика (Temporal logic) добавляет временнОе измерение (dimension) в булеву логику (Boolean logic) и тестирует отсутствие (absence), наличие (presence), неизменность/повторяемость (persistence), последовательность (sequence), и прочее определённых событий.
- Свойства/утверждения (Property) это формальное описание поведения проекта, взятое из спецификации проекта и выраженное в терминах временной логики (temporal logic).
- Свойства/утверждения (Properties) могут быть выражены с помощью PSL (Property Specification Language – теперь включен в VHDL) или с помощью SVA (подмножество SystemVerilog Assertions – работает с VHDL через модули проверок (checker modules)).
- Последовательности (Sequences) являются простейшей формой свойств/утверждений, представляющие последовательность событий/состояний.
Clocking Properties
- И PSL и SVA используют дискретное время для временной логики (temporal logic), например, они фиксируют/собирают (sample) значения сигналов в проекте по определённым синхронным событиям (clocking events)
- PSL позволяет установить синхросигнал по умолчанию, используя:
-
default clock is rising_edge(CLK1);
-
- или задать синхросигнал для заданного свойства/утверждения (или последовательности), используя:
-
my_prop_or_seq @falling_edge(CLK2);
-
- Можно использовать функции rose() и fell() для обнаружения изменения сигналов в целях «внутреннего тактирования» (“internal clocking”)
Примеры простых последовательностей
Последовательность событий/объединение/конкатенация (Concatenation): A является true в текущем периоде синхросигнала, а B является true в следующем периоде:
Объединение/конкатенация с последовательным повторением (Concatenation with Consecutive Repetition): A является true для 2 периодов синхросигнала, а B является true для 2 периодов синхросигнала (начиная со следующей выборки после окончания последовательности A):
Последовательное повторение с диапазоном (Consecutive Repetition With Range): A является true для 2-х периодов синхросигнала, а B является true от 2 до 3 периодов синхросигнала (начиная со следующего отсчета после окончания последовательности A):
Соединение с повторением (Fusion with Repetition): A является true для 2-х периодов синхросигнала, а B является true от 2 до 3 периодов синхросигнала (начиная с того же отсчёта, где оканчивается последовательность A):
Ещё примеры последовательностей
Inclosure: A является true для 2 периодов синхросигнала в приделах (within) времени 5 периодов синхросигнала, пока B равно true:
Не последовательное повторение (Non-consecutive Repetition): A является true для 2 периодов синхросигнала (не обязательно последовательных) в приделах (within) времени 5-ти периодов синхросигнала, пока B равно true :
Go-to Repetition: A равно true для 2 периодов синхросигналов (не последовательных, но включая последнюю выборку в последовательности) в течении (within) 5 периодов синхросигнала, когда B равно true:
Примеры свойств/утверждений (Property)
Оператор always: Сигнал POWER должен быть всегда (always) равен '1':
- always (POWER='1')
Оператор never: Сигнал Z никогда не должен быть true сразу после Y:
- never {Y ; Z}
Оператор eventually!: Сигнал DONE должен быть true до окончания моделирования:
- eventually! DONE
Non-overlapping implication: If X is true for 2 cycles, then Y is true for 3 cycles starting at the last sample of X:
Overlapping implication: If X is true for 2 cycles, then Y is true for next 3 cycles after the last sample of X:
Property Coverage vs. Assertions
- Свойсвта/Утвержения, проверяемые директивой assert, предупреждают нас только если что-либо пошло не так (что не хорошо для покрытия).
- Нужно использовать Свойство/Утверждение с директивой cover для подтверждения того, что поведение, которое оно (утверждение) представляет, было протестировано.
- Свойства/Утверждения используемые с директивой cover включают property coverage;
- приходит сообщение, когда Свойство/Утверждение выполняется успешьно и отчет показывает все свойства/утверждения, которые не были покрыты.
- (Vacuous pass — situation when implication antecedent is false — avoids false alarms in assertions, but triggers false positives in covers)
- Свойства/Утверждения с импликацией (|=>, |->) являются очень удобными в assertions (утверждениях), но не очень подходящими для covers (покрытия).
- Vacuous pass — ситуация, когда мипликация предыдущего шага является ложным — ............
Design Example
- Quote from the design specification:
- Signal DVALID should be activated 3 to 5 clock cycles after activation of ACK and 2 to 4 clock cycles before deactivation of ACK.
- DVALID should remain active at least 2 clock cycles after deactivation of ACK.
- First phase of the property:
- { rose(ACK) : (ACK='1')[*3 to 5] }
- Second phase:
- { rose(DVALID) : ((ACK and DVALID)='1')[*2 to 4] }
- or even
- { rose(DVALID) : (DVALID='1')[*2 to 4] }
- Third, final phase:
- { fell(ACK) : (DVALID='1')[*2 to inf] }
Пример проекта – продолжение
- Можно вставлять PSL код в специальные комментарии в VHDL;
- таким образом, этот код не будет оказывать влияния на синтез и похожие программы.
- Можно задать 3 последовательности (sequences) для предстваления трёх фаз задаваемого свойства.
- Конечное описания свойства (property) объединяет эти 3 последовательности.
- Помеченная меткой директива cover показывает симулятору как проверять это свойство.
--@clk rising_edge(CLK); --@psl sequence ack35_s is { rose(ACK) : (ACK='1')[*3 to 5] } ; --@psl sequence dvalid24_s is { rose(DVALID) : (DVALID='1')[*2 to 4] } ; --@psl sequence dvalid2inf_s is { fell(ACK) : (DVALID='1')[*2 to inf] } ; --@psl property ackdvalid_p is { ack35_s ; dvalid24_s ; dvalid2inf_s } ; --@psl ackdvalid_c: cover(ackdvalid_p) report "Sequence ACK/DVALID covered!";
Советы по покрытию свойств (Property Coverage Hints)
- Дополнительные ресурсы при моделировании необходимы для проверки свойств, поэтому, чтобы следует не злоупотреблять с их добавлением.
- не следует добавлять свойства, описывающие очевидное поведение, например, счёт счётчика. Неисправности в таких случаях будет легко определить при моделировании.
-
Следует добавить свойства, проверяющие критическое поведение (critical behaviors), особенно если они не демонстрируют сразу же как изменится сигнал на верхнем уровне.
- Добавить свойства, тестирующие взаимодействие данных данных, поступающих из различных блоков проекта (особенно при работе с IP-блоками).
Выводы
- Покрытие свойств проверяет функциональную корректность проекта с помощью сравнения его поведения по отношению к свойствам проекта.
- Покрытие свойств требует некоторого кодирования на языке PSL (или SVA) и соответствующей лицензии для моделирования.
- 100% покрытие свойств говорит о том, что все свойства, которые вы задали, были выполнены, так что выбирайте их разумно.
- Менее чем 100% покрытия свойств означает то, что поведение проекта не соответствует требованиям спецификации проекта!
- Свойства работают также при формальной верификации.
Smart Functional Coverage
How OS-VVM Does It Better in VHDL
Почему функциональное покрытие
- Иногда цель покрытия трудно выразить в терминах поведения;
- Это может быть проще задать, используя значения переменных проекта.
- Давайте рассмотрим следующий пример климат-контроллера, читающего данные с 8-битного датчика влажности:
- показания от 0 до 100 могут вызвать 5 различных действий,
- Показания выше 100 являются ошибочными (запрещёнными).
- Если определить все возможные значения переменной датчика, как показано ниже. Как мы можем убедиться в том, что все диапазоны были протестированы, и не было избыточного тестирования?
Значение диапазонов |
от 0 до 9 | от 10 до 29 | от 30 до 70 | от 71 до 90 | от 91 до 100 | от 101 до 255 |
---|---|---|---|---|---|---|
Статус | Too_Low | Low | Normal | High | Too_High | Illegal |
Покрытие корзин (Bins)
Value Range | 0 to 9 | 10 to 29 | 30 to 70 | 71 to 90 | 91 to 100 | 101 to 255 |
---|---|---|---|---|---|---|
Status | Too_Low | Low | Normal | High | Too_High | Illegal |
- Функциональное покрытие (Functional coverage) подсчитывает значения переменных проекта по заранее определённым корзинам (bins) — группам значений, которые имеют специальное значение в проекте.
- Корзины, используя только одну переменную создают структуру данных, которая называют элементом покрытия (coverage item) или точкой покрытия (coverage point), например, 6 корзин для заданной переменной сенсора влажности.
- Можно создать корзины перекрёстного покрытия (cross coverage bins) совмещающие значения нескольких переменных, чтобы получить элемент перекрёстного покрытия (cross coverage item).
- If we have action variable in our climate control design with values Idle, Humidify, Dehumidify, Alarm we can create bins like this: (Low, Humidify), (Normal, Idle), (High, Dehumidify), (Illegal, Alarm), etc.
- Если есть действующая/активная (action) переменная в приведённом проекте климат-контроля со значениями Idle, Humidify, Dehumidify, Alarm мы можем создать корзины как следующие: (Low, Humidify), (Normal, Idle), (High, Dehumidify), (Illegal, Alarm), и т.д.
- Корзины могу считать отсчеты, защёлкивать ошибки или могут игнорироваться во время моделирования.
Функционально покрытие (ФП) и Рандомизация(Randomization)
- Функциональное покрытие (Functional coverage) может работать самостоятельно, но это наиболее удобно при совмещении с constrained random stimulus.
- In our humidity sensor example, we can randomly generate readouts and stop simulation when each bin was hit at least once; this way we complete tests much faster than in the case of scanning through all possible sensor readouts.
- Some languages have elaborate constraint system for random variables that requires dedicated constraint solver and works independently from functional coverage.
- What if we could have live feedback coming from the FC engine that controls randomization?
Smart Functional Coverage
- Open Source VHDL Verification Methodology (OS-VVM*) introduced to VHDL the concept of smart functional coverage.
- OS-VVM contains both randomization and functional coverage packages that can work independently, but also create coverage → randomization feedback that enables smarter, more efficient verification.
- Smart coverage controls randomization process to ensure that values belonging to already covered bins are no longer randomly generated.
- * To learn more about OS-VVM, please watch recording of our previous webinar or visit osvvm.org.
Smart Coverage Benefits
- When random number generator produces uniformly distributed values from the range 1..n, it takes approximately n log(n) trials to cover all values in the range. This number is even higher for non-uniform distributions.
- Smart coverage reduces the number of trials to precisely n.
- In plain language, smart coverage gives you guarantee that each value in the randomized range will show up only once.
- You can fine tune smart coverage by using different randomization weights for different coverage bins.
Smart Coverage Example
- Let’s say that we 100x100 display matrix that we want to test randomly so that each pixel is tested at least once.
variable XYCov : CovPType; -- coverage item object declared using -- CovPType from the OS-VVM package variable X,Y : integer; -- index data buffers . . . XYCov.AddCross(GenBin(0,99), GenBin(0,99)); -- 100x100 bin matrix XYCov.InitSeed(XYCov'instance_name); -- seed for smart coverage . . . while not XYCov.IsCovered loop -- loop runs until indices covered wait until rising_edge(CLK); -- sampling event detection (X, Y) := XYCov.RandCovPoint; -- randomize uncovered indices XYCov.ICover((X, Y)); -- collect cross data end loop;
Summary
- Functional coverage checks correctness of the design by collecting values (or sets of values) of design variables during simulation.
- Bin definition requires sound knowledge of the design structure and functionality.
- Functional coverage requires some coding in VHDL — minimal if you use OS-VVM.
- 100% property coverage says that all bins you have specified were hit during simulation.
- Smart coverage speeds up simulation by controlling randomization dynamically.
Conclusion
Summary, Contact Data, Q&A
Which Coverage?
Coverage Kind | Coding Required? | Tool Setup Required? | Special License? | Checks Code Structure | Checks Design Behavior |
---|---|---|---|---|---|
Code Coverage | No | Yes | Yes | ![]() |
|
Property Coverage | Yes | No | Yes | ![]() | |
Functional Coverage | Yes | No | No | ![]() |
- As we see in the comparison table, there is no single kind of coverage that has advantages only.
- Code coverage checks code structure, but may be expensive.
- Property coverage is excellent for checking behavior, but may be expensive, too.
- Functional coverage with OS-VVM has only one drawback – it requires some coding...
- Balanced use of those three coverage kinds should dramatically increase design quality and reduce verification time.