Skip to main content
Logo image

Section 8.4 Testbenches for synchronous systems

The new feature that must be added to a testbench for a synchronous system is a clock generator. Here is an example, a testbench for the simple two-bit counter Listing 8.3.4.
-- Testbench for two-bit binary counter
library ieee;
use ieee.std_logic_1164.all;

entity counter2_tb is                      
end counter2_tb;

architecture testbench of counter2_tb is

-- Declare UUT
component counter2 is
   port( clk:  in  std_logic;         
         X:    out std_logic_vector(1 downto 0) );   
 end component;

-- Declare and initialize signals
constant CLK_PERIOD: time := 100ns;               -- 1
signal clk: std_logic := '0';            
signal X:   std_logic_vector(1 downto 0) := "00";

begin

-- Instantiate UUT and wire to signals
uut: counter2 port map
        clk => clk,                                                   
        X   => X );

-- Generate stimuli
clk_proc:  process                               -- 2                       
begin
     clk <= '1';
     wait for CLK_PERIOD/2;
     clk <= '0';
     wait for CLK_PERIOD/2;
end process clk_proc;

--stim_proc:  process                           -- 3
--begin
--end process stim_proc;

end testbench;
Listing 8.4.1. VHDL testbench for two-bit counter model, Listing 8.3.4. Comments are keyed to explanations in the text.
Three features of this testbench distinguish it from previous testbenches:
  1. The clock period is declared as a named constant. As in conventional programming languages, it is always advisable to use a symbolic name for numerical constants. Then, if the value needs to be updated in the future, it is only necessary to change the numerical value once, rather than at every appearance of the value in the code. VHDL includes a datatype time, which can be expressed in seconds (s), milliseconds (ms), microseconds (us), and nanoseconds (ns). Here, assigning CLK_PERIOD the value 100ns establishes a 10MHz clock.
  2. A separate process is used to generate the clock. It sets the clk signal HIGH, waits for half the clock period (50ns), then sets it LOW, and waits for half the clock period. The process resumes from the top when the wait time is up, and repeats without end, generating a clock with 100ns period.
  3. There are no stimuli for this counter other than the clock, so the normal stimulus process is not used in this testbench.

Checkpoint 8.4.2. Simulation: Four-bit binary counter.

Here is a VHDL model and testbench for a four-bit binary counter
 1 
www.edaplayground.com/x/2ww2
. Run the simulation and observe the behavior in the timing diagram.
If we want to simulate a counter with reset and enable, Exercise 8.3.1, we need to generate the enable and reset signals in the testbench. We can do this with the stimulus process.
When you design a testbench, you want to make sure that you cover the cases of interest and not miss important edge cases. Here, it is important to demonstrate that the counter can be reset to zero. An exhaustive test would ensure that the counter could be reset from every state, e.g., count to 1, reset, count to 2, reset, count to 3, reset, ..., but this is too much. We can be confident, from the way the model is written, that if reset works for an arbitrary count value, it will work for all values. Likewise, with the enable, we want to show that the counter can be stopped, then started back up from where it left off. We of course want to show that the counter will still roll over from its maximum count to zero. And, finally, we want to demonstrate the priority of reset over enable; the counter should be resettable whether it is running or stopped. Study how these tests are implemented in the testbench shown in Listing 8.4.3.
-- Testbench for binary counter with reset and enable
library ieee;
use ieee.std_logic_1164.all;

entity counter_reseten_tb is                      
end counter_reseten_tb;

architecture testbench of counter_reseten_tb is

-- Declare UUT
component counter_reseten is
   port( clk:   in  std_logic;   
         reset: in  std_logic;
         CE:    in  std_logic;   
         y:     out std_logic_vector(7 downto 0) );   
 end component;

-- Declare and initialize signals
constant CLK_PERIOD: time := 100ns;                
signal clk:       std_logic := '0';    
signal reset, CE: std_logic := '0';        
signal y:         std_logic_vector(7 downto 0) := x"00";

begin

-- Instantiate UUT and wire to signals
uut: counter_reseten port map
        clk   => clk, 
        reset => reset,
        CE    => CE,                                                  
        y     => y );

-- Generate stimuli
-- These processes run concurrently.
clk_proc:  process                                                      
begin
     clk <= '1';
     wait for CLK_PERIOD/2;
     clk <= '0';
     wait for CLK_PERIOD/2;
end process clk_proc;

stim_proc:  process                           
begin
     CE <= '0';  reset <= '1';     -- Hold in reset
     wait for 2*CLK_PERIOD;        -- for two clock cycles

     reset <= '0';                 -- Release reset, but still holding
     wait for 2*CLK_PERIOD;

     CE <= '1';                    -- Enable counting
     wait for 5*CLK_PERIOD;

     reset <= '1';                 -- Reset while counting
     wait for 2*CLK_PERIOD;

     reset <= '0';                 -- Start counting again
     wait for 4*CLK_PERIOD;
     CE <= '0';                    -- Hold while counting
     wait for 4*CLK_PERIOD;

     CE <= '1';                    -- Re-enable and 
     wait;                            -- let it run
end process stim_proc;

end testbench;
Listing 8.4.3. VHDL testbench for binary counter with reset and enable.

Checkpoint 8.4.4. Simulation: Counter with enable and reset.