如何写过渡的覆盖点?

new*_*bie 4 verilog system-verilog

我的 RTL 设计中有一个 N 位寄存器,我想检查测试平台是否涵盖以下特定情况:

000..0 -> 000..001 -> 000....011 -> 00...111 -> ...... -> 111....111
Run Code Online (Sandbox Code Playgroud)

我不知道如何covergroup为上面的内容写一个。我可以看到过渡覆盖是如何有用的。举个例子:

covergroup cg; 
cover_point_y : coverpoint y { 
bins tran_34 = (3=>4); 
bins tran_56 = (5=>6); 
} 
Run Code Online (Sandbox Code Playgroud)

然而,就我而言,我的寄存器是参数化的(N 位:)reg[(N-1):0],并且它太大而无法手动写入完整序列。我可以写一个generateorfor循环来覆盖上面的序列吗?

Tud*_*imi 6

我不太清楚你想要涵盖哪些过渡。我想您想涵盖每个值都更改为其他值。您需要记住的是,您可以在=>运算符的任一侧写入多个值。例如:

cover_point_y : coverpoint y { 
  bins transitions = ( 0, 1 => 0, 1 );
}
Run Code Online (Sandbox Code Playgroud)

这将为0 => 0, 0 => 1, 1 => 0,创建垃圾箱1 => 1。如果我正确解释 BNF,根据 LRM,您放在=>运算符两侧的值的类型为covergroup_value_range,这意味着应该接受覆盖点的任何值范围语法。这意味着以下内容也应该是合法的:

cover_point_y : coverpoint y { 
  bins transitions = ( [0 : 2^N - 1] => [0 : 2^N - 1] );
}
Run Code Online (Sandbox Code Playgroud)

这应该创建从每个值到每个其他值的转换箱。您在这里受到工具支持的支配。例如,这在我的模拟器中不起作用,但在其他模拟器中可能有效。

如果您想排除某些转换(例如,0 => 01 => 1等),这无论如何都不会帮助您,因为指定转换箱的语法表达能力不够......

别担心,有办法做到这一点。回到基础上,过渡覆盖基本上是当前值和过去值之间的交叉覆盖的一种形式。交叉覆盖允许以更多样化的方式指定垃圾箱。您需要跟踪您所覆盖的变量的先前值。您需要注意的是,只有在采样了至少 2 个值后才应该开始收集覆盖范围(以便您拥有前一个值)。通过过渡覆盖,该工具可以在幕后为您完成此操作。

我能想到的最好方法是将其包装covergroup在一个类中:

class cg_wrapper #(int unsigned WIDTH = 3);
  covergroup cg with function sample(bit [WIDTH-1 : 0] val,
    bit [WIDTH-1 : 0] prev
  );
    coverpoint val;
    coverpoint prev;

    cross prev, val;
  endgroup

  function new();
    cg = new();
  endfunction

  // ...
endclass
Run Code Online (Sandbox Code Playgroud)

该类将跟踪先前的值以及是否收集了先前的值(即我们尝试对第二个值进行采样):

class cg_wrapper #(int unsigned WIDTH = 3);
  protected bit has_prev;
  protected bit [WIDTH-1 : 0] prev;

  // ...
endclass
Run Code Online (Sandbox Code Playgroud)

为了确保在适当的点对覆盖率进行采样,该类将公开一个sample(...)函数(类似于覆盖组具有的功能),该函数处理对实际覆盖组的采样并存储先前的值:

class cg_wrapper #(int unsigned WIDTH = 3);
  // ...

  function void sample(bit [WIDTH-1 : 0] val);
    if (has_prev)
      cg.sample(val, prev);
    prev = val;
    has_prev = 1;
  endfunction
endclass
Run Code Online (Sandbox Code Playgroud)

这将确保您获得有意义的传球。例如,使用sample(...)0和调用两次1,将仅导致从0到的单个“转换” 1(即,交叉中的一个容器被填充)。

如果您想开始排除垃圾箱的“转换”,您可以使用很多不同的方法来做到这一点。例如,要排除相同的转换,您可以执行以下操作:

cross prev, val {
  ignore_bins ignore =
    (binsof (val) && binsof (prev)) with (prev == val);
}
Run Code Online (Sandbox Code Playgroud)

这会忽略0 => 01 => 12 => 2等类型的转换。

AMIQ Consulting 还发表了一篇不错的文章,展示了一些指定交叉垃圾箱的很酷的方法。