2. Schritt: Simulation und Inbetriebnahme
In diesem Schritt werden wir die Testbench anpassen um die Blinkfrequenz nach Power On zu überprüfen.
Anschließend werden wir die UUT so weit anpassen, dass der Test erfolgreich durchläuft.
Das Programmgerüst enthält bereits eine einfache Ausgabe für einen Testreport. Die generierte Datei befindet sich in dem gleichen Verzeichnis, wie die Vivado-Projektdatei.
Des weiteren befinde sich dort zwei Unterprogramme zum Messen und Testen der Blinkperiode. Das Messen der Blinkperiode erfolgt in MeasureLedPeriod;
--! measure LED period
procedure MeasureLedPeriod(constant maxCycles : in integer; signal Led_period : out time) is
variable i : integer;
variable s : integer;
variable rise_1 : integer;
variable rise_2 : integer;
begin
s := 0; -- initial state
Led_period <= 0 ns; -- timeout return value
for i in 1 to maxCycles loop -- timeout condition
wait until rising_edge(Ext_Clk); -- measure in clock ticks
case s is
when 0 => -- wait for initial condition
if (Led = '0') then
s := 1; -- initial condition reached
end if;
when 1 => -- wait for rising edge
if (Led = '1') then
s := 2; -- first rising edge reached
rise_1 := i; -- remember clock tick
end if;
when 2 => -- wait for LED being off again
if (Led = '0') then
s := 3; -- LED is off again reached
end if;
when 3 => -- wait for rising edge
if (Led = '1') then
s := 4; -- nothing more to do
rise_2 := i; -- remember clock tick
Led_period <= (rise_2 - rise_1) * Clk_period;
wait for 10 ps; -- Let variable value settle
return; -- got result
end if;
when others =>
return;
end case;
end loop;
end MeasureLedPeriod;
Ohne jetzt auf zu viele Details einzugehen wartet dieses Unterprogramm auf die erste steigende Flanke des LED Signals, merkt sich den Zeitpunkt, wartet auf die zweite steigende Flanke und errechnet daraus die Periode, die im Ausgangssignal Led_period abgelegt wird.
Das zweite Unterprogramm testet ob die erwartete Periode eingehalten wird und kümmert sich entsprechend des Ergebnisses um die Ausgabe auf den Report und den Fehlerausgang:
--! measure LED period
procedure CheckLedPeriod(constant expected : in time; signal LED_period : inout time;
signal TestErr : out std_logic) is
begin
MeasureLedPeriod(2*expected/Clk_period, LED_period);
if (LED_period = expected) then
tb_report(" Expected " & time'Image(expected) & ": passed.");
else
TestErr <= '1';
tb_report(" Expected " & time'Image(expected) & "; Found " & time'Image(LED_per) & ": Failed!");
end if;
end CheckLedPeriod;
In der Testbench sind auch noch zwei weitere Prozesse enthalten:
--! Generate system clock
p_clk : process
begin
Ext_Clk <= not Ext_Clk;
wait for Clk_period/2;
end process;
--! Check for test bench time out
p_control : process
begin
wait for 20 ms;
-- the test bench should already have terminated!
assert false
report "Test timed out!"
severity failure;
end process;
p_clk erzeugt das Taktsignal. Es handelt sich hierbei also um den externen Oszillator.
p_control sorgt dafür, dass, falls die Testbench in einer Endlosschleife gefangen wäre, der Test nach einer gewissen Zeit abgebrochen würde.
Damit ist das Handwerkszeug gegeben, um einen ersten Test durchführen zu können. Es soll getestet werden, ob die LED nach dem Start des FPGAs mit der richtigen Frequenz blinkt.
Die Zeitdefinitionen dafür sind in der Testbench bereits vorhanden. Dabei ist zu beachten, dass die Simulation ja um den Faktor 10000 schneller ablaufen soll als die Realität, 250 Hz entsprechen dadurch in der Simulation 400 ns.
-- Time definitions
constant Clk_period : time := 8 ns; --! ZYBO Clock frequency is 125 MHz
-- constant Clk_period : time := 10 ns; --! ARTY Clock frequency is 100 MHz
constant LED_min_per : time := 400 ns; --! LED period in fastest mode
constant LED_res_per : time := LED_min_per*256; --! LED period after reset
constant LED_max_per : time := LED_res_per*16; --! LED period in slowest mode
In der Testbench muss nun also der Testcase 1 angepasst werden:
TestCase <= 1;
tb_report("Test Case 1: LED Period after power on...");
expected_time := LED_res_per;
CheckLedPeriod(expected_time, LED_per, TestErr);
Und die UUT muss natürlich auch angepasst werden um dem Simulationsfaktor 10.000 wenigstens in etwa gerecht zu werden. Der binäre Logarithmus von 10000 ist ca. 13,3. Also wird in BlinkingLed.vhd anstatt Bit 26 das Bit 13 auf die LED ausgegeben.
LED <= ToggleCntR(13);
Jetzt kann die Simulation durchgeführt werden. Diese schlägt natürlich fehl, weil auf das genaue Timing keine Rücksicht genommen worden ist.
TestBlinkingLed.log
Testing BlinkingLed: ==================== Test Case 1: LED Period after power on... Expected 102400000 ps; Found 131072000 ps: Failed! Test completed with error(s)
Inbetriebnahme der UUT
Wie in der Spezifikation angegeben soll ja ein Taktgeber mit 500 Hz (5 MHz in der Simulation) erzeugt werden, der dann einen 13 Bit Frequenzgenerator ansteuert.
Auf dem ZYBO, bei 125 MHz, muss der Taktgeber von 0 bis 249999 (in der Simulation bis 24) zählen. D.h. nach der entsprechenden Periode wird der Taktgeber zurückgesetzt und der Frequenzgenerator inkrementiert. Die LED wird dann zunächst von Bit 8 des Frequenzgenerators ausgegeben.
Folgende Anpassungen in BlinkingLed.vhd müssen also durchgeführt werden:
signal FreqGenR : std_logic_vector(12 downto 0); --! Generate blinking frequencies
...
--! Flipflops with synchronous reset
p_sync : process (Clk)
begin
if rising_edge(Clk) then
if (InitR = '1') then
ToggleCntR <= (others => '0');
else
-- if (ToggleCntR = 249999) then
if (ToggleCntR = 24) then
ToggleCntR <= (others => '0');
else
ToggleCntR <= ToggleCntR + 1;
end if;
end if;
end if;
end process;
--! Flipflops with synchronous reset and clock enable
p_ce : process (Clk)
begin
if rising_edge(Clk) then
if (InitR = '1') then
FreqGenR <= (others => '0');
elsif (ToggleCntR = 24) then
FreqGenR <= FreqGenR + 1;
end if;
end if;
end process;
LED <= FreqGenR(8);
Dabei ist natürlich zu beachten, dass die Signaldeklaration vor dem begin der architecture stehen muss. Jetzt kann die Simulation erneut durchgeführt werden und diesmal läuft sie durch.
TestBlinkingLed.log
Testing BlinkingLed: ==================== Test Case 1: LED Period after power on... Expected 102400000 ps: passed. Test completed successfully
Weiter zum 3. Schritt