Search code examples
simulationvhdlclockhardware

VHDL - How should I create a clock in a testbench?


How should I create a clock in a testbench? I already have found one answer, however others on stack overflow have suggested that there are alternative or better ways of achieving this:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

ENTITY test_tb IS 
END test_tb;

ARCHITECTURE behavior OF test_tb IS

    COMPONENT test
        PORT(clk : IN std_logic;)
    END COMPONENT;

   signal clk : std_logic := '0';
   constant clk_period : time := 1 ns;

BEGIN

   uut: test PORT MAP (clk => clk);       

   -- Clock process definitions( clock with 50% duty cycle is generated here.
   clk_process :process
   begin
        clk <= '0';
        wait for clk_period/2;  --for 0.5 ns signal is '0'.
        clk <= '1';
        wait for clk_period/2;  --for next 0.5 ns signal is '1'.
   end process;

END;

(source here)


Solution

  • My favoured technique:

    signal clk : std_logic := '0'; -- make sure you initialise!
    ...
    clk <= not clk after half_period;
    

    I usually extend this with a finished signal to allow me to stop the clock:

    clk <= not clk after half_period when finished /= '1' else '0';
    

    If you use a std_logic item for your finished signal, it can be driven from all the items in your test environment:

    signal finished : std_logic;
    
    ....
    stimulus_process:process
    begin
       finished <= '0';
       drive_various_signals_sync_with_clk;
       finished <= '1';
    end process;
    
    monitor_process:process
    begin
       finished <= '0';
       check_all_signals_until_all_tests_complete;
       finished <= '1';
    end process;
    

    Then the clock only stops after all elements have finishde. And when there are no more transactions (on signals) scheduled, your simulation will stop cleanly.


    Gotcha alert: Care needs to be taken if you calculate half_period from another constant by dividing by 2. The simulator has a "time resolution" setting, which often defaults to nanoseconds... In which case, 5 ns / 2 comes out to be 2 ns so you end up with a period of 4ns! Set the simulator to picoseconds and all will be well (until you need fractions of a picosecond to represent your clock time anyway!)