Easy Tutorial
❮ Programming Language As A Pepole Verilog Statements Block ❯

6.6 Verilog Simulation Stimuli

Category Verilog Tutorial

Keywords: testbench, simulation, file I/O

After the Verilog code design is completed, an important step is to perform logical function simulation. The simulation stimulus file is called a testbench, which is placed at the top level of each design module to systematically instantiate and simulate the module.

It is not an exaggeration to say that for slightly complex Verilog designs, if simulation is not performed, even experienced veterans will not work properly in more than 99.9999% of designs. It cannot be said that simulation is more important than design, but generally, the time spent on simulation will be more than the time spent on design. Sometimes, considering various application scenarios, the writing of the testbench may also be more complex than the Verilog design. Therefore, the digital circuit industry will specifically divide design engineers and verification engineers.

Next, let's have a simple study of the testbench.

Testbench Structure Division

In fact, the most basic structure of the testbench includes signal declaration, stimulation, and module instantiation.

According to the complexity of the design, it is necessary to introduce clock and reset parts. Of course, for more complex designs, the stimulation part will also be more complex. According to your own verification needs, choose whether to need self-checking and stop simulation parts.

Of course, the reset and clock generation parts can also be seen as stimulation, so they can all be implemented in a statement block. You can also take the results of self-checking as the condition for ending the simulation.

In actual simulation, you can write the testbench according to your personal habits, and here is just a personal summary.

Testbench Simulation Example

In the previous chapters, many testbenches have been written. In fact, their structures are also roughly the same.

Next, let's take a simple example of data splicing and analyze the testbench in detail.

A 2-bit data splicing into an 8-bit data function module is described as follows:

Example

module data_consolidation
  (
    input clk,
    input rstn,
    input [1:0] din, //data in
    input din_en,
    output [7:0] dout,
    output dout_en //data out
  );

  // data shift and counter
  reg [7:0] data_r;
  reg [1:0] state_cnt;
  always @(posedge clk or negedge rstn) begin
    if (!rstn) begin
      state_cnt <= 'b0;
      data_r <= 'b0;
    end
    else if (din_en) begin
      state_cnt <= state_cnt + 1'b1; //data count
      data_r <= {data_r[5:0], din}; //data splicing
    end
    else begin
      state_cnt <= 'b0;
    end
  end
  assign dout = data_r;

  // data output en
  reg dout_en_r;
  always @(posedge clk or negedge rstn) begin
    if (!rstn) begin
      dout_en_r <= 'b0;
    end
    //When the count is 3 and the fourth data is input, the data output enable signal is output synchronously
    else if (state_cnt == 2'd3 & din_en) begin
      dout_en_r <= 1'b1;
    end
    else begin
      dout_en_r <= 1'b0;
    end
  end
  //Here, dout_en is not declared as a reg variable directly, but is assigned by the related register
  assign dout_en = dout_en_r;

endmodule

The corresponding testbench is described as follows, with added file I/O statements:

Example

`timescale 1ns/1ps

//============== (1) ==================
//signals declaration
module test;
  reg clk;
  reg rstn;
  reg [1:0] din;
  reg din_en;
  wire [7:0] dout;
  wire dout_en;

  //============== (2) ==================
  //clock generating
  real CYCLE_200MHz = 5; //
  always begin
    clk = 0; #(CYCLE_200MHz/2);
    clk = 1; #(CYCLE_200MHz/2);
  end

  //============== (3) ==================
  //reset generating
  initial begin
    rstn = 1'b0;
    #8 rstn = 1'b1;
  end

  //============== (4) ==================
  //motivation
  int fd_rd;
  reg [7:0] data
else begin
   $display("-------------------------------------");
   $display("Error occurs in data process!!!");
   $display("-------------------------------------");
end
#1 ;
$finish;
end
end

endmodule // test

The simulation results are as follows. As can be seen from the figure, the design of the data integration function meets the requirements:

[](https://www.tutorialpro.org/wp-content/uploads/2020/09/Yp7UIofA10Bynfgh.png)

### Testbench Analysis

**1) Signal Declaration**

When declaring a testbench module, it is generally not necessary to declare ports. This is because the stimulus signals are usually all within the testbench module, with no external signals.

The declared variables should correspond to all the ports of the module being tested. Of course, the names of the variables do not have to be the same as the names of the ports of the module being tested. However, the variables corresponding to the input end of the module being tested should be declared as reg type, such as clk, rstn, etc., and the variables corresponding to the output end should be declared as wire type, such as dout, dout_en.

**2) Clock Generation**

There are many ways to generate a clock, and the following two methods can also be used for reference.

## Example

initial clk = 0; always #(CYCLE_200MHz/2) clk = ~clk;

initial begin clk = 0; forever begin #(CYCLE_200MHz/2) clk = ~clk; end end


It should be noted that when using the inversion method to generate a clock, the initial value must be assigned to the clk register.

When using parameters to specify the time delay, if the delay parameter is a floating point number, the parameter should not be declared as a parameter type. For example, the value of the variable CYCLE_200MHz in the example is 2.5. If its variable type is parameter, the final clock period is likely to be 4ns. Of course, the precision of the timescale also needs to be increased, and the unit and precision cannot be the same, otherwise, the fractional part of the time delay assignment will also not work.

**3) Reset Generation**

The reset logic is relatively simple, generally the initial value is set to 0, and after a short delay, reset to 1.

Most of the simulations here use low-effective reset.

**4) Stimulation Part**

What kind of input signals should be generated in the stimulation part is designed according to the needs of the module being tested.

In this example:

- (4.1) Initialize the input signals of the module being tested to prevent the appearance of undetermined values X. The generation of stimulation data requires reading from the data file.

- (4.2) Use a task to open a file, as long as the file exists, you can get a non-zero handle signal fp_rd. fp_rd specifies the starting address of the file data.

- (4.3) The operation is to wait for the reset, so that the system has a safe and stable testable state.

- (4.4) Start the loop to read data and give stimulation. Sending data on the falling edge of the clock is to better sample data on the rising edge of the module being tested.

Use the system task $fread, through the handle signal fd_rd, to put the read 16-bit data variable into the read_temp buffer.

The first few data of the input data file are shown in the following screenshot. Since $fread can only read binary files, the first line of the input file corresponds to the ASCII code 330a, so we want to get the data 3 in the file, we should take the data from the 9th to the 8th bit of the variable read_temp.

The signal data_in_temp is a close integration of the input data signal, and the subsequent verification module will take this as a reference to determine whether the simulation is normal and whether the module design is correct.

- (4.5) Choose to stop inputting data 2 cycles after the clock rising edge, so that the module being tested can normally sample the last data enable signal and integrate the data normally.

When the amount of data is relatively small, you can use the system task $readmemh in Verilog to read hexadecimal data directly by line. Keep the data and format in the file data_in.dat unchanged, then this stimulation part can be described as:

## Example

reg [1:0]    data_mem [39:0]; reg [7:0]    data_in_temp; //for self check integer      k1; initial begin din_en    = 1'b0; din       = 'b0; $readmemh("../tb/data_in.dat" -8.1 Verilog Numerical Conversion

-Advanced Verilog Tutorial

WeChat Follow

❮ Programming Language As A Pepole Verilog Statements Block ❯