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

Проектирование цифровых систем на языках описания аппаратуры/Лекция 11

Материал из Wiki
Перейти к: навигация, поиск
Лекции ПЦСЯОА

Лекции

Практические

Доп. материалы

Заголовок
Верификация VHDL описаний цифровых систем. Генерация псевдослучайных тестов и функциональное покрытие
Автор
Ланкевич Ю.Ю.
Нижний колонтитул
Проектирование цифровых систем на языках описания аппаратуры/Лекция 11
Дополнительный нижний колонтитул
Ланкевич Ю.Ю., 12:55, 20 октября 2020


Содержание

Слайд:Структура тестирующей программы

Тестирующие программы, реализующие процесс тестирования VHDL модели, не имеют входных и выходных портов. Архитектурное тело тестирующей программы обычно состоит из трех либо четырех частей.
[svg]

  1. Декларативная часть. В декларативной части архитектурного тела указывается тестируемый компонент (интерфейс VHDL модели проектируемого устройства либо системы), а также задаются сигналы, являющиеся входными и выходными портами устройства.
  2. Вызов модели. В исполняемом разделе архитектурного тела, т. е. после ключевого слова Begin, записывается оператор port map для вызова модели устройства.
  3. Задание входных воздействий. В третьей части в исполняемом разделе архитектурного тела записываются входные наборы, подаваемые на вход тестируемого компонента, либо программным образом обеспечивается генерация входных наборов по тем или иным правилам.
  4. Сравнение полученных реакций модели с ожидаемыми реакциями. Если тестирующая программа записала полученные реакции модели в виде файла, то данный файл может быть сравнен с файлом ожидаемых реакций, который обычно считается эталонным.

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

Слайд:Пример схемы для верификации

Далее будут представлены различные варианты организации тестирующих программ для одной и той же модели двухразрядного умножителя mult_2.

1  library ieee;
2  use ieee.std_logic_1164.all;
3
4  entity mult_2 is
5      port (
6             s1, s0, r1, r0 : in std_logic;
7             t3, t2, t1, t0 : out std_logic);
8  end mult_2;
9  architecture struct of mult_2 is
10     component add1
11         port ( b1, b2 : in std_logic;
12                c1, s1 : out std_logic);
13     end component;
14     signal p1, p2, p3, p4 : std_logic;
15 begin
16     t0 <= r0 and s0;
17     p1 <= r1 and s0;
18     p2 <= r0 and s1;
19     p4 <= r1 and s1;
20     circ1 : add1
21         port map (b1=>p1, b2=>p2, c1=>p3, s1=>t1);
22     circ2 : add1
23         port map (b1=>p3, b2=>p4, c1=>t3, s1=> 2);
24 end struct;

VHDL модель полусумматора add1.

1  library ieee;
2  use ieee.std_logic_1164.all;
3  entity add1 is
4      port( b1, b2 : in std_logic;
5            c1, s1 : out std_logic);
6  end add1;
7  architecture beh of add1 is
8  begin
9      s1 <= (b1 and (not b2)) or ((not b1) and b2);
10     c1 <= b1 and b2;
11 end beh;

Слайд:Задание тестирующих наборов в тестирующей программе

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

пример тестбенча

Слайд:Задание тестирующих наборов в тестирующей программе

1  library ieee;
2  use ieee.std_logic_1164.all;
3  entity mult_2_tb1 is
4  end;
5  architecture tb of mult_2_tb1 is
6      component mult_2 is
7          port(
8               s1, s0, r1, r0 : in std_logic;
9               t3, t2, t1, t0 : out std_logic);
10     end component;
11     signal s1, s0, r1, r0 : std_logic;
12     signal t3, t2, t1, t0 : std_logic;
13 begin
14     DUT : mult_2 port map (s1, s0, r1, r0, t3, t2, t1, t0);
15     s1 <= '0',
16           '1' after 20 ns,
17           '1' after 40 ns,
18           '0' after 60 ns;
19     s0 <= '1',
20           '0' after 20 ns,
21           '1' after 40 ns,
22           '0' after 60 ns;
23     r1 <= '0',
23           '0' after 20 ns,
24           '1' after 40 ns,
25           '0' after 60 ns;
26     r0 <= '1',
27           '1' after 20 ns,
28           '1' after 40 ns,
29           '1' after 60 ns;
30 end tb;

