Veröffentlicht am: 07.03.2018
Von: JLusiardi
In Kategorie: Hardware
Will man seine in VHDL erstellten Komponenten testen bietet sich eine Simulation mit anschließender Überprüfung der entsprechenden Signale an. Dies manuell durchzuführen ist zeitaufwändig und fehleranfällig.
Eine Lösung bietet VUnit in Kombination mit GHDL an. GHDL ist ein quell offener Simulator für VHDL Programme. Leider ist GHDL nicht in den Debian Paketquellen enthalten, da die IEEE Bibliotheken von Debian als unfrei eingestuft werden. Also müssen wir dieses Paket selbst bauen und installieren. Dazu bietet sich eine VM / ein Docker Container oder ähnliches an, da einige Pakete zum Erstellen des Pakets notwendig sind. Folgende Kommandos erstellen aus den Quellen von github ein installierbares Debian-Paket:
apt update
apt install git gnat build-essential zlib1g-dev checkinstall
git clone https://github.com/ghdl/ghdl.git
git checkout v0.35
cd ghdl
./configure --prefix=/usr/local
make
checkinstall -y --install=no --requires=libgnat-6
--maintainer=ghdl@lusiardi.de --nodoc --pkglicense=GPLv2
--pkgversion=0.35
dpkg -i ghdl_0.35-1_amd64.deb
Vorteil: dieses Paket kann über die gewohnte Paketverwaltung installiert und auch wieder deinstalliert werden. Natürlich sollte man immer das aktuellste Release oder auch den Master mit git auschecken.
Anschließend installieren wir VUnit mit
pip install -U vunit_hdl
Nun können mit einem kleinen Python-Wrapper in VHDL geschriebene Unit-Tests ausgeführt werden:
from os.path import join, dirname
from vunit import VUnit
root = dirname(__file__)
ui = VUnit.from_argv()
lib = ui.add_library("lib")
lib.add_source_files(join(root, "*.vhd"))
ui.main()
Wie sieht aber nun ein solcher Unit-Test aus? Nehmen wir als Beispiel einen 4-bit Parity Generator:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY four_bit_parity IS
PORT (
data: IN std_logic_vector(3 DOWNTO 0);
parity: OUT std_logic
);
END ENTITY;
ARCHITECTURE behavior_four_bit_parity OF four_bit_parity IS
BEGIN
parity <= data(0) xor data(1) xor data(2) xor data(3);
END behavior_four_bit_parity;
Ein entsprechender Unit-Test könnte nun so aussehen:
library IEEE;
use IEEE.std_logic_1164.all;
library vunit_lib;
context vunit_lib.vunit_context;
entity four_bit_parity_tb is
generic (runner_cfg : string);
end four_bit_parity_tb;
architecture sim of four_bit_parity_tb is
SIGNAL d_in: STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL p: STD_LOGIC;
constant clk_period : time := 10 ps;
begin
main : process
begin
test_runner_setup(runner, runner_cfg);
while test_suite loop
if run("0000") then
d_in <= "0000";
wait for 10 ps;
check_equal(p, '0');
end if;
if run("0001") then
d_in <= "0001";
wait for 10 ps;
check_equal(p, '1');
end if;
end loop;
test_runner_cleanup(runner);
end process;
uut: entity work.four_bit_parity port map (d_in, p);
END sim;
Nun kann man mit ./run.py die Tests durchführen und erhält (hoffentlich) folgendes Ergebnis:
$ ./run.py
Re-compile not needed
Starting lib.four_bit_parity_tb.0000
Output file: vunit_out/test_output/lib.four_bit_parity_tb.0000_86984b0155942bf3d3645c1aa56926538590d91f/output.txt
pass (P=1 S=0 F=0 T=2) lib.four_bit_parity_tb.0000 (0.6 seconds)
Starting lib.four_bit_parity_tb.0001
Output file: vunit_out/test_output/lib.four_bit_parity_tb.0001_fdfc81920e3c3468dfe6138ee1107bbf4bea3958/output.txt
pass (P=2 S=0 F=0 T=2) lib.four_bit_parity_tb.0001 (0.6 seconds)
==== Summary =======================================
pass lib.four_bit_parity_tb.0000 (0.6 seconds)
pass lib.four_bit_parity_tb.0001 (0.6 seconds)
====================================================
pass 2 of 2
====================================================
Total time was 1.2 seconds
Elapsed time was 1.2 seconds
====================================================
All passed!
Frohes Testen! Weitere Informationen zu VUnit und den vorhandenen Funktionen findet man in der VUnit Dokumentation. Etwas ist allerdings zu beachten, dass eventuell nicht alle VHDL Konstrukte, die durch GHDL in Tests akzeptiert werden schlussendlich auch durch z.B. Quartus II synthetisierbar sind. Hier sind also eventuell Nacharbeiten am eigentlichen VHDL-Code notwendig.