How to cover latency between request and response

945 views Asked by At

Let's say we have a protocol where request req is asserted with req_id and corresponding rsp will be asserted with rsp_id. These can be out of order. I want to cover the number of clks or latency between req with particular req_id and rsp with the same id. I tried something like this. Is this correct way of doing? Is there any other efficient way?

covergroup cg with function sample(int a);
  coverpoint a {
  a1: bins short_latency = {[0:10]};
  a2: bins med_latency = {[11:100]};
  a3: bins long_latency = {[101:1000]};
  }
endgroup
// Somewhere in code
cg cg_inst = new();

sequence s;
  int lat;
  int id;
  @(posedge clk) disable iff (~rst)
    (req, id = req_id, lat = 0) |-> ##[1:$] ((1'b1, lat++) and (rsp && rsp_id == id, cg_inst.sample(lat)));
endsequence
3

There are 3 answers

0
Tudor Timi On BEST ANSWER

You're trying to use the |-> operator inside a sequence, which is only allowed inside a property.

If rsp can only come one cycle after req, then this code should work:

property trans;
    int lat, id;

    (req, id = req_id, lat = 0) |=> (1, lat++) [*0:$] ##1 rsp && rsp_id == id
      ##0 (1, $display("lat = %0d", lat));
endproperty

The element after ##0 is there for debugging. You can omit it in production code.

I wouldn't mix assertions and coverage like this, though, as I've seen that the implication operators can cause issues with variable flow (i.e. lat won't get updated properly). You should have a property that just covers that you've seen a matching response after a request:

property cov_trans;
    int lat, id;

    (req, id = req_id, lat = 0) ##1 (1, lat++) [*0:$] ##1 rsp && rsp_id == id
      ##0 (1, $display("cov_lat = %0d", lat));
endproperty

cover property (cov_trans);

Notice that I've used ##1 to separate the request from the response.

0
Rahul Menon On

Alternatively...

property/sequences though they appear to be small code , in this case for every req ( which has not yet received a rsp ) a seperate process with its own counter is forked. This results in many counters doing very similar work. In case there are many req in flight ( and/or many instances of the property or sequence ) it will start adding into simulation run-time [ even though this is just a small block of code ]

so another approach is to keep the trigger simpler and we try to keep the processing linear.

int counter=0; // you can use a larger variablesize to avoid the roll-over issue
int arr1[int] ;  // can use array[MAX_SIZE] if you know the max request id is small
always @( posedge clk ) counter <= counter + 1 ; // simple counter 


function int latency (int type_set_get , int a ) ;
    if ( type_set_get == 0 ) arr1[a] = counter; // set
                                 //DEBUG $display(" req id %d latency %d",a,counter-arr1[a]);
                                 // for roll-over - if ( arr1[a] > counter ) return ( MAX_VAL_SIZE  - arr1[a] + counter ) ; 
   return (counter - arr1[a]);  //return the difference between captured clock and current clock .
endfunction

property ps();
  @(posedge clk) 
     disable iff (~rst) 
         ##[0:$]( (req,latency(0,req_id) ) or  (rsp,cg_inst.sample(latency(1,rsp_id))) );
endproperty

assert property (ps);

The above property is triggered only when req/rsp is seen and only 1 thread is active looking for it. If needed extra checks can be added into the function , But for latency counting this should be fine.

Anecdote :

Mentor AE - Dan discovered an assertion which was slowing our simulations by as much as 40 % . The poorly written assertion was part of our block tb and its effects went unnoticed there , as our block level test, run times were limited. It then sneaked into our top-level tb causing untold runtime losses till it was discovered a year later :) . [ guess we should have profiled our simulation runs earlier ]

Say for example if the above protocol implemented an abort at a later time, then the req-rsp thread will continue to process and wait ( till the simulation ends) for an aborted transaction , though it will not affect the functionality , it will sneakily continue to hog processor resources doing nothing useful in return. Till finally an vendor AE steps in to save the day :)

1
Rahul Menon On

Basically your idea is right , But looks like the right hand side of the sequence will be evaluated once when the condition is true and hence the lat will be incremented only once .

You will need a loop mechanism to count the latency.

Below is an sample working example. You can change [1:$], ##1 etc based on how close the signals are generated

property ps;
  int lat;
  int id;
  @(posedge clk)
     disable iff (~rst)
        (req, id = req_id, lat = 0) |=> (1'b1, lat++)[*1:$] ##1 (rsp && rsp_id == id, cg_inst.sample(lat));
endproperty

assert property (ps);