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

Проектирование цифровых систем на языках описания аппаратуры/Лекция 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 программы комбинаторно усложняются, если тестируемый компонент имеет десяток (и более) различных входных и выходных векторов.