Tuesday, June 23, 2015

Need For Testing Testbench

Need for testing:
1.      To verify the functionality of the design according to specifications.
2.      To perform random testing and hence to reduce the test time of the design.
3.      To detect failures so that bugs (in software code) can be identified and corrected before it gets shipped to costumer. (There are possibilities that error may in the specification itself. Sometimes miscommunications between teams may lead to wrong design.)
A test bench or testing workbench is a virtual environment used to verify the correctness or soundness of a design or model, for example, a software product.
In hardware testing of electronic devices, where an engineer would sit at a lab bench with tools for measurement and manipulation, such as oscilloscopes, multimeters, soldering irons, wire cutters and manually verify the correctness of the device under test (DUT).
In software or firmware or hardware engineering, a test bench refers to an environment in which the product under development is tested with the aid of software and hardware tools.
The software may need to be modified slightly in some cases to work with the test bench but careful coding can ensure that the changes can be undone easily and without introducing bugs.
Components of a test bench
A test bench has four components:
  1. Input: The entrance criteria or deliverables needed to perform work
  2. Procedures to do: The tasks or processes that will transform the input into the output
  3. Procedures to check: The processes that determine that the output meets the standards
  4. Output: The exit criteria or deliverables produced from the workbench
Kinds of test benches
The following types of test bench are the most common: Test Benches
  1. Stimulus only — contains only the stimulus driver and DUT; does not contain any results verification.
  2. Full test bench — Contains stimulus driver, known good results, and results comparison.
  3. Simulator specific — the test bench is written in a simulator-specific format.
  4. Hybrid test bench — Combines techniques from more than one test bench style.
  5. Fast test bench — Test bench written to get ultimate speed from simulation.
Test Benches
To simulate your design, you need both the design under test (DUT) or unit under test (UUT) and the stimulus provided by the test bench. 

A test bench is HDL code that allows you to provide a documented, repeatable set of stimuli that is portable across different simulators.

A test bench can be as simple as a file with clock and input data or a more complicated file that includes error checking, file input and output, and conditional testing.

Methods to create the test bench:
  •  Text editor
This is used to verify complex designs. It allows you to use all the features available in the HDL language and gives you flexibility in verifying the design.
Advantages:  It produces more precise and accurate results than using the Test Bench Waveform Editor.
Disadvantages: It is more challenging to create the code.
To assist in creating the test bench, you can create a template that lays out the initial framework, including the instantiation of the UUT and the initializing stimulus for your design. 
  •  Test Bench Waveform Editor
This is used to verify less complicated simulation tasks and is recommended if you are new to HDL simulation. It allows you to graphically enter the test bench to drive the stimulus to your design.
Advantages: Easy to work.
Disadvantages: implementation and analysis of complex designs.
Test Bench Strategies
Because the test bench becomes a part of the hierarchy in your code, the following has to considered:
  •  Make the test bench the top level of the code.
The test bench instantiates the unit under test (UUT), and stimulus is applied from the top-level test bench to the lower-level design or portion of the design being tested.
  •  Use the instance name UUT for the instantiated unit under test.
This is the default instance name that Project Navigator expects.
You can use the same test bench for both functional and timing simulation. Following are general recommendations that apply to both types of simulation:
  •  Initialize all input ports at simulation time zero, but do not drive expected stimulus until after 100 nanoseconds (ns) simulation time.
During timing simulation, a global set/reset signal is automatically pulsed for the first 100 ns of simulation. To keep the test bench consistent for both timing and functional simulation, it is recommended that you hold off input stimulus until the global set/reset has completed.
  •  Do not provide data to the input ports at the same time as the clock.
For non-timing simulation, this can cause some signals to be applied before the clock and some after the clock. Apply data only after the clock is applied to the input ports. This makes it easier to keep track of which clock edge data changes are being applied.
  •  If output checking is performed in the test bench, apply data just before the next clock cycle.
For timing simulation, it could take up to an entire clock cycle for the data to propagate through the logic and settle to a known value. Checking data too early in the clock cycle may yield incorrect results.
Example:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity test is
port (clk : in std_logic;
      count : out std_logic_vector(3 downto 0);
      reset :in std_logic
     );
end test;

