Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Writing Testbench help needed thanks for help

Status
Not open for further replies.

salim.alam2

Junior Member level 3
Joined
May 8, 2016
Messages
27
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
246
I was trying to write a test bench and i got some problems

1. dose the testbench code should be in different file than the main code or both together in the same file?
2. I was trying to write a testbench to verify the behavior of a calculator including the error detection feature. I must verify that it detects errors, that error bit is cleared when a clear operation is performed and that other operations are blocked when the error bit is set, but it is not working

Could you please help

This is the testbench code that I wrote:

Code:
Library IEEE;
    USE IEEE.std_logic_1164.all;
    USE IEEE.numeric_std.all;
    
    Entity calculator_test is
    end calculator_test;
    
    Architecture test of calculator_test is 
    component calculator_1 is
    Port ( clk : in std_logic; 				                      -- clock
    	Clear, load, add, complement : in std_logic;		     -- operation signals
     	Din : in std_logic_vector (15 downto 0);	          -- input data
    	Result : out std_logic_vector (15 downto 0));	     -- output data
    End component;
    
    signal clk_test : std_logic := '0';
    signal Clear_test, load_test, add_test, complement_test : std_logic;
    signal Din_test, Result_test : std_logic_vector (15 downto 0); 
    
    begin 
      UUT : calculator_1
      Port map ( clk => clk_test,
        Clear => Clear_test,
        load => load_test,
        add => add_test,
        complement => complement_test,
        Din => Din_test,
        Result => Result_test);
        
      Testbench_process : process
      begin
        wait for 0 ns; Clear_test <='1';
        assert (Result_test = "0000000000000000") report "Fail Clear" severity error;
        wait for 10 ns; load_test <='1';
        assert (Result_test = Din_test) report "Fail Laod" severity error;
        wait for 10 ns; add_test <='1';
        assert (Result_test = "1XXXXXXXXXXXXXXXX") report "Fail Add" severity failure;
        wait for 10 ns; complement_test <='1';
        assert (Result_test = not Din_test) report "Fail Complement" severity error;
        wait for 10 ns;
      end process;
    end test;

Thanks for your help
 

At first glance I noticed you are missing a process to generate a clock. See the following link for clock generation suggestions: .

Without running it myself, I don't know what else might be wrong.
 
dose the testbench code should be in different file than the main code or both together in the same file?

The TB code itself should always be a different file. You instantiate your main-code in the TB.
You see a TB appears like a wrapper module over your main module.
Remember that the main code should always be synthesizable but the TB code may not necessarily be synthesizable.

As written in the above post, successful clock generation in the TB is a must. After that go on for debugging what is wrong.
 
Thanks a lot for your help guys,
I made some changes but i still have problems.

Code:
Library IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.all;

Entity calculator_test is
end calculator_test;

Architecture test of calculator_test is 
component calculator_1 is
Port ( clk : in std_logic; 				                      -- clock
	Clear, load, add, complement : in std_logic;		     -- operation signals
 	Din : in std_logic_vector (15 downto 0);	          -- input data
	Result : out std_logic_vector (15 downto 0));	     -- output data
End component;

signal clk_test : std_logic := '0';
signal Clear_test, load_test, add_test, complement_test : std_logic := '0';
signal Din_test : std_logic_vector (15 downto 0) := "1111111111111111";
signal Result_test : std_logic_vector (15 downto 0);
Constant clk_period_x : Time := 5 ns;


begin 
  UUT : calculator_1
  Port map ( clk => clk_test,                         -- Maping The Ports
             Clear => Clear_test,
             load => load_test,
             add => add_test,
             complement => complement_test,
             Din => Din_test,
             Result => Result_test);
             
             
  clock_process : process                               -- Independent Process For Clock Generation
begin
  clk_test <= Not(clk_test);
  wait for clk_period_x;
end process clock_process;

    
  Testbench_process : process                         -- Process For Stimuli Generation
  begin
    wait for 0 ns; Clear_test <='1';
    assert (Result_test = "0000000000000000") report "Fail Clear" severity error;
    wait for 10 ns; Clear_test <='0'; load_test <='1';
    assert (Result_test = Din_test) report "Fail Laod" severity error;
    wait for 10 ns; load_test <='0'; add_test <='1';
    assert (Result_test = "1XXXXXXXXXXXXXXXX") report "Fail Add" severity failure;
    wait for 10 ns; add_test <='0'; complement_test <='1';
    assert (Result_test = not Din_test) report "Fail Complement" severity error;
  
  end process;
