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
for basics of testbenches see: Writing Test Benches - Verilog — Alchitry
here is a primer for writing testbench from Cornell
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
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