Testbenches are generally quite simple, because they always have the same five parts, written in nearly the same way. To demonstrate, we will write a testbench for the two-input multiplexer model Listing 5.3.1. The model has a control input, S, two data inputs, A and B, and an output, y. Every testbench has the same parts, as shown in the listing, below. The same testbench will apply to all of the two-input multiplexer models with the same ports, regardless of their architectures.
library ieee;
use ieee.std_logic_1164.all;
-- (1) EMPTY ENTITY DECLARATION
-- Testbenches never have I/O ports
entity mux2to1_tb is
end mux2to1_tb;
architecture testbench of mux2to1_tb is
-- (2) DECLARE THE UUT AS A COMPONENT
-- Must match the entity declaration in the UUT's model
component mux2to1 is
port( A, B: in std_logic;
S: in std_logic;
y: out std_logic );
end component;
-- (3) DECLARE SIGNALS TO CONNECT TO THE UUT
-- Customary to give them the same names as the UUT's ports
signal a, b, s: std_logic := '0'; -- inputs intialized to '0'
signal y: std_logic;
begin
-- (4) INSTANTIATE THE UUT IN THE TESTBENCH
-- Analogous to wiring a physical device in to the test equipment
uut: mux2to1 port map
a => a, -- "=>" means "port maps to signal"
b => b, -- separated by commas, not semicolons
s => s,
y => y );
-- (5) GENERATE STIMULI
-- Systematically generate all combinations of input
stim_proc: process -- No sensitivity list
begin
s <= '0'; a <= '0'; b <= '0'; -- May place all on one line, for compactness
wait for 100ns; -- Process suspends, resumes after 100ns
s <= '0'; a <= '0'; b <= '1'; -- Each line is one row of truth table
wait for 100ns;
s <= '0'; a <= '1'; b <= '0';
wait for 100ns;
...
s <='1'; a <= '1'; b <= '1';
wait;
-- Process halts here
end process stim_proc;
end testbench;
Listing7.2.1.VHDL testbench for two-input multiplexer model, Listing 5.3.1
Notes on the five testbench sections:
The entity may be named anything, but I find it helpful to construct a name by appending “_tb” to the name of the entity of the unit under test. The testbench’s entity does not have ports. It is self-contained.
The VHDL model for the UUT must be declared to the testbench so that it can be used, like declaring function prototypes in a conventional language. The designation component indicates that the UUT is a separate unit that is “plugged into” the testbench.
These signals are the nets that “wire” the UUT to the testbench. It is conventional to give them the same names as their corresponding UUT ports. The “ :=’0’ ” appended to each line is a special assignment that gives the signals an initial value of ’0’.
The UUT is instantiated into the testbench. The notation “a => a,” indicates that port a of the UUT is mapped, or connected, to signal a of the testbench. Later, the testbench will drive signal a with ’0’ or ’1’, which will, in turn, drive port a of the UUT.
The stimulus process asserts and deasserts the signals driving the UUT ports. In the first line, all three inputs are scheduled to be ’0’. In the next line, the process suspends, assigning ’0’ to each input. The process resumes after 100ns, and the simulator moves to the next line, changing one of the inputs. In this way, all eight combinations of the three inputs are applied to the UUT, followed by a delay to observe the system’s response. The final wait statement has no criterion for resuming execution, so the process and the simulation halt here.
-- Testbench for two-input one-hot decoder, with enable
library ieee;
use ieee.std_logic_1164.all;
entity dec2to4_en_tb is
end dec2to4_en_tb;
architecture testbench of dec2to4_en_tb is
-- Declare UUT
component dec2to4_en is
port( en: in std_logic;
x: in std_logic_vector(1 downto 0);
y: out std_logic_vector(3 downto 0) );
end component;
-- Declare and initialize signals
signal en: std_logic := '0';
signal x: std_logic_vector(1 downto 0) := "00";
signal y: std_logic_vector(3 downto 0);
begin
-- Instantiate UUT and wire to signals
uut: dec2to4_en port map
en => en,
x => x,
y => y );
-- Generate stimuli
stim_proc: process
begin
en <= '0';
x <= "00"; wait for 100ns;
x <= "01"; wait for 100ns; -- en is still '0' until it is changed
x <= "10"; wait for 100ns;
x <= "11"; wait for 100ns;
en <= '1'; -- Now enable the decoder
x <= "00"; wait for 100ns;
x <= "01"; wait for 100ns;
x <= "10"; wait for 100ns;
x <= "11"; wait for 100ns;
en <= '0'; wait; -- Disable the decoder and halt
end process stim_proc;
end testbench;
Listing7.2.3.VHDL testbench for enabled two-to-four decoder model, Exercise 6.5.2