Register Transfer Level Hardware Description with Verilog:Writing Test benches
Writing Test benches
Verilog coding styles discussed so far were for coding hardware structures, and in all cases synthesizability and direct correspondence to hardware were our main concerns. In contrast, testbenches do not have to have hardware correspondence and they usually do not follow any synthesizability rules. We will see that delay specifications, and initial statements that do not have a one-to-one hardware correspondence are used generously in testbenches.
For demonstration of testbench coding styles, we use the Verilog code of Figure 88.53 that is a 101 Moore detector, as the circuit to be tested. This description is functionally equivalent to that of Figure 88.44. The difference is in the use of condition expressions (?:) instead of if-else statements, and separating the output assignment from the main always block. This code will be instantiated in the testbenches that follow.
Generating Periodic Data
Figure 88.54 shows a testbench module that instantiates moore_detector and applies test data to its inputs. The first statement in this code is the 'timescale directive that defines the time unit of this description. The testbench itself has no ports, which is typical of all testbenches. All data inputs to a circuit-under- test are locally generated in its testbench.
Because we are using procedural statements for assigning values to ports of the circuit-under-test, all variables mapped with the input ports of this circuit are declared as reg. The testbench uses two initial blocks and two always blocks. The first initial block {XE “initial block”} initializes clock, x, and reset to 0, 0, and 1,
respectively. The next initial block waits for 24 time units (ns in this code), and then sets reset back to 0 to allow the state machine to operate.
The always blocks shown produce periodic signals with different frequencies on clock and x. Each block waits for a certain amount of time and then it complements its variable. Complementing begins with the initial values of clock and x as set in the first initial block. We are using different periods for clock and x, so that a combination of patterns on these circuit inputs is seen. A more deterministic set of values could be set by specifying exact values at specific times.
Random Input Data
Instead of the periodic data on x we can use the $random predefined system function to generate random data for the x input. Figure 88.55 shows such a testbench.
This testbench also combines the two initial blocks for initially activating and deactivating reset into one. In addition, this testbench has an initial block that finishes the simulation after 165 ns.
When the flow into a procedural block reaches the $finish system task, the simulation terminates and exits. Another simulation control task that is often used is the $stop task that only stops the simulation and allows resumption of the stopped simulation run.
Timed Data
A very simple testbench for our sequence detector can be done by applying test data to x and timing them appropriately to generate the sequence we want, very similar to the way values were applied to reset in the previous examples. Figure 88.56 shows this simple testbench.
Techniques discussed in the above examples are just some of what one can do for test data generation. These techniques can be combined for more complex examples. After using Verilog for some time, users form their own test-generation techniques. For small designs, simulation environments generally provide waveform editors and other tool-dependent test-generation schemes. Some tools come with code fragments that can be used as templates for testbenches.
An important issue in developing testbenches is external file IO. Verilog allows the use of $readmemh and $readmemb system tasks for reading hex and binary test data into a declared memory. Moreover, for writing responses from a circuit-under-test to an external file, $fdisplay can be used.
Comments
Post a Comment