end test;

I have this problem

6.png

and when simulating my Result is always Unknown

6.1.png
 

Your signal Result_test is undefined, but you only show the code for the instantiation of the calculator_1 component. As Result_test is an output of the caclulator_1 component all I can assume is the output Result is not driven by calculator_1.
 
Ask yourself the following questions:

1. What is the "UUT : calculator_1" supposed to do? Do you understand its operation (and architecture) and input/output signals?
2. What is a test bench supposed to do in general? What is it supposed to do with your UUT.

If your are clear with the above, you can successfully write a test-bench.
 
The output still undefined

This is the code that i am trying to test using testbench:


Code:
Library IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.all;

Entity calculator is
Port ( clk : in std_logic; 				                        -- clock
	Clear, load, add, complement : in std_logic;		        -- operation signals
 	Din : in std_logic_vector (15 downto 0);	                        -- input data
	Result : out std_logic_vector (15 downto 0));	                -- output data
End calculator;

Architecture a1 of calculator is
Signal dReg : std_logic_vector (15 downto 0);                      -- Difining signals to be used inside my process
signal error_flag : std_logic := '0';                                     -- dReg as a result, error_flag as a carry 
Signal final : std_logic_vector (15 downto 0);                       -- final as a final result

Begin 
Process (clk)                                                             -- The first process to do the operations
Begin
	If (rising_edge (clk)) then
 		If (clear ='1') then                                         -- if we perform a clean the result(dReg) and
      dReg <= "0000000000000000";error_flag <= '0';           -- the carry(error_flag), whold be zeros
    elsif error_flag = '0' then
	  	if (load ='1') then
 			dReg <= Din;
 		elsif (add ='1') then
 			dReg <= std_logic_vector(unsigned(dReg)+ unsigned(Din) & error_flag ); -- Using flag & to be able to assign additional bit
 		elsif (complement='1') then
 			dReg <= not Din;

			--values of dreg and din are converted to unsigned type with unsigned() function.
			--the unsigned values are added
			--the result is converted to standard logic vector with std_logic_vector() function.
			
	case  error_flag  is                                -- This additional case is used to
    when '0' => final <= dReg;                        -- detect when the error_flag is zero
    when others => null;                              -- so there will be a result and in
  end case;                                           -- other case NULL
  
       end if;
 			end if;
		end if;
end Process; 

Result <= final;                                      -- The Final Result 

end a1;


and this is my test code :

Code:
Library IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.all;

Entity calculator_test is
end calculator_test;

Architecture test of calculator_test is 
component calculator is
Port ( clk : in std_logic; 				                      -- clock
	Clear, load, add, complement : in std_logic;		     -- operation signals
 	Din : in std_logic_vector (15 downto 0);	          -- input data
	Result : out std_logic_vector (15 downto 0));	     -- output data
End component;

signal clk_test : std_logic := '0';
signal Clear_test, load_test, add_test, complement_test : std_logic := '0';
signal Din_test : std_logic_vector (15 downto 0) := "1111111111111111";
signal Result_test : std_logic_vector (15 downto 0);
Constant clk_period_x : Time := 5 ns;


begin 
  UUT : calculator
  Port map ( clk => clk_test,                         -- Maping The Ports
             Clear => Clear_test,
             load => load_test,
             add => add_test,
             complement => complement_test,
             Din => Din_test,
             Result => Result_test);
             
             
clock_process : process                               -- Independent Process For Clock Generation
  begin
    clk_test <= Not(clk_test);
    wait for clk_period_x;
end process clock_process;

    
tb_process : process                         -- Process For Stimuli Generation
  begin
    wait for 0 ns; Clear_test <='1';
    wait for 10 ns; Clear_test <='0'; load_test <='1';
    wait for 10 ns; load_test <='0'; complement_test <='1';
    wait for 10 ns; complement_test <='0'; add_test <='1';
    assert (Result_test <= "1XXXXXXXXXXXXXXXX") report "Fail Add" severity failure;
  end process tb_process;
end test;

7.png

Thanks again
 

You are using wait statements in your testbench, there is a race condition between the clock edge and the transitions of the signals, basically this is a delta time failure due to not understanding how a simulator schedules events.

Use either a clocked process or use delays (after) in the testbench signals to shift the transitions away from the clock edges.

