Search code examples
vhdlmodelsim

How to implement a test bench file for a 8x1 Multiplexer with 32-bit line width?


I'm writing a VHDL code to model an 8x1 multiplexer where each input has 32-bit width. So I created an array to model the MUX but now I'm stuck with the Test Bench, it's gotten so complicated. Here is my original file (I'm sure it has so many redundancies) How can I actually make the test bench to recognize my array (R_in) from the component's file and then how will I stimulate it?

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY mux8_1 IS
   PORT(Rs  :IN STD_LOGIC_VECTOR(2 DOWNTO 0);
    in0,in1,in2,in3,in4,in5,in6,in7 :IN STD_LOGIC_VECTOR(31 DOWNTO 0);
    R_out   :OUT STD_LOGIC_VECTOR(31 DOWNTO 0)
       );
END mux8_1;

ARCHITECTURE behaviour OF mux8_1 IS

type t_array_mux is array (0 to 7) of STD_LOGIC_VECTOR(31 DOWNTO 0);
signal R_in:t_array_mux;

BEGIN

R_in(0) <= in0;
R_in(1) <= in1;
R_in(2) <= in2;
R_in(3) <= in3;
R_in(4) <= in4;
R_in(5) <= in5;
R_in(6) <= in6;
R_in(7) <= in7;


process(R_in, Rs)
BEGIN

CASE Rs IS

WHEN "000"=>R_out<=R_in(0);
WHEN "001"=>R_out<=R_in(1);
WHEN "010"=>R_out<=R_in(2);
WHEN "011"=>R_out<=R_in(3);
WHEN "100"=>R_out<=R_in(4);
WHEN "101"=>R_out<=R_in(5);
WHEN "110"=>R_out<=R_in(6);
WHEN "111"=>R_out<=R_in(7);
WHEN OTHERS=>R_out<= (others => '0');

END CASE;
END process;
END behaviour;

And here is my "in progress" test bench file. Just ignore the "stimulus process" part I know it's wrong I just couldn't figure out how to write it for a 32-bit signal.

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;

ENTITY mux8_1_TB IS
END mux8_1_TB;

ARCHITECTURE behaviour OF mux8_1_TB IS

COMPONENT mux8_1
   PORT(Rs  :IN STD_LOGIC_VECTOR(2 DOWNTO 0);
    in0,in1,in2,in3,in4,in5,in6,in7 :IN STD_LOGIC_VECTOR(31 DOWNTO 0);
    R_out   :OUT STD_LOGIC_VECTOR(31 DOWNTO 0)
       );
END COMPONENT;

type t_array_mux is array (0 to 7) of STD_LOGIC_VECTOR(31 DOWNTO 0);

--Inputs
signal R_in:t_array_mux:=(others=>'0');
signal in0,in1,in2,in3,in4,in5,in6,in7 :STD_LOGIC_VECTOR(31 DOWNTO 0):=(others=>'0');
signal Rs  :STD_LOGIC_VECTOR(2 DOWNTO 0):=(others=>'0');

--Outputs
signal R_out:STD_LOGIC_VECTOR(31 DOWNTO 0);

-- Instantiate the Unit Under Test + connect the ports to my signal
BEGIN

R_in(0) <= in0;
R_in(1) <= in1;
R_in(2) <= in2;
R_in(3) <= in3;
R_in(4) <= in4;
R_in(5) <= in5;
R_in(6) <= in6;
R_in(7) <= in7;

uut: mux8_1 PORT MAP(
    Rs=>Rs,
    R_in=>R_in,
    R_out=>R_out
       );

-- Stimulus process (where the values -> inputs are set) 

PROCESS
begin

R_in<="01010101";
    wait for 10 ns;
Rs<="001";
    wait for 10 ns;
Rs<="010";
    wait for 20 ns;
Rs<="011";
    wait for 30 ns;
Rs<="100";
    wait for 40 ns;
Rs<="101";
    wait for 50 ns;
Rs<="110";
    wait for 60 ns;
Rs<="111";
    wait for 70 ns;

END PROCESS;
END;

Solution

  • You need to change your uut port map so instead of R_in, it has individual in0 - in7 ports to match your mux8_1 component definition. Then, map in0 - in7 testbench signals directly to these ports:

     uut: mux8_1 port map(
         ...
         in0 => in0,
         in1 => in1,
         ...
         );
    

    Or if you want to keep the R_in signal, port map like this:

    uut: mux8_1 port map(
             ...
             in0 => R_in(0),
             in1 => R_in(1),
             ...
             );
    

    This assignment to R_in in your testbench is incorrect:

    R_in<="01010101";
    

    R_in is defined as a t_array_mux type, so it can't be assigned a bit vector value. It has to be assigned to an array of 32-bit std_logic_vector. That line should really be removed altogether, as you're already making assignments to R_in in another location outside of the process. Multiple assignments will cause signal contention.

    You're initializing R_in in your testbench like this:

    signal R_in:t_array_mux:=(others=>'0');
    

    The others keyword as you've used it will only work on an individual std_logic_vector. You need to nest others for your array of std_logic_vector:

    signal R_in:t_array_mux:=(others=>(others=>'0'));
    

    You'll want to assign values to your 32-bit in0 - in7 signals so you can see the output of your mux change in the sim. They can be assigned outside the stimulus process. You can assign them using hex-notation (x preceding "") or just binary:

    in0 <= x"12345678"; --hex
    

    or

    in0 <= "00010010001101000101011001111000"; --binary
    

    Your stimulus process looks fine. As you change Rs, you would expect to see the different input values on R_out. You could add a single wait; at the end of the process, or the process will keep repeating until the end of sim.

    Component ports with user-defined types

    Alternatively, you could port map your R_in testbench signal directly to a R_in port on your component as you've done, but it would take a bit more work. Your mux8_1 component definition does not have an R_in port. You can add a t_array_mux type port named R_in, if you define the t_array_mux type in a package which you then include in your component and testbench files

    library work;
    use work.your_package_name.all;
    

    in addition to library IEEE, etc. Then you can use the t_array_mux type in your component port definition:

    ENTITY mux8_1 IS
      PORT(Rs    : IN STD_LOGIC_VECTOR(2 DOWNTO 0);
           R_in  : IN T_ARRAY_MUX; --User-defined port type
           R_out : OUT STD_LOGIC_VECTOR(31 DOWNTO 0)
           );
    END mux8_1;
    

    This will allow you to do the port mapping of your uut the way you currently have it. You'll have to add the package to the project or compile list in whatever tool you're using.