Hi,
I’m witnessing an unexpected behavior in my testbench: asymmetric behavior of logic and wire while both defined as outputs in the port list of a black box module.
In the code below I built a toy example to demonstrate the issue.
The use case that the example tries to mimic is a full chip environment in which some of the rtl is replaced by black box module that should be driven by an agent in the verification environment.
I thought that the code below is trivial and I expected that both output (‘a’,‘b’), will be driven by my driver. But this is not the case, while ‘b’ is properly initialized, ‘a’ stays as ‘x’ for all the simulation:
- tb.dut_i.a is const ‘x’ during all the simulation
- tb.dut_i.b starts as ‘z’ and goes to ‘0’ at the first posedge of clk.
The only difference between ‘a’ and ‘b’ is that in the black box dut ‘a’ is defined as logic and ‘b’ is left as default (hence defined as wire?).
I assumed that an undriven logic output will be modeled as a net and with this assumption it will be symmetric to a wire.
My questions are:
- How come that tb.dut_i.a is not initialized by the driver when do_reset is called?
- What can I change in my agent or interface to initialized both signals types with the same code?
// interface with clocking block
interface test_if (
input logic clk,
input logic reset_n,
logic a,
logic b);
clocking master_cb @(posedge clk);
default input #5ps output #250ps;
output a;
output b;
endclocking
endinterface
// black box dut
module dut (input logic clk,
input logic reset_n,
output logic a, // a is logic
output b); // b is wire
endmodule
// driver for verification
class driver;
virtual test_if vif;
function new(virtual test_if a_vif);
vif = a_vif;
endfunction
task run();
forever @(vif.master_cb, negedge vif.reset_n) begin
if (!vif.reset_n) begin
do_reset();
end else begin
$display("not in reset");
end
end
endtask
task do_reset();
vif.master_cb.a <= '0; // fails in simulaiton
vif.master_cb.b <= '0; // succeeded in simulation
endtask
endclass
// program to mimics the test
program test(test_if tif);
driver test_driver;
initial begin
test_driver = new(tif);
fork
test_driver.run();
join_none
#1000;
end
endprogram
// top level TB
module tb();
logic clk;
logic reset_n;
dut i_dut(.clk(clk),.reset_n(reset_n));
test_if tif(.clk(i_dut.clk),
.reset_n(i_dut.reset_n),
.a(i_dut.a),
.b(i_dut.b));
test i_test(tif);
// clock
initial begin
forever begin
#5;
clk = ~clk;
end
end
// reset
initial begin
clk = '0;
reset_n = '0;
#300;
reset_n = '1;
end
endmodule