Writing Test Benches

(from VHDL Made Easy!)


While much of this book has focused on the uses of VHDL for synthesis, one of the primary reasons to use VHDL is its power as a test stimulus language. As logic designs become more complex, comprehensive, up-front verification becomes critical to the success of a design project. In fact, as you become proficient with simulation, you will quickly find that your VHDL simulator becomes your primary design development tool. When simulation is used right at the start of the project, you will have a much easier time with synthesis, and you will spend far less time re-running time-intensive processes, such as FPGA place-and-route tools and other synthesis-related software.

To simulate your project, you will need to develop an additional VHDL program called a test bench. (Some VHDL simulators include a command line stimulus language, but these features are no replacement for a true test bench.) Test benches emulate a hardware breadboard into which you will "install" your synthesizable design description for the purpose of verification.

Test benches can be quite simple, applying a sequence of inputs to the circuit over time. They can also be quite complex, perhaps even reading test data from a disk file and writing test results to the screen and to a report file. A comprehensive test bench can, in fact, be more complex and lengthy (and take longer to develop) than the synthesizable circuit being tested. As you will begin to appreciate while reading this chapter, test bench development will be where you make use of the full power of VHDL and your own skills as a VHDL "coder".

Depending on your needs (and whether timing information related to your target device technology is available), you may develop one or more test benches to verify the design functionally (with no delays), to check your assumptions about timing relationships (using estimates or unit delays), or to simulate with annotated post-route timing information so you can verify that your circuit will operate in-system at speed.

During simulation, the test bench will be the top level of a design hierarchy. To the simulator, there is no distinction between those parts of the design that are being tested and the test bench itself. In your own mind, however, you can think of the test bench as a separate circuit, analogous to a large automated tester.

In most of this book, we have been emphasizing those aspects of the VHDL language that are synthesizable. In doing so, we have actually seen only a subset of the VHDL language in the examples presented. When writing test benches, you will most likely use a broader range of language features. You may use records and multi-dimensional arrays to describe test stimuli, write loops, create subprograms to simplify repetitive actions, and/or use VHDL's text I/O features to read and write files of data.

A Simple Test Bench

The simplest test benches are those that apply some sequence of inputs to the circuit being tested (the Unit Under Test, or UUT) so that its operation can be observed in simulation. Waveforms are typically used to represent the values of signals in the design at various points in time. Such a test bench must consist of a component declaration corresponding to the unit under test, and a description of the input stimulus being applied to the UUT.

The following example demonstrates the simplest form of a test bench, and tests the operation of a NAND gate:

library ieee;                  -- Load the ieee 1164 library

use ieee.std_logic_1164.all;   -- Make the package 'visible'



use work.nandgate;             -- We'll use the NAND gate model from 'work'



-- The top level entity of the test bench has no ports...

--

entity testnand is

end testnand;



architecture stimulus of testnand is

    -- First, declare the lower-level entity...

    component nand

        port  (A,B: in std_logic;

               Y: out std_logic);

    end component;



    -- Next, declare some local signals to assign values to and observe...

    signal A,B: std_logic;

    signal Y: std_logic;



begin

    -- Create an instance of the comparator circuit...

    NAND1: nandgate port map(A => A,B => B,Y => Y);



    -- Now define a process to apply some stimulus over time...

    process

        constant PERIOD: time := 40 ns;

    begin

        A <= '1';

        B <= '1';

        wait for PERIOD;

        assert (Y = '0')

            report "Test failed!" severity ERROR;

        A <= '1';

        B <= '0';

        wait for PERIOD;

            assert (Y = '1')

            report "Test failed!" severity ERROR;

        A <= '0';

        B <= '1';

        wait for PERIOD;

            assert (Y = '1')

            report "Test failed!" severity ERROR;

        A <= '0';

        B <= '0';

        wait for PERIOD;

            assert (Y = '1')

            report "Test failed!" severity ERROR;

        wait;

    end process;   

end stimulus;

Reading from the top of this test bench, we see:


As you can see, the Test Bench chapter of VHDL Made Easy! is very detailed. It goes on to cover an extensive array of test bench issues, including test vectors, and reading and writing files with text I/O.

Plus, this chapter includes the driving game, a fun example circuit inspired by Altera Corporation's “ChipTrip” example. In our version of the design, the objective is to create a sequence of test inputs, in the form of a human and VHDL-readable file, that will cause an imaginary work-weary engineer to proceed from his office to the beach, as quickly as possible, without getting a speeding ticket. To make the trip more interesting, our hero must stop and pick up a pizza on the way.

Speaking of which: if you're work-weary and looking for a VHDL resource that's easy to read, easy to follow, and chock full of useful sample code, your wait is over. VHDL Made Easy! is here. Why, you can even read it over pizza at the beach!


[How to order VHDL Made Easy!]