Слайд:Генерация тестирующих наборов

Достаточно часто, особенно при тестировании блоков комбинационной логики, возникает потребность в генерации всевозможных тестовых наборов – n-разрядных двоичных векторов. Число всех различных n-разрядных двоичных векторов равно 2n , поэтому такая генерация возможна дляограниченного числа n, например, для n≤30.

пример тестбенча

В тестирующей программе генерация наборов осуществляется согласно возрастанию их десятичного эквивалента, проще говоря, наборы перечисляются, как в левой части таблицы истинности, задающей булеву функцию либо систему булевых функций. Генерация всевозможных 2n наборов (в двоичном коде) согласно возрастанию десятичного эквивалента осуществляется в бесконечном цикле, т. е. после набора 1111 генерируется набор 0000, затем 0001, и т. д. Поэтому для такой программы не рекомендуется выполнять в системе моделирования команду RUN ALL.

Слайд:Генерация тестирующих наборов

1  library ieee;
2  use ieee.std_logic_1164.all;
3  entity mult_2_tb3 is
4  end;
5  architecture tb of mult_2_tb3 is
6      component mult_2 is
7          port (s1, s0, r1, r0 : in std_logic;
8                t3, t2, t1, t0 : out std_logic);
9      end component;
10     signal s1, s0, r1, r0 : std_logic := '0';
11     signal t3, t2, t1, t0 : std_logic;
12 begin
13     DUT : mult_2 port map (s1, s0, r1, r0, t3, t2, t1,t0);
14     -- не выполнять RUN ALL
15     s1 <= not s1 after 160 ns;
16     s0 <= not s0 after 80 ns;
17     r1 <= not r1 after 40 ns;
18     r0 <= not r0 after 20 ns;
19 end tb;

Слайд:Моделирование с проверкой ожидаемых реакций

Тестирующая программа реализует процесс тестирования, представленный на рисунке ниже.

пример тестбенча

Файл IN.TST представляет собой тест, т. е. наборы входных сигналов, подаваемых на входы тестируемой системы. Файл AWAIT_OUT.TST представляет собой выходные реакции. Каждой строке (входному набору) соответствует строка с тем же номером в файле ожидаемых реакций. Файл OUT.TST представляет собой реакции системы. Данный файл формируется при моделировании.

Слайд:Моделирование с проверкой ожидаемых реакций

Алгоритм тестирования следующий:

  • из файла IN.TST в цикле считывается строка за строкой;
  • считывание строки текстового файла осуществляется функцией readline;
  • Затем функция read превращает символы в тип std_logic_vector.
  • считанная строка “помещается” в переменную data, потом данные входные воздействия передаются в вектор din, который командой
(s1, s0, r1, r0) <= din;

распределяет разряды на вход модели mult_2.


В каждой итерации цикла считывается также строка из файла AWAIT_OUT.TST. Каждая строка – это вектор (ожидаемая реакция системы). Потом идет ожидание 20 ns – это важно, чтобы подождать и записать затем модельную реакцию схемы в файл OUT.TST. Функция write преобразует std_logic_vector в строку символов, функция writeline записывает строку в файл. Затем идет сравнение строк ожидаемой и действительной реакций. Если есть ошибка, то наращивается значение сигнала errors, подсчитывающего число несовпадающих модельных и ожидаемых реакций. Если ошибок нет, то выдается сообщение "Done!". Если ожидаемая реакция не совпадает с модельной, то выдается номер ошибки и время моделирования (такт), в которое ошибка произошла. Рекомендуется выполнить моделирование с правильным и неправильным файлом ожидаемых реакций. Заметим, что ошибки могут быть и в файле ожидаемых реакций.

Слайд:Моделирование с проверкой ожидаемых реакций

