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