In the example below, I am trying to pulse the data
output on my_interface
. However, data
always remains 0.
interface my_interface(
input clock,
output data);
clocking cb @(posedge clock);
output data;
endclocking
endinterface // my_interface
module test;
logic clock;
wire data;
my_interface my_interface(.*);
initial begin
clock = 0;
#1 $display("%0d data:%0d", $time, data);
#10;
my_interface.cb.data <= 1;
#1 $display("%0d data:%0d", $time, data);
@(my_interface.cb);
my_interface.cb.data <= 0;
#1 $display("%0d data:%0d", $time, data);
#20 $display("%0d data:%0d", $time, data);
$finish();
end
always #5 clock = ~clock;
endmodule
The sim output is:
# 1 data:z
# 12 data:z
# 16 data:0
# 36 data:0
I'd like to understand why is data
never 1
in the example above?
I can fix the issue by replacing #10
with @(my_interface.cb);
, but I don't know why this fix works.
Code and results on EDA Playground: http://www.edaplayground.com/s/4/198
It's very dangerous to use any other blocking events other than @(my_interface.cb) when driving or sampling clocking block signals The reason your code is behaving that way is because of this statement in section 14.16 Synchronous drives:
It is possible for a drive statement to execute at a time that is not coincident with its clocking event. Such drive statements shall execute without blocking, but shall perform their drive action as if they had executed at the time of the next clocking event.
In your example, your two drive statements wind up driving in the same cycle, and last write wins.
So the rule is only to use @(my_interface.cb) to block a process that is driving or sampling clocking block signals. That includes not using wait(cb.signal) and instead using @(cb iff (cb.signal))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With