You are using a case to check the error_flag, which is redundant as there is no way to be in that section of code with error_flag anything but '0' so the statement final <= dreg; will always apply.

You seem to be coding from a software approach instead of thinking in terms of hardware (Flip-flops, multiplexers, comparators, etc).
 
Thanks for your help, Actually i tried the delays (after) it worked for me, but now I am using wait because it is required from me to do it with wait.

I modified my code and my test code and everything is working except the add operation

this is my code

Code:
Library IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.all;

Entity calculator is
Port ( 
  clk : in std_logic; 				                            -- clock
	Clear, load, add, complement : in std_logic;		      -- operation signals
 	Din : in std_logic_vector (15 downto 0);	           -- input data
	Result : out std_logic_vector (16 downto 0);	       -- output data
	
	
End calculator;

Architecture a1 of calculator is

signal dReg : std_logic_vector (16 downto 0);         -- Difining signals to be used inside process
signal error_flag : std_logic := '0';              	         -- dReg as a result, error_flag as a carry 
signal final : std_logic_vector (15 downto 0);        -- final as a final result

Begin 
 
Process (clk)                                         -- The first process to do the operations
begin
	If (rising_edge (clk)) then
 		If (clear ='1') then                              -- if we perform a clean the result(dReg) 
                           -- and the carry(error_flag), whold be zeros
	    error_flag <= '0';
      final <= "0000000000000000";
	  elsif (load ='1') then
 			final <= Din;
 			error_flag <= '0';
 		elsif (add ='1') then
 			dReg <= std_logic_vector(unsigned ('0' & final) + unsigned ('0' & Din));           -- Using flag & to be able to assign additional bit
 		  error_flag <= dReg (16);
                  final <= dReg(15 downto 0);     
 		elsif (complement='1') then
 			final <= not Din;
 			error_flag <= '0';

			--values of dreg and din are converted to unsigned type with unsigned() function.
			--the unsigned values are added
			--the result is converted to standard logic vector with std_logic_vector() function.
 
       end if;
		end if;
end Process; 

Result <= '0' & final;
Result (16) <= error_flag;
                                     -- The Final Result 

end a1;

and the test code is

Code:
Library IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.all;

Entity calculator_test is
end calculator_test;

Architecture test of calculator_test is 
component calculator is
Port ( clk : in std_logic; 				                      -- clock
	Clear, load, add, complement : in std_logic;		     -- operation signals
 	Din : in std_logic_vector (15 downto 0);	          -- input data
	Result : out std_logic_vector (16 downto 0));	     -- output data
End component;

signal clk_test : std_logic := '0';
signal Clear_test, load_test, add_test, complement_test : std_logic := '0';
signal Din_test : std_logic_vector (15 downto 0) := "0001111111110001";
signal Result_test : std_logic_vector (16 downto 0);
Constant clk_period_x : Time := 5 ns;


begin 
  UUT : calculator
  Port map ( clk => clk_test,                         -- Maping The Ports
             Clear => Clear_test,
             load => load_test,
             add => add_test,
             complement => complement_test,
             Din => Din_test,
             Result => Result_test);
            
             
             
clock_process : process                               -- Independent Process For Clock Generation
  begin
    clk_test <= Not(clk_test);
    wait for clk_period_x;
end process clock_process;

    
tb_process : process                         -- Process For Stimuli Generation
  begin
        
    Clear_test <='1' ; wait for 10 ns;

    Clear_test <='0' ;
    
    load_test <='1' ;wait for 10 ns;

    load_test <='0' ; 
    
    complement_test <='1' ; wait for 10 ns;
    
    complement_test <='0' ;
    
    add_test <='1' ; wait for 10 ns;
    assert (Result_test (16) <= '1') report "Fail Add" severity failure;
    
    add_test <='0' ; 
    
    load_test <='1' ;wait for 10 ns;

    load_test <='0' ; 

  end process;
end test;

10.png
 

Thanks for your help, Actually i tried the delays (after) it worked for me, but now I am using wait because it is required from me to do it with wait.
I didn't not say remove the waits I told you to add after to the assignments to move the edges away from the clock edges.
Capture.JPG
The first set of circles shows the rising clock edge and Clear rising too. HUH? how did the synchronous clear take effect on the exact same clock cycle!

Middle column of circles, on the rising edge of clock and the rising edge of load you loaded the contents of the Result. WTF!? Is this some new kind of 0 setup FF?

Last column of circles, on the rising edge of clock and the rising edge of complement the output immediately gets inverted, Wow get me some of those hyper speed 0 ns setup FFs, so I can build Terahertz logic designs!

What all this means is your simulation is lying to you about the actual physical behavior of the real hardware, because you didn't read my post carefully enough to understand what I was telling you. Your simulation is showing every one of the transitions has a delta time failure due to the testbench applying signals in a race condition between the clock and the signal transitions. You need to read up on VHDL scheduling and how it works. I won't attempt to explain it here as I'm not an expert at the VHDL scheduler as I hardly ever write in VHDL, but I know enough to tell you to add delays to your assignments in the testbench or drive those same assignments using the exact same clock source that runs your DUT logic.

I modified my code and my test code and everything is working except the add operation
No your simulation is applying stimulus that doesn't represent a working design. As you haven't FIXED the problem I was referring to with the after.
 
Hello

I was trying to synthesis my code :

Code:
Library IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.all;

Entity calculator is
Port ( 
  clk : in std_logic; 				                            -- clock
	Clear, load, add, complement : in std_logic;		      -- operation signals
 	Din : in std_logic_vector (15 downto 0);	           -- input data
	Result : out std_logic_vector (16 downto 0);	       -- output data
	segment1 : out std_logic_vector(6 downto 0):= "0000001";        -- 7 bit decoded output.
	segment2 : out std_logic_vector(6 downto 0):= "0000001";        -- 7 bit decoded output.
	segment3 : out std_logic_vector(6 downto 0):= "0000001";        -- 7 bit decoded output.
	segment4 : out std_logic_vector(6 downto 0):= "0000001";        -- 7 bit decoded output.
	segment5 : out std_logic_vector(6 downto 0):= "0000001");       -- 7 bit decoded output.
	
End calculator;

Architecture a1 of calculator is

signal dReg : std_logic_vector (16 downto 0);         -- Difining signals to be used inside process
signal error_flag : std_logic;              	         -- dReg as a result, error_flag as a carry 
signal BCD1,BCD2,BCD3,BCD4 : std_logic_vector (3 downto 0);           -- Defining signal
signal BCD5 : std_logic;
signal clk1 : std_logic;
signal out1,out2,out3,out4,out5 : std_logic_vector(6 downto 0);


component seg is
port (BCD1,BCD2,BCD3,BCD4 : in std_logic_vector(3 downto 0);         -- BCD input
      BCD5 : in std_logic;
      out1,out2,out3,out4,out5: out std_logic_vector(6 downto 0);
      clk1 : in std_logic);
end component;


Begin 
  
  Map1 : seg 
  port map (BCD1 => dReg(3 downto 0),               -- Interconnecting ports with signal 
            out1 => segment1,
            BCD2 => dReg(7 downto 4),               -- Interconnecting ports with signal
            out2 => segment2,
            BCD3 => dReg(11 downto 8),              -- Interconnecting ports with signal
            out3 => segment3,
            BCD4 => dReg(15 downto 12),             -- Interconnecting ports with signal
            out4 => segment4,
            BCD5 => dReg(16),                       -- Interconnecting ports with signal
            out5 => segment5,
            clk1 => clk);
  
  
  
Process (clk)                                        -- The first process to do the operations
begin

  If (rising_edge (clk)) then
 		If (clear ='1') then                             -- if we perform a clean the result(dReg)
	    error_flag <= '0';                             -- and the carry(error_flag), whold be zeros
		  dReg <= "00000000000000000";
		elsif (load ='1') then                           -- the load operation it only performed when error_flag ='0'
		if (error_flag <='0') then
 			dReg <= '0' & Din;
		end if;
 		elsif (add ='1') then                            -- the add operation it only performed when error_flag ='0'
		if (error_flag <='0') then
 			dReg <= std_logic_vector(unsigned (dReg) + unsigned ('0' & Din)); 
		end if;
 		elsif (complement='1') then                      -- the complement operation it only performed when error_flag ='0'
		if (error_flag <='0') then
 			dReg <= '0' & not Din;
 		end if;

			--values of dreg and din are converted to unsigned type with unsigned() function.
			--the unsigned values are added
			--the result is converted to standard logic vector with std_logic_vector() function.
  
       end if;
       error_flag <= dReg (16);                                     

		end if;
end Process; 

Result <= dReg;                     -- The Final Result 
                              

proc1 : process (clk1,BCD1)
begin
if (clk1'event and clk1='1') then
  case BCD1 is
when "0000"=> out1 <="0000001";                   -- '0'
when "0001"=> out1 <="1001111";                   -- '1'
when "0010"=> out1 <="0010010";                   -- '2'
when "0011"=> out1 <="0000110";                   -- '3'
when "0100"=> out1 <="1001100";                   -- '4' 
when "0101"=> out1 <="0100100";                   -- '5'
when "0110"=> out1 <="0100000";                   -- '6'
when "0111"=> out1 <="0001111";                   -- '7'
when "1000"=> out1 <="0000000";                   -- '8'
when "1001"=> out1 <="0000100";                   -- '9' 
when others=> out1 <="1111010";                   -- Display 'r' in other cases.
  end case;
  if (error_flag ='1') then
    out1 <="1111010";                             -- Display 'r' in cases of error_flag ='1'
  end if;
end if;
end process proc1;


proc2 : process (clk1,BCD2)
begin
if (clk1'event and clk1='1') then
  case BCD2 is
when "0000"=> out2 <="0000001";                   -- '0'
when "0001"=> out2 <="1001111";                   -- '1'
when "0010"=> out2 <="0010010";                   -- '2'
when "0011"=> out2 <="0000110";                   -- '3'
when "0100"=> out2 <="1001100";                   -- '4' 
when "0101"=> out2 <="0100100";                   -- '5'
when "0110"=> out2 <="0100000";                   -- '6'
when "0111"=> out2 <="0001111";                   -- '7'
when "1000"=> out2 <="0000000";                   -- '8'
when "1001"=> out2 <="0000100";                   -- '9'
when others=> out2 <="1100010";                   -- Display 'o' in other cases.
  end case;
  if (error_flag ='1') then
    out2 <="1100010";                             -- Display 'o' in cases of error_flag ='1'
  end if;
end if;
end process proc2;


proc3 : process (clk1,BCD3)
begin
if (clk1'event and clk1='1') then
  case BCD3 is
when "0000"=> out3 <="0000001";                   -- '0'
when "0001"=> out3 <="1001111";                   -- '1'
when "0010"=> out3 <="0010010";                   -- '2'
when "0011"=> out3 <="0000110";                   -- '3'
when "0100"=> out3 <="1001100";                   -- '4' 
when "0101"=> out3 <="0100100";                   -- '5'
when "0110"=> out3 <="0100000";                   -- '6'
when "0111"=> out3 <="0001111";                   -- '7'
when "1000"=> out3 <="0000000";                   -- '8'
when "1001"=> out3 <="0000100";                   -- '9' 
when others=> out3 <="1111010";                   -- Display 'r' in other cases.
  end case;
  if (error_flag ='1') then
    out3 <="1111010";                             -- Display 'r' in cases of error_flag ='1'
  end if;
end if;
end process proc3;


proc4 :process (clk1,BCD4)
begin
if (clk1'event and clk1='1') then
  case BCD4 is
when "0000"=> out4 <="0000001";                   -- '0'
when "0001"=> out4 <="1001111";                   -- '1'
when "0010"=> out4 <="0010010";                   -- '2'
when "0011"=> out4 <="0000110";                   -- '3'
when "0100"=> out4 <="1001100";                   -- '4' 
when "0101"=> out4 <="0100100";                   -- '5'
when "0110"=> out4 <="0100000";                   -- '6'
when "0111"=> out4 <="0001111";                   -- '7'
when "1000"=> out4 <="0000000";                   -- '8'
when "1001"=> out4 <="0000100";                   -- '9'
when others=> out4 <="1111010";                   -- Display 'r' in other cases.
  end case;
  if (error_flag ='1') then
    out4 <="1111010";                             -- Display 'r' in cases of error_flag ='1'
  end if;
end if;
end process proc4;


                                                 
proc5 : process (clk1,BCD5)
begin                                             -- This Segment will not Display
if (clk1'event and clk1='1') then                 -- any thing but 'E'
  case BCD5 is
when '0'=> out5 <="0000001";                      -- '0'
when '1'=> out5 <="0110000";                      -- Display 'E' in this cases.
when others=> out5 <="0000001";                   -- Display '0' in other cases.
  end case;
end if;
end process proc5;

end a1;

I got a problem defining the Port map name:
Capture.PNG

Thanks a lot.
 

you have to compile the entity/architecture for seg
 
Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top