Francisco Leon
Francisco Leon

Reputation: 78

Stop VHDL simulation with wait statements

When testing a simple counter implementation, the VHDL simulation is not exiting the simulation. My intention is to stop both concurrent processes using the shared variable changed by the main process. But the main process is not stopping the clock process.

My counter implementation is:

entity dff is
port(
    direction, reset, clk, load : in std_logic;
    din : in std_logic_vector(3 downto 0);
    dout : out std_logic_vector(3 downto 0));
end dff;

architecture behav of dff is
    signal temp : std_logic_vector(3 downto 0);
begin
    process(clk, reset)
begin
     if (reset='1') then
         temp <= "0000";
         elsif rising_edge(clk) then
            if (load='1') then
                temp <= din;
            else
                if (direction='0') then
                    temp <= std_logic_vector(unsigned(temp) + 1);
                else
                    temp <= std_logic_vector(unsigned(temp) - 1);
                end if;
            end if;
        end if;
        dout <= temp;
    end process;
end behav;

And my testbench:

architecture behav of test_tb is
    component dff port(
        direction, reset, clk, load : in std_logic;
        din : in std_logic_vector(3 downto 0);
        dout : out std_logic_vector(3 downto 0));
    end component;
    signal direction, reset, clk, load : std_logic := '1';
    signal din, dout : std_logic_vector(3 downto 0) := x"7";
    shared variable simend : boolean := false;
begin

    clkk : process
    begin
        if simend=false then
            clk <= not clk after 50 ns;
        else
            wait;
        end if;
    end process clkk;

    uut : dff port map(
        direction, reset, clk, load, din, dout);

    stim : process
    begin
        reset <= '0';
        wait for 1 us;
        load <= '0';
        wait for 2 us;
        direction <= '0';
        wait for 2 us;
        load <= '1';
        wait for 1 us;
        reset <= '1';
        wait for 0.5 us;

        simend := true;
        wait;
    end process stim;
end behav;

Upvotes: 2

Views: 8884

Answers (3)

Matthew
Matthew

Reputation: 13977

I would code your clock generator more like this:

clkk : process
begin
    while simend=false loop
        clk <= not clk;
        wait for 50 ns;
    end loop;
    wait;
end process clkk;

It is possible to execute your clkk process without ever executing a wait statement. (The line clk <= not clk after 50 ns does not wait or block - <= is a non-blocking assignment.) Therefore, you have an infinite loop that will never stop. You can see this by running this example on EDA Playground where the simulation time never advances and, because the maximum runtime on EDA Playground is 1 minute, times out after 1 minute.

Also, I would recommend not using a shared variable for simend. Instead, why not use a signal? You code would not even be compiable in VHDL-2000 onwards, because after VHDL-2000, shared variables had to be protected types. You can see that a warning is produced on EDA Playground unless you set the option to compile VHDL-93. Compiling for VHDL-93, would prevent you using the stop (or finish) procedures.

Upvotes: 1

Jim Lewis
Jim Lewis

Reputation: 3983

I agree with @scary_jeff, std.env.stop is a great answer here. If I am just calling it in one place, my preference is to leave off the package reference and just call it:

std.env.stop;

In the event you are stuck with an older simulator, you can use

report "Just Kidding.   Test Done."  severity failure ;

OTOH if you need to coordinate ending a simulation between multiple processes and add a watch dog timer to your simulation run, you might consider the procedure Osvvm.TbUtilPkg.WaitForBarrier. It is used as shown below. The first call to WaitForBarrier(TestDone, 5 ms) will wake up in 5 ms in the event that TestDone does not happen before then and stop the simulation at that time.

signal TestDone : integer_barrier := 1 ;

ControlProc : process
begin
  -- initialize test
  SetAlertLogName("Uart1_Rx") ;
  . . .
  WaitForBarrier(TestDone, 5 ms) ; -- control process uses timeout
  AlertIf(now >= 5 ms, "Test finished due to Time Out") ;
  ReportAlerts ;
  std.env.stop ;
end process ControlProc ;

CpuProc : process
begin
  InitDut(. . . )_;
  Toggle(CpuReady) ;
  -- run numerous Cpu test transactions
  . . .
  WaitForBarrier(TestDone) ;
  wait ;
end process CpuProc ;

UartTxProc : process
Begin
  WaitForToggle(CpuReady) ;
  -- run numerous Uart Transmit test transactions
  . . .
  WaitForBarrier(TestDone) ;
  wait ;
end process UartTxProc ;
. . .

You can find the OSVVM library at both osvvm.org and on github. There is also a complete user guide in for this package in the download.

Upvotes: 1

scary_jeff
scary_jeff

Reputation: 4374

An alternative way to end the simulation if you have a VHDL2008-compliant simulator is to:

use std.env.stop;

you can then end the simulation by calling stop:

stop;

This seems to me to be more elegant than waiting for a lack of clock transitions to cause the simulator iteration limit to be reached.

Upvotes: 5

Related Questions