您现在的位置是:首页 >技术教程 >Initial Block and Testbenches in Verilog网站首页技术教程

Initial Block and Testbenches in Verilog

EverNoob 2023-05-19 20:00:02
简介Initial Block and Testbenches in Verilog

Property of Initial Block

1. procedural: all statements by default, are executed sequentially within any given block

2. not synthesizable: used only for driving simulations

3. pre-sim: executed at time 0, before executing any other simulation code

4. no-repeat: each block is executed only once

5. parallel: all initial blocks are executed in parallel, hence there are no guaranteed order of execution for blocks

for more detail see here

Testbenches

for basics of testbenches see: Writing Test Benches - Verilog — Alchitry 

here is a primer for writing testbench from Cornell

Multiple Tests with Initial Block

 with the above stated property 5, it is clear that:

[GPT3.5] No, a Verilog testbench module cannot include multiple initial blocks. The `initial` block is used to specify the behavior of the simulation at the beginning of the simulation. When a testbench is executed, the simulation starts at time 0 and executes the statements inside the `initial` block. Therefore, having multiple `initial` blocks would cause ambiguity in the start time of the simulation.

a wrong template:

`include "mips_alu.vl"

module test_mips_alu;

  // Inputs
  reg [31:0] a;
  reg [31:0] b;
  reg [2:0] alu_op;

  // Outputs
  wire [31:0] out;
  wire zero_flag;

  // Instantiate the module to be tested
  mips_alu dut (
    .a(a),
    .b(b),
    .alu_op(alu_op),
    .out(out),
    .zero_flag(zero_flag)
  );

  // Test case 1: ADD operation
  initial begin
    a = 10;
    b = 20;
    alu_op = 3'b000; // ADD
    #10; // Wait for some time to let the output stabilize
    if (out !== 30 || zero_flag) begin
      $error("Test case 1 failed!");
      $display("The value of a is %h", a);
      $display("The value of b is %h", b);
      $display("The value of alu_op is %b", alu_op);
      $display("The value of out is %h", out);
      $display("The value of zero_flag is %b", zero_flag);
    end
  end

  // Test case 2: SUB operation
  initial begin
    a = 50;
    b = 20;
    alu_op = 3'b001; // SUB
    #10; // Wait for some time to let the output stabilize
    if (out != 30 || zero_flag != 0) begin
      $error("Test case 2 failed!");
      $display("The value of a is %h", a);
      $display("The value of b is %h", b);
      $display("The value of alu_op is %b", alu_op);
      $display("The value of out is %h", out);
      $display("The value of zero_flag is %b", zero_flag);
    end
  end

  // Test case 3: AND operation
  initial begin
    a = 32'hF0F0F0F0;
    b = 32'h0F0F0F0F;
    alu_op = 3'b010; // AND
    #10; // Wait for some time to let the output stabilize
    if (out !== 32'h00000000 || zero_flag !== 1) begin
      $error("Test case 3 failed!");
      $display("The value of a is %h", a);
      $display("The value of b is %h", b);
      $display("The value of alu_op is %b", alu_op);
      $display("The value of out is %h", out);
      $display("The value of zero_flag is %b", zero_flag);
    end
  end

  // Test case 4: OR operation
  initial begin
    a = 32'hF0F0F0F0;
    b = 32'h0F0F0F0F;
    alu_op = 3'b011; // OR
    #10; // Wait for some time to let the output stabilize
    if (out !== 32'hFFFFFFFF || zero_flag !== 0) begin
      $error("Test case 4 failed!");
      $display("The value of a is %h", a);
      $display("The value of b is %h", b);
      $display("The value of alu_op is %b", alu_op);
      $display("The value of out is %h", out);
      $display("The value of zero_flag is %b", zero_flag);
    end
  end

  // Test case 5: XOR operation
  initial begin
    a = 32'hF0F0F0F0;
    b = 32'hFFFF0000;
    alu_op = 3'b100; // XOR
    #10; // Wait for some time to let the output stabilize
    if (out !== 32'h0F0FF0F0 || zero_flag !== 0) begin
      $error("Test case 5 failed!");
      $display("The value of a is %h", a);
      $display("The value of b is %h", b);
      $display("The value of alu_op is %b", alu_op);
      $display("The value of out is %h", out);
      $display("The value of zero_flag is %b", zero_flag);
    end
  end

  // Test case 6: SLL operation
  initial begin
    a = 32'hF0F0F0F0;
    b = 4;
    alu_op = 3'b101; // SLL
    #10; // Wait for some time to let the output stabilize
    if (out !== 32'h0F0F0F00 || zero_flag !== 0) begin
      $error("Test case 6 failed!");
      $display("The value of a is %h", a);
      $display("The value of b is %h", b);
      $display("The value of alu_op is %b", alu_op);
      $display("The value of out is %h", out);
      $display("The value of zero_flag is %b", zero_flag);
    end
  end

  // Test case 7: SRL operation
  initial begin
    a = 32'hF0F0F0F0;
    b = 4;
    alu_op = 3'b110; // SRL
    #10; // Wait for some time to let the output stabilize
    if (out !== 32'h0F0F0F0F || zero_flag !== 0) begin
      $error("Test case 7 failed!");
      $display("The value of a is %h", a);
      $display("The value of b is %h", b);
      $display("The value of alu_op is %b", alu_op);
      $display("The value of out is %h", out);
      $display("The value of zero_flag is %b", zero_flag);
    end
  end
endmodule

the initialization is all entangled, and it seems the case 5 has the last word

to fix the racing condition, we can:

1. simply add safe intervals between each test case; or combine the whole group into 1 single initial block and add intervals between changes of input set

// Test case 1: ADD operation
  initial begin
    #0
    a = 10;
    b = 20;
    alu_op = 3'b000; // ADD
    #10; // Wait for some time to let the output stabilize
    if (out !== 30 || zero_flag) begin
      $error("Test case 1 failed!");
      $display("The value of a is %h", a);
      $display("The value of b is %h", b);
      $display("The value of alu_op is %b", alu_op);
      $display("The value of out is %h", out);
      $display("The value of zero_flag is %b", zero_flag);
    end
    else
      $display("Test case 1 passed!");
  end

  // Test case 2: SUB operation
  initial begin
    #100
    a = 50;
    b = 20;
    alu_op = 3'b001; // SUB
    #10; // Wait for some time to let the output stabilize
    if (out != 30 || zero_flag != 0) begin
      $error("Test case 2 failed!");
      $display("The value of a is %h", a);
      $display("The value of b is %h", b);
      $display("The value of alu_op is %b", alu_op);
      $display("The value of out is %h", out);
      $display("The value of zero_flag is %b", zero_flag);
    end
    else
      $display("Test case 2 passed!");
  end

  // Test case 3: AND operation
  initial begin
    #200
    a = 32'hF0F0F0F0;
    b = 32'h0F0F0F0F;
    alu_op = 3'b010; // AND
    #10; // Wait for some time to let the output stabilize
    if (out !== 32'h00000000 || zero_flag !== 1) begin
      $error("Test case 3 failed!");
      $display("The value of a is %h", a);
      $display("The value of b is %h", b);
      $display("The value of alu_op is %b", alu_op);
      $display("The value of out is %h", out);
      $display("The value of zero_flag is %b", zero_flag);
    end
    else
      $display("Test case 3 passed!");
  end

or

initial begin
    // Test case 1: ADD operation
    a = 10;
    b = 20;
    alu_op = 3'b000; // ADD
    #10; // Wait for some time to let the output stabilize
    if (out !== 30 || zero_flag) begin
      $error("Test case 1 failed!");
      $display("The value of a is %h", a);
      $display("The value of b is %h", b);
      $display("The value of alu_op is %b", alu_op);
      $display("The value of out is %h", out);
      $display("The value of zero_flag is %b", zero_flag);
    end
    else
      $display("Test case 1 passed!");

    // Test case 2: SUB operation
    #50
    a = 50;
    b = 20;
    alu_op = 3'b001; // SUB
    #10; // Wait for some time to let the output stabilize
    if (out != 30 || zero_flag != 0) begin
      $error("Test case 2 failed!");
      $display("The value of a is %h", a);
      $display("The value of b is %h", b);
      $display("The value of alu_op is %b", alu_op);
      $display("The value of out is %h", out);
      $display("The value of zero_flag is %b", zero_flag);
    end
    else
      $display("Test case 2 passed!");

    // Test case 3: AND operation
    #50
    a = 32'hF0F0F0F0;
    b = 32'h0F0F0F0F;
    alu_op = 3'b010; // AND
    #10; // Wait for some time to let the output stabilize
    if (out !== 32'h00000000 || zero_flag !== 1) begin
      $error("Test case 3 failed!");
      $display("The value of a is %h", a);
      $display("The value of b is %h", b);
      $display("The value of alu_op is %b", alu_op);
      $display("The value of out is %h", out);
      $display("The value of zero_flag is %b", zero_flag);
    end
    else
      $display("Test case 3 passed!");
  end

2. define each test case as a tasks/functions and call them in the initial blocks sequentially

module example_module;

  // Define a task that takes two inputs and one output
  task add_numbers(input a, b, output sum);
    begin
      sum = a + b;
    end
  endtask

  initial begin
    // Call the task within the initial block
    integer result;
    add_numbers(2, 3, result);
    $display("The sum of 2 and 3 is %d", result);
  end

endmodule

to handle it more elegantly, see modelsim - How to run multiple testcases in verilog? - Stack Overflow

for more on tasks see Verilog Task

3. we can include all test input sets in a loop within the initial block to enforce sequential execution

module testbench;

reg [7:0] test_values [3:0] = '{8'hAA, 8'h55, 8'hF0, 8'h0F};
// Define an array of 4 test values

initial begin
  for (int i = 0; i < 4; i++) begin
    $display("Running test %0d with value %h", i, test_values[i]);
    // Display the current test number and test value
    // You can replace $display with your own test code

    // Insert your DUT instantiation and test code here
  end
end

endmodule

Sequential Simulation with iVerilog and GTKWave

Simulating Verilog HDL using iVerilog and GTKwave - Circuit Fever

key instructions:

1. compile "iverilog -o dst src"  ==> same as gcc

2. simulate "vvp executable"

3. use "$dumpfile", "$dumpvars" to create .vcd file for visualization in GTKWave

==> about how to use $dumpvars

1. it must be included inside the initial block

2.

Verilog $dumpvars and $dumpfile and

module DFF (
  input clock, D,
  output reg Q,
  output Qbar
);

  assign Qbar = ~Q;
  
  always @(posedge clock) begin
    Q <= D;
  end
  
endmodule

module DFF_Testbench;

  // Declare inputs and outputs
  reg clock;
  reg D;
  wire Q;
  wire Qbar;
  
  // Instantiate DFF module
  DFF DUT (
    .clock(clock),
    .D(D),
    .Q(Q),
    .Qbar(Qbar)
  );

  // Clock generator
  always #5 clock = ~clock;
  
  // Stimulus
  initial begin
  	// direct sim. file
	$dumpfile("d_latch.vcd");
	$dumpvars(0, DFF_Testbench);

    D = 0;
    clock = 0;
    #10 D = 1;
    #10 D = 0;
    #10 D = 1;
    #10 D = 0;
    #10 $finish;
  end
  
  // Display results
  always @(posedge clock) begin
    $display("D=%b Q=%b Qbar=%b", D, Q, Qbar);
  end
  
endmodule
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。