In reply to ben@SystemVerilog.us:
Ben, Thanks for you ideas. That example still requires that I determine what the actual delay is, and then modify my checker. Your generate loop approach, however, did give me a couple of other ideas.
Here’s a solution that I really like for it’s conciseness and readability. I collect coverage on all of the delays, use a coverage action to get that information into a variable where I can test it, and then assert that the coverage is one hot.
Some simulators require that you enable coverage options to make the cover property’s pass statement work, so that’s a real negative here. I also doubt if formal tools can consume this code. My debug tools also do a poor job of tracing drivers for the cycle_delay[n] bits.
module same_cycle_delta2( input logic clk, enable,
input logic a, b );
default clocking cb@( posedge clk); endclocking
A_no_overlaps: assume property( disable iff (!enable) a |-> b or !b ##1 ( !a throughout b[->1] ) );
logic [10:0] cycle_delay;
C_disable: cover property( !enable ) cycle_delay <= 0; // clear when disabled, like an RTL reset
for( genvar N=0; N<=10; N++ ) begin: delay
C_delay: cover property( disable iff (!enable) a ##0 !b[*N] ##1 b ) cycle_delay[N] <= 1'b1;
end
A_same_delta: assert property( disable iff (!enable) $onehot0( cycle_delay ) );
endmodule // same_cycle_delta2
Which finally lead me to this next solution. It doesn’t require any coverage options for it to work and my debuggers have no issues tracing driers through this code. Not sure about formal and $past in this context, but that’d be easy to replace with a shift register.
module same_cycle_delta3( input logic clk, enable,
input logic a, b );
default clocking cb@( posedge clk); endclocking
A_no_overlaps: assume property( disable iff (!enable) a |-> b or !b ##1 ( !a throughout b[->1] ) );
logic [4:0] cycle_delay, n_cycle_delay;
always @(posedge clk or negedge enable) begin
if (!enable)
cycle_delay <= 0;
else
cycle_delay <= n_cycle_delay;
end
// How can this be generated concisely in a generate loop?
assign n_cycle_delay[0] = cycle_delay[0] || a && b;
assign n_cycle_delay[1] = cycle_delay[1] || $past(a,1) && !a && b ;
assign n_cycle_delay[2] = cycle_delay[2] || $past(a,2) && !$past(a,1) && !a && b ;
assign n_cycle_delay[3] = cycle_delay[3] || $past(a,3) && !$past(a,2) && !$past(a,1) && !a && b ;
assign n_cycle_delay[4] = cycle_delay[4] || $past(a,4) && !$past(a,3) && !$past(a,2) && !$past(a,1) && !a && b ;
A_same_delta: assert property( disable iff (!enable)
$onehot0( cycle_delay ) );
endmodule
I made a few attempts at creating a generate loop for the n_cycle_delay logic, however it kept getting messy and unreadable.
I was thinking I should also try an approach using an ‘expect’ statement, but I expect I’ll bump into limited tool support for that.
-Ryan