I have to write a single SVA for the complete protocol shown in this image
I wrote the following SVA but it doesn't capture the immediate ack. How do I fix that
#(posedge clk)
$rose(val) |=>
( $stable(data) && !ack && val ) ##[1:64] ( ack && val ) ##1 ( !ack && !val )
Looking at your assertion, it won't capture the immediate ACK because you are expecting a sequence excluding an immediate ACK with !ack. I would re-write your assertion as:
sequence seq;
$stable({address, data}) ##[0:63] (val && ack && $stable({address, data})) ##1 !ack ##1 !val;
endsequence
property p;
#(posedge clk)
$rose(val) |=> seq;
endproperty
as_protocol : assert property(p);
Related
If there were no enable signal, inputReady ##N outputValid would do the job. But, how should I exclude the cycles when enable is deasserted? Is there a short solution?
If you want to include only the portion when enable is asserted, you can just use a repetition operation. For example, if N == 4:
inputReady ##0 enable [*4] ##1 enable && outputValid;
// or
inputReady ##0 enable [*5] ##0 outputValid;
// or
inputReady && enable ##1 enable [*3] ##1 enable && outputValid;
The repetition is equivalent to N-1 delays:
enable ##1 enable ##1 enable ##1 enable
If you're building an assertion to check if-this-then-that, you could use the simple form:
inputReady |-> enable [*5] ##0 outputValid;
These are all equivalent:
inputReady |-> enable [*4] ##1 enable && outputValid;
inputReady && enable |=> enable [*4] ##0 outputValid;
inputReady && enable |=> enable ##1 enable ##1 enable ##1 enable && outputValid;
Im writing assertions for a handshake protocol where there can be back to back requests and acks. Acks can come between 1 to 5 cycles after req. How can I use assertions to make sure there is 1 ack for every req while also taking glitching on req or ack into account ?
property p1:
#(posedge clk) req ##[1:5] ack ;
endproperty
property p2:
#(posedge clk) $rose(ack) |-> $past(req,5);
Im not sure if this keeps 1-to-1 mapping of req vs ack.
Can there be two requests before an ack? If not I would write :
property p_test;
#(posedge clk)
$rose(req) |=> !req[*0:$] ##0 ack;
endproperty
It works if req is pulse only
Property2 below is not in sync with property 1.
property p2: #(posedge clk) $rose(ack) |-> $past(req,5);
You are saying that ack must have had a request 5 clocks earlier. But property 1 says that req followed by ack is valid.
I think you need a id with a request that you can match when the ack happens.
sequence s_ack_check;
byte id;
(req && id == ack_id) ##[1:5](ack && ack_id == id);
endsequence
I take it you meant that there could be multiple reqs before any acks? If so, the solution needs either property variables or helper logic. Formal properties don't have memory or counters (without using variables).
Here's some code if you want to use helper logic:
Assume you allow at most 15 outstanding and it takes at most 25 clocks to get all acks:
logic [3:0] req_cnt, ack_cnt;
always # (posedge clk) if (rst) req_cnt <= 0; else req_cnt <= req_cnt + req;
always # (posedge clk) if (rst) ack_cnt <= 0; else ack_cnt <= ack_cnt + ack;
assert property (# (posedge clk) disable iff (rst) sync_accept_on(req) ##25 req_cnt == ack_cnt);
Count the requests and acks. Then assert that after 25 cycles of no req, the req_cnt == ack_cnt.
If there's never more than 1 req outstanding, the logic is much simpler. Please clarify if that is the case.
I am trying to achieve req ##[3:5]ack using fork..join. I am able to run logic for req##[5]ack. But I am unable to run for req ##[3:5]ack.
I am trying-
wait(req)
fork:check_ack
begin
wait(ack)
$display("Ack passed");
end
begin
repeat(5)
#(posedge clk);
$display("Ack failed");
end
begin
repeat(3)
#(posedge clk);
$display("Ack failed");
end
join_any
disable check_ack;
I need to somehow continue to check after 3 cycles also.
You need to create a state bit that indicates when you are inside the range.
bit in_range;
#(posedge clk iff req);
fork
begin
in_range = 0;
#(posedge clk iff ack) if (in_range) $display("passes");
else $display("fails");
end
begin
repeat(3) #(posedge clk) ;
in_range <='1;
wait(0);
end
begin
repeat(5) #(posedge clk);
$display("fails");
end
join_any
disable fork;
property clk_req_check;
#(posedge upbm_clk) disable iff (~upbm_reset_n)
//#(posedge upbm_clk);
case (sb_adrc)
2'b00 : 1'b1 |-> (clk_req[0] == 1'b1) [*] (sb_adrc != 2'b00);
2'b01 : 1'b1 |-> (clk_req[1] == 1'b1) [*] (sb_adrc != 2'b01);
2'b10 : 1'b1 |-> (clk_req[2] == 1'b1) [*] (sb_adrc != 2'b10);
2'b11 : 1'b1 |-> (clk_req[3] == 1'b1) [*] (sb_adrc != 2'b11);
default : 1'b0;
endcase
endproperty: clk_req_check
** Error: (vlog-13069) cad_property.sv(5): near "case": syntax error, unexpected case.
without disable_iff
** Error: (vlog-13069) cad_property.sv(3): near "case": syntax error, unexpected case, expecting disable.
case/endcase within an assertion may not supported in your version of Questa.
That's interesting, I've never tried writing a case statement inside a concurrent assertion, not sure if that is allowed. Thinking about it though, you want to simultaneously be checking all 4 values of sb_adrc with concurrent assertions (which run constantly on every upbm_clk), which feels to me that you need 4 separate concurrent assertions. Each one similar to the following:
property clk_req_check;
#(posedge upbm_clk) disable iff (~upbm_reset_n)
sb_adrc == 2'b00 |-> (clk_req[0] == 1'b1) ##1 (sb_adrc != 2'b00)
endproperty
How would I write SVA that checks that if sig goes high trigger was high 4 cycles before trigger [*4] |-> signal
is not good enough because it does not check that signal didn't go high for 3 cycles. Should I use $past how ??
This would check that on a rising edge of sig, trigger was high 4 clk cycles ago:
assert_name: assert property (
#(posedge clk) (
($rose(sig) -> $past(trigger,4))
)
);
There's nothing stopping you writing a small piece of synthesisable RTL which counts how many cycles trigger has been high.
always #(posedge clk) begin
if (trigger) begin
triggerCount := triggerCount + 1;
end else begin
triggerCount := 0;
end
end
assert_name: assert property (
#(posedge clk) (
($rose(sig) -> triggerCount == 4)
)
);