What I’m trying to do is essentially verify that the input port of some module is driven by the correct clock domain. To check this, I want to write an assertion that looks sort of like this:
@(input_signal) |-> @(posedge clk)
In order to verify that any change in input_signal happens only on posedge of a given clock. To the best of my knowledge, it isn’t possible in SystemVerilog. Is there a way to implement this sort of functionality in an assertion (or via some other tool)?
I took 2 approaches,explore these solutions and get back to us.
It provides error counters or a pass counter for each edge of sig1.
/* What I'm trying to do is essentially verify that the input port of some module
is driven by the correct clock domain. To check this,
I want to write an assertion that looks sort of like this:
@(input_signal) |-> @(posedge clk)
In order to verify that any change in input_signal
happens only on posedge of a given clock. To the best of my knowledge,
it isn't possible in SystemVerilog. Is there a way to implement
this sort of functionality in an assertion (or via some other tool)?
*/
module top;
bit clk, sig1, dis, reset_n=1;
int err1, err2, ok2, debug2, tfire;
// always @(sig1) // approavh 1
// assert final($past(sig1,1,1, @(posedge clk)) != sig1) else
// err1=err1+1;
function void f; err1=err1+1; endfunction
always @(sig1) // approach 1, value based
#1 // needed for the $past
assert ($past(sig1,1,1, @(posedge clk)) != sig1) else f();
task automatic t_stable(); //
realtime t;
tfire=tfire+1;
t=$realtime; // new sig1 change after posedge clk
//#1; // debug2=debug2+1; // debug
@(posedge clk) debug2=debug2+1;
assert($realtime - t <= 21ns &&
$realtime -t >= 20ns) ok2=ok2+1;
else err2=err2+1;
endtask
always @(sig1) begin
fork t_stable(); join_none; // time based
end
initial forever #10 clk = !clk;
initial begin
$dumpfile("dump.vcd"); $dumpvars;
#5 sig1 = 1;
@(posedge clk) sig1<= !sig1;
#3 sig1 <= !sig1;
@(posedge clk) sig1<= !sig1;
@(posedge clk) sig1<= !sig1;
#8 sig1 <= !sig1;
repeat(4) @(posedge clk) sig1<= !sig1;
#20 $finish();
end
endmodule
The reason I initially wrote it with the task is because that’s how I saw it: at the leading clocking event (the @(sig1) I fire an automatic task that has a life of its own. This is explained in my paper "Understanding the SVA Engine Using the Fork-Join Model Verification Horizons - July 2020 | Verification Academy
Using a model, the paper addresses important concepts about attempts and threads. Emphasizes the total independence of attempts.
You should read this paper if you want to relly understand a good modeling of assertions.
The updated model with this new property is at (4) - EDA Playground
The simulation results are at
function void f; err1=err1+1; endfunction
always @(sig1) // approach 1, value based
#1 // Needed for the $past of the posedge of clk just prior
assert ($past(sig1,1,1, @(posedge clk)) != sig1) else f();
Thanks Ben, I appreciate the answer. I figured that at the very least I could use $realtime, but your solution was more elegant than what I hacked together.