0

I wrote this VHDL-program vor an ALU and its testbench that is working:

ALU-code:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity ALU_CLK is
port(   Clk : in std_logic; --clock signal
        InRegA,InRegB : in signed(31 downto 0); --input operands
        InOp : in unsigned(2 downto 0); --Operation to be performed
        OutReg : out signed(31 downto 0);  --output of ALU
        OutZero : out std_logic
        );
end ALU_CLK;

architecture Behavioral of ALU_CLK is

signal Reg1,Reg2,Reg3 : signed(31 downto 0) := (others => '0');

begin

Reg1 <= INregA;
Reg2 <= InRegB;
OutReg <= Reg3;
process(Clk)
    variable temp: signed(31 downto 0);
begin
 if(rising_edge(Clk)) then
      case InOp is
            when "010" => 
                 temp := Reg1 + Reg2;    --addition
            when "000" => 
                 temp := Reg1 and Reg2;  --AND gate  
            when "001" => 
                 temp := Reg1 or Reg2;   --OR gate                 
            when others =>
                 NULL;
      end case;   
             if temp  = (31 downto 0=>'0') then
                OutZero <= '1';
                else
                OutZero <= '0';
            end if;
            Reg3 <= temp;
   end if; 
end process;    
end Behavioral; 

The testbench code:

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

ENTITY tb IS
END tb;

ARCHITECTURE ALU_CLK OF tb IS 

   signal Clk : std_logic := '0';
   signal A,B,R : signed(31 downto 0) := (others => '0');
   signal Op : unsigned(2 downto 0) := (others => '0');
   signal zero :  std_logic :='0';
   constant Clk_period : time := 10 ns;

BEGIN
   uut: entity work.ALU_CLK PORT MAP (
          Clk => Clk,
          InRegA => A,
          InRegB => B,
          InOp => Op,
          OutReg => R,
          OutZero => zero
        );

   Clk_process :process
   begin
        Clk <= '0';
        wait for Clk_period/2;
        Clk <= '1';
        wait for Clk_period/2;
   end process;

   -- Stimulus process
   stim_proc: process
   begin        
      wait for Clk_period*1;
          --test normal operations
        A  <= "00000000000000000000000000010011"; --19 in decimal
        B  <= "00000000000000000000000000001100"; --12 in decimal
        Op <= "000";  wait for Clk_period; --Bitwise and A and B
        Op <= "001";  wait for Clk_period; --Bitwise or B from A.
        Op <= "010";  wait for Clk_period; --addition A nad B  
      wait;
   end process;   
END;

To shorten the code listings a bit I did not post all the operations the ALU does. I can manage it to change the ALU to one without the clk but how can I test it with a testbench?

kimliv
  • 427
  • 1
  • 8
  • 25

3 Answers3

2

Even in a test bench for a module without a clock, it may be a good idea to have a clock that can time the test events, and make it easier to see the test progress in waveforms.

So after removal of the clock from the ALU, the test bench process can control stimuli and do the checks like:

