Open Source VHDL Verification Methodology/Описание пакета CoveragePkg
Материал из Wiki
- Руководство пользователя (eng)
- Описание пакета CoveragePkg (eng)
- Описание пакета RandomPkg (eng)
Первый пример: ручное отслеживание размера пакета
Функциональное покрытие может быть собрано с любого кода. Пакет CoveragePkg и синтаксис языка предназначены исключительно для упрощения этой возможности. В качестве первого примера, просто напишем код.
В пакетной передаче (такой как Ethernet), наиболее интересные эффекты возникают когда размер передачи равно или близко к минимальному или максимальному размеру передачи. Важно, чтобы происходили передачи среднего размера, но чтобы их было не слишком много. Для этого примера, предположим, что нас интересуют следующие пересылки следующих размеров или диапазонов: 1, 2, 3, 4–127, 128–252, 253, 254, 255. Эти размеры передач взяты из плана тестирования.
Нужно также определиться в какой момент собирать данные покрытия. В следующем коде используется положительный фронт синхросигнала Clk при установленном флаге TransactionDone в 1.
signal Bin : integer_vector(1 to 8) ; . . . process begin wait until rising_edge(Clk) and TransactionDone = '1' ; case to_integer(unsigned(ActualData)) is when 1 => Bin(1) <= Bin(1) + 1 ; when 2 => Bin(2) <= Bin(2) + 1 ; when 3 => Bin(3) <= Bin(3) + 1 ; when 4 to 127 => Bin(4) <= Bin(4) + 1 ; when 128 to 252 => Bin(5) <= Bin(5) + 1 ; when 253 => Bin(6) <= Bin(6) + 1 ; when 254 => Bin(7) <= Bin(7) + 1 ; when 255 => Bin(8) <= Bin(8) + 1 ; when others => end case ; end process ;
Любое покрытие может быть описано таким образом. Однако, это является слишком трудоёмким и узконаправленным. Можно было бы сделать небольшое улучшение этого описания путём переноса кода в процедуру. Это поможет с локальным повторным использованием, но по прежнему не будет встроенных функций (таких как отчет или сохранение базы).
Основы покрытия точек (Point или Item Coverage) в пакете CoveragePkg
Точка покрытия рассматривает значения в пределах одного объекта, например, как мы делали в примере в предыдущем разделе. Основные шаги выполнены, когда сбор функционального покрытия объявить покрытие объекта, модель (описание) покрытия, накопление покрытие, взаимодействие со структурой охвата данных и отчет о покрытии. (The basic steps done when collecting functional coverage are declare the coverage object, model (describe) the coverage, accumulate the coverage, interact with the coverage data structure, and report the coverage.) В этом разделе мы рассмотрим, как это сделать с CoveragePkg.
Элемент (атом) или точка покрытия (одиночный объект) это набор из одной или более корзин, так, например, 8 корзин было в предыдущем примере: 1, 2, 3, от 4 до 127, от 128 до 252, 253, 254, 255. В пакете CoveragePkg каждая карзина представляет собой минимальное и максимальное значения (фактически диапазон). Корзины, которые имеют только одно значение, такие как 1, представляются парой 1, 1 (что значит значения от 1 до 1). Внутреннее представление значений минимума и максимума сохраняется в структуре (тип record) вместе с информацией о других корзинах.
Структура данных для покрытия скрыта с помощью защищенного типа (типа protected) CovPType. Первый шаг для моделирования элемента (точки) монтирования является создание открытой переменной (shared variable) для хранения структуры данных, такой как CovBin1 в приведённом ниже описании:
architecture Test1 of tb is shared variable CovBin1 : CovPType ; begin
Следующий шаг — это вызов функции GenBin, чтобы создать корзины, и затем вызов метода (функции) AddBins, чтобы добавить корзины в защищённый тип. Версия GenBin, показанная ниже, имеет три параметра: минимальное значение, максимальное значение и число карзин. Вызов, GenBin(1,3,3), разбивает диапазон от 1 до 3 на три отдельных корзины с диапазонами от 1 до 1, от 2 до 2, и от 3 до 3.
TestProc : process begin -- min, max, #bins CovBin1.AddBins(GenBin(1, 3, 3)); -- bins 1 to 1, 2 to 2, 3 to 3 . . .
Дополнительные вызов AddBins добавит дополнительные корзины к структуре данных. В результате, вызов, GenBin(4, 252, 2), добавит две корзины с диапазонами от 4 до 127 и от 128 до 252 соответственно.
CovBin1.AddBins(GenBin( 4, 252, 2)) ; -- bins 4 to 127 and 128 to 252
Так как создание одной корзины на значение в диапазоне является основным, то есть так же версия функции (метода) GenBin, которая имеет два параметра: минимальное и максимальное значения, которая создаёт одну корзину на значение. В результате, вызов GenBin(253, 255) добавит три корзины с диапазонами от 253 до 253, от 254 до 254, и от 255 до 255.
CovBin1.AddBins(GenBin(253, 255)) ; -- bins 253, 254, 255
Следующий шаг это вызов метода ICover для сбора покрытия. Эта методология поддерживает или синхронный сбор данных (по синхросигналу, как показано ниже) (clock based sampling) или сбор данных, основанный на передаче (транзакции – transaction based sampling) (путём вызова метода ICover после транзакции, которая возвращает значение — будет показано в последующих примерах).
-- Accumulating coverage using clock based sampling loop wait until rising_edge(Clk) and nReset = '1' ; CovBin1.ICover(to_integer(unsigned(RxData_slv))) ; end loop ; end process ;
Когда тест будет тест выполнен, то необходимо вывести отчет о покрытии. Один из способов сделать это — вызов метода IsCovered. Метод IsCovered возвращает значение true, когда все корзины в структуре данных покрытия достигли своих целей. Также как ICover, метод IsCovered вызывается в момент сбора данных (или по переходу или по транзакции). Вызов метода WriteBin выводит результаты покрытия в выходной поток (в окно транскрипта, если симулятор запущен интерактивно). Следующий код печатает результаты покрытия после достижения полного покрытия.
ReportCov : process begin wait until rising_edge(Clk) and Bin1.IsCovered ; CovBin1.WriteBin ; wait ; end process ;
Весь пример в целом показан ниже. Обратите внимание, что когда работаете с покрытием, то мы в основном работаем с целыми числами (integer). Все входные переменные в методах GenBin и ICover имеют тип integer, метод WriteBin выводит результаты тоже в целочисленных значениях. Каждый из методов имеет дополнительную перегрузку, которая будет описана позже.
architecture Test1 of tb is shared variable CovBin1 : CovPType ; -- Coverage Object begin TestProc : process begin -- Model the coverage CovBin1.AddBins(GenBin(1, 3 )); -- bins 1, 2, 3 CovBin1.AddBins(GenBin( 4, 252, 2)) ; -- bins 4 to 127 and 128 to 252 CovBin1.AddBins(GenBin(253, 255 )) ; -- 253, 254, 255 -- Accumulating coverage using clock based sampling loop wait until rising_edge(Clk) and nReset = '1' ; CovBin1.ICover(to_integer(unsigned(RxData_slv))) ; end loop ; end process ; ReportCov : process begin wait until rising_edge(Clk) and Bin1.IsCovered ; CovBin1.WriteBin ; wait ; end process ;
Перекрёстное покрытие (Cross Coverage)
Совместное покрытие контролирует отношение между различными объектами, так например как в АЛУ выполнены все возможные операции с каждой из возможных различных пар регистров. Схема в примере следующая:
В этой задаче для упрощения принято, что в АЛУ поддерживается только операция сложения. Перекрёстное покрытие требует чтобы каждый регистр использовался с другим каждым регистром. Это приводит к следующей матрице искомых точек покрытия.
SRC2 | |||||||||
---|---|---|---|---|---|---|---|---|---|
R0 | R1 | R2 | R3 | R4 | R5 | R6 | R7 | ||
SRC1 | R0 | ||||||||
R1 | |||||||||
R2 | |||||||||
R3 | |||||||||
R4 | |||||||||
R5 | |||||||||
R6 | |||||||||
R7 |
При выполнении перекрёстного покрытия, необходимо выполнить те же самые шаги, которые использовались при создании точек покрытия: объявление, модель, сбор, взаимодействие и отчет. Эти шаги показаны в коде, приведённом ниже. Первый шаг объявления объекта покрытия ACov, как открытой переменной (shared). Следующий шаг создание модели покрытия, используя метод AddCross. Для перекрёстного покрытия метод AddCross заменяет метод AddBins. Более подробно об этом позже. Следующий шаг создание транзакции пока не будет достигнуто полное покрытие. Первым делом в этом цикле является проверка состояния покрытия с помощью метода IsCovered. Далее использование метода RandInt для псевдослучаного выбора адресов регистров и получения значения, которое лежит в диапазоне от 0 до 7. Более подробно о методе RandInt есть в документации на пакет RandomPkg (доступной по ссылке http://www.SynthWorks.com/downloads). Эти адреса регистров используются процедурой DoAluOp для создания транзакций. После того как транзакция выполнена, проводится сбор данных с помощью метода ICover. После завершения цикла записывают результаты покрытия и выполнение тестбенча прекращается (используя процедуру EndStatus).
architecture Test2 of tb is shared variable ACov : CovPType ; -- Declare Cov Object begin TestProc : process variable RV : RandomPType ; variable RegIn1, RegIn2 : integer ; begin ACov.AddCross( GenBin(0,7), GenBin(0,7) ); -- Model while not ACov.IsCovered loop -- Interact -- Randomize register addresses -- see RandomPkg documentation RegIn1 := RV.RandInt(0, 7) ; RegIn2 := RV.RandInt(0, 7) ; DoAluOp(TRec, RegIn1, RegIn2) ; -- Do a transaction ACov.ICover( (RegIn1, RegIn2) ) ; -- Accumulate end loop ; ACov.WriteBin ; -- Report EndStatus(. . . ) ; end process ;
Сбор данных о перекрёстном покрытии является большей частью похож на сбор данных о точке покрытия, кроме того, что шаги создания модели и сбора данных изменились. Метод AddCross создаёт векторное произведение (cross product) корзин точек (созданных с помощью функции GenBin), заданных в качестве входных переменных (аргументов). Каждый вызов GenBin(0,7) создаёт 8 корзин: 0, 1, 2, 3, 4, 5, 6, 7. В результате чего AddCross создаёт 64 карзины со следующими парами: (0,0), (0,1), (0,2), (0,3), (0,4), (0,5), (0,6), (0,7), (1,0), (1,1), (1,2), (1,3), … , (7,0), (7,1), (7,2), (7,3), (7,4), (7,5), (7,6), (7,7).
На этапе сбора данных по прежнему вызывается метод ICover, однако, с перекрёстным покрытием. Метод ICover имеет вход типа integer_vector с одним значением для каждой точки в перекрёстном покрытии. В результате, вызов требует второй набор круглых скобок для обозначения типа integer_vector, состоящего из двух элементов RegIn1 и RegIn2.
Эта модель делает только перекрёстное произведение двух точек, но метод AddCross поддерживает пересечение до 20 элементов.
Проблема настраиваемой генерации псевдослучайных тестов (Constrained Random)
Ранее было отмечено, что тестебенч с перестраиваемым генератором псевдослучайных значений требует O(N * Log N) циклов, чтобы получить N-уникальных тестовых состояний. Функция log N может увеличить время моделирования от 10 до 100 раз. Запуская предыдущего тестбенча АЛУ, получили следующую матрицу покрытия, когда код был выполнен. Это заняло 315 ≈ 64 * log(64) псевдослучайных тестов. Изменяя начальное значение (seed), число выполненных псевдослучайных чисел может увеличиваться или уменьшаться (но это было бы глупо пытаться уменьшить число итераций запусков тестов).
SRC2 | |||||||||
---|---|---|---|---|---|---|---|---|---|
R0 | R1 | R2 | R3 | R4 | R5 | R6 | R7 | ||
SRC2 | R0 | 6 | 6 | 9 | 1 | 4 | 6 | 6 | 5 |
R1 | 3 | 4 | 3 | 6 | 9 | 5 | 5 | 4 | |
R2 | 4 | 1 | 5 | 3 | 2 | 3 | 4 | 6 | |
R3 | 5 | 5 | 6 | 3 | 3 | 4 | 4 | 6 | |
R4 | 4 | 5 | 5 | 10 | 9 | 10 | 7 | 7 | |
R5 | 4 | 6 | 3 | 6 | 3 | 5 | 3 | 8 | |
R6 | 3 | 6 | 3 | 4 | 7 | 1 | 4 | 6 | |
R7 | 7 | 3 | 4 | 6 | 6 | 5 | 4 | 5 |
Интелектуальное покрытие (Intelligent Coverage)
Интелектуальное покрытие это то, что отличает пакет CoveragePkg от других методологий покрытия (основананных на синтаксисе и других). Процесс прост. Добавляются цели покрытия и/или веса для структуры данных и псевдослучайного выбора дырок (holes) в покрытии, чтобы следующий элемент был сгенерирован. Используя это можно генерировать каждый элемент точное число раз, сколько задано в его цели. Код показан ниже:
architecture Test3 of tb is shared variable ACov : CovPType ; -- Declare Cov Object begin TestProc : process variable RegIn1, RegIn2 : integer ; begin -- AtLeast, Bin1, Bin2 ACov.AddCross( 2, GenBin(0,7,8), GenBin(0,7,8) ); -- Model while not ACov.IsCovered loop -- Interact -- Randomize register addresses -- see RandomPkg documentation (RegIn1, RegIn2) := ACov.RandCovPoint ; DoAluOp(TRec, RegIn1, RegIn2) ; -- Do a transaction ACov.ICover( (RegIn1, RegIn2) ) ; -- Accumulate end loop ; ACov.WriteBin ; -- Report EndStatus(. . . ) ; end process ;
В таком подходе добавляются цели покрытия для шагов моделирования (AddCross, AddBins, и/или GenBin) и используется RandCovPoint для псевдослучайного тестирования. В листинге выше, параметр AtLeast метода AddCross равен 2. Это значит, что корзина считается не покрытой (coverage hole), пока она не сработает дважды. Метод RandCovPoint псевдослучайно выбирает корзину покрытия, которая ещё не покрыта и тогда выбирает псевдослучайно выбирает значение, которое входит в эту корзину покрытия. Метод RandCovPoint всегда возвращает значение типа integer_vector.
Incremental Coverage Construction
Не всякое покрытие может быть смоделировано как векторное произведение (перекрёстное произведение) множества точек. Вместо этого могут быть исключены либо отдельные точки, либо ряды или столбцы точек. Хотя методы AddCross и AddBins позволяют ввести всю информацию в одном вызове, они также позволяют инкрементное добавление в модель покрытия. Лучше думать о том, что исключить, но в пакете CoveragePkg мы думали о том, что мы хотим в моделе и постепенно добавляли в структуру модели корзину за корзиной, если это необходимо. Таким образом, создание высоко точной модели перекрёстного покрытия относительно проста.
Высокоточная модель перекрёстного покрытия важна. Без неё, достигнуть 100% покрытия невозможно. В дополнение, методология интеллектуального покрытия не будет работать без этого. Инкрементное формирование модели покрытия также способствует заданию разных корзин с различными весами.
В качестве примера рассмотрим АЛУ, добавляя запрет регистров, которые будут использоваться сами с собой. Кроме того, каждой строке задаётся своя цель покрытия, как показано в таблице ниже. По умолчанию цель покрытия также используется в качестве веса. Вес определяет относительную частоту возникновения элемента в течении псевдослучайного тестирования. Хотя это и не реальный пример, но он показывает возможности пакета CoveragePkg по моделированию покрытия. свещения.
Coverage Goal | Bin1 | Bin2 |
---|---|---|
1 | 0 | 1, 2, 3, 4, 5, 6, 7 |
2 | 1 | 0, 2, 3, 4, 5, 6, 7 |
3 | 2 | 0, 1, 3, 4, 5, 6, 7 |
4 | 3 | 0, 1, 2, 4, 5, 6, 7 |
5 | 4 | 0, 1, 2, 3, 5, 6, 7 |
6 | 5 | 0, 1, 2, 3, 4, 6, 7 |
7 | 6 | 0, 1, 2, 3, 4, 5, 7 |
8 | 7 | 0, 1, 2, 3, 4, 5, 6 |
Для моделирования показанного выше покрытия, можно выполнить отдельный вызов каждой отличной цели покрытия
architecture Test4 of tb is shared variable ACov : CovPType ; -- Declare Cov Object begin TestProc : process variable RegIn1, RegIn2 : integer ; begin -- Capture coverage model ACov.AddCross( 1, GenBin (0), GenBin(1,7)) ; ACov.AddCross( 2, GenBin (1), GenBin(0) & GenBin(2,7)) ; ACov.AddCross( 3, GenBin (2), GenBin(0,1) & GenBin(3,7)) ; ACov.AddCross( 4, GenBin (3), GenBin(0,2) & GenBin(4,7)) ; ACov.AddCross( 5, GenBin (4), GenBin(0,3) & GenBin(5,7)) ; ACov.AddCross( 6, GenBin (5), GenBin(0,4) & GenBin(6,7)) ; ACov.AddCross( 7, GenBin (6), GenBin(0,5) & GenBin(7)) ; ACov.AddCross( 8, GenBin (7), GenBin(0,6) ) ; while not ACov.IsCovered loop -- Interact -- Randomize register addresses -- see RandomPkg documentation (RegIn1, RegIn2) := ACov.RandCovPoint ; DoAluOp(TRec, RegIn1, RegIn2) ; -- Do a transaction ACov.ICover( (RegIn1, RegIn2) ) ; -- Accumulate end loop ; ACov.WriteBin ; -- Report EndStatus(. . . ) ; end process ;
GenBin, IllegalBin, и IgnoreBin
GenBin, IllegalBin, и IgnoreBin используются для создания корзин типа CovBinType. Использование функций заменяет необходимость в знании деталей типов. CovBinType является массивом типа record CovBinBaseType. Это показано ниже.
type CovBinBaseType is record . . . end record ; type CovBinType is array (natural range <>) of CovBinBaseType ;
GenBin
Далее представлены пять вариантов функции GenBin. Функции с параметрами AtLeast и Weight предназначаются в основном для использования с контактами.
function GenBin(Min, Max, NumBin : integer ) return CovBinType ; function GenBin(Min, Max : integer) return CovBinType ; function GenBin(A : integer) return CovBinType ; -- Only intended for constants function GenBin(AtLeast, Weight, Min, Max, NumBin : in integer) return CovBinType ; function GenBin(AtLeast, Min, Max, NumBin : integer ) return CovBinType ;
Версия функции GenBin, показанная ниже, имеет три параметра: минимальное значение, максимальное значение и число корзин. Вызов GenBin(1, 3, 3) разбивает диапазон от 1 до 3 на 3 разных корзины с диапазонами от 1 до 1, от 2 до 2, и от 3 до 3.
-- min, max, #bins CovBin1.AddBins(GenBin(1, 3, 3)); -- bins 1 to 1, 2 to 2, 3 to 3
Если значений меньше (между максимом и минимумом) чем корзин, то только "max – min + 1" корзин будет создано. В результате вызова GenBin(1,3,20) всё равно будет создано три корзины с диапазонами: от 1 до 1, от 2 до 2, и от 3 до 3.
CovBin2.AddBins( GenBin(1, 3, 20) ) ; -- bins 1 to 1, 2 to 2, and 3 to 3
Если значений больше (между минимумом и максимумом), чем корзин и диапазон не делится поровну между корзинами, то каждая корзина имеет в среднем (max – min + 1)/bins. При этом последние корзины будут иметь немного большее значение, по сравнению с предыдущими корзинами. Точная используемая формула это (число оставшихся значений)/(число оставшихся корзин). В результате выполнения функции GenBin(1, 14, 4) создаётся четыре корзины с диапазонами от 1 до 3, от 4 до 6, от 7 до 10, и от 11 до 14.
CovBin2.AddBins( GenBin(1, 14, 4) ) ; -- 1 to 3, 4 to 6, 7 to 10, 11 to 14
Так как создание одной корзины на значение в диапазоне часто встречается, то есть также версия функции GenBin, которая имеет два параметра: минимальное и максимальное значения, которая создаёт одну корзина на значение. В результате первый вызов AddBins/GenBin может быть сокращен следующим образом.
-- min, max CovBin1.AddBins(GenBin(1, 3)); -- bins 1 to 1, 2 to 2, and 3 to 3
Функция GenBin может быть также вызвана с одним параметром, тогда одно значение, которое включается в корзину. В этом случае выполнение функции GenBin(5) создаст одиночную корзину с диапазоном от 5 до 5. Следующие два вызова являются эквивалентными.
CovBin3.AddBins( GenBin(5) ) ; CovBin3.AddBins( GenBin(5,5,1) ) ; -- equivalent call
Запрещённые и игнорируемые корзины
При создании корзин, иногда необходимо обозначить корзины как запрещённые и обозначить ошибки, или как игнорируемые действия и не считать их.
Функции IllegalBin и IgnoreBin используются для создания запрещённых и игнорируемых корзин. Одна версия IllegalBin и IgnoreBin имеет три параметра: минимальное значение, максимальное значение и число корзин (точно как в функции GenBin).
-- min, max, NumBin IllegalBin( 1, 9, 3) -- создаёт 3 запрещённые корзины: 1-3, 4-6, 7-9 IllegalBin( 1, 9, 1) -- создаёт одну запрещённую корзину с диапазоном 1-9 IgnoreBin ( 1, 3, 3) -- создаёт 3 игнорируемых корзины: 1, 2, 3
Существует также версия функций IgnoreBin и IllegalBin с двумя параметрами, которая создаёт одну корзину. Несколько примеров, показывающих это приведено ниже. В то время как это не похоже на действие функции GenBin с двумя параметрами, но это совпадает с общим поведением создания запрещённых и игнорируемых корзин.
-- min, max IllegalBin( 1, 9) -- создаёт одну запрещённую корзину с диапазоном 1-9 IgnoreBin ( 1, 3) -- создаёт одну игнорируемую корзину с диапазоном 1-3
Существует также версия функций IgnoreBin и IllegalBin с одним параметром, которая создаёт одиночную корзину с одним значением. Примеры этого показаны ниже.
-- AVal IllegalBin( 5 ) -- creates one illegal bin with range 5-5 IgnoreBin ( 7 ) -- creates one ignore bin with range 7-7
Предопределённые корзины
Далее показаны предопределённые корзины.
constant ALL_BIN : CovBinType := GenBin(integer'left, integer'right, 1) ; constant ALL_COUNT : CovBinType := GenBin(integer'left, integer'right, 1) ; constant ALL_ILLEGAL : CovBinType := IllegalBin(integer'left, integer'right, 1) ; constant ALL_IGNORE : CovBinType := IgnoreBin(integer'left, integer'right, 1) ; constant ZERO_BIN : CovBinType := GenBin(0) ; constant ONE_BIN : CovBinType := GenBin(1) ;
Совмещение (combining) корзин
Так как все функции GenBin, IllegalBin, и IgnoreBin возвращают значение типа CovBinType, их результаты могут быть объединены (конкатенация) вместе. В результате следущее выполнение функции GenBin создаёт корзины: от 1 до 1, от 2 до 2, от 3 до 3, от 2 до 127, от 128 до 252, от 253 до 253, от 254 до 254, и от 255 до 255.
CovBin1.AddBins(GenBin(0, 2) & GenBin(3, 252, 2) & GenBin(253, 255));
Вызовы функций GenBin, IllegalBin, и IgnoreBin могут также комбинироваться. В результате в следующем примере создаётся четыре отдельных допустимых корзины и одна игнорируемая корзина, а всё остальное попадает в запрещённую корзину.
CovBin2.AddBins( GenBin(1,2) & IgnoreBin(3,4) & GenBin(5,6) & ALL_ILLEGAL ) ;
Создание структуры данных (Data Structure Construction)
Методы AddBins и AddCross используются для создания структуры покрытия данных.
Метод AddBins
Метод AddBins используется для добавления корзин точки покрытия в структуру данных покрытия. Каждый раз, когда вызывается этот метод, новые корзины добавляются после уже созданных корзин. Метод AddBins имеет дополнительные параметры для возможности задания цели покрытия (AtLeast) и веса псевдослучайного тестирования (Weight). Используя раздельные вызовы AddBins, каждая корзина может иметь различные цель покрытия и/или вес псевдослучайного тестирования.
procedure AddBins (CovBin : CovBinType) ; procedure AddBins (AtLeast : integer ; CovBin : CovBinType) ; procedure AddBins (AtLeast, Weight : integer ; CovBin : CovBinType) ;
Метод AddCross
Метод AddCross используется для добавления корзин перекрёстной верификации в структуру данных покрытия. При каждом вызове этого метода добавляются новые корзины после уже созданных корзин. Также как AddBins, метод AddCross имеет дополнительные параметры для задания цели покрытия (AtLeast) и веса псевдослучайного тестирования (Weight). Используя раздельные вызовы AddCross, каждая корзина может иметь различные цель покрытия и/или вес псевдослучайного тестирования.
procedure AddCross( Bin1, Bin2 : CovBinType ; Bin3, Bin4, Bin5, Bin6, Bin7, Bin8, Bin9, Bin10, Bin11, Bin12, Bin13, Bin14, Bin15, Bin16, Bin17, Bin18, Bin19, Bin20 : CovBinType := NULL_BIN ) ; procedure AddCross( AtLeast : integer ; Bin1, Bin2 : CovBinType ; Bin3, Bin4, Bin5, Bin6, Bin7, Bin8, Bin9, Bin10, Bin11, Bin12, Bin13, Bin14, Bin15, Bin16, Bin17, Bin18, Bin19, Bin20 : CovBinType := NULL_BIN ) ; procedure AddCross( AtLeast : integer ; Weight : integer ; Bin1, Bin2 : CovBinType ; Bin3, Bin4, Bin5, Bin6, Bin7, Bin8, Bin9, Bin10, Bin11, Bin12, Bin13, Bin14, Bin15, Bin16, Bin17, Bin18, Bin19, Bin20 : CovBinType := NULL_BIN ) ;
Множественное соответствие внутри структуры данных покрытия
Когда покрытие имеет больше одной корзины, то корзины обрабатываются по порядку. По умолчанию, если корзины пересекаются, то только первая подходящая корзина учитывается.
Такое поведения управляется переменной CountMode. Это является экспериментальной функцией и может быть исключено в будущих версиях, если это будет влиять на время моделирования. По умолчанию эта переменная имеет значение COUNT_FIRST. Установка режима счета в COUNT_ALL, как показано ниже, позволяет считать все подходящие корзины.
type CountModeType is (COUNT_FIRST, COUNT_ALL) ; CovBin4.SetCountMode(COUNT_ALL) ; -- Count all matching bins CovBin4.SetCountMode(COUNT_FIRST) ; -- default. Only count first matching bin
Looking forward to revision 3.0 of the package, when CountMode is COUNT_FIRST, bins that are contained in earlier bins will be removed. Repeated count bins will be merged. This action is likely to subsume the need for COUNT_ALL and works better in an environment with Intelligent Coverage and a mixture of count, ignore, and illegal bins. If you have a needed use model for COUNT_ALL, make sure to contact the package author. Also make sure to set it before adding items to the coverage model.
В будущей версии 3.0 пакета, режим когда CountMode установлен в COUNT_FIRST, когда обрабатываются только первая подходящая корзина будет исключен. Повторяющиеся считаемые корзины будут объединены. Это действие может вобрать в себя необходимость COUNT_ALL и работает лучше в окружении для интеллектуального покрытия и смеси считаемых, игнорируемых и запрещённых корзин. Если вам необходимо использовать модель COUNT_ALL, то свяжитесь с автором пакета. Также будьте уверены, что установили его прежде чем добавлять элементы в модель покрытия.
Управление отчетом для запрещённых корзин
По умолчанию запрещённые корзины считаются и отмечаются ошибкой. Такое поведения управляется переменной IllegalMode. Значение по умолчанию этой переменной ILLEGAL_ON. Установка режима счета в ILLEGAL_OFF, как показано ниже, отключает печать сообщение об ошибках.
type IllegalModeType is (ILLEGAL_ON, ILLEGAL_OFF) ; CovBin4.SetIllegalMode(ILLEGAL_OFF) ; -- Illegal printing off CovBin4.SetIllegalMode(ILLEGAL_ON) ; -- Default: Illegal printing on
Метод SetBinSize
Метод SetBinSize предустанавливает число корзин, создаваемое в структуре данных покрытия. Используйте это для малых корзин для сохранения места или больших корзин для исключения изменения размера и копирования, которые происходят при изменении размеров корзин.
procedure SetBinSize (NewNumBins : integer) ;
Накопление покрытия (Accumulating Coverage)
Метод ICover используется для накопления покрытия. Для точек покрытия, метод ICover принимает значение integer. Для перекрёстного покрытия, метод ICover принимает значение integer_vector. Интерфейсы процедуры показаны ниже. Поскольку накопление покрытия написано процедурно, то ICover поддерживает сохранение данных по клоку или транзакции (примеры обоих методов были показаны выше).
procedure ICover( CovPoint : in integer ) ; procedure ICover( CovPoint : in integer_vector ) ;
Поскольку входы должны быть типа integer или integer_vector, то необходимо использовать преобразование типов. Для конвертации std_logic_vector в integer, numeric_std_unsigned в numeric_std есть следующие преобразования.
CovBin3.ICover( to_integer(RxData_slv) ) ; -- using numeric_std_unsigned (2008) CovBin3.ICover( to_integer(unsigned(RxData_slv)) ) ; -- using numeric_std
Чтобы преобразовать std_logic или boolean в integer, пакет CoveragePkg предоставляет перегруженную функцию to_integer.
CovBin3.ICover( to_integer(Empty) ) ; -- std_logic CovBin3.ICover( to_integer(Empty = '1') ) ; -- boolean
Для конвертации типов std_logic_vector или boolean_vector в integer_vector (побитно), пакет CoveragePkg предоставляет функцию to_integer_vector.
CrossBin.ICover( to_integer_vector(CtrlReg_slv) ) ; -- std_logic_vector CrossBin.ICover( to_integer_vector((Empty='1')&(Rdy='1')) ) ; -- boolean_vector
Since the language does not do introspection of aggregate values when determining the type of an expression, the boolean vector expression needs to be constructed using concatenation (as shown above) rather than aggregates (as shown below).
Так как язык не делает самоанализ (самодиагностика) совокупности значений при определении типа выражения, то выражение с булевым вектором должно быть построено используя операцию конкатенации (показано выше), а не множества (как показано ниже).
--! CrossBin.ICover( to_integer_vector( ((Empty='1'),(Rdy='1')) )); -- ambiguous
Отчет о покрытии
Процедуры WriteBin и WriteCovHoles используются для отчета о покрытии. Следующие интерфейсы поддерживаются для этих перегруженных методов. Параметры типа String используются, так как язык не разрешает использовать параметры типа file в методах защищённых (protected) типов.
procedure WriteBin ; procedure WriteBin (FileName : string; OpenKind : File_Open_Kind := APPEND_MODE) ; procedure WriteCovHoles ( PercentCov : real := 100.0 ) ; procedure WriteCovHoles ( FileName : string; PercentCov : real := 100.0 ; OpenKind : File_Open_Kind := APPEND_MODE ) ;
Метод WriteBin печатает (выводит) результаты покрытия с с выводом одной корзины на строку. Есть две версии. Первая не имеет аргументов и выводит в стандартный поток OUTPUT. Это показано ниже. Следует обратить внимание, что корзины, отмеченные как игнорируемые не выводятся WriteBin, а корзины отмеченные как запрещённые выводятся только если они имеют не нулевые значения счетчика (счёта).
ReportCov : process begin wait until rising_edge(Clk) and Bin1.IsCovered ; CovBin1.WriteBin ; wait ; end process ;
Другая версия метода принимает два аргумента. Первый аргумент FileName задаёт имя файла (тип string). Второй аргумент задаёт значение OpenKind (to file_open) и принимает одно из значений WRITE_MODE или APPEND_MODE. Аргумент OpenKind инициализируется в значение APPEND_MODE.
-- FileName, OpenKind CovBin1.WriteBin ("Test1.txt", WRITE_MODE);
Метод WriteCovHoles выводит результаты покрытия, которые ниже параметра PercentCov. Следует обратить внимание, что корзины помеченные как запрещённые или игнорируемые не выводятся методом WriteCovHoles. Параметр ProcentCov инициализируется в 100% и обычно таким и остается.
CovBin1.WriteCovHoles ;
Другая версия WriteCovHoles задаёт FileName, PercentCov, и OpenKind в похожем стиле метода WriteBin. Аргумент инициализируется в APPEND_MODE. Это показано ниже.
-- FileName, PercentCov OpenKind CovBin1.WriteCovHoles("Test1.txt", 100.0, APPEND_MODE);
Методы SetName и SetItemName используютя для печати первой и второй строки заголовка для методов WriteBin и WriteCovHoles. SetName предназначается для ссылки на имя или цель корзины покрытия. SetItemName предназначена для вывода столбцов заголовка для корзин покрытия. Каждая из них также использует их строковые параметры для инициализации внутреннего начального значения(seed) для псевдослучайного генератора чисел.
CovBin1.SetName("DMA") ; -- Group name - prints first CovBin1.SetItemName("Stat, WordCnt") ; -- Item Names
12 Coverage Goals, Weights, and Randomization
Цели, веса покрытия и псевдослучайное покрытие является ядром методологии интеллектуального покрытия.
Цели и веса покрытия
Цель покрытия задаёт сколько раз значение должно попасть в корзину прежде чем корзина будет считаться проверенной (покрытой). Вес псевдослучайного тестирования определяет относительное число раз выбора корзины при псевдослучайном тестировании. Любое из следующего может определяться для использования в качестве веса псевдослучайного тестирования: цель покрытия, вес, или оставшееся покрытие . Каждая корзина может иметь различные цель и вес покрытия.
Выбор режима веса выполнен используя SetWeightMode. Следующая таблица показывает текущий набор поддерживаемых режимов и то, как вес псевдослучайного тестирования (генерации) вычисляется.
Mode Weight At_Least AtLeast Weight Weight Remain Scale*AtLeast – Count Scale is used to adjust the weight when the desired percent coverage is above or below 100%
Интерфейс для процедуры SetWeightMode показан ниже. Следует обратить внимание на то, что параметр Scale процедуры SetWeightMode и режимы REMAIN_AT_LEAST и REMAIN_WEIGHT являются экспериментальными и их может не быть в следующих версиях пакета.
type WeightModeType is (AT_LEAST, WEIGHT, REMAIN, REMAIN_AT_LEAST, REMAIN_WEIGHT); procedure SetWeightMode (A : WeightModeType; Scale : real := 1.5) ;
Добавление цели покрытия и веса в модель покрытия
Все методы создания корзин и функции поддерживают дополнительный параметр, которы позволяет определять AtLeast (цель покрытия) and Weight (потенциальный выбор веся псевдослучайного генератора). В основно это определяется в методах AddBins и AddCover, как было показано ранее.
Позже будет показано, что GenBin, IllegalBin, IgnoreBin, и GenCross также поддерживают задание AtLeast и Weight, но они в основном позволяют задать это в качестве константы.
Основы псевдослучайного тестирования
Псевдослучайное тестирование осуществляется с помощью RandCovPoint или RandCovHole. RandCovPoint возвращает псевдослучайно выбранное значение типа integer_vector из псевдослучайно выбранной корзины. RandCovHole возвращает псевдослучайно выбранную корзину и возвращает тип RangeArrayType
. Только корзины, которые не достигли заданного процента от цели покрытия (по умолчанию 100%) используются для псевдослучайного генератора значений. Тип RangeArrayType и задание функции показаны ниже. Следует обратить внимание на то, что рекомендуется использовать RandCovPoint, если возможно, так как RangeArrayType может измениться.
type RangeType is record min, max : integer ; end record ; type RangeArrayType is array (integer range <>) of RangeType; impure function RandCovHole (PercentCov : real := 100.0) return RangeArrayType ; impure function RandCovPoint (PercentCov : real := 100.0) return integer_vector ;
Генератор псевдослучайных чисел, запрещённые и игнорируемые корзины
RandCovPoint и RandCovHole никогда не выберут корзины, обозначенные как запрещённые, либо игнорируемые. Однако, если считаемая корзина перекрывает запрещённую или игнорируемую корзину, тогда запрещённое или игнорируемое значение может быть выдано генератором псевдослучайных чисел. В настоящий момент метод около этого, необходимо тщательно создавать ваши корзины, чтобы этого не произошло.
12.5 Randomization Thresholds
Каждый вызов RandCovPoint и RandCovHole позоволяет определять PercentCov. Для большинства тестов значение 100.0%. RandCovPoint и RandCovHole псевдослучайно выбирают любую корзину, которая имеет покрытие, менее чем задано в PercentCov.
Задание PercentCov менее 100.0 позволяет определить выполняются ли определённые пороги внутри корзин покрытия. В идеале этот порог будет иметь некоторое значение, которое в рамках определённого процента от текущего минимального покрытия в модели покрытия и будет увеличиваться с увеличением минимального (минимума) покрытия. Задавая значение PercentCov менее чем текущее значение минимального покрытия, например, 0.0, будет использоваться автоматическое установление порога. Автоматический порог устанавливается равным текущее минимальное покрытие плюс значение внутренней переменной CovThresholdPercent. Внутренняя переменная CovThresholdPercent устанавливается с помощью процедуры SetCovThreshold. При использовании автоматического задания порога, рекомендуется устанавливать PercentCov равным 0.0.
procedure SetCovThreshold (Percent : real) ;
Автоматическое задание порога полезно при попытке достичь сбалансированного решения всех корзин, когда корзины имеют цель покрытия, которая больше 1. Автоматическое задание порога расширяет понятие циклического псевдослучайного тестирования (cyclic randomization), чтобы работать через набор значений перекрёстного покрытия, где каждое значение должно произойти несколько раз.
Задание начальных значений псевдослучайного генератора (Seed)
Внутреннее начальное значение генератора псевдослучайных чисел может инициализировано, использую методы InitSeed [string] и InitSeed [integer]. Примеры их использования приведены ниже.
procedure InitSeed (S : string ) ; procedure InitSeed (I : integer ) ; . . . CovBin1.InitSeed( CovBin1'path_name ) ; -- string procedure SetSeed (RandomSeedIn : RandomSeedType ) ; impure function GetSeed return RandomSeedType ;
В дополнении, методы SetName и SetItemName (используя с отчетом о покрытии) также вызывают InitSeed со своим параметром. Примеры показаны ниже. В результате, для большинства тестов, использовать SetName или SetItemName достаточно, чтобы быть уверенным, что каждая модель покрытия имеет уникальное начальное значение (seed) генератора случайных чисел.
procedure SetName (NameIn : String) ; procedure SetItemName (ItemNameIn : String) ; . . . CovBin1.SetName("DMA: Stat, WordCnt") ; -- also calls InitSeed
Методы GetSeed и SetSeed предназначены для сохранения и восстановления значения seed. В этом случае значение seed имеет тип RandomSeedType, который определён в пакете RandomBasePkg. Пакет RandomBasePkg также определяет процедуры для чтения и записи значений RandomSeedType.
Взаимодействие со структурой данных покрытия
В дополнение к псевдослучайной генерации чисел, следующие методы обеспечивают взаимодействие со структурами данных покрытия.
impure function IsCovered (PercentCov : real := 100.0) return boolean ; impure function CovBinErrCnt return integer ; impure function GetMinCov return real ; impure function GetMaxCov return real ; impure function CountCovHoles (PercentCov : real := 100.0) return integer ; impure function GetCovHole(ReqHoleNum : integer := 1 ; PercentCov : real := 100.0) return RangeArrayType ;
Метод IsCovered возвращает значение true, когда все счётчики корзин в структуре данных покрытия достигли своей цели. Так как ICover, метод IsCovered вызывается в точке отбора данных по синхросигналу или по транзакции.
Метод CovBinErrCnt суммирует значения счетчиков всех корзин ошибок и возвращает результирующее значение. В основном CovBinErrCnt вызывается в конце тестбенча для модели покрытия, которая имеет корзины обозначенные как запрещённые.
TestErrCount := CovBin1.CovBinErrCnt + (Other_Error_Sources) ;
Метод GetMinCov возвращает наименьшее значение счетчика какой-либо отслеживаемой корзины. Метод GetMaxCov возвращает наибольшее значение счётчика в контролируемых корзинах. Обе эти функции вызываются следующим образом
MinCov := CovBin1.GetMinCov ; MaxCov := CovBin1.GetMaxCov ;
Метод CountCovHoles возвращает число дырок (holes), которые ниже значения параметра PercentCov (в основном установленное по умолчанию 100.0).
-- PercentCov NumHoles := CovBin1.CountCovHoles( 100.0 ) ;
Метод GetCovHole берёт корзину с номером ReqHoleNum с значением покрытия меньше, чем значение PercentCov. Следующий вызов GetCovHole берёт пятую корзину, которая имеет покрытие менее 100%. Следует обратить внимание, что ReqHoleNum должно быть в диапазоне между 1 и CountCovHoles. Значение, возвращаемое GetCovHole, имеет тип RangeArrayType (такой же тип возвращается методом RandCovHole).
-- ReqHoleNum, PercentCov TestData := CovBin1.GetCovHole( 5, 100.0 ) ;
Операции над базой данных покрытия
Покрытие может быть собрано с помощью записи результатов покрытия с одного теста и затем прочитано обратно в начале следующего теста. Методы, использующиеся для этого, приведены ниже. Параметры типа string используются, так как язык не позволяет использовать параметры типа file с методами защищённого типа.
procedure ReadCovDb (FileName : in string) ; procedure WriteCovDb (FileName : in string; OpenKind : File_Open_Kind := APPEND_MODE ) ;
Метод WriteCovDb сохраняет результаты покрытия в файл. Он имеет два аргумента. Первый аргумент FileName задаёт имя файла и имеет тип string. Второй аргумент OpenKind задаёт режим открытия файла (file_open) и принимает значения WRITE_MODE, либо APPEND_MODE. Аргумент OpenKind инициализируется значением APPEND_MODE. Пример показан ниже.
-- FileName, OpenKind CovBin1.WriteCovDb( "CovDb.txt", WRITE_MODE ) ;
Метод ReadCovDb читает значения из файла. Он имеет один параметр типа string. Пример приведён ниже.
-- FileName CovBin1.ReadCovDb( "CovDb.txt" );
Метод SetCovZero устанавливает все счётчики покрытия в корзине покрытия в 0. Это позволяет установить счетчики в 0 после чтения базы данных покрытия. Простой вызов этого метода показан ниже.
CovBin1.SetCovZero ; -- set all counts to 0
Метод Deallocate освобождает все структуры базы данных.
CovBin1.Deallocate ;
Создание корзин с помощью констант
Константы используются с двумя целями. Первая — это создание коротких удобных имён для корзин точек покрытия (обычное предназначение констант) и затем использование этих имён позже в формировании модели покрытия. Вторая — это создание всей модели покрытия в постоянной, чтобы облегчить повторное использование модели.
Константы для корзин точек покрытия
В предыдущей модели, мы создали модель перекрёстного покрытия, используя следующий вызов метода AddCross.
ACov.AddCross( GenBin(0,7), GenBin(0,7) ); -- Model
На этапе уточнения создана константа корзины точки для регистра адреса, такого как REG_ADDR, показанного ниже. REG_ADDR имеет тип CovBinType. Поскольку константы могут получать свой диапазон, основываясь на объекте им присвоенному, то проще всего оставить CovBinType неограниченным (по диапазону).
constant REG_ADDR : CovBinType := GenBin(0, 7) ;
Однажды созданная константа, может использоваться и для будущих выражений, как показано ниже. Также как обычные константы, это увеличивает читаемость и редактируемость (удобство сопровождения) кода.
ACov.AddCross(REG_ADDR, REG_ADDR); -- Model
Since each element in a point bin may require different coverage goals or weights, additional overloading of GenBin were added. These are shown below.
Поскольку каждый элемент в корзине точки может требовать различных целей покрытия или весов, то были добавлены дополнительные перегруженные функции GenBin. Это показано ниже.
function GenBin(AtLeast, Weight, Min, Max, NumBin : integer ) return CovBinType ; function GenBin(AtLeast, Min, Max, NumBin : integer ) return CovBinType ;
Как показано ранее, корзины точе могут быть собраны с помощью конкатенации. Следующий пример создаёт две корзины от 0 до 31 с целью покрытия 5, и от 32 до 63 с целью покрытия 10.
constant A_BIN : CovBinType := GenBin(5, 0, 31, 1) & GenBin(10, 32, 63, 1) ;
Запись модели перекрёстного покрытия с помощью констант
Чтобы захватить модель перекрёстного покрытия в константу требуется некоторые дополнительные типы и функции. Следующая методология основана на стандарте языка до VHDL-2008 и требует отдельного определения типа для каждого размера модели перекрёстного покрытия. В настоящий момент перекрёстное произведение до 9 отдельных элементов поддерживается следующим типом. В стандарте VHDL-2008, где композиция (composites) допускается, чтобы иметь элементы не ограниченного диапазона, это бы сократилось к одному типу (и перекрёстное произведение более 9 элементов могло бы с лёгкостью поддерживаться).
type CovMatrix2Type is array (natural range <>) of CovMatrix2BaseType; type CovMatrix3Type is array (natural range <>) of CovMatrix3BaseType; type CovMatrix4Type is array (natural range <>) of CovMatrix4BaseType; type CovMatrix5Type is array (natural range <>) of CovMatrix5BaseType; type CovMatrix6Type is array (natural range <>) of CovMatrix6BaseType; type CovMatrix7Type is array (natural range <>) of CovMatrix7BaseType; type CovMatrix8Type is array (natural range <>) of CovMatrix8BaseType; type CovMatrix9Type is array (natural range <>) of CovMatrix9BaseType;
Функция GenCross используется для генерирования этого перекрёстного произведения. Необходимо раздельное перегрузка функций для каждого из этих типов. Интерфейс, которые генерирует CovMatrix2Type и CovMatrix9Type показаны ниже.
function GenCross( -- cross 2 point bins - see method AddCross constant AtLeast : integer ; constant Weight : integer ; constant Bin1, Bin2 : in CovBinType ) return CovMatrix2Type ; function GenCross(AtLeast : integer ; Bin1, Bin2 : CovBinType) return CovMatrix2Type ; function GenCross(Bin1, Bin2 : CovBinType) return CovMatrix2Type ; function GenCross( -- cross 9 point bins - intended only for constants constant AtLeast : integer ; constant Weight : integer ; constant Bin1, Bin2, Bin3, Bin4, Bin5, Bin6, Bin7, Bin8, Bin9 : in CovBinType ) return CovMatrix9Type ; function GenCross( AtLeast : integer ; Bin1, Bin2, Bin3, Bin4, Bin5, Bin6, Bin7, Bin8, Bin9 : CovBinType ) return CovMatrix9Type ; function GenCross( Bin1, Bin2, Bin3, Bin4, Bin5, Bin6, Bin7, Bin8, Bin9 : CovBinType ) return CovMatrix9Type ;
Теперь можно записать нашу константу для примера модели покрытия АЛУ.
constant ALU_COV_MODEL : CovMatrix2Type := GenCross(REG_ADDR, REG_ADDR);
Когда необходимо добавить это в нашу структуру данных покрытия, необходимы методы, которые обрабатывают типы CovMatrix2Type ... CovMatrix9Type. Это обрабатывается перегруженными версиями метода AddBins, показанными ниже.
procedure AddBins (CovBin : CovMatrix2Type) ; procedure AddBins (CovBin : CovMatrix3Type) ; procedure AddBins (CovBin : CovMatrix4Type) ; procedure AddBins (CovBin : CovMatrix5Type) ; procedure AddBins (CovBin : CovMatrix6Type) ; procedure AddBins (CovBin : CovMatrix7Type) ; procedure AddBins (CovBin : CovMatrix8Type) ; procedure AddBins (CovBin : CovMatrix9Type) ;
Для создания структуры данных покрытия для простой модели покрытия АЛУ, необходимо вызвать метод AddBins как показано ниже.
ACov.AddBins( ALU_COV_MODEL ); -- Model
Метод GenCross также позволяет задавать веса. В простой форме метода AddCross, можно достроить нашу модель покрытия постепенно наращивая, используя константы и конкатенацию. Это показано в следующем примере.
architecture Test4 of tb is shared variable ACov : CovPType ; -- Declare Cov Object constant ALU_BIN_CONST : CovMatrix2Type := GenCross(1, GenBin (0), GenBin(1,7)) & GenCross(2, GenBin (1), GenBin(0) & GenBin(2,7)) & GenCross(3, GenBin (2), GenBin(0,1) & GenBin(3,7)) & GenCross(4, GenBin (3), GenBin(0,2) & GenBin(4,7)) & GenCross(5, GenBin (4), GenBin(0,3) & GenBin(5,7)) & GenCross(6, GenBin (5), GenBin(0,4) & GenBin(6,7)) & GenCross(7, GenBin (6), GenBin(0,5) & GenBin(7)) & GenCross(8, GenBin (7), GenBin(0,6) ) ; begin TestProc : process variable RegIn1, RegIn2 : integer ; begin -- Capture coverage model ACov.AddBins( ALU_BIN_CONST ) ; while not ACov.IsCovered loop -- Interact -- Randomize register addresses -- see RandomPkg documentation (RegIn1, RegIn2) := ACov.RandCovPoint ; DoAluOp(TRec, RegIn1, RegIn2) ; -- Do a transaction ACov.ICover( (RegIn1, RegIn2) ) ; -- Accumulate end loop ; ACov.WriteBin ; -- Report EndStatus(. . . ) ; end process ;
Повторное использование покрытия
Есть несколько способов повторного использования модели покрытия. Если целью является повторное использование и накопление покрытия по многим тестам, то единственный способ добиться этого заключается в использовании методов WriteCovDb и ReadCovDb. Если целью является только повторное использования самой модели покрытия, то либо константы, либо подпрограммы могут быть использованы. Вызовы метода ICover обычно достаточно просты, чтобы не было необходимости упрощать их.
Компиляция
Компилируются все пакеты в библиотеку, названную SynthWorks. В настоящий момент пакет CoveragePkg не использует каких либо функций стандарта VHDL-2008, так как это только одна версия пакет. Вашим программам необходима ссылка на пакет CoveragePkg.
library SynthWorks ; use SynthWorks.CoveragePkg.all ;
Сопоставление пакета CoveragePkg и синтаксиса языка
Базовый уровень точек покрытия (или элементов покрытия), которые могут быть собраны с помощью пакета CoveragePkg похожи на те, которые могут быть достигнуты с помощью языка 'e' (IEEE 1647). Пакет CoveragePkg и 'e' позволяют, чтобы корзины точек покрытия состояли из одиночных значений или одиночного диапазона. SystemVerilog расширяет это, позволяя значения, диапазон или набор значений и диапазонов. Пока эта дополнительная возможность SystemVerilog является привлекательной, хотя нет очевидных преимуществ, которые, которые оправдывали бы дополнительные сложности, требующиеся чтобы задать это в модель покрытия.
For cross coverage, both SystemVerilog and 'e' focus on first capturing item coverage and then doing a cross of the items. There is some capability to modify the bins contents within the cross, but at best it is awkward. On the other hand, CoveragePkg allows one to directly capture cross coverage, bin by bin and incrementally if necessary. Helper functions are provided to simplify the process. This means for simple things, such as making sure every register pair of an ALU is used, the coverage is captured in a very concise syntax, however, when more complex things need to be done, such as modeling the coverage for a CPU, the cross coverage can be captured on a line by line basis.
Для перекрёстного покрытия, и SystemVerilog и 'e' фокусируют на первом сборе точек покрытия и затем делать пересечение точек. Это некоторая возможность для изменения содержания корзин внутри пересечения, но в лучшем случае это не удобно. С другой стороны, пакет CoveragePkg позволяет непосредственный сбор перекрёстного покрытия, корзины к корзине и постепенно, если необходимо. Помогающие функции обеспечивают упрощение процесса. Это значит для простых вещей, таких как, чтобы убедиться что каждая пара регистров АЛУ использовалась, покрытие собирается в очень краткий синтакси, однако, когда более сложные вещи необходимо выполнить, такие как моделирование покрытие CPU. перекрёстное покрытие может быть собрано на основе нескольких строк.
В результате с пакетом CoveragePkg проще собрать покрытие высокой точности внутри одного объекта покрытия. Модель покрытия высокой точности в одном объекте покрытия требует выполнения интеллектуального покрытия.
Устаревшие методы
В оригинальном проекте функций обратной связи покрытия и псевдослучайной генерации чисел, не было цели покрытия и веса. Кроме этого, каждая корзина имела вес 1 и цель покрытия определялась параметром AtLeast в вызове функций. Эти функции показаны ниже. В их реализации, все корзины имели одинаковые цели покрытия. Использование параметра AtLeast было включено параметром PercentCov значением типа real. В дополнение, каждая корзина теперь имеет возможность иметь разные цель покрытия и вес. С различными значениями цели покрытия PercentCovбыла заменена на параметр AtLeast. Функциональность параметра AtLeast была поглощена параметром PercentCov. Параметр PercentCov 200.0 эквивалентен значению 2 параметра AtLeast.
impure function GetMinCov return integer ; impure function GetMaxCov return integer ; impure function CountCovHoles ( AtLeast : integer ) return integer ; impure function IsCovered ( AtLeast : integer ) return boolean ; impure function GetCovHole ( ReqHoleNum : integer := 1 ; AtLeast : integer ) return RangeArrayType ; impure function RandCovHole ( AtLeast : in integer ) return RangeArrayType ; impure function RandCovPoint (AtLeast : in integer ) return integer_vector ; procedure WriteCovHoles ( AtLeast : in integer ) ; procedure WriteCovHoles ( FileName : string; AtLeast : in integer ; OpenKind : File_Open_Kind := APPEND_MODE ) ;
Работа на будущее
CoveragePkg.vhd находится в процессе разнаботки и периодически обновлятя. Некоторые планы на будущие версии:
- Добавить метод сжатия, который удаляет обычные корзины, которые полностью содержатся в ранее определённых игнорируемых или запрещённых корзинах.
- добавить глобальные настройки покрытия защищённого типа.
- добавить возможность для глобального включения/отключения сбора покрытия.
- Установить значения по умолчанию для CountMode, IllegalMode, WeightMode, CovThresholdPercent в глобальной модели покрытия.
- Удалить OrderCount (который был предназначен для отладки).
- Пересмотреть перегруженный метод AddBins по отношению к AddCross — так чтобы оставить AddBins единственным методом необходимым для создания структуры данных покрытия.
21 Other Packages
In addition to the CoveragePkg, we also are freely distributing our randomization packages (RandomPkg, RandomBasePkg, SortListPkg_int). See http://www.SynthWorks.com/downloads. Over time we will also be releasing other packages and hope to convince simulation vendors to distribute our libraries with their tools.
22 About the Author
Jim Lewis, the founder of SynthWorks, has twenty-six years of design, teaching, and problem solving experience. In addition to working as a Principal Trainer for SynthWorks, Mr Lewis has done ASIC and FPGA design, custom model development, and consulting. Mr Lewis is an active member of the VHDL standards effort and is the current IEEE VHDL Study Group chair. I am passionate about the use of VHDL for verification. If you find bugs with any of SynthWorks' packages or would like to request enhancements, you can reach me at jim@synthworks.com.
23 References
[1] Jim Lewis, VHDL Testbenches and Verification, student manual for SynthWorks' class.
[2] Andrew Piziali, Functional Verification Coverage Measurement and Analysis, Kluwer Academic Publishers 2004, ISBN 1-4020-8025-5
[3] IEEE Standard for System Verilog, 2005, IEEE, ISBN 0-7381-4811-3
[4] IEEE 1647, Standard for the Functional Verification Language 'e', 2006
[5] A Fitch, D Smith, Functional Coverage - without SystemVerilog!, DVCON 2010
Когда покрытие кода не эффективно
While code coverage is generally a useful metric, there are some cases where it does not accomplish what we want.
Пока покрытие кода является основной полезной метрико, есть несколько случаев, в которых она выполняет не то, что бы хотелось.
Чтобы понять эту проблему, обратися к следующему процессу. Если все elA, SelB, и SelC равны 1 при положительном фронте на Clk, тогда все линии кода выполнятся и покрытие кода будет 100%. однако, только одно выражение "Y <= A" повлияет на выход. Выражения "Y <= C" и "Y <= B" не будут активными, а значит не будут проверены.
PrioritySel : process (Clk) begin if rising_edge(Clk) then Y <= "00000000" ; if (SelC = '1') then Y <= C ; end if ; if (SelB = '1') then Y <= B ; end if ; if (SelA = '1') then Y <= A ; end if ; end if ; end process ;
В комбинационной логике, эта проблема только становится хуже. Если изменить приведённый выше процесс как показано ниже, то процесс запускается при любом изменении своих входов. И по прежнему будут проблемы показанные выше. В дополнение, процесс сейчас запускает и собирает покрытие основанное на любом изменении сигнала. Сигналы могут меняться множество раз в течении заданного периода синхросигнала, из-за различий в задержках - или дельта задержек в (RTL) или реальных задержек распространения (в моделировании на уровне вентилей).
PrioritySel : process (SelA, SelB, SelC, A, B, C) begin Y <= "00000000" ; if (SelC = '1') then Y <= C ; end if ; if (SelB = '1') then Y <= B ; end if ; if (SelA = '1') then Y <= A ; end if ; end process ;
Поскольку функциональное покрытие зависит от наблюдаемых состояний в проекте, то могут покрыты все зоны. Также есть дополнительные инструменты, которые направлены на решение этих проблем с покрытием кода.