I am verifying an Async FIFO and want to verify that the data packets are pushed and popped in the correct order, with the right values.
I wrote a property, which is producing some spurious errors. Where am I going wrong? Thanks in advance. :
wrdata and rddata are actual data read from the bus. The pathnames to the signals, are passed to the property.
property p_check_data (clk_wr, clk_rd, push, pop, wrdata, rddata, full, rst_wr, rst_rd) ;
logic txdata; // Local variable to store data written on a push
disable iff (rst_wr | rst_rd)
@(posedge clk_wr)
(full !== 1)|->
@(posedge push) @(posedge clk_wr) (1,txdata = wrdata) ##1
@(posedge pop) @(posedge clk_rd)##2 (rddata == txdata);
endproperty
Multiple pushes before a pop
Your code tried to do a push followed by a pop. That does not address the multiple pushes and then a pop. The issue with your code is that if you have 2 or more pushes before a pop, all the pending attempts will execute immediately at the pop and the rdata will not be matched with the local variable data. Upon a push, you need to push the data into a verification queue to be used by SVA (instead of a local variable). Upon a pop, you pop that data.
To fix this, you need a tag to be attached to the assertion so that all pending assertions are not answered with a single pop.
Multiclocking
How many clocks do you have? Four? the rd, wr, push, pop clocks?
No you don’t!
So then, is it possible to verify the first-in-first-out functionality of the FIFO?
Using local variables to hold the data being pushed, and the address pointers to then check if the data out is the same during a pop isn’t possible as local variables cause performance issues/not allowed depending on local variable size. We can’t have queues to hold the values either to write assertions on. If I wanted to write auxiliary code then it will mostly be a copy of the RTL which defeats the purpose. Is there something I am missing?
Yes, you’ll need support logic for a ghost Fifo (golden copy).
Another approach (untested and incorrect as it is written) is to use support logic with local variables. Below is the concept, modified from a different model.
int data_in, data_out;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
push_count <= 0;
pop_count <= 0;
end
else begin // RTL updates push and pop counts, not the assertion
if ($rose(push)) push_count <= push_count + 1;
if (pop) pop_count <= pop_count + 1;
end
end
property pushpop_unique;
int v_serving_push_count;
int v_data;
@(posedge clk) ($rose(push), v_serving_push_count=push_count, v_data=data_in) |->
(##[1:5] pop ##1 pop_count==v_serving_push_count) ##0 v_data==data_out;
endproperty
ap_pushpop_unique: assert property(pushpop_unique);