.. _w05-test: ================================================ Wykład 5: Symulacja, testy, weryfikacja formalna ================================================ Data: 07.11.2018 .. toctree:: .. contents:: Symulatory Veriloga =================== Symulator języka Verilog to program bezpośrednio ewaluujący konstrukcje Veriloga (w przeciwieństwie do syntezy, czyli tłumaczenia na sprzęt). Można w nim używać pełnego zbioru funkcjonalności języka Verilog (nie tylko syntezowalnego podzbioru) -- symulatory pozwalają na przykład wypisać coś na ekran bądź otwierać pliki na dysku. Symulatorów używa się do przetestowania poprawnego działania układu przed uruchomieniem go na sprzęcie. Wspomnę tutaj o następujących symulatorach: - Icarus Verilog (znany również jako ``iverilog``) -- otwarty symulator Veriloga. - Verilator -- tłumaczy syntezowalny kod Veriloga na kod C++, który można wlinkować do własnego programu. Nie może być używany do uruchamiania zwykłych testów napisanych w Verilogu, za to pozwala nam używać naszego symulowanego układu z poziomu C++. Open source. - XSIM -- symulator Xilinxa, wbudowany w ISE. Oprócz Veriloga wspiera VHDL i testowanie zamkniętych logic core'ów. Bardzo nie open source. Icarus Verilog -- użycie ------------------------ ``a.v``:: module hello; initial begin $display("Hello, world!"); end endmodule Użycie:: # -s wybiera główny moduł. $ iverilog a.v -s hello $ ./a.out Hello, world! $ .. note:: Wygenerowany plik ``a.out`` *nie* jest kodem maszynowym, tylko skryptem napisanym w reprezentacji pośredniej Icarus Veriloga). Testy ===== Aby symulacja miała sens, musimy napisać przypadki testowe (tzw. testbench). Przypadek testowy to moduł w (niesyntezowalnym) Verilogu, który używa danego syntezowalnego modułu, który chcemy przetestować. Testowany moduł przyjęło się nazywać DUT (Device Under Test):: module flop( input wire D, input wire CLK, output reg Q ); initial Q = 0; always @(posedge CLK) Q <= D; endmodule module testbench; reg D = 0; reg CLK = 0; wire Q; flop DUT(D, CLK, Q); initial begin if (Q !== 0) $display("Err 1"); D = 1; // # czeka X kroków symulacji. #1 if (Q !== 0) $display("Err 2"); CLK = 1; #1 if (Q !== 1) $display("Err 3"); D = 0; CLK = 0; #1 if (Q !== 1) $display("Err 4"); D = 0; CLK = 1; #1 if (Q !== 0) $display("Err 5"); $finish; end endmodule (:download:`test_flop.v`) Aby dostać się do wewnętrznych sygnałów testowanego modułu, można użyć składni ``DUT.`` (narusza to enkapsulację, ale w testach można). Warto tutaj wspomnieć o dwóch typach porównania w Verilogu: ``==`` (i jego negacja ``!=``) oraz ``===`` (i negacja ``!==``). ``==`` jest syntezowalnym porównaniem, w którym stany nieokreślone się propagują (``0 == X`` daje wynik ``X``, ``X == X`` daje wynik ``X``) -- jest to porównanie, którego należy używać zawsze w syntezowalnym kodzie. ``===`` natomiast jest porównaniem, które traktuje każdą z 4 możliwych wartości bitu jako niezależną wartość (``0 === X`` daje wynik ``0``, ``X === X`` daje wynik ``1``) -- nelaży go używać w testach, by upewnić się, że nasz układ daje odpowiednie wyniki.