如何覆盖请求和响应之间的延迟

How to cover latency between request and response

假设我们有一个协议,其中请求 req 使用 req_id 断言,相应的 rsp 将使用 rsp_id 断言。这些可能是乱序的。我想涵盖具有特定 req_idreq 和具有相同 ID 的 rsp 之间的时钟数或延迟。我试过这样的事情。这是正确的做法吗?还有其他有效的方法吗?

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

基本上你的想法是正确的,但看起来当条件为真时序列的右侧将被评估一次,因此纬度只会增加一次。

您将需要一个循环机制来计算延迟。

下面是一个示例工作示例。您可以根据生成信号的接近程度更改 [1:$]、##1 等

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);

您正在尝试在序列中使用 |-> 运算符,这只允许在 属性 中使用。

如果rsp只能在req之后出现一个周期,那么这段代码应该可以工作:

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

##0 之后的元素用于调试。您可以在生产代码中省略它。

不过,我不会像这样混合断言和覆盖,因为我已经看到蕴涵运算符会导致变量流出现问题(即 lat 无法正确更新)。您应该有一个 属性,它仅涵盖您在请求后看到的匹配响应:

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);

请注意,我使用 ##1 将请求与响应分开。

或者...

property/sequences 虽然它们看起来是小代码,但在这种情况下,对于每个请求(尚未收到响应),都会分叉一个具有自己计数器的单独进程。这导致许多计数器执行非常相似的工作。如果有很多请求在运行中(and/or 许多 属性 或序列的实例)它将开始添加到模拟 运行-time [即使这只是一小段代码]

所以另一种方法是使触发器更简单,我们尽量使处理保持线性。

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);

上面的属性只有在看到req/rsp并且只有1个线程在寻找它时才会触发。 如果需要,可以在函数中添加额外的检查,但对于延迟计数来说,这应该没问题。

轶事:

Mentor AE - Dan 发现了一个断言,它使我们的模拟速度减慢了 40%。写得不好的断言是我们块 tb 的一部分,它的影响在那里没有被注意到,因为我们的块级测试,运行 次是有限的。然后它潜入我们的顶级 tb,造成无法估量的 运行 时间损失,直到一年后才被发现 :) 。 [猜想我们应该在 运行s 之前分析我们的模拟 ]

例如,如果上述协议在稍后实现了中止,则 req-rsp 线程将继续处理并等待(直到模拟结束)中止的事务,尽管这不会影响功能,它将偷偷摸摸地继续占用处理器资源,在 return 中无所作为。直到最后一个供应商 AE 介入来挽救这一天:)