1  library ieee;
2  use ieee.std_logic_1164.all;
3  use ieee.numeric_std.all;
4  use std.textio.all;
5  use ieee.std_logic_textio.all;
6  architecture tb2 of mult_2_tb7 is
7      component mult_2 is
8          port (
9                s1, s0, r1, r0 : in std_logic;
10               t3, t2, t1, t0 : out std_logic);
11         end component;
12     signal s1, s0, r1, r0 : std_logic;
13     signal t3, t2, t1, t0 : std_logic;
14     signal din, dout : std_logic_vector (3 downto 0);
15     signal errors : natural := 0;
16 begin
17     DUT : mult_2 port map (s1, s0, r1, r0, t3, t2, t1, t0);
18
19     (s1, s0, r1, r0) <= din;
20     dout <= (t3, t2, t1, t0);
21     p1 : process
22     file fin, fout, fexpected : text;
23     variable l : line;
24     variable data, data_expected : std_logic_vector (3 downto 0);
25     begin
26         file_open(fin, "IN.TST", read_mode);
27         file_open(fexpected, "AWAIT_OUT.TST", read_mode);
28         file_open(fout, "OUT.TST", write_mode);
29         while not (endfile(fin)) loop
30             readline(fin, l);
31             read(l, data);
32             din <= data;
33             readline(fexpected, l);
34             read(l, data_expected);
35             wait for 20 ns;
36             data := dout;
37             write(l, data);
38             writeline(fout, l);
39             if (data /= data_expected) then
40                 assert (false) report "ERRORS =" & to_string(errors) & " !" severity failure;
41                 errors <= errors + 1;
42             end if;
43         end loop;
44         file_close(fout);
45         file_close(fin);
46         file_close(fexpected);
47         err : assert (errors = 0) report "ERRORS =" & to_string(errors) & " !" severity failure;
48         finish: assert (errors /= 0) report "Done!" severity warning;
49         wait;
50     end process p1;
51 end architecture tb2;

Слайд:Генерация псевдослучайных тестов и функциональное покрытие

В данном разделе рассматривается настраиваемая генерация псевдослучайных тестов и функциональное покрытие. Настраиваемая генерация псевдослучайных тестов позволяет обнаруживать случайные ошибки в проектах в отличие от проблемно-ориентированных или прямых тестов. Функциональное покрытие (functional coverage) предназначено для измерения того, какая часть функций проекта была проверена во время выполнения моделирования. В методологии OS-VVM функциональное покрытие осуществляется сбором значений переменных и сигналов VHDL проекта при выполнении моделирования. Методология OS-VVM базируется на VHDL пакетах CoveragePkg и RandomPkg стандарта VHDL’2008.

Рассмотрим подход к генерации псевдослучайных тестовых векторов на примере тестирования простейшего VHDL проекта цифровой системы – умножителя mult, предназначенного для перемножения целых положительных чисел a, b, заданных в двоичном коде. Точнее говоря, каждое из этих чисел задается в виде

a, b : in std_logic_vector (4 downto 1);

Слайд:Пример схемы на алгоритмическом уровне

Умножитель описан на алгоритмическом уровне: с помощью функции to_integer, находящейся в пакете numeric_std, входящем в стандартную библиотеку ieee, осуществляется переход к численным значениям входных векторов, затем полученные числа перемножаются, после чего осуществляется преобразование произведения e в выходной вектор d.

1  library ieee;
2  use ieee.std_logic_1164.all;
3  use ieee.numeric_std.all;
4  entity mult is
5      port ( a, b : in std_logic_vector (4 downto 1);
6             d : out std_logic_vector (8 downto 1));
7  end mult;
8  architecture functional of mult is
9      signal e : integer range 0 to 225;
10 begin
11     p0 : process(a, b)
12         variable a_int, b_int : integer range 0 to 15;
13     begin
14         a_int := to_integer(unsigned(a));
15         b_int := to_integer(unsigned(b));
16         e <= a_int * b_int;
17     end process;
18     d <= std_logic_vector(to_unsigned(e, 8));
19 end functional;

Слайд:Тестирующая программа на основе генерации псевдослучайных наборов

