przemysław sołtan - kik

Transkrypt

przemysław sołtan - kik
PRZEMYSŁAW SOŁTAN
e-mail: [email protected]
Historia projektu
04.05.2004 – wersja vhdlUnit 1.06 (dodanie dodatkowej procedury vhdlUnicClock z możliwością
ustalania rodzaju sygnału inicjującego zegar stymulus'a; dodanie funkcji negowania typu nstd_logic nstd2neg)
24.03.2004 – wersja vhdlUnit 1.05 (bugg fix!)
23.03.2004 – wersja vhdlUnit 1.04 (dodanie pola info do metod asercji – assertEqual)
14.03.2004 – wersja vhdlUnit 1.02 (obsługa dodatkowych asercji dla typów std_logic_vector i
nstd_logic_vector)
10.03.2004 – wersja vhdlUnit 1.0 beta (modyfikacja dokumentacji i inicjalizacja projektu witryny
internetowej prezentującej projekt http://kik.ie.tu.koszalin.pl/vhdlunit )
1.03.2004 – ukończenie ostatecznej wersji publikacji opisującej bibliotekę vhdlUnit (materiał po
akceptacji ukaże się na konferencji Reprogramowalnych Układów Cyfrowych - RUC'2004 w Szczecinie)
24.02.2004 – wersja vhdlUnit_08_alpha
15.02.2004 – wersja vhdlUnit_07_alpha (dodanie procedury obsługi uniwersalnych zegarów taktujących
vhdlUnitClock wykorzystywanych w testbencha'ch)
3.02.2004 – wersja vhdlUnit_06_alpha
31.01.2004 – wersja vhdlUnit_05_alpha
30.01.2004 – podział biblioteki na moduły (vhdlUnit.vhd i vhdlUnit_ext_nstd_logic.vhd)
30.09.2003 – wersja vhdlUnit_04_alpha
30.09.2003 – aktualizacja dokumentacji
26.11.2003 – wersja vhdlUnit_03_alpha
25.11.2003 – obsługa logów (log4vhdl) – wersja rozwojowa
13.11.2003 – inicjalizacja modułu TCL do graficznej obsługi biblioteki
22.09.2003 – wersja vhdlUnit_02_alpha
22.09.2003 – obsługa serii testów (dodanie vhdlUnit.properties)
21.09.2003 – wersja vhdlUnit_01_alpha
28.08.2003 - inicjacja projektu realizacji testów jednostkowych w języku VHDL – potrzeba stworzenia
automatyzowanego środowiska do prac projektowych prowadzonych w ramach grantu
Wykryte błędy do poprawienia:
24.03.2004 – spradzić poprawność konwersji nstd2std() dla nstd_logic_vector np. nstd2std(cout & sout)
Wstęp
Testy jednostkowe jako zestaw zautomatyzowanych testów działają na wyższym poziomie, niż
kompilator, który sprawdza składnię programu. Zadaniem testów jest kontrola prawidłowego działania
(semantykę) programu.
Raporty
Testy
jednostkowe
Testowany
System
Zastosowanie „sprzężenia zwrotnego”, które pokazuje jakość wykonanej pracy za pomocą
zautomatyzowanych testów jednostkowych.
Projekt VhdlUnit jest wzorowany na pakiecie JUnit wspomagającego wykonywanie testów
jednostkowych programów tworzonych przy użyciu języka Java. Projekt VhdlUnit jest zestawem funkcji
testowych napisanych przy użyciu vhdl z przeznaczeniem do automatycznego wywoływania serii
testbenchy i raportowania poprawności wykonywanych wyników. Generowane raporty są dostępne w
postaci dokumentu html.
Specyfikacja projektu opisywana zostaje w postaci testów jednostkowych.
Testy jednostkowe Junit (Erich Gamma, Kent Beck)
Stosowanie standardowej asercji w vhdl'u.
assert a = b
report 'Błąd...: a jest równe b'
severity ERROR;
•
•
•
•
NOTE - can be used to pass information messages from simulation
WARNING - can be used in unusual situation in which the simulation can be continued, but the results
may be unpredictable
ERROR - can be used when assertion violation makes continuation of the simulation not feasible
FAILURE - can be used when the assertion violation is a fatal error and the simulation must be
stopped at once
Wady:
• przerwanie przy napotkaniu pierwszego błędu (???)
• obecność kodu wewnątrz projektu
• brak nechanizmów uruchamiania (???)
• brak możliwości raportowania przebiegu testu
Stosowanie testów jednostkowych vhdlUnit
Zalety:
• wiele mechanizmów uruchamiania testów (???)
• oddzielenie testów od kodu (zewnętrzna biblioteka)
• niezależność od środowiska projektowego (całość testów opisana przy użyciu vhdl'a)
• przypadki testowe (???)
• budowanie raportów
• process (najmniejszą jednostką testową)
Uruchamianie
Proces wykonania testu przebiega w trzech fazach.
Faza I – wykonanie metody initialize
Faza II – wywołanie testBenach’y poszczególnych architektur projektowanego układu lub grupy układów
Faza III – wykonanie metody finalize
Podczas inicjalizacji następuje przygotowanie ustawień początkowych i zostaje utworzony plik
vhdlUnit.htm raportujący przebieg testu.
Zastosowanie testów nadaje się do testowania pojedynczego układu (entity) dla jednej lub wielu
architektur, jak również dla grupy niezaleznych układów. To projektant decyduje jaki test (testy)
realizować.
Faza III kończy realizację testów i przygotowuje ostateczne zestawienie zapisywane w raportowanym
pliku html.
open new
update
Raport
(Html/XML)
update
update
close
initialize
VhdlUnit_tb
(unit_initialize)
test 1
test 2
Testowane
komponenty
test N
finalize
VhdlUnit_tb
(unit_finalize)
vhdlUnit.do
Zastosowanie Fazy I i III wynika z bezstanowości języka vhdl, tzn. Braku możliwości przekazywania
parametrów pomiędzy poszczególnymi testami. Komunikację taką zrealizowano jednak przy pomocy
pliku konfiguracyjnego vhdlUnit.properties uaktualnianego po zakończeniu każdego testu.
----------------------------------------------------------------------- Komponent inicjalizacji i zakonczenia testu
---------------------------------------------------------------------library IEEE;
use IEEE.STD_LOGIC_1164.all;
use work.vhdlUnit_cfg.all;
use work.vhdlUnit.all;
entity vhdlUnit_tb is
end vhdlUnit_tb;
---------------------------------------------------------------------architecture unit_initialize of vhdlUnit_tb is
begin
InitializeTestCase : process
begin
initialize;
wait for 2ns;
wait;
end process;
end unit_initialize;
---------------------------------------------------------------------architecture unit_finalize of vhdlUnit_tb is
begin
FinalizeTestCase : process
begin
finalize;
wait for 2ns;
wait;
end process;
end unit_finalize;
---------------------------------------------------------------------configuration INITIALIZE_VHDL_UNIT of vhdlUnit_tb is
for unit_initialize end for;
end INITIALIZE_VHDL_UNIT;
configuration FINALIZE_VHDL_UNIT of vhdlUnit_tb is
for unit_finalize end for;
end FINALIZE_VHDL_UNIT;
----------------------------------------------------------------------
Raportowanie
Raportowanie przy użyciu html (xml w przygotowaniu).
Raportowanie testów w xml jako dane daje możliwość ich obróbki przez zewnetrzne bibliot
eki (przekształcenia XSL – np. Wizualizacja graficzna przy użyciu SVG – grafiki wektorowej, zdalene
wywoływanie testów i ich automat).yczne publikowane w sieci internet – praca grupowa).
Nadawanie wersji generowanych raportów (dokumentowanie postępu prac)
Porównywanie różnic w poszczególnych raportach (w planach)
GUI
Przykładowy ekran z Junit (testów jednostkowych w javie) oraz vhdlUnit (w przygotowaniu GUI w TCL)
.
Prosty przykład
Przykład bramki logicznej i kilku testów
Metodologia projektowania
- zaprojektowanie bloku entity
- zaprojektowanie testbenchy
- zaprojektowanie testów jednostkowych
- iteracyjne projektowanie architektury (poprawianie) i wykonywanie testów jednostkowych
Wcześniejsze opracowanie testów
Definicja wymagań:
Testy funkcjonalności (vhdlUnit)
Extreme Programming w VHDL?
Metodologia Extreme Programming polega przede wszystkim na tym, aby projektowanie rozpocząć od
zdefiniowania testów.
Testy gwarantują zachowanie określonej funkcjonalności w procesie tworzenia projektu.
Automatyzacja testów wymusza zachowanie powtarzalności zachowania środowiska projektu.
Testowalność – określenie warunków akceptacji systemu.
Proces weryfikacji trwa przez czały okrec projektowania. Głównym celem jest identyfikacja defektów
projektowanego systemu oraz ocena, czy system spełnia oczekiwania odbiorcy.
Celem testowania jest wykrycie obecności błędów, a nie ich braku (trudności w dowodzeniu poprawności
– wiarygodności – duża złożoność).
Testowanie ma na celu stwierdzenie istnienia błędów.
Testowanie modułów (unit testing) – testowanie poszczególnych komponentów systemu w izolacji od
pozostałych.
Testowanie integracyjne (integration testing) – testowanie interfejsów współpracujących ze sobą
modułów lub podsystemów
Testowanie systemowe – szczegółowe testowanie funkcjonowania całego systemu.
Testowanie akceptacyjne – wykonywane w celu stwierdzenia, czy system spełnia swoje wynagania.
(zwykle podzbiór testów systemowych).
Testowanie regresywne – identyfikacja błędów wprowadzonych do już isniejącej i testowanej
funkcjonalności (np. Podczas nanoszenia poprawek).
Plan testów:
Odwzorowanie testów systemowych na wymagania (weryfikacja pokrycia testów).
Wyszczególnienie co będzie podlegać testowaniu.
Procedury przechowywania testów (przechowywanie wyników testów)
Wymagania sprzętowe
Testowanie kolejnych poprawek:
– uruchamiamy i patrzymy na wynik (wielokrotne wywoływanie tych samych faz)
– zaprojektowanie TestBench'y – procedury dostarczające danych wejściowych i sprawdzające wynik
– wykorzystanie test framework – raporty z wyników testu, lepsza kontrola procesu testowania.
Komponent
TestBench
TestUnit+metoda assercji (weryfikacja wyniku)
Osadzanie testów
Wykorzystanie plików (np. VhdlUnit.do) do lokalizacji testów – wywołanie określonych testów
Tryb tekstowy i GUI
Dlaczego?
Tworzenie testów wraz z kodem ma swoje zalety:
– (testy automatycznie wykrywają błędy
wprowadzane przy poprawkach
lub dodawaniu funkcjonalności
– testy stanowią formę dokumentacji kodu – wiadomo
jak ma się zachowywać kod
– naprzemienne kodowanie i tworzenie testów
wprowadza inkrementny tryb pracy (eliminacja
przykrych niespodzianek)
XP zaleca nawet pisanie unit testów przed odpowiednim fragmentem kodu.
Dobry test
Test, który pokazuje, że program w danej sytuacji nie funkcjonuje prawidłowo.
Aby wykazać, że dany program nie posiada błędów, trzeba przeprowadzić wszystkie możliwe testy (w
praktyce jest to niemożliwe).
Testowanie typowych przypadków, niż sprawdzanie przypadków skrajnych (???)
Przy testowaniu ważniejsza jest funkcjonalność całego projektu, niż poszczególnych komponenów.
Testy jednostkowe - Projekt VhdlUnit
Instalacja biblioteki vhdlUnit


umieścić archiwum biblioteki w katalogu źródeł
do TestBenach’a dołączyć bibliotekę vhdlUnit:
library ieee,nstd_logic_2000;
use ieee.std_logic_1164.all;
use nstd_logic_2000.nstd_logic_2000.all;
use work.vhdlUnit.all;
entity gedeon_and2_tb is
end gedeon_and2_tb;
. . .

do TestBencha’a dodać proces testu jednostkowego
. . .
begin
------------------------------------------------------------------- TEST CASE
-----------------------------------------------------------------TestCase : process
constant test_time: time := 50ns;
begin
setUp("gedeon_and2");
-- inicjalizacja testu
wait
wait
wait
wait
for
for
for
for
tearDown;
assertTime(50ns);
assertTime(100ns);
assertTime(150ns);
assertTime(200ns);
assertEquals("o",o,'0');
assertEquals("o",o,'0');
assertEquals("o",o,'0');
assertEquals("o",o,'1');
-- koniec testu
wait;
end process;
-----------------------------------------------------------------. . .

do makra vhdlUnit.do dodać dane symulacji przykładowego układu
clear
SetActiveLib -work
# Test INITIALIZE_VHDL_UNIT
comp -include "$DSN\src\vhdlUnit.vhd"
asim INITIALIZE_VHDL_UNIT
run 1ns
endsim
# TESTBENCH_FOR_gedeon_and2
comp -include "$DSN\src\gedeon\gedeon_and2.vhd"
comp -include "$DSN\src\TestBench\gedeon_and2_TB.vhd"
asim TESTBENCH_FOR_gedeon_and2
run 200 ns
endsim
# Test FINALIZE_VHDL_UNIT
asim FINALIZE_VHDL_UNIT
run 1ns
endsim
Makro startowe
Do uruchomienia testów jednostkowych wykorzystano język makr udostępniony przez środowisko
ActiveHdl. W przypadku symulatorów innych firm należy wykorzystać ich specyficzne właściwości.
Sam test polega na wykonaniu wszystkich symulacji testowych z dodatkową symulacją począkową
(INITIALIZE_VHDL_UNIT) i końcową (FINALIZE_VHDL_UNIT). Symulacja początkowa służy do
inicjalizacji całego testu, a końcowa do jego zamknięcia. Obie symulacje wywołują odpowiednie funkcje
biblioteki vhdlUnit opisane przy uzyciu języka vhdl.
Stosowanie dodatkowych symulacji wynika z bezstanowości języka vhdl pomiędzy dwoma różnymi
symulacjami (brak możliwości przekazywania wartości zmiennych pomiędzy dwoma symulacjami).
Makro startowe vhdlUnit.do wywołania symulacji testowej.
clear
SetActiveLib -work
#----------------------------------------------------# Test INITIALIZE_VHDL_UNIT
#----------------------------------------------------comp -include "$DSN\src\vhdlUnit.vhd"
asim INITIALIZE_VHDL_UNIT
run 1ns
endsim
#----------------------------------------------------# Test TESTBENCH_FOR_gedeon_and4
#----------------------------------------------------comp -include "$DSN\src\gedeon\gedeon_and4.vhd"
comp -include "$DSN\src\TestBench\gedeon_and4_TB.vhd"
asim TESTBENCH_FOR_gedeon_and4
run 800 ns
endsim
#----------------------------------------------------# Test TESTBENCH_FOR_gedeon_and8
#----------------------------------------------------comp -include "$DSN\src\gedeon\gedeon_and8.vhd"
comp -include "$DSN\src\TestBench\gedeon_and8_TB.vhd"
asim TESTBENCH_FOR_gedeon_and8
run 12800 ns
endsim
#----------------------------------------------------# Test . . .
#----------------------------------------------------# . . .
#----------------------------------------------------# Test FINALIZE_VHDL_UNIT
#----------------------------------------------------asim FINALIZE_VHDL_UNIT
run 1ns
endsim
Po zainicjowaniu danej symulacji (asim TESTBENCH_FOR_gedeon_and4) symulacja zostaje wykonana
przez określony okres czasu (run 800ns), a następnie wykonane zostaje polecenie zakończenia
symulacji (endsim) w celu umożliwienia inicjalizacji następnych symulacji.
Komponenty inicjalizacji i finalizacji testu
Proces inicjalizacji i finalizacji testu jest wykonywany za pomocą bloku testowego vhdlUnit_tb
zdefiniowanego wewnątrz pliku vhdlUnit.vhd. Blok ten zawiera dwie architektury umożliwiające
wykonanie funkcji initialize lub finalize w zależności od ustawień konfiguracji.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use work.vhdlUnit.all;
entity vhdlUnit_tb is
end vhdlUnit_tb;
---------------------------------------------------------------------architecture unit_initialize of vhdlUnit_tb is
begin
InitializeTestCase : process
begin
initialize;
wait for 2ns;
wait;
end process;
end unit_initialize;
---------------------------------------------------------------------architecture unit_finalize of vhdlUnit_tb is
begin
FinalizeTestCase : process
begin
finalize;
wait for 2ns;
wait;
end process;
end unit_finalize;
---------------------------------------------------------------------configuration INITIALIZE_VHDL_UNIT of vhdlUnit_tb is
for unit_initialize end for;
end INITIALIZE_VHDL_UNIT;
configuration FINALIZE_VHDL_UNIT of vhdlUnit_tb is
for unit_finalize end for;
end FINALIZE_VHDL_UNIT;
----------------------------------------------------------------------
Opis funkcji i procedur pakietu vhdlUnit
procedure setUp(name : in string);
procedure tearDown;
procedure fail(name : in string);
function assertWait(t:in time)return time;
function assertTime(t:in time)return time;
procedure assertEquals(name : in String; arg1,arg2 : in nstd_logic);
procedure assertZero(arg: in nstd_logic);
procedure assertTrue(arg: in nstd_logic);
procedure assertFalse(arg: in nstd_logic);
procedure assertInfo(message: in string);
function nstd2std(arg : in nstd_logic) return std_logic;
function std2nstd(arg : in std_logic) return nstd_logic;
Funkcje w przygotowaniu:
procedure assertSame(name : in String; arg1,arg2 : in nstd_logic);
procedure assertNotSame(name : in String; arg1,arg2 : in nstd_logic);
AssertionFailedError
Realizacja przykładowych procesów testowych
Zdefiniowane przykładowe procesy testowy pobierają stany sygnałów testbench’a wykonującego
test funkcjonalny przykładowego układu. W tym przypadku mamy dostęp do czterech sygnałów
pobudzających (in_1, in_2, in_3, in_4) oraz jednego sygnału odpowiedzi (out_1). Układ testowy realizuje
funkcję czterowejściowej bramki AND.
Proces testowy oparty o opis wzorca w postaci bezpośrednich porównań
Proces dla określonych przedziałów czasu pobiera wartość sygnału z wyjścia out_1 i porównuje z
odpowiednią stałą wartością.
------------------------------------------------------------------- TEST CASE
-----------------------------------------------------------------TestCase : process
begin
setUp("gedeon_and4");
-- inicjalizacja testu
wait
wait
wait
wait
wait
wait
wait
wait
wait
wait
wait
wait
wait
wait
wait
wait
for
for
for
for
for
for
for
for
for
for
for
for
for
for
for
for
assertTime(50ns); assertEquals("out_1",out_1,'0');
assertTime(100ns); assertEquals("out_1",out_1,'0');
assertTime(150ns); assertEquals("out_1",out_1,'0');
assertTime(200ns); assertEquals("out_1",out_1,'0');
assertTime(250ns); assertEquals("out_1",out_1,'0');
assertTime(300ns); assertEquals("out_1",out_1,'0');
assertTime(350ns); assertEquals("out_1",out_1,'0');
assertTime(400ns); assertEquals("out_1",out_1,'0');
assertTime(450ns); assertEquals("out_1",out_1,'0');
assertTime(500ns); assertEquals("out_1",out_1,'0');
assertTime(550ns); assertEquals("out_1",out_1,'0');
assertTime(600ns); assertEquals("out_1",out_1,'0');
assertTime(650ns); assertEquals("out_1",out_1,'0');
assertTime(700ns); assertEquals("out_1",out_1,'0');
assertTime(750ns); assertEquals("out_1",out_1,'0');
assertTime(800ns); assertEquals("out_1",out_1,'1');
tearDown;
-- koniec testu
wait;
end process;
------------------------------------------------------------------
Proces testowy oparty o opis wzorca w postaci wektora danych
Proces dla określonych przedziałów czasu pobiera wartość sygnału z wyjścia out_1 i porównuje z
odpowiednią wartością z tablicy wektorów.
------------------------------------------------------------------- TEST CASE
-----------------------------------------------------------------TestCase : process
constant
test_vector:
nstd_logic_vector(1
to
16)
"0000000000000001";
constant test_time: time := 50ns;
begin
setUp("gedeon_and4");
-- inicjalizacja testu
:=
for i in 1 to test_vector'LENGTH loop
wait for assertTime(i*test_time);
assertEquals("out_1",out_1,test_vector(i));
end loop;
tearDown;
-- koniec testu
wait;
end process;
------------------------------------------------------------------
Proces testowy oparty o opis wzorca w postaci funkcji
Proces dla określonych przedziałów czasu pobiera wartość sygnału z wyjścia out_1 i porównuje z
odpowiednią wartością zmiennej test_out określoną na podstawie funkcji funkcjonalnego opisu wzorca
(bramki AND) z pobieraniem aktualnych wartości sygnałów z testbencha (sygnały in_1, in_2, in_3 i
in_4).
------------------------------------------------------------------- TEST CASE
-----------------------------------------------------------------TestCase : process
constant test_time: time := 50ns;
constant test_count: integer:= 16;
variable test_out : std_logic;
begin
setUp("gedeon_and4");
-- inicjalizacja testu
for i in 1 to test_count loop
wait for assertTime(i*test_time);
test_out := nstd2std(in_1) and
nstd2std(in_2) and
nstd2std(in_3) and
nstd2std(in_4);
-- opis wzorca
assertEquals("out_1",out_1,std2nstd(test_out));
end loop;
tearDown;
-- koniec testu
wait;
end process;
Opis testu dla 16 bitowego multipleksera (technologia prądowa)
------------------------------------------------------------------- TEST CASE
-----------------------------------------------------------------TestCase : process
constant test_time: time := 50ns;
constant test_count: integer:= 16;
variable test_out : std_logic;
variable s : std_logic_vector(3 downto 0);
begin
setUp("Multiplekser mux16_1e - wersja pradowa");
-- inicjalizacja testu
for i in 1 to test_count loop
wait for assertTime(i*test_time);
s(0):=
s(1):=
s(2):=
s(3):=
nstd2std(s0);
nstd2std(s1);
nstd2std(s2);
nstd2std(s3);
if e='1' then
case s is
when "0000" => test_out := nstd2std(d0);
when "0001" => test_out := nstd2std(d1);
when "0010" => test_out := nstd2std(d2);
when "0011" => test_out := nstd2std(d3);
when "0100" => test_out := nstd2std(d4);
when "0101" => test_out := nstd2std(d5);
when "0110" => test_out := nstd2std(d6);
when "0111" => test_out := nstd2std(d7);
when "1000" => test_out := nstd2std(d8);
when "1001" => test_out := nstd2std(d9);
when "1010" => test_out := nstd2std(d10);
when "1011" => test_out := nstd2std(d11);
when "1100" => test_out := nstd2std(d12);
when "1101" => test_out := nstd2std(d13);
when "1110" => test_out := nstd2std(d14);
when "1111" => test_out := nstd2std(d15);
when others => null;
end case;
else
test_out:='0';
end if;
assertEquals("o",o,std2nstd(test_out));
end loop;
tearDown;
-- koniec testu
wait;
end process;
------------------------------------------------------------------
Moduły rozszerzające
Biblioteka vhdlUnit została zastosowana przy testowaniu prądowego układu FPGA. W tym celu
zaprojektowano moduł rozszerzający funkcjonowanie biblioteki o nowy typ danych nstd_logic.
Zewnętrzna biblioteka nstd_logic_2000 zaprojektowana przez autorów publikacji umozliwia realizację
modeli układów cyfrowych pracujacych w logice wielowartościowej[tu odniesienie do literatury].
Weryfikacja opracowanych układów
Weryfikacja opracowanych układów (Opracowanie modelów VHDL, Realizacja w układzie scalonym,
wyniki testów, opracowanie własnych i dostosowanie istniejących programów do sprawdzenia
poprawności schematu i działania układu)
Zastosowanie:
Model prądowego układu FPGA realizowanego w ramach grantu (tu podać numerek).
Zalety:
• modyfikacja elementów projektu i wykonanie grupowych testów funkcjonalności wcześniej
sprawdzanych konfiguracji układu. (łatwość eksperymentowania z nowymi pomysłami z
uwzdlędnieniem weryfikacji wcześniej wykonanej pracy).
Wnioski
Możliwości dalszego rozwoju biblioteki:



Dodanie nowych funkcji i procedur assercji dla różnych typów danych (std_logic, ustd_logic,
nstd_logic, integer, string, real, std_logic_vector itd...)
Realizacja procesów testowych w oparciu o wzorce danych zawartych w zewnętrznych plikach
(plik tekstowy oraz waveform)
Rozbudowa części raportowania o generację dokumentów XML
Bibliografia
http://www.xprogramming.com