Erläuterungen
Im Definitionsbereich der Architektur werden die verwendeten Module und die Signale der Testbench deklariert. Es werden zumindest die Ein- und Ausgangs-Signale der UUT benötigt. Zusätzlich werden in unserem Fall aber auch noch einige Signale für die Testbench selber deklariert:
architecture Behavioral of TestSimpleLed is
component SimpleLed
port (
Button : in std_logic;
Led : out std_logic
);
end component;
--Inputs
signal Button : std_logic := '0'; -- Signal is high active
--Outputs
signal Led : std_logic;
--Test
signal TestCase : natural;
signal TestErr : std_logic := '0';
begin
Eingangssignale der UUT bekommen Initialisierungswerte. Diese werden mit := zugewiesen (Normalerweise ist der Zuweisungsoperator für Signale <=. Initialisierungswerte werden allerdings mit := zugewiesen). Dadurch haben die Eingänge der UUT beim Start der Testbench definierte Pegel und die UUT macht nicht schon ab Anfang irgendetwas undefiniertes.
Da der Button High-Aktiv ist, wird er hier mit '0' initialisiert um zu signalisieren, dass er noch nicht gedrückt ist.
Die Signale TestCase und TestErr, sind zusätzliche Signale für die Testbench um den Ablauf des Tests im Simulationsfenster verfolgen zu können. Diese werden von der Testbench verwaltet.
Im Body der Testbench wird zuerst die UUT instantiiert:
uut: SimpleLed port map (
Button => Button,
Led => Led
);
Dabei werden die internen Signale der UUT mit den Signalen der Testbench verbunden. In diesem Fall sind die Signalnamen identisch was bei der Testbench üblich ist.
Zum anderen wird zumindest ein Prozess benötigt, welcher die UUT stimuliert und erkennt ob das Modul korrekt funktioniert. Diesen Prozess zu erstellen ist die eigentliche Aufgabe dieses Kapitels.
stim_proc: process
begin
wait for 100 ns;
report "=======================================================";
report "Only end of test and errors will be reported";
Jeder Prozess in VHDL hat einen Namen und enthält Anweisungen die in einen begin/end-Kontext eingebettet sind. Die obigen Anweisungen sind typisch für eine Testbench. Sie wären so nicht synthetisierbar aber für einen Test natürlich hilfreich.
TestCase <= 1;
wait for 100 ns;
if (Led /= '0') then
TestErr <= '1';
report "Initial state failed";
end if;
Im ersten Testcase wird zuerst das Testcase-Signal gesetzt, damit man später in der Ausgabe erkennen kann, welcher Testcase gerade durchgeführt wird. Zur Überprüfung der UUT können nun einfach die Ausgangssignale auf bestimmte Zustände getestet werden. Durch das Flag TestErr wird hier gezeigt, wann ein Fehler aufgetreten ist. Im Konsolenfenster würde man im Fehlerfall die entsprechende Fehlermeldung erhalten.
TestCase <= 2;
Button <= '1';
wait for 100 ns;
if (Led /= '1') then
TestErr <= '1';
report "Button pressed, but LED is off";
end if;
Während im ersten Schritt die Reset-Bedingung getestet wurde wird im zweiten Schritt die UUT stimuliert (Button <= '1') und wiederum getestet, ob sich die Schaltung richtig verhält. Natürlich müsste man auf die Reaktion nicht 100 ns warten. Diese Zeit ist für eine sinnvolle Darstellung gewählt.
TestCase <= 3;
Button <= '0';
wait for 100 ns;
if (Led /= '0') then
TestErr <= '1';
report "Button released, but LED is on";
end if;
Im dritten Testcase wird nur noch geprüft ob die LED nach dem Loslassen des Tasters auch wieder aus geht.
TestCase <= 0;
wait for 100 ns;
TestErr <= not TestErr;
wait for 30 ns;
TestErr <= not TestErr;
wait for 100 ns;
if (TestErr = '0') then
report "Test completed successfully";
else
report "Test completed with error(s)";
end if;
report "=======================================================";
assert false; -- stop simulation
Am Schluss der Stimulation wird nur noch entsprechend des bisherigen Verlaufs der Simulation der Erfolg/Misserfolg ausgegeben. Diese Art der Ausgabe ist rein willkürlich gewählt.
Bei mir wird am Ende ein Puls auf TestErr ausgegeben (durch dessen zweimalige Invertierung). Dieser zeigt nach oben (Daumen hoch), falls kein Fehler während des Tests aufgetreten ist, ansonsten nach unten (Daumen runter).
wait;
end process;
end Behavioral;
Dann muss nur noch der Prozess und die Testbench abgeschlossen werden.
Weiter zu den Übungen