-
Notifications
You must be signed in to change notification settings - Fork 0
VUnit uputstvo
VUnit je open-source framework za unit testiranje VHDL/Verilog koda. Donosi moderne metodologije softverskog testiranja u verifikaciju hardverskog dizajna.
- Python-baziran test runner: Koristi Python skripte za otkrivanje, kompajliranje i pokretanje testova
- Automatsko otkrivanje testova: Automatski pronalazi sve testbench-eve
- CI/CD prilagođen: Jednostavna integracija u continuous integration pipeline-ove
- Agnostičan prema simulatoru: Radi sa više simulatora (ModelSim, GHDL)
- Bogata biblioteka asercija: Pruža sveobuhvatne funkcije za provjeru i logovanje
- Fleksibilna organizacija testova: Podržava test suite-ove, test case-ove i konfiguracije
- Python 3.7 ili noviji (VUnit zahtijeva Python 3.7+)
- GHDL
# Instalirajte Python (ako već nije instaliran)
sudo apt update
sudo apt install python3 python3-pip
# Instalirajte GHDL
sudo apt install ghdl
# Instalirajte VUnit
pip3 install vunit_hdl# Instalirajte Python (ako već nije instaliran)
sudo pacman -Syu python
# Instalirajte GHDL
sudo pacman -Syu ghdl
# Instalirajte VUnit iz AUR-a
# Opcija 1 - Korištenjem AUR helper-a:
yay -Syu python-vunit_hdl
# Opcija 2 - Ručna instalacija:
git clone https://aur.archlinux.org/python-vunit_hdl.git
cd python-vunit_hdl
makepkg -si- Instalirajte Python: Preuzmite sa python.org i uvjerite se da je dodan u PATH
-
Instalirajte GHDL: Preuzmite najnovije izdanje sa github.com/ghdl/ghdl/releases, ekstraktujte ga i dodajte
bindirektorij u PATH -
Instalirajte VUnit: Otvorite Command Prompt i izvršite:
pip3 install vunit_hdl
Svaki VUnit testbench slijedi ovu strukturu:
library vunit_lib;
context vunit_lib.vunit_context;
entity tb_example is
generic (runner_cfg : string);
end entity;
architecture tb of tb_example is
begin
main : process
begin
test_runner_setup(runner, runner_cfg);
while test_suite loop
if run("test_pass") then
report "This will pass";
elsif run("test_fail") then
assert false report "It fails";
end if;
end loop;
test_runner_cleanup(runner);
end process;
end architecture;-
VUnit biblioteka i kontekst: Moraju biti uključeni na vrhu
library vunit_lib; context vunit_lib.vunit_context;
-
Runner configuration generic: Potreban da bi VUnit kontrolisao testbench
generic (runner_cfg : string);
-
Test runner wrapper: Okružuje sav test kod
test_runner_setup(runner, runner_cfg); -- Naš kod za testiranje izmedju test_runner_cleanup(runner);Važno: Ne koristite
wait;prije cleanup linije, jer testbench mora dostići cleanup da bi se pravilno završio. -
Test suite petlja: Sadrži sve test case-ove
while test_suite loop if run("test_name_1") then -- Test kod elsif run("test_name_2") then -- Test kod end if; end loop;
Da bi se komponente definisane u dizajnu uspješno instancirale, potrebno je koristiti definisanu design_lib biblioteku umjesto work biblioteke. Kroz ovu biblioteku pristupa se RTL dizajnu u /hardware/design.
Instanciranju komponente sada treba pristupiti na sljedeći način:
- Deklarisati pomenutu biblioteku u okviru testa
library design_lib;- Instancirati komponentu na odgovarajući način u okviru arhitekture testa
uut_entity_name : entity design_lib.entity_name
port map (
a_i => a_i,
b_i => b_i,
c_o => c_out
);pri čemu treba voditi računa da portovi moraju odgovarati onima definisanim u dizajnu i definisanim signalima u okviru arhitekture testa, redom.
VUnit pokreće testbench više puta—jednom za svaki test case. Na primjer, ako imate tri run() komande, testbench će se izvršiti tri puta:
- Prvo pokretanje: Izvršava se samo kod unutar
run("test_1") - Drugo pokretanje: Izvršava se samo kod unutar
run("test_2") - Treće pokretanje: Izvršava se samo kod unutar
run("test_3")
Recimo da imamo alu sa funkcijom reseta i operacijama sabiranja i oduzimanja. Njegov test-suite loop će biti:
while test_suite loop
if run("test_reset") then
info("Testing reset functionality");
rst <= '1';
wait for clk_period * 2;
rst <= '0';
wait for clk_period;
check_equal(result, std_logic_vector(to_unsigned(0, 8)),
"Result should be 0 after reset");
elsif run("test_add") then
info("Testing add operation");
a <= std_logic_vector(to_unsigned(10, WIDTH));
b <= std_logic_vector(to_unsigned(3, WIDTH));
op <= "001";
wait for clk_period;
check_equal(result, std_logic_vector(to_unsigned(13, WIDTH)));
elsif run("test_subtract") then
info("Testing subtract operation");
a <= std_logic_vector(to_unsigned(10, WIDTH));
b <= std_logic_vector(to_unsigned(3, WIDTH));
op <= "010";
wait for clk_period;
check_equal(result, std_logic_vector(to_unsigned(7, WIDTH)));
end if;
end loop;Ne moramo imati zasebanu run() komandu za svaki pojedinačni test case. Možemo grupisati srodne testove zajedno:
if run("test_add_exhaustive") then
info("ADD: Testing all 65,536 combinations");
fail_count := 0;
test_count := 0;
op <= "001"; -- ADD operacija
for i in 0 to 255 loop
for j in 0 to 255 loop
a <= std_logic_vector(to_unsigned(i, 8));
b <= std_logic_vector(to_unsigned(j, 8));
wait for 10 ns;
test_count := test_count + 1;
-- Provjera očekivanog rezultata
if to_integer(unsigned(result)) /= (i + j) mod 256 then
fail_count := fail_count + 1;
error("ADD fail: " & to_string(i) & " + " & to_string(j));
end if;
end loop;
end loop;
info("ADD Results:");
info(" Total: " & to_string(test_count));
info(" Passed: " & to_string(test_count - fail_count));
info(" Failed: " & to_string(fail_count));
check(fail_count = 0, "ADD exhaustive test had failures");
elsif run("test_subtract_exhaustive") then
-- Slično iscrpno testiranje za oduzimanje
end if;-
info("poruka")- Ispisuje informativnu poruku na terminal -
warning("poruka")- Prijavljivanje upozorenja (ne zaustavlja test) -
error("poruka")- Prijavljuje grešku i zaustavlja trenutni test -
failure("poruka")- Prijavljuje kritičan neuspjeh i zaustavlja sve testove
-
check_equal(actual, expected)- Provjerava da li su dvije vrijednosti jednake -
check_equal(actual, expected, "poruka")- dodatni argument "poruka" koji javlja poruku na neuspiješan check. -
check(uslov, "poruka")- Provjerava da li je uslov istinit -
check_true(uslov)- Provjerava da li je uslov istinit -
check_false(uslov)- Provjerava da li je uslov neistinit, takođe mogu sa porukom.
-- Jednostavna provjera jednakosti
check_equal(result, expected_value);
-- Sa opisnom porukom
check_equal(counter_out, std_logic_vector(to_unsigned(5, 8)),
"Counter should be 5 after 5 clock cycles");
-- Provjera boolean uslova
check(unsigned(result) < 256, "Result should be less than 256");
-- True/False provjere
check_true(overflow_flag = '1', "Overflow flag should be set");
check_false(underflow_flag = '1', "Underflow flag should not be set");Da pokrenete sve testove, izvršite sljedeću komandu iz ```/scripts/`` direktorijuma:
python3 run.pyOvo će otkriti i pokrenuti sve testove u hardware/tests/ direktoriju.
# Izlistajte sve dostupne testove
python3 run.py --list
# Primjer ispisa:
# lib.counter_tb.test_reset
# lib.counter_tb.test_count_up
# lib.counter_tb.test_overflow
# Pokrenite specifičan test
python3 run.py "*test_reset"
# Pokrenite sve testove koji odgovaraju obrascu
python3 run.py "*count*"-
Organizacija testova: Generisati srodne test case-ove pod smislenim
run()imenima - Smislena imena testova: Koristiti jasna, deskriptivna imena za test case-ove
- Informativne poruke: Uvijek pružaiti korisne poruke o greškama u asercijama
- Nezavisnost testova: Svaki test case treba biti nezavisan i ne treba se oslanjati na druge
- Granični slučajevi: Testirajti granične uslove i edge slučajeve
-
Dokumentacija: Koristiti
info()za dokumentovanje šta svaki test radi
Za više informacija, posjetite VUnit dokumentaciju.