Xilinx шаблон модуля на VHDL та TestBench для тестування

Інтерес до теми ПЛІС зростає постійно, але поріг входження високий. Навіть купівля дорогої налагоджувальної плати мало рятує ситуацію, оскільки для вивчення 80% матеріалів не потрібна налагоджувальна плата. Процес створення модулів для тестування представляє серйозну проблему для новачків і вимагає багато часу та зусиль для подолання порогу входження. Крім того, знайомство з моделюванням дозволить на практиці ознайомитися зі створенням і роботою цифрових пристроїв без додаткових витрат.

Мета статті заповнити цей пробіл і по кроках показати процес створення зв'язки Цільовий модуль => Тестбенч. Проекти роблю на мові VHDL у САПР Vivado від Xilinx.

1. Створення проекту

Стартова сторінка Vivado. Створюємо наш майбутній проект. У імені проекту не повинно бути російських букв і повний адреса повинна бути не більшою за 255 символів.

Створюємо проект

Вказуємо місце розташування проекту

Вибираємо RTL проект

Нічого не додаємо в проект

Вибираємо нашу цільову ПЛІС. У даному випадку я вибрав ПЛІС, яка стоїть на налагоджувальній платі Digilent Basys 3.

Підтверджуємо створення проекту.

Створений проект

Додаємо в проект основний модуль, який потім планується завантажити в FPGA. Для цього натискаємо на значок "+" в вікні Sources

Вводимо назву нашого модуля

Підтверджуємо додавання основного модуля.

Додаємо модуль для testbench.

Вводимо назву для testbench

Підтверджуємо додавання нашого testbench

Для того, щоб testbench запустився при симуляції, необхідно його зробити Top.

Для цього натискаємо правою кнопкою миші і вибираємо в меню Set as Top

В результаті отримаємо таке вікно

Після вставки коду у файли invertor і testbench отримаємо наступний вигляд проекту

2. Написання основного модуля і тестбенча для нього

При роботі з ПЛІС можна розділити проект на цільові модулі та модулі для тестування, ще їх називають testbench. Без testbench неможливо вивчати мови HDL і стандартні конструкції проектування схем. Наведу шаблон для симуляції генерації тактування і підключення модуля invertor.

Напишемо простий модуль для основного модуля invertor, який інвертує вхідний сигнал на мові VHDL. Коментарі починаються після двох тире "- -". Кожен модуль знаходиться у своєму файлі.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Розкоментуйте наступну декларацію бібліотеки, якщо використовуєте
-- арифметичні функції з Signed або Unsigned значеннями
--use IEEE.NUMERIC_STD.ALL;

-- Розкоментуйте наступну декларацію бібліотеки, якщо інстанціюєте
-- будь-які Xilinx leaf cells у цьому коді.
--library UNISIM;
--use UNISIM.VComponents.all;

--// опис цільового модуля
entity invertor is
  Port (
    a:in std_logic; --// вхідний сигнал 
    b:out std_logic -- // вихідний сигнал
     );
end invertor;

--// реалізація модуля
architecture Behavioral of invertor is
begin
b<= not a; -- // інверсія вхідного сигналу
end Behavioral; 

Entity - це такий чорний ящик, який має входи та виходи, а Architecture - це реалізація логіки цього чорного ящика. Завдяки умовному синтезу, у одного ящика може бути безліч реалізацій. Коли ми позначаємо Top, значить, ми вибрали основний чорний ящик, в який ми будемо кладти інші чорні ящики і з'єднувати їх сигналами.

Нижче наведений текст testbench для модуля симуляції тактового сигналу з частотою в 100 MHz. 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Розкоментуйте наступну декларацію бібліотеки, якщо використовуєте
-- арифметичні функції з Signed або Unsigned значеннями
use IEEE.NUMERIC_STD.ALL;

-- Розкоментуйте наступну декларацію бібліотеки, якщо інстанціюєте
-- будь-які Xilinx leaf cells у цьому коді.
--library UNISIM;
--use UNISIM.VComponents.all;

--// для тестбенча зовнішніх портів не потрібно
entity testbench is
--  Port ( );
end testbench;
--// реалізація архітектури
architecture Behavioral of testbench is
--// підключення компонента invertor
component invertor
  Port (
    a:in std_logic; 
    b:out std_logic
     );
end component;
--// ініціалізація внутрішніх сигналів 
signal clk: std_logic:='1'; -- // початкове значення для тактування
constant period:time:=10 ns; --// Період частоти тактування симуляції 100MHz
signal output: std_logic;   --// вихід інвертованого сигналу

begin
--// Симуляція тактування 
clock_gen: process
begin
    loop                --// початок безкінечного циклу 
    clk<=not clk;       --// інверсія тактування
    wait for period/2;  --// очікування часу
    end loop;           --// кінець безкінечного циклу
end process;

--// створюємо екземпляр компонента, для якого
example: invertor
port map(
        a=>clk,     --// асоціюємо тактовий сигнал з входом а
        b=>output   --// асоціюємо вихідний сигнал з виходом b
        );

end Behavioral;

Для testbench у entity немає портів входу і виходу, оскільки по суті це і є наша ПЛІС. Оскільки це найголовніший чорний ящик, тому ми його і налаштовуємо як Top. Тактування ми симулюємо в блоці clock: process. Для того, щоб інверсія працювала, потрібно не забути у початкового сигналу при ініціалізації задати початкове значення '0' або '1', оскільки за замовчуванням логічний рівень невідомий. Для того, щоб підключити наш модуль, який ми збираємося тестувати, необхідно спочатку підключити його реалізацію, а далі ми створюємо екземпляри і асоціюємо його входи та виходи з сигналами від інших модулів.

Після того, як ми підключили тестований екземпляр до тактування, можна натиснути на кнопку Run Simulation, отримаємо наступну картину симуляції

Як бачимо, вихід інвертований відносно тактового сигналу.

В статті я намагався по кроках показати весь шлях створення проекту, розробки шаблону основного модуля і testbench для перевірки його роботи. Я не став зупинятися на описі конструкцій мови VHDL, компенсуючи це коментарями.

Прикріплені файли:

Top