1  library ieee;
2  use ieee.std_logic_1164.all;
3  use ieee.math_real.all;
4  use ieee.numeric_std.all;
5  entity tstb is
6  end;
7  architecture beh of tstb is
8      component mult
9          port ( a, b : in std_logic_vector (4 downto 1);
10                d    : out std_logic_vector (8 downto 1));
11     end component;
12     signal a, b : std_logic_vector (4 downto 1);
13     signal d : std_logic_vector (8 downto 1);
14 begin
15     p0 : mult
16         port map (a => a, b => b, d => d);
17     RandomGenProc1 : process
18         variable RndValA, RndValB : real;
19         -- Random value
20         variable RndA, RndB : integer;
21         variable SeedA1 : positive := 7;
22         -- initialize seeds
23         variable SeedA2 : positive := 1;
24         variable SeedB1 : positive := 4;
25         -- initialize seeds
26         variable SeedB2 : positive := 2;
27     begin
28         for i in 1 to 100 loop
29             -- randomize 0.0 to 1.0
30             uniform(SeedA1, SeedA2, RndValA);
31             -- randomize 0.0 to 1.0
32             uniform(SeedB1, SeedB2, RndValB);
33             RndA := integer(trunc(RndValA*16.0));
34             -- scale to 0 to 15
35             RndB := integer(trunc(RndValB*16.0));
36             -- scale to 0 to 15
37             a <= std_logic_vector(to_unsigned(RndA, 4));
38             b <= std_logic_vector(to_unsigned(RndB, 4));
39             wait for 10 ns;
40         end loop;
41         wait ;
42     end process;
43 end;

Слайд:Тестирующая программа на основе генерации псевдослучайных наборов

Тестирующая программа tstb написана для организации тестовых воздействий, подаваемых на вход компонента mult. Данный компонент предназначен для перемножения целых положительных чисел a и b, заданных четырехразрядными векторами, результатом является восьмиразрядный вектор, представляющий числа из диапазона 0, 225. Такой диапазон получается из-за того, что числа a, b принимают значения из диапазона 0, 15. Процедура uniform(SeedA1, SeedA2, RndValA); -- генерация числа a пакета math_real позволяет получить псевдослучайное вещественное число RndValA по начальным значениям SeedA1, SeedA2 генератора. Сосредоточим основное внимание на подготовке тестирующих векторов a, b. В процессе RandomGenProc1 выполняются две процедуры ieee.math_real.uniform (из пакета math_real библиотеки ieee) для генерации двух псевдослучайных вещественных чисел RndValA, RndValB из диапазона (0.0, 1.0) (не включая граничных значений 0.0 и 1.0), данные числа затем будут преобразованы в 4-разрядные векторы (числа) a, b. Для генерации числа a процедуре uniform требуется задать начальные значения, например SeedA1, SeedA2, результатом ее выполнения будет псевдослучайное число RanValA. Функция ieee.math_real.trunc позволяет произвести округление вниз (отбрасывание дробной части), затем выполняется переход к целому числу RndA, которое с помощью функции to_unsigned пакета numeric_std преобразуется в вектор с требуемым числом (4) разрядов. Аналогичным образом все повторяется для получения второго псевдослучайного числа b. Такие пары псевдослучайных чисел a, b генерируются в цикле. Длину цикла for можно изменять. В рассматриваемом примере некоторые комбинации (например, от 226 до 255) выходов компонента mult никогда не могут появиться, а ведь они могут идти на вход другого функционального блока в «большом» проекте. Аналогично и для входных значений – в каких-то проектах некоторые входные комбинации могут быть запрещенными, за ними целесообразно следить при тестировании, отслеживать их появление – они могут свидетельствовать об ошибке в каких-то функциональных блоках. Рассмотрим достоинства и недостатки используемых средств генерации входных векторов, далее будем говорить о псевдослучайных числах a, b. Во-первых, в данной тестирующей программе генератором чисел можно управлять, изменяя только начальные значения seed1, seed2. Во-вторых, нужно дополнительно написать довольно сложные программы, если требуется

  • генерировать последовательности псевдослучайных чисел, подчиняющиеся требуемым законам распределения вероятностей их появления, например нормальному закону с заданными параметрами;
  • исключать значения некоторых чисел из определенных диапазонов;
  • перебирать все значения каждого из чисел a, b;
  • перебирать все варианты пар значений чисел a, b;
  • получать все комбинации значений выходов тестируемого компонента.

Проблемы и соответствующие VHDL программы комбинаторно усложняются, если тестируемый компонент имеет десяток (и более) различных входных и выходных векторов.