covergroup: その他の機能とtips

本記事はSystem Verilogのcovergroupの説明シリーズです。全体でかなりボリュームがあるため、以下に分割しています。上から順番に読んでいただくことをお勧めします。

1. [covergroupの記述方法](https://qiita.com/triggerfish/items/6053d93d99e084e8976f)
* [covergroup: coverpoint binsの記述方法](https://qiita.com/triggerfish/items/5766e890f1d108693a3f)
* [covergroup: cross binsの記述方法](https://qiita.com/triggerfish/items/d2feca30d05e51d3f93b)
* [covergroup: その他の機能とtips](https://qiita.com/triggerfish/items/39ee2ded512fa3df2974)

本記事ではSystem Verilogのcovergroupについて、他の一連の記事で触れることのできなかった項目について説明します。

# 配列に対するカバレッジ
ここでは配列に対するカバレッジの取り方を説明します。

以下の3 bitのlogicの配列であるdatのカバレッジを考えます。配列であるdatのそれぞれの要素のカバレッジを見ます。配列なのでcoverpointの対象として直接指定することはできません。

```verilog
  localparam DAT_WIDTH = 3;
  rand logic [DAT_WIDTH - 1:0] dat [$];
```

対応するには、まずsample functionをオーバーライドして、datの一つの要素についてのcoverpointを作成します。sample functionはcovergroupが初めから持っているfunctionです。オーバーライドすることでサンプル時の動作を変更することができます。

```verilog
  covergroup cg with function sample(logic [DAT_WIDTH - 1:0] v);
    option.per_instance = 1;
    cp: coverpoint v; // Automatic bins auto[0] ... auto[7]
  endgroup
```

そして、sampleメソッドを呼ぶときは、配列の要素方向にループさせます。

```verilog
    foreach (dat[i]) begin
      cg.sample(dat[i]);
    end
```

これで配列の要素に対してのカバレッジを取ることができます。全体のプログラム例は以下の通りです。

```verilog
class MyTest;
  localparam DAT_WIDTH = 3;

  rand logic [DAT_WIDTH - 1:0] dat [$];

  covergroup cg with function sample(logic [DAT_WIDTH - 1:0] v);
    option.per_instance = 1;
    cp: coverpoint v; // Automatic bins auto[0] ... auto[7]
  endgroup

  function new();
    cg = new;
  endfunction

  function void run();
    randomize() with {dat.size() inside {[10:20]};};

    foreach (dat[i]) begin
      $display("i = %d, dat = 0x%h", i, dat[i]);
      cg.sample(dat[i]);
    end
  endfunction
endclass

program top;
  initial begin
    MyTest myTest;

    myTest = new;
    myTest.run();
  end
endprogram
```

EDA Playgroundにソースコードがありますので、WEB browserから各自実行して結果を確かめることができます。実行後にダウンロードされるファイルの中のcov.txtがカバレッジリポートになります。
[covergroup to array] (https://www.edaplayground.com/x/4xeW)


# functionの戻り値へのcoverpoint
functionの戻り値はlogicのベクタだけど、coverageはenumとして取りたい場合があります。特に困るのがenumの要素数とlogicベクタの要素数が一致していない場合です。以下の例だとenumでは3通りの値しかとらないのに、logic [1:0]では4通りの値になります。coverpointをlogicとして扱うと、使用しない値はignore_binでいちいち指定しないと絶対にカバーされないbinが生成されてしまいます(本例では3が絶対にカバーされない値)。

```verilog
typedef enum logic [1:0] {ZERO, ONE, TWO} reg_t;

class RegClass;
  reg_t v;

  function logic [1:0] get;
    return v;
  endfunction
endclass
```

対応は簡単で、coverpointで指定する時に対象の型にキャスティングするだけです。

```verilog
  covergroup cg;
    cp: coverpoint reg_t'(regClass.get());
  endgroup
```

UVMのRAL(Register Abstraction Layer)はget()での戻り値はデフォルトでは64ビットになっています。例えenable/disableのような1ビットのフィールドに対しても64ビット幅でデータが返ってきてしまいます。このようなモードビットのために、汎用のtypedefを定義しておくとcoverpointの定義が少し楽になります。

```verilog
 typedef enum logic {FALSE, TRUE} boolean_t;

 covergroup cg;
    cp1: coverpoint uvm_reg_field_class.get(); // This coverpoint will generate bins for 64 bit space
    cp2: coverpoint boolean_t'(uvm_reg_field_class.get()); // Bin will be just FALSE and TRUE
 endgroup
```


以下がサンプルプログラム全体です。

```verilog
typedef enum logic [1:0] {ZERO, ONE, TWO} reg_t;

class RegClass;
  rand reg_t v;

  function logic [1:0] get;
    return v;
  endfunction
endclass


class MyTest;
  RegClass regClass;

  covergroup cg;
    option.per_instance = 1;
    cp1: coverpoint regClass.get();
    cp2: coverpoint reg_t'(regClass.get());
  endgroup

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

  function void run();
    regClass.randomize();
    cg.sample();
  endfunction
endclass

program top;
  initial begin
    MyTest myTest;

    myTest = new;
    myTest.run();
  end
endprogram
```

以下がカバレッジレポートです。logic [1:0]をそのままcoverpointにしたcpではbinが4通りできていますが、reg_tにキャスティングした結果をcoverpointにしたcp2では、bin数は3になっています。

```plaintext
    COVERGROUP COVERAGE
    ===============================================================
    |         Covergroup         |  Hits   |  Goal /  |  Status   |
    |                            |         | At Least |           |
    ===============================================================
    | TYPE /MyTest/cg            | 29.166% | 100.000% | Uncovered |
    ===============================================================
    | INSTANCE <UNNAMED1>        | 29.166% | 100.000% | Uncovered |
    |----------------------------|---------|----------|-----------|
    | COVERPOINT <UNNAMED1>::cp1 | 25.000% | 100.000% | Uncovered |
    |----------------------------|---------|----------|-----------|
    | bin auto[0]                |       1 |        1 | Covered   |
    | bin auto[1]                |       0 |        1 | Zero      |
    | bin auto[2]                |       0 |        1 | Zero      |
    | bin auto[3]                |       0 |        1 | Zero      |
    |----------------------------|---------|----------|-----------|
    | COVERPOINT <UNNAMED1>::cp2 | 33.333% | 100.000% | Uncovered |
    |----------------------------|---------|----------|-----------|
    | bin auto[ZERO]             |       1 |        1 | Covered   |
    | bin auto[ONE]              |       0 |        1 | Zero      |
    | bin auto[TWO]              |       0 |        1 | Zero      |
    ===============================================================
```

EDA Playgroundにソースコードがありますので、WEB browserから各自実行して結果を確かめることができます。実行後にダウンロードされるファイルの中のcov.txtがカバレッジリポートになります。
[covergroup type cast] (https://www.edaplayground.com/x/5YWL)

# 参考文献
 "19 Functional coverage". [1800-2017 - IEEE Standard for SystemVerilog--Unified Hardware Design, Specification, and Verification Language](https://doi.org/10.1109/IEEESTD.2018.8299595). pp.553-590.