-- Combined stimuli and check process
process is
begin
  ...
  -- === 2 + 2 test ===
  -- Stimuli control
  wait until rising_edge(clk);
  InRegA <= to_signed(2, InRegA'length);
  InRegB <= to_signed(2, InRegA'length);
  InOp   <= "010";  -- Add
  -- Output check
  wait until falling_edge(clk);
  assert OutReg = InRegA + InRegB;
  assert (OutZero = '1') = (OutReg = 0);
  ...
end process;

To simplify the check part, it can be moved to a separate process and the check can be made depending on the operation like:

-- Check process
process (clk) is
begin
  if falling_edge(clk) then
    if check then
      -- OutReg check
      case InOp is
        when "010"  => assert OutReg = InRegA + InRegB;      -- Add
        when "000"  => assert OutReg = (InRegA and InRegB);  -- And
        when "001"  => assert OutReg = (InRegA or InRegB);   -- Or
        when others => report "Unsupported operation" severity ERROR;
      end case;
      -- OutZero check
      assert (OutZero = '1') = (OutReg = 0);
    end if;
  end if;
end process;

The check signal is controlled by the stimuli process, to guard when the check is to be made, in order to avoid false errors in startup or for other special conditions.

Morten Zilmer
  • 15,586
  • 3
  • 30
  • 49
1
     library IEEE;
     use IEEE.STD_LOGIC_1164.ALL;
     use IEEE.STD_LOGIC_ARITH.ALL;
     use IEEE.STD_LOGIC_UNSIGNED.ALL;
     entity alu32bit is
     port(en:in STD_LOGIC;
          opc:in STD_LOGIC_VECTOR(3 downto 0);
          a_in,b_in:in STD_LOGIC_VECTOR(31 downto 0);
          y_op:out STD_LOGIC_VECTOR(31 downto 0));
     end alu32 bit;

     architecture Behavioral of alu32 bit is
     begin
      Process(en,a_in,b_in,opc)
     begin
     if(en='1')then
     when "0001"=>y_op<=a_in+b_in;
     when "0010"=>y_op<=a_in-b_in;
     when "0011"=>y_op<=not a_in;
     when "0100"=>y_op<=a_in and b_in;
     when "0101"=>y_op<=a_in or b_in;
     when "0110"=>y_op<=a_in nand b_in;
     when "0111"=>y_op<=a_in xor b_in;
     when others=>null;
     end case;
     else
     y_op<="ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
     end if;
     end process;
     end Behavioral;
akshata
  • 11
  • 1
0

In the end I got this:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity ALU_32 is
port(  
        InRegA,InRegB : in signed(31 downto 0); --input operands
        InOp : in unsigned(2 downto 0); --Operation to be performed
        OutReg : out signed(31 downto 0);  --output of ALU
          OutZero : out std_logic
        );
end ALU_32;

architecture Behavioral of ALU_32 is

--temporary signal declaration.
signal Reg1,Reg2,Reg3 : signed(31 downto 0) := (others => '0');

begin

Reg1 <= InRegA;
Reg2 <= InRegB;
OutReg <= Reg3;

process(InOp, InRegA, inRegB)
    variable temp: signed(31 downto 0);
begin
      case InOp is
            when "010" => 
                 temp := Reg1 + Reg2;    --addition
            when "110" => 
                 temp := Reg1 - Reg2;    --subtraction
            when "000" => 
                 temp := Reg1 and Reg2;  --AND gate  
            when "001" => 
                 temp := Reg1 or Reg2;   --OR gate               
            when "100" => 
                 temp := Reg1 nor Reg2;  --NOR gate    
            when "011" => 
                 temp := Reg1 xor Reg2;  --XOR gate   
            when "101" => 
                 temp := not Reg1;       --NOT gate
            when "111" => 
                 if Reg1 < Reg2 then     --SLT (set on less than) gate
                     temp   := (others => '1');
                     else
                     temp   := (others => '0');
                 end if;
            when others =>
                 NULL;
      end case; 

             if temp  = (31 downto 0=>'0') then
                OutZero <= '1';
                else
                OutZero <= '0';
            end if;
            Reg3 <= temp;

end process;    

end Behavioral;

And the working testbench is:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

ENTITY tb2 IS
END tb2;

ARCHITECTURE ALU_32 OF tb2 IS 


    COMPONENT ALU_32
    PORT(
         InRegA : IN  signed(31 downto 0);
         InRegB : IN  signed(31 downto 0);
         InOp : IN  unsigned(2 downto 0);
         OutReg : OUT  signed(31 downto 0);
         OutZero : OUT  std_logic
        );
    END COMPONENT;


   --Inputs
   signal InRegA : signed(31 downto 0) := (others => '0');
   signal InRegB : signed(31 downto 0) := (others => '0');
   signal InOp : unsigned(2 downto 0) := (others => '0');

    --Outputs
   signal OutReg : signed(31 downto 0);
   signal OutZero : std_logic;
   -- No clocks detected in port list. Replace <clock> below with 
   -- appropriate port name 

   --constant <InOp>_period : time := 10 ns;

BEGIN

   -- Instantiate the Unit Under Test (UUT)
   uut: ALU_32 PORT MAP (
          InRegA => InRegA,
          InRegB => InRegB,
          InOp => InOp,
          OutReg => OutReg,
          OutZero => OutZero
        );

   -- Stimulus process
   stim_proc: process
   begin        
      -- hold reset state for 100 ns.
      wait for 100 ns;  

      -- insert stimulus here 
        --test normal operations
        InRegA  <= "00000000000000000000000000010011"; --19 in decimal
        InRegB  <= "00000000000000000000000000001100"; --12 in decimal
        InOp <= "000";  wait for 100  ns;    --Bitwise and A and B
        InOp <= "001";  wait for 100  ns;    --Bitwise or B from A.
        InOp <= "010";  wait for 100  ns;    --addition A nad B
        InOp <= "100";  wait for 100  ns;    --Bitwise NOR of A and B
        InOp <= "011";  wait for 100  ns;    --Bitwise XOR of A and B
        InOp <= "110";  wait for 100  ns;    --substract A and B
        InOp <= "101";  wait for 100  ns;    --Bitwise NOT of A
        InOp <= "111";  wait for 100  ns;    --Bitwise SLT of A and B
        -- test SLT the other way around
        InRegB  <= "00000000000000000000000000010011"; --19 in decimal
        InRegA  <= "00000000000000000000000000001100"; --12 in decimal
        InOp <= "111";  wait for 100  ns;    --Bitwise SLT of A and B
        -- test Branch equal  that substraction is 0 and zero is 1
        InRegA  <= "00000000000000000000000000001011"; --11 in decimal
        InRegB  <= "00000000000000000000000000001011"; --11 in decimal
        InOp <= "110";  wait for 100  ns;    --substract A and B

      wait;
   end process;
END;

Here is the result of the simulation:

enter image description here

kimliv
  • 427
  • 1
  • 8
  • 25