Ngoloo
Ngoloo

Reputation: 23

How to implement a test bench for 4x1 mux

I'm struggling to write a test bench for this:

    ---------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
---------------------------------------
ENTITY mux IS
    PORT ( a, b, c, d, s0, s1: IN STD_LOGIC;
         y: OUT STD_LOGIC);
END mux;
---------------------------------------
ARCHITECTURE pure_logic OF mux IS
BEGIN
    y <= (a AND NOT s1 AND NOT s0) OR
 (b AND NOT s1 AND s0) OR
 (c AND s1 AND NOT s0) OR
 (d AND s1 AND s0);
END pure_logic;
---------------------------------------

This is my progress so far. I am not quite sure how to write the stimulus part. I tried running it through a behavioral simulation, but I am getting Undefined Errors in the results.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity mux_tb is
--  Port ( );
end mux_tb;

architecture Behavioral of mux_tb is
    component mux
         PORT ( a, b, c, d, s0, s1: IN STD_LOGIC;
         y: OUT STD_LOGIC);
    end component;

    signal a : std_logic;
    signal b : std_logic;
    signal c : std_logic;
    signal d : std_logic;
    signal s0 : std_logic;
    signal s1 : std_logic;
    signal y : std_logic;
 
begin
    uut: mux port map (
        a => a,
        b => b,
        c => c,
        d => d,
        s0 => s0,
        s1 => s1,
        y => y
    );

    process
    begin
    s0 <= '0'; s1 <= '0';
    wait for 100 ns;
    s1 <= '0'; s0 <= '1';
    wait for 100ns;
    s1 <= '1'; s0 <= '0';
    wait for 100ns;
    s1 <= '1'; s0 <= '1';

    end process;
end Behavioral;

Could anyone explain what I am doing wrong?

Upvotes: 2

Views: 1082

Answers (3)

TonyM
TonyM

Reputation: 124

I am not quite sure how to write the stimulus part

You appear to be asking for a design technique that can be used to stimulate the inputs.

A simple method for testing a purely combinatorial circuit like your component is to drive the inputs from a test counter. In this case, it can be a 7-bit std_logic_vector counter.

Then write a loop with 128 passes. On each pass, it will perform the component's logic function on the counter value to produce an expected result. The pass will wait for the component outputs to settle then use an assert to compare the actual result with the expected result and display an error if they don't match. Then increment counter and do the next pass.

Upvotes: -2

user1818839
user1818839

Reputation:

You might want separate loops for the ABCD inputs and the select inputs. This makes it easier to see that the output reacts to B but not A,C,D inputs when the select is set to B, and so on. Clearer than trying to interpret a 6 bit number.

In addition to the stimulus part covered in other answers, a good TB will compute (or read from an array or file or something) the expected outputs, and compare these with the actual outputs, reporting any differences ... you can use Assert/Report for this.

If you then log Pass/Fail and number of errors (possibly to a file) at end of test, you can use this in regression tests and never have to stare at waveforms again. That's when it gets to be a time saver.

See also osvvm.org and Vunit (on github) for tools to help.

Upvotes: 1

user16145658
user16145658

Reputation: 755

Your testbench does not supply stimuli for a, b, c and d. You need to assign them as well as s0 and s1.

architecture full_behavior of mux_tb is
    component mux
         PORT ( a, b, c, d, s0, s1: IN STD_LOGIC;
         y: OUT STD_LOGIC);
    end component;

    signal a : std_logic;
    signal b : std_logic;
    signal c : std_logic;
    signal d : std_logic;
    signal s0 : std_logic;
    signal s1 : std_logic;
    signal y : std_logic;
    
    use ieee.numeric_std.all;  -- CHANGED Added use clause
begin
uut: 
    mux port map (
        a => a,
        b => b,
        c => c,
        d => d,
        s0 => s0,
        s1 => s1,
        y => y
    );
STIMULI_ASSERT:
    process
       variable inputs:  std_logic_vector (3 downto 0); -- data inputs
       variable s1s0:    integer range 0 to 3;    -- selects as integer
    begin
        for i in 0 to 63 loop
            (d, c, b, a, s1, s0) <= to_unsigned(i, 6);
            wait for 100 ns;
            inputs := (d, c, b, a);
            s1s0 := to_integer(unsigned'(s1 & s0));
            assert y = inputs(s1s0)
                report "Expected " & std_ulogic'image(inputs(s1s0)) &
                       " got " & std_ulogic'image(y)
                severity error;
        end loop;
        wait;
    end process;
end architecture;

You can do this with a for loop which assigned values to all the mux inputs. Additionally if all the inputs are ordered you can use s0 and s1 to select which of the data inputs should appear on y.

Here the for loop range is determined by the power of two raised to the number of inputs.

This

        (d, c, b, a, s1, s0) <= to_unsigned(i, 6);

is an aggregate assignment that takes it's type from context (the entire statement). 6 is the number of inputs and specifies the length of integer value i converted to unsigned. The assignment is to individual elements of the target aggregate.

this

        inputs := (d, c, b, a);

has the type of the aggregate specified by the assignment target (std_logic_vector).

and this

        s1s0 := to_integer(unsigned'(s1 & s0));

saves the integer value of the concatenation of s1 & s0 specified as type unsigned to s1s0.

The assertion checks the expected output as an indexed value of the data inputs against y and when not equal reports an error along with the expected and y values.

We use type unsigned declared in IEEE package numeric_std along with it's operations when we want to treat a composite value as an unsigned number.

Upvotes: 4

Related Questions