The simple XOR verification example discussed in this section does not cover all the components discussed in "Components of a Verification Environment" on page 18. However, it does give the reader an idea of building a verification environment in e.
The purpose of this example is to introduce the reader to e. Syntax details are not explained in this section but will be covered in later chapters. It is important to pay attention to only the high-level verification structure at this point. We will learn e syntax in great detail in later chapters. There are plenty of comments throughout the examples in this section. However, the actual e code is very simple.
A Verilog example is described in this section. However, e code will work with either a Verilog or VHDL design.
The design to be tested is a simple XOR flipflop. Figure 2-6 shows the circuit diagram for this flipflop.
The Verilog code for the XOR DUT is shown in Example 2-2 below.
//Definition of XOR Module 'define width 2 module xor_mod (out, a, b, clk); parameter width = 'width; input clk; // 1 bit input input [width-1:0] a, b; // 2 bit inputs output [width-1:0] out; // 2 bit output reg [width-1:0] out; always @(posedge clk) out = #1 (a ^ b); endmodule // xor module
The XOR DUT is instantiated inside the module xor_top. Module xor_top instantiates the DUT, creates a clock whereby e code synchronizes with DUT and declares variables a, b, and out. The Verilog code for the xor_top module is shown in Example 2-3.
// Top level module to test an n-bit XOR Verilog design // that is to be tested using e 'define width 2 //Define a 2 bit width //Define the top level module module xor_top; //Define the parameters parameter width = 'width; parameter clock_period = 100; //Define variables for a, b and out reg [width-1:0] a, b; wire [width-1:0] out; // Setup clock. This clock will be used by // e code to synchronize with DUT. reg clk; initial clk =0; always #(clock_period/2) clk = ~clk; //Verilog monitor task task mon ; begin $monitor($time,"clk=%b a=%b b=%bout=%b",clk,a,b,out); end endtask // Instantiate the n-bit XOR DUT xor_mod x1(out,a,b,clk); endmodule
Thus, in the simulator, the hierarchy of the Verilog design is as shown in Figure 2-7 below.
The test plan for the above DUT is very simple.
Test all legal combinations of a and b (any 0,1 combination is legal).
Check values of out against expected values.
The clk variable will be used by e code to synchronize with the DUT. The test plan will be executed from e code, i.e., the values of inputs a and b will be chosen and toggled from within e code. Figure 2-8 shows the interaction between Specman Elite and the Simulator.
Various verification components will be needed to verify the XOR DUT. The test hierarchy to verify the XOR DUT will be represented in e. Figure 2-9 shows a possible hierarchy for the verification environment. We have omitted the protocol checker from this example for the sake of brevity.
The e code for the verification environment is shown in Example 2-4 below. Each component in the verification is highlighted with comments. There is no need to understand the syntax for the e code shown in this example. The purpose of displaying the e code is to give the reader a feel for the syntax. Details of e syntax will be described in later chapters.
This is a test environment for the XOR DUT written in e out[1:0] == (a[1:0] ^ b[1:0]) Beginning of e code to verify XOR DUT <' //--------------------------------------------------- // Data object. This is the basic stimulus item that will // be applied to the DUT. struct operation { a: int (bits: 2 ); //input to DUT b: int (bits: 2 ); //input to DUT !result_from_dut: int (bits:2); //output from DUT }; //--------------------------------------------------- // sys instantiates a list of basic stimulus items. These // form the test vectors to apply to DUT. The number // of test vectors is constrained to be less than 20. extend sys { ops: list of operation; // List of stimulus items keep ops.size() < 20; //Keep number of stimulus items < 20 }; //--------------------------------------------------- // Can call a Verilog task directly from within e code verilog task 'xor_top.mon'(); //Need full path name //--------------------------------------------------- // struct verify. Input Driver, Output Receiver and // Data Checker functions are all combined into this // struct. Typically, these functions would be in separate // structs or units. struct verify { //Create an event fall_clk that will be triggered //at each falling edge of clk. Specman Elite will be //invoked by the Verilog simulator at each occurrence. event fall_clk is fall('~/xor_top/clk')@sim; //Define a time consuming method to run input driver, //output receiver and data checker functions //This procedure is synchronized to falling edge of clk. verify_xor() @fall_clk is { 'xor_top.mon'(); //Call the Verilog task for each operation (op) in sys.ops { //For each data item //in list execute block //Write values to Verilog variable //This part does task of Input Driver '~/xor_top/a' = op.a; //Apply value of a to Verilog variable '~/xor_top/b' = op.b; //Apply value of b to Verilog variable wait [1]; // wait one cycle, i.e till next falling edge //Read values from Verilog variable //This part does task of Output Receiver op.result_from_dut = '~/xor_top/out1'; print op; // Print the current data object //Check output against expected values //This part does task of Data Checker check that op.result_from_dut == (op.a ^ op.b); //Emit an event for the coverage group to sample data emit op.done; }; //End of for each loop //Stop the run, finish simulation stop_run(); }; //End of method verify_xor //Invoke the verify_xor method at simulation time 0 run() is also { start verify_xor(); }; }; //End of struct verify //--------------------------------------------------- //Extend sys to instantiate the verify struct defined above extend sys { verify1: verify; //Instance named verify1 }; //--------------------------------------------------- //Define coverage analyzer group //Coverage group is defined inside the struct operation //instead of defining it as a separate struct or unit extend operation { event done; //Whenever this event is emitted, take //a snapshot of the items below cover done is { item a; //Snapshot of value of a item b; //Snapshot of value of b cross a, b; //Cross coverage of a and b values }; }; //Setup needed to enable coverage extend sys { //Extend sys //to set up tool configuration. setup_test() is also { set_config(cover, mode, count_only); //Enable count_only coverage }; //--------------------------------------------------- '> End of e code to verify XOR DUT
The specman.v file contains the interface between the Simulator and Specman Elite.[6] This file is compiled into the Verilog simulator and run with the other DUT files. This file is created automatically by Specman Elite. All e code is loaded into Specman Elite and then a command is invoked to create this file. Figure 2-10 shows the interaction between Specman Elite and the HDL Simulator.
[6] The file specman.vhd is created in a VHDL environment.
The specman.v file should never be modified manually. It should always be created with a Specman Elite command. Specman.v file contains a Verilog module called specman. Example 2-5 shows the code generated for the specman.v file generated for the XOR DUT verification example. There is no need to understand the code inside the specman.v file.
/* specman.v - A Specman Elite stubs file (top module is xor) */ /* Generated automatically on Thu Oct 31 12:15:25 2002*/ module specman; parameter sn_version_id = 944493104; /* Version */ parameter sn_version_date = 100998; /* Version date*/ event sn_never_happens; always @sn_never_happens begin $sn(); end reg sn_register_memory; event sn_register_memory_event; initial begin sn_register_memory=0; end always @(sn_register_memory_event) begin sn_register_memory=1; end initial begin ->sn_register_memory_event; end event require_specman_tick; event emit_specman_tick; always @(require_specman_tick) begin #0 ->emit_specman_tick ; end /* Verilog task xor_top.mon */ reg mon_0_trig; always @(posedge mon_0_trig) begin xor_top.mon; mon_0_trig = 0; ->require_specman_tick; end reg finish_test; always @(posedge finish_test) begin $finish; end endmodule /* specman */ module specman_trace; endmodule /* specman_trace */
The following steps summarize the flow of running the simulation to verify the XOR DUT example.
To run the simulation, both Specman Elite and the Simulator processes are invoked simultaneously. Specman Elite gains control and the Simulator stops at simulation time t=0. The control is then explicitly passed to the Simulator and the simulation is started.
The Simulator continues to run until it reaches a falling edge of the clock (set by event fall_clk which has its sampling event @sim). At this point, the Simulator halts further execution and transfers control to Specman Elite.
Specman Elite executes the first action in the verif_xor() method at the first falling edge of the clock. The verif_xor() method applies the a and b inputs to the DUT. Then, it encounters a wait keyword, so it transfers control back to Simulator.
The Simulator continues simulation until it reaches the next falling edge of the clock. Control is passed back to Specman Elite. The verif_xor() method gathers the output and checks the output against the expected value. An event done is emitted for the coverage analyzer to take a sample. Then it goes to the top of the for each loop and applies the a and b inputs of the next stimulus item to the DUT.
Simulation continues with control passing back and forth between Specman Elite and the Simulator until a and b inputs for all stimulus items in the ops list are applied to the DUT and the outputs are checked. When all stimulus items are applied, Specman Elite quits the for each loop and encounters a stop_run() invocation. This indicates completion of simulation.
The coverage results can be displayed. The coverage report tells which values of a and b inputs have not been covered. The next test can cover these values until all possible values of a and b inputs are covered.