architecture Behavioral of test is
signal c : std_logic_vector(3 downto 0) :=(others => '0');  --initializing count to zero.
begin
count <= c;
process(clk,reset)
begin
if(clk'event and clk='1') then
-- when count reaches its maximum(that is 15) reset it to 0
if(c = "1111") then
c <="0000";
end if;
c <= c+'1';  --increment count at every positive edge of clk.
end if;
if(reset='1') then  --when reset equal to '1' make count equal to 0.
c <=(others => '0');  -- c ="0000"
end if;
end process;

end Behavioral;
 
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;

-- entity declaration for your testbench.Dont declare any ports here
ENTITY test_tb IS
END test_tb;

ARCHITECTURE behavior OF test_tb IS
   -- Component Declaration for the Unit Under Test (UUT)
    COMPONENT test  --'test' is the name of the module needed to be tested.
--just copy and paste the input and output ports of your module as such.
    PORT(
         clk : IN  std_logic;
         count : OUT  std_logic_vector(3 downto 0);
         reset : IN  std_logic
        );
    END COMPONENT;
   --declare inputs and initialize them
   signal clk : std_logic := '0';
   signal reset : std_logic := '0';
   --declare outputs and initialize them
   signal count : std_logic_vector(3 downto 0);
   -- Clock period definitions
   constant clk_period : time := 1 ns;
BEGIN
    -- Instantiate the Unit Under Test (UUT)
   uut: test PORT MAP (
         clk => clk,
          count => count,
          reset => reset
        );      

   -- Clock process definitions( clock with 50% duty cycle is generated here.
   clk_process :process
   begin
        clk <= '0';
        wait for clk_period/2;  --for 0.5 ns signal is '0'.
        clk <= '1';
        wait for clk_period/2;  --for next 0.5 ns signal is '1'.
   end process;
   -- Stimulus process
  stim_proc: process
   begin        
        wait for 7 ns;
        reset <='1';
        wait for 3 ns;
        reset <='0';
        wait for 17 ns;
        reset <= '1';
        wait for 1 ns;
        reset <= '0';
        wait;
  end process;

END;
2. If multiple clocks are to be generated with different frequencies, then clock generation can be simplified if a procedure is called as concurrent procedure call.
library ieee;
use ieee.std_logic_1164.all;

entity tb is
end entity;

architecture sim of tb is

  -- Procedure for clock generation
  procedure clk_gen(signal clk : out std_logic; constant FREQ : real) is
    constant PERIOD    : time := 1 sec / FREQ;        -- Full period
    constant HIGH_TIME : time := PERIOD / 2;          -- High time
    constant LOW_TIME  : time := PERIOD - HIGH_TIME;  -- Low time; always >= HIGH_TIME
  begin
    -- Check the arguments
    assert (HIGH_TIME /= 0 fs) report "clk_plain: High time is zero; time resolution to large for frequency" severity FAILURE;
    -- Generate a clock cycle
    loop
      clk <= '1';
      wait for HIGH_TIME;
      clk <= '0';
      wait for LOW_TIME;
    end loop;
  end procedure;

  -- Clock frequency and signal
  signal clk_166 : std_logic;
  signal clk_125 : std_logic;

begin

  -- Clock generation with concurrent procedure call
  clk_gen(clk_166, 166.667E6);  -- 166.667 MHz clock
  clk_gen(clk_125, 125.000E6);  -- 125.000 MHz clock

  -- Time resolution show
  assert FALSE report "Time resolution: " & time'image(time'succ(0 fs)) severity NOTE;

end architecture;

Simulation Overview
During HDL simulation, the simulator software verifies the functionality and timing of your design or portion of your design. The simulator interprets VHDL or Verilog code into circuit functionality and displays logical results of the described HDL to determine correct circuit operation. Simulation allows you to create and verify complex functions in a relatively small amount of time.

Simulation takes place at several points in the design flow. It is one of the first steps after design entry and one of the last steps after implementation, as part of verifying the end functionality and performance of the design. Simulation is an iterative process, which may require repeating until both design functionality and timing is met. For a typical design, simulation comprises the following high-level steps:
  1. Compilation of the simulation libraries
  2. Creation of the design and test bench  
  3. Functional simulation
  4. Implementation of the design and creation of the timing simulation netlist
  5. Timing simulation
Functional Simulation
After you compile the simulation libraries and create the test bench and design code, you can perform functional simulation on the design.

Functional simulation is an iterative process, which may require multiple simulations to achieve the desired end functionality of the design.

Once the desired functionality is achieved, use the output data to create a self-checking testbench. ISim has the capability to generate a self-checking testbench. It is important to set up the proper infrastructure for this type of simulation; spending time up front may save time in back end design debugging.

The general recommendations are:
  •  Spend time up front to create a good test bench.
Creating a test bench that you can use for both functional and timing simulation can save time.
  •  Ensure that your libraries are properly compiled and mapped.
If your design includes Xilinx CORE Generator cores, make sure that your libraries are properly compiled and mapped to the simulator. If you are using the ISim or the ModelSim Xilinx Edition simulator, this is automatically done for you.
  •  Automate the compilation and elaboration simulation steps.
When you invoke the simulator from within Project Navigator, the ISE® tools automatically run these steps. If you are running the simulator outside of Project Navigator, it is recommended that you create a script or use another method to automate these steps. 
  •  Customize the simulator interface to present the information needed to debug the design.
You may want to include the information console, the structure or hierarchy view, and the waveform viewer as well as other facilities to evaluate the simulation. Customization can improve the simulation experience and can be tied into the automation of the compilation and elaboration steps.
If you are using a waveform viewer as a part of simulation debugging, organize the waveform view to display the proper signals in the proper order with the proper radices. This saves time and helps prevent confusion in interpreting simulation results.



No comments:

Post a Comment