SystemVerilog covergroup の基礎

---

## はじめに

LSI や SoC の検証において、**機能カバレッジ (functional coverage)** は、テストが設計仕様をどれだけ網羅しているかを定量的に評価するための重要な指標です。検証の抜け漏れを防ぎ、設計が意図通りにテストされたことを客観的に示すために不可欠な要素となります。
SystemVerilog の `covergroup` を用いることで、テストシナリオに対する値の分布や組み合わせ（これらを「カバレッジ項目」と呼びます）を定義・集計し、未検証のパターン（「カバレッジホール」）を明示できます。

通常、どのような機能カバレッジ項目を測定するかは、設計仕様に基づいて作成される**検証計画書 (Verification Plan)** で定義されます。`covergroup` は、この検証計画書で定義された項目を検証環境に実装するための具体的な手段となります。

本記事では、主に検証の初心者に向けて、`covergroup` の基本構文から、クロスカバレッジやマルチクロックドメイン対応、UVM 統合、最適化テクニック、そしてカバレッジ結果の分析といった実践的な内容までを踏まえて解説します。

---

## カバレッジの種類

まず前提として、カバレッジには大きく分けて以下の様に、コードカバレッジ (code coverage)と、機能カバレッジ (functional coverage)の２種類があります。
この内、SystemVerilog の `covergroup` は 機能カバレッジ (functional coverage) を定義・収集するための仕組みであり、テストベンチ側で観測したい入力パターンや状態の組み合わせを網羅的に評価できます。

1.  **コードカバレッジ (code coverage)**
    *   **目的**：RTL コードそのものの網羅度を測る
    *   **主な指標**：
        *   命令網羅 (statement coverage)
        *   分岐網羅 (branch coverage)
        *   条件網羅 (condition coverage)
        *   トグルカバレッジ (toggle coverage)
        *   FSM カバレッジ (Finite State Machine coverage)
    *   **ツール**：シミュレータオプション（例：`-cover`／`-cov`）で自動取得

2.  **機能カバレッジ (functional coverage)**
    *   **目的**：**設計仕様**上必要な入力、状態遷移、動作シーケンスがテストでどれだけ網羅されているかを測る
    *   **定義方法**：SystemVerilog の `covergroup` を使い、`coverpoint`／`cross` で観測対象を明示的に指定
    *   **特徴**：
        *   検証者が意図した観点（仕様ベース）でカバレッジ項目を定義可能
        *   カバレッジグループごとにビン（`bins`）を自由に設計可能
        *   複数信号の組み合わせ（`cross`）や条件付きサンプリング（`iff`）にも対応
    *   **活用例 (この記事の最後にも参考の活用例を記載しています)**：
        *   プロトコルの各トランザクション種別（Read/Write/Idleなど）の発生回数やパラメータの組み合わせ
        *   特定モードにおける設定レジスタ値の組み合わせ
        *   FIFO の Full/Empty/AlmostFull/AlmostEmpty 状態遷移
        *   割り込み要因と優先度レベルの組み合わせ
        *   マルチクロックドメイン間転送レイテンシの分布
        *   AXI バースト転送長（ビート数）の分布
        *   クロックドメイン間ハンドシェイクの成功／失敗割合
        *   リセットシーケンス中のステートマシン遷移パターン
        *   メモリアクセスパターン（連続読み出し／ランダム読み出し）の比率
        *   キャッシュヒット／ミスの組み合わせ
        *   エラー検出動作（パリティエラー検出回数、タイムアウト発生回数）
        *   データストリームのフロー制御バースト数とサイズの組み合わせ
        *   QoS スケジューラにおける優先度ごとのスループット分布
        *   電源管理ドメインの ON/OFF 切り替え頻度と期間の分布
        *   システム起動シーケンス各フェーズの到達有無
        *   複数マスター環境でのバス競合発生タイミング分布
        *   エンドツーエンド遅延 ($t_{\mathrm{end2end}}$) の最小／最大／中央値

本記事では、機能カバレッジ (functional coverage) 収集のための `covergroup` の構文や活用テクニックを解説します。

---

## covergroup の基本構文

```systemverilog
covergroup CG_name [ ( [ cvg_port_list ] ) ] @( sampling_event ) [iff ( condition )];
  // coverpoint / cross / option / method 定義
endgroup : CG_name // オプション: 終了を明示
```

*   `CG_name`：任意のカバレッジグループ名
*   `( [ cvg_port_list ] )`：(オプション) `covergroup` に引数を渡すためのポートリスト。動的なインスタンス生成時に使用。
*   `@( sampling_event )`：サンプリングを行うトリガとなるイベント（例：`@(posedge clk)`, `@(some_event)`）。省略すると手動で `.sample()` 呼び出しが必要。
*   `iff ( condition )`：(オプション) `sampling_event` が発生しても、`condition` が真の時のみサンプリングを実行する。
*   グループ内に `coverpoint` や `cross` を定義し、観測対象の信号や組み合わせを指定する。
*   `option` でグループ全体の設定（ゴール、重みなど）を、`method` でカスタム動作（サンプリング時の処理など）を定義可能。

---

## coverpoint の使い方

`coverpoint` は、単一の変数や式の値を監視し、定義されたビンに分類してカウントします。

### 基本形

```systemverilog
coverpoint signal_or_expression [ iff (condition) ] {
  bins bin_name1 = { value_set1 };
  bins bin_name2 = value_set2; // {} は省略可
  bins bin_name_array[] = { value_range }; // 配列ビン
  // ... 他のビン定義
  // オプション (ignore_bins, illegal_bins, etc.)
}
```

*   `signal_or_expression`：観測対象のシグナル、変数、または式。
*   `iff (condition)`：(オプション) この `coverpoint` 固有のサンプリング条件。`covergroup` 全体の `iff` に加えて評価される。
*   `bins`：値を分類するための「箱」。名前と値の集合（単一値、リスト `{val1, val2}`、範囲 `{[low:high]}`、遷移 `{val1 => val2}` など）を定義。
*   `bin_name[]`：同じ定義で複数のビンを生成する配列ビン。`{[0:3]}` なら `bin_name[0]`, `bin_name[1]`, `bin_name[2]`, `bin_name[3]` ができる。
*   自動ビン生成：`bins auto_bin = default;` のように `default` を使うと、他のビンでカバーされなかった値が自動的にビンに割り当てられる。

### `with`句による複雑なビン定義

`with` 句を使うと、カバーポイントの式（`item` で参照）に対する条件でビンを定義できます。

```systemverilog
coverpoint packet_size {
  bins small = { [1:64] };
  // 65以上で、かつ偶数のパケットサイズのみを large_even ビンに入れる
  bins large_even = { [65:$] } with (item % 2 == 0);
  bins large_odd  = { [65:$] } with (item % 2 != 0);
  // $ は最大値を示す
}
```

### 主なオプション

*   `ignore_bins name = { value_set };`：指定した値はカバレッジ計算から除外する（例：リセット中の値、未定義の値）。
*   `illegal_bins name = { value_set };`：指定した値が発生したらエラーまたは警告を出す（設計上ありえない値）。シミュレーション停止も可能。
*   `bins default = default;` または `bins others = default;`: 明示的に定義されなかった値がヒットした場合にカウントされるビン。`illegal_bins` と併用する場合は `others` が推奨されることも。
*   `option.weight = N;`：この `coverpoint` または特定のビンの重要度を設定（デフォルトは1）。カバレッジ計算時に考慮される。
*   `option.goal = M;`：この `coverpoint` またはグループ全体のカバレッジ目標値 (%) を設定（デフォルトは100）。レポートツールで目標達成度が確認できる。
*   `option.auto_bin_max = N;`: 自動生成されるビンの最大数を制限。意図しない多数のビン生成を防ぐ。
*   `at_least = N;`: 各ビンが少なくともN回ヒットしないとカバーされたとみなさない設定。

```systemverilog
coverpoint data iff (valid) { // validが1の時だけサンプリング
  bins valid_values = { [1:10] };
  // 0 は無視する値
  ignore_bins zero_val = { 0 };
  // 11以上の値は仕様違反
  illegal_bins out_of_range = { [11:$], default }; // defaultで未定義値も捕捉
  option.goal = 90; // このポイントの目標は90%
  option.weight = 2; // このポイントは他の2倍重要
  // valid_values 内の各ビンは最低 5 回ヒットさせる
  bins valid_values { at_least = 5; }
}
```

---

## cross coverage

複数の `coverpoint` (または変数) の値の組み合わせ（クロス積）を評価します。組み合わせ爆発を起こしやすいため、定義には注意が必要です。

### 全組み合わせ評価 (非推奨な場合が多い)

```systemverilog
covergroup CG @(posedge clk);
  cp1: coverpoint sig1 { bins b1 = {0,1}; }
  cp2: coverpoint sig2 { bins bA = {"A","B"}; }

  // cp1 と cp2 の全組み合わせ (0,"A"), (0,"B"), (1,"A"), (1,"B") を測定
  cross cp1, cp2;
endgroup
```
*   上記例では `2 * 2 = 4` 個のクロスビンが生成されます。`coverpoint` のビン数が増えると、クロスビンの数は指数関数的に増加します。

### 特定組み合わせのみの評価 (`bins`定義 + `binsof`/`with`)

意味のある組み合わせや、特に注目したい組み合わせだけを明示的に定義することが推奨されます。`binsof(coverpoint)` で特定のカバーポイントのビン集合を参照し、`.with(expression)` でそのカバーポイントの値 (`item` で参照可) が `expression` を満たすビンに絞り込むことができます。

```systemverilog
parameter CMD_READ = 2'b01, CMD_WRITE = 2'b10, CMD_IDLE = 2'b00;
parameter ADDR_LOW_MAX = 10'h0FF, ADDR_HIGH_MIN = 10'h100, ADDR_MAX = 10'h3FF;

covergroup CG @(posedge clk);
  cmd: coverpoint command { // command は logic [1:0] 型と仮定
    bins READ  = { CMD_READ };
    bins WRITE = { CMD_WRITE };
    bins IDLE  = { CMD_IDLE };
  }
  addr: coverpoint address { // address は logic [9:0] 型と仮定
    bins low  = { [0 : ADDR_LOW_MAX] };
    bins high = { [ADDR_HIGH_MIN : ADDR_MAX] };
  }
  len: coverpoint length { // length は logic [3:0] 型と仮定
    bins short = { [1:4] };
    bins long  = { [5:$] }; // $ は length の最大値を示す
  }

  // READコマンドでアドレスがHIGH、かつ長さがLONGの場合のみを測定
  cross cmd, addr, len {
    // binsof(cp).with(expr) : cp の値 item が expr を満たすビンを選択
    bins read_high_long = binsof(cmd).with(item == CMD_READ) && // cmd が READ のビン
                          binsof(addr).with(item >= ADDR_HIGH_MIN) && // addr が high のビン
                          binsof(len).with(item >= 5); // len が long のビン

    // WRITEコマンドで short length の場合 (アドレスは問わない)
    // binsof(cp).bin_name : cp の特定のビン名を参照する省略形も使える
    bins write_short    = binsof(cmd).WRITE && // cmd が WRITE のビン (binsof(cmd).with(item == CMD_WRITE) と同義)
                          binsof(len).short;   // len が short のビン (binsof(len).with(item inside {[1:4]}) と同義)

    // IDLEコマンドは無視する (crossの対象外にする)
    ignore_bins idle_cmd = binsof(cmd).with(item == CMD_IDLE); // cmd が IDLE のビンは無視
  }
endgroup
```
*   `binsof(cp).with(expr)`: `cp` という `coverpoint` のうち、その値 `item` が `expr` を満たすようなビンを選択する基本的な構文です。
*   `binsof(cp).bin_name`: もし `coverpoint cp` に `bin_name` という名前のビンが定義されていれば、そのビンを直接参照する省略形も利用できます。
*   これらの構文を使い、必要な組み合わせだけを効率的に定義することで、組み合わせ爆発を防ぎます。

### `cross` のオプション

`coverpoint` と同様に `option.goal`, `option.weight`, `ignore_bins`, `illegal_bins` などを `cross` に対して設定できます。

---

## サンプルコード

以下に、`coverpoint` と `cross` を使用した基本的な `covergroup` の例を示します。

```systemverilog
module tb;
  logic clk = 0, rst_n = 0;
  always #5 clk = ~clk;
  initial begin
    rst_n = 0;
    #20 rst_n = 1;
  end

  logic [4:0] data;
  logic       enable;
  logic [1:0] mode; // 0: idle, 1: read, 2: write, 3: reserved

  // カバレッジグループ定義
  covergroup cg @(posedge clk iff rst_n); // リセット解除後のみサンプリング
    // data coverpoint: ビンを意味のある範囲に分割
    cp_data: coverpoint data {
      bins low        = { [0:7]   };
      bins med        = { [8:15]  };
      bins high       = { [16:30] }; // 31はillegal
      bins zero       = { 0 }; // 意図を明確にするため独立ビン
      illegal_bins reserved_val = { 31 }; // 31は不正値
    }
    // enable coverpoint: on/off
    cp_enable: coverpoint enable {
      bins off = {0};
      bins on  = {1};
    }
    // mode coverpoint: 各モードを定義
    cp_mode: coverpoint mode {
      bins idle  = {0};
      bins read  = {1};
      bins write = {2};
      illegal_bins reserved_mode = {3};
    }

    // cross coverage: enableがONの時の、read/write と data の組み合わせ
    // レポートで参照しやすいようにクロスにラベル 'x_emc' を付与
    x_emc: cross cp_enable, cp_mode, cp_data {
      // enableがOFFの時、またはmodeがidleの時は無視
      ignore_bins disable_or_idle = binsof(cp_enable).with(item == 0) || // enableがoffのビン
                                     binsof(cp_mode).with(item == 0);   // または modeがidleのビン

      // readでdataがlowの組み合わせ (binsof の省略形を使用)
      bins read_low = binsof(cp_enable).on && binsof(cp_mode).read && binsof(cp_data).low;

      // writeでdataがmed/highの組み合わせ (binsof.with と || を使用)
      bins write_med_high = binsof(cp_enable).with(item == 1) && // enableがon
                            binsof(cp_mode).with(item == 2) &&   // modeがwrite
                            (binsof(cp_data).med || binsof(cp_data).high); // dataがmedまたはhigh

      // その他の有効な組み合わせ (read-med, read-high, write-low) も自動でビンが作られるが、
      // 特定の組み合わせを強調したい場合は上記のように明示的に定義する。
      option.goal = 95; // このクロスカバレッジの目標は95%
    }
  endgroup

  // インスタンス化
  cg cg_inst = new;

  // 刺激生成と自動サンプリング
  initial begin
    wait(rst_n); // リセット解除を待つ
    repeat (200) begin
      @(posedge clk);
      // 刺激生成ロジックは自動サンプリングによって covergroup が評価する
      if (!$urandom_range(0, 5)) begin // ランダムに enable=0 を入れる
        enable = 0;
        mode = 0; // idle
        data = 0;
      end else begin
        enable = 1;
        data   = $urandom_range(0, 31); // illegal値も発生させる可能性
        mode   = $urandom_range(0, 3);  // illegal値も発生させる可能性
      end
    end
    // 結果表示
    $display("------------------------------------");
    $display("Coverage Report for cg_inst:");
    $display("Overall Coverage = %0.2f %%", cg_inst.get_coverage());
    $display("  cp_data coverage   = %0.2f %%", cg_inst.cp_data.get_coverage());
    $display("  cp_enable coverage = %0.2f %%", cg_inst.cp_enable.get_coverage());
    $display("  cp_mode coverage   = %0.2f %%", cg_inst.cp_mode.get_coverage());
    // ラベル付けしたクロス 'x_emc' を参照してカバレッジを取得
    $display("  cross x_emc coverage = %0.2f %%", cg_inst.x_emc.get_coverage());
    $display("------------------------------------");

    // 詳細レポート (シミュレータ依存の可能性あり)
    // cg_inst.get_coverage_display(); // Questa Cover等で使える場合がある

    $finish;
  end
endmodule
```

---

## サンプルコードの改善：カバレッジ定義のパッケージ化

上記のサンプルコードは `covergroup` の基本的な使い方を示すには十分ですが、実際のプロジェクトでは、カバレッジ定義をテストベンチモジュールから分離し、再利用可能にすることが推奨されます。SystemVerilog の `package` を利用することで、これを実現できます。

**パッケージ化のメリット:**

1.  **再利用性:** 同じカバレッジ定義を複数のテストベンチや検証コンポーネントで容易に共有できます。
2.  **関心の分離:** カバレッジ定義のロジックをテストベンチの刺激生成やチェックロジックから分離し、コードの見通しを良くします。
3.  **保守性:** カバレッジ定義の修正が必要になった場合、パッケージファイルを変更するだけで、それを利用する全ての箇所に反映されます。

以下に、元のサンプルコードのカバレッジグループ定義をパッケージ化する手順とコード例を示します。ここでは、`with function sample` を使用して、サンプリングするデータを `covergroup` に渡す方法を採用します。これにより、サンプリングイベント (`@`) を `covergroup` 定義から分離でき、より柔軟な制御が可能になります。

### 1. カバレッジ定義パッケージ (`coverage_pkg.sv`)

まず、`covergroup` 定義を含むパッケージを作成します。

```systemverilog
// --- coverage_pkg.sv ---
package coverage_pkg;

  // カバレッジグループ定義 (パッケージ内)
  // with function sample を使い、サンプリングするデータを引数で受け取る
  // 元の @(posedge clk iff rst_n) は削除
  covergroup cg with function sample (logic [4:0] data, logic enable, logic [1:0] mode);

    // --- Coverpoints (定義は元のサンプルと同じ) ---
    cp_data: coverpoint data {
      bins low        = { [0:7]   };
      bins med        = { [8:15]  };
      bins high       = { [16:30] };
      bins zero       = { 0 };
      illegal_bins reserved_val = { 31 };
    }
    cp_enable: coverpoint enable {
      bins off = {0};
      bins on  = {1};
    }
    cp_mode: coverpoint mode {
      bins idle  = {0};
      bins read  = {1};
      bins write = {2};
      illegal_bins reserved_mode = {3};
    }

    // --- Cross Coverage (定義は元のサンプルと同じだが、レポート用にラベルを追加) ---
    // レポートで参照しやすいようにクロスにラベル 'x_emc' を付与
    x_emc: cross cp_enable, cp_mode, cp_data {
      ignore_bins disable_or_idle = binsof(cp_enable).with(item == 0) ||
                                     binsof(cp_mode).with(item == 0);
      bins read_low = binsof(cp_enable).on && binsof(cp_mode).read && binsof(cp_data).low;
      bins write_med_high = binsof(cp_enable).with(item == 1) &&
                            binsof(cp_mode).with(item == 2) &&
                            (binsof(cp_data).med || binsof(cp_data).high);
      option.goal = 95;
    }
  endgroup : cg

endpackage : coverage_pkg
```

**変更点のポイント:**

*   `covergroup` 定義を `package coverage_pkg; ... endpackage` で囲みます。
*   `covergroup cg @(posedge clk iff rst_n);` を `covergroup cg with function sample (logic [4:0] data, logic enable, logic [1:0] mode);` に変更しました。
    *   サンプリングイベント (`@`) と条件 (`iff`) を削除し、代わりに `with function sample(...)` を使用します。これにより、サンプリングするデータ (`data`, `enable`, `mode`) を `sample()` メソッドの引数として受け取れるようになります。
*   `cross` 定義にラベル `x_emc:` を追加しました。これにより、レポート表示時に `cg_inst.x_emc.get_coverage()` のように、特定のクロスを名前で参照できるようになります。

### 2. テストベンチモジュール (`tb.sv`) の修正

次に、テストベンチモジュールがこのパッケージを利用するように修正します。

```systemverilog
// --- tb.sv --- (パッケージを利用するテストベンチ)
module tb;
  // 作成したパッケージをインポート
  import coverage_pkg::*;

  // --- 信号定義 (変更なし) ---
  logic clk = 0, rst_n = 0;
  always #5 clk = ~clk;
  initial begin
    rst_n = 0;
    #20 rst_n = 1;
  end

  logic [4:0] data;
  logic       enable;
  logic [1:0] mode; // 0: idle, 1: read, 2: write, 3: reserved

  // --- カバレッジグループ定義はパッケージに移動したため、ここでは削除 ---

  // --- インスタンス化 (パッケージ内の covergroup を使う) ---
  // coverage_pkg::cg の型でインスタンス化
  // new() には引数不要 (with function sample のため)
  cg cg_inst = new;

  // --- 刺激生成と手動サンプリング ---
  initial begin
    wait(rst_n); // リセット解除を待つ
    repeat (200) begin
      @(posedge clk);
      // 元の covergroup の `iff rst_n` 条件をここでチェック
      if (rst_n) begin
        // 刺激生成ロジック (変更なし)
        if (!$urandom_range(0, 5)) begin
          enable = 0;
          mode = 0; // idle
          data = 0;
        end else begin
          enable = 1;
          data   = $urandom_range(0, 31); // illegal値も発生させる可能性
          mode   = $urandom_range(0, 3);  // illegal値も発生させる可能性
        end

        // 手動で sample メソッドを呼び出し、現在の値を渡す
        cg_inst.sample(data, enable, mode);
      end
    end

    // --- 結果表示 (cross の参照方法を修正) ---
    $display("------------------------------------");
    $display("Coverage Report for cg_inst (Packaged):");
    $display("Overall Coverage = %0.2f %%", cg_inst.get_coverage());
    $display("  cp_data coverage   = %0.2f %%", cg_inst.cp_data.get_coverage());
    $display("  cp_enable coverage = %0.2f %%", cg_inst.cp_enable.get_coverage());
    $display("  cp_mode coverage   = %0.2f %%", cg_inst.cp_mode.get_coverage());
    // ラベル付けしたクロス 'x_emc' を参照してカバレッジを取得
    $display("  cross x_emc coverage = %0.2f %%", cg_inst.x_emc.get_coverage());
    $display("------------------------------------");

    $finish;
  end
endmodule
```

**変更点のポイント:**

*   `import coverage_pkg::*;` をモジュールの先頭に追加し、パッケージの内容を利用可能にします。
*   モジュール内に直接記述されていた `covergroup cg ... endgroup` は削除します。
*   `covergroup` のインスタンス化を `cg cg_inst = new;` とします (`coverage_pkg::cg` が型名）。`new` に引数は不要です（`with function sample` を使用しているため）。
*   元の自動サンプリング `@(posedge clk iff rst_n)` に代わり、`initial` ブロック内で `@(posedge clk);` の後に `if (rst_n)` 条件を追加し、その中で `cg_inst.sample(data, enable, mode);` を呼び出して手動でサンプリングを実行します。これにより、元のサンプリング条件を維持しつつ、`covergroup` 定義からはタイミング依存性を排除できました。
*   レポート表示部分で、クロスカバレッジ率を取得する際に `cg_inst.x_emc.get_coverage()` を使用するように修正しました。

---

## カバレッジ結果の取得とレポート

シミュレーション中に収集されたカバレッジデータは、プログラムからアクセスしたり、ツール固有のレポート機能で確認したりできます。

*   **プログラムからのアクセス (IEEE 標準メソッド):**
    *   `get_coverage()`: `covergroup` インスタンス全体のカバレッジ率 (%) を返します。
    *   `get_inst_coverage()`: `coverpoint` または `cross` のインスタンスのカバレッジ率 (%) を返します。
        *   `cg_inst.cp_data.get_coverage()`: 特定の `coverpoint` のカバレッジ率。
        *   `cg_inst.cross_name.get_coverage()`: 特定の `cross` のカバレッジ率 (例: `cg_inst.x_emc.get_coverage()`)。
        *   `cg_inst.get_coverage(covered_bins, total_bins)`: 引数を渡すと、ヒットしたビン数と総ビン数を取得できます。
*   **シミュレータ固有のメソッド:**
    *   `$get_coverage()`: (古い形式) `get_coverage()` と同様。
    *   `get_coverage_message()` / `sprint()`: 人が読める形式の簡単なレポート文字列を返す場合がありますが、標準ではありません。
*   **ツールによるレポート:**
    *   シミュレータ (Questa, VCS, Xcelium など) は、シミュレーション終了時にカバレッジデータベース (例: UCDB) を出力するオプションを持っています。
    *   専用のカバレッジユーティリティ (urg, Questa Cover, Verdi Coverage など) を使用して、データベースを読み込み、詳細なHTMLレポートやテキストレポートを生成できます。これらのレポートでは、各ビンが何回ヒットしたか、どのビンがヒットしていないか (カバレッジホール) を視覚的に確認できます。

カバレッジ率は基本的に以下の式で計算されます (重み付けがない場合):

$$
\mathrm{Coverage率} = \frac{\mathrm{ヒットしたビンの数}}{\mathrm{総ビン数 (ignore\_binsを除く)}} \times 100\%
$$

`option.weight` が設定されている場合は、重みを考慮した計算になります。

---

## ベストプラクティス

効果的な機能カバレッジを定義・運用するためのヒントです。

1.  **検証計画との連携:**
    *   必ず検証計画書に基づいてカバレッジ項目を定義します。「何を検証したいのか」が不明確なまま `covergroup` を書いても意味がありません。
    *   検証計画書とカバレッジモデル (`covergroup` のコード) のトレーサビリティを確保します。

2.  **意味のあるビン定義とビン数の制御:**
    *   仕様上の意味のある境界値、代表値、コーナーケースを中心にビンを定義します。
    *   `cross` で組み合わせ爆発を起こさないように、本当に重要な組み合わせだけを定義します。`ignore_bins` や `binsof().with()` を駆使して不要なクロスビンを除外します。
    *   `option.auto_bin_max` で意図しない自動ビン生成を抑制します。

3.  **Illegal/Ignore ビンの積極的な活用:**
    *   `illegal_bins`: 仕様に反する値や状態を定義し、早期にバグを発見します。
    *   `ignore_bins`: リセット中、未定義状態、"don't care" な条件など、カバレッジ計算に含めるべきでない値を明確に除外します。

4.  **サンプリングポイントと条件 (`@`, `iff`, 手動`.sample()`) の最適化:**
    *   自動サンプリング (`@(event)`) を基本とし、サンプリング漏れを防ぎます。
    *   `iff (condition)` を使って、意味のあるタイミング（例：トランザクションが有効な時、特定のモードの時）でのみサンプリングします。
    *   `iff` 条件に使う信号は、サンプリングイベントに対して安定しているものを選び、グリッチによる誤サンプリングを避けます。
    *   複雑な条件やクラスベース環境では、手動 `.sample()` や `with function sample()` を使う方が柔軟性が高い場合があります。手動サンプリングの場合、呼び出し条件を適切に制御することで、無駄なサンプリングを避けます。

5.  **カバレッジホール分析の実施:**
    *   カバレッジ率が 100% に満たない場合、単に数値を見るだけでなく、「どのビンが埋まっていないか（カバレッジホール）」を特定します。
    *   レポートツールを活用してホールを特定し、その原因を分析します（テスト不足、制約の問題、到達不能な設計、仕様バグ、カバレッジモデルの誤りなど）。

6.  **カバレッジドリブン検証 (CDV) の導入:**
    *   カバレッジホールの分析結果に基づき、テストを追加したり、ランダム制約を調整したりして、効率的にカバレッジを向上させるアプローチ（CDV）を実践します。

7.  **カバレッジ除外 (Waiver) の適切な管理:**
    *   設計上到達不能、テスト不要、あるいは意図的に未検証とするカバレッジ項目を除外 (Waiver) する場合は、必ずその理由を明確に記録し、チーム内でレビュー・承認プロセスを経て管理します。安易な Waiver は検証漏れのリスクを高めます。ツールが提供する Waiver 機能を利用することが一般的です。

8.  **命名規則とコメント:**
    *   `covergroup`, `coverpoint`, `cross`, `bins` には、その目的がわかるような一貫性のある名前を付けます。
    *   なぜそのビンを定義したのか、なぜその組み合わせをクロスしたのかなど、意図をコメントで残します。

9.  **コードの構造化（パッケージ化）:**
    *   関連する `covergroup` 定義は `package` にまとめることで、再利用性を高め、テストベンチコードの見通しを良くします。（「サンプルコードの改善：カバレッジ定義のパッケージ化」参照）

---

## 動的カバレッジとリセット

`covergroup` はクラス内で定義したり、配列として生成したりすることで、動的にインスタンス化・管理できます。

```systemverilog
// パラメータ化された covergroup (with function sample を使用する例)
covergroup DynamicCG #(int WIDTH = 8, int GOAL = 90) (string name) with function sample (logic [WIDTH-1:0] data_bus);
  // --- Type Options (型定義時に設定、全インスタンスのデフォルト) ---
  type_option.weight = 1; // 型全体のデフォルト重み
  type_option.comment = $sformatf("Dynamic Covergroup for %0d-bit data", WIDTH);

  // --- Instance Options (インスタンスごと、またはグループ定義内で設定) ---
  option.per_instance = 1; // インスタンスごとにカバレッジを計算
  option.goal = GOAL;      // インスタンスのゴール (パラメータで渡す)
  option.name = name;      // インスタンス名 (引数で渡す)

  cp_data: coverpoint data_bus { // sample 関数の引数を直接 coverpoint 対象にする
    bins range = { [0 : (1<<WIDTH)-1] };
  }
  // ...
endgroup

class CoverageCollector #(int WIDTH = 8); // クラスもパラメータ化
  localparam MAX_INST = 10;
  // DynamicCG 型の連想配列 (名前 -> インスタンスハンドル)
  DynamicCG #(.WIDTH(WIDTH)) cg_insts[string];

  function new(); endfunction

  function void create_cg(string inst_name, int goal_param = 90);
    if (!cg_insts.exists(inst_name)) begin
      // 幅パラメータ(WIDTH)はクラスパラメータを使用し、ゴールを引数で指定してインスタンス生成
      // new() の引数は covergroup 定義の引数リスト `(string name)` に対応
      cg_insts[inst_name] = new #(.GOAL(goal_param)) (inst_name);
      `uvm_info("CG_CREATE", $sformatf("Created covergroup instance '%s' with WIDTH=%0d, GOAL=%0d",
                                        inst_name, WIDTH, goal_param), UVM_MEDIUM)
    end else begin
      `uvm_warning("CG_CREATE", $sformatf("Covergroup instance '%s' already exists.", inst_name))
    end
  endfunction

  task run_sampling(string inst_name, logic [WIDTH-1:0] data);
    if (cg_insts.exists(inst_name)) begin
      // 手動サンプリング (with function sample を使用)
      cg_insts[inst_name].sample(data);
    end else begin
       `uvm_warning("CG_SAMPLE", $sformatf("Attempted to sample non-existent covergroup '%s'", inst_name))
    end
  endtask

  function void reset_coverage(string inst_name);
    if (cg_insts.exists(inst_name)) begin
      // 特定インスタンスのカウントをリセット
      cg_insts[inst_name].reset();
       `uvm_info("CG_RESET", $sformatf("Reset coverage for instance '%s'", inst_name), UVM_MEDIUM)
    end
  endfunction

  function real get_coverage(string inst_name);
    if (cg_insts.exists(inst_name)) begin
      return cg_insts[inst_name].get_coverage();
    end else return 0.0;
  endfunction

endclass
```

*   `new(...)`: `covergroup` をインスタンス化します。パラメータや引数を渡すことができます。`with function sample` を使う場合、`new` の引数は `covergroup` 定義の括弧 `()` 内の引数リストに対応します（`sample` 関数の引数リストではない）。
*   `option.per_instance = 1;`: これを設定すると、各インスタンスが独立してカバレッジ計算を行います（デフォルトは0で、同じ型の全インスタンスで集計）。
*   `type_option.` : `covergroup` の**型定義時**に設定し、その型から生成される**全てのインスタンスのデフォルト値**となります。
*   `option.` : `covergroup` の**インスタンスごと**、またはグループ定義内で設定し、そのインスタンス（またはそのグループ）の挙動を制御します。`type_option` の値を上書きできます。
*   `sample(...)`: `@(event)` を使用しない場合や、イベントに依存しないタイミングでサンプリングしたい場合に、手動で値を渡してサンプリングを実行します。`covergroup` 定義時に `with function sample(...)` を使うことで、引数を `coverpoint` で直接参照できます。クラスベース環境では特に便利です。
*   `reset()`: その `covergroup` インスタンスの全てのビンのカウントを 0 にリセットします。特定のテストフェーズ間でカバレッジをクリアしたい場合などに使用します。

---

## カバレッジ測定の最適化テクニック

カバレッジ収集はシミュレーションパフォーマンスに影響を与える可能性があります。以下は最適化のためのテクニックです。

*   **シミュレーション速度 vs カバレッジ詳細度:**
    *   詳細すぎるビン定義や、膨大な数のクロスビンは、シミュレーション速度を低下させる要因になります。
    *   重要度の低い組み合わせや、頻繁に発生しないが単純な値は、粗い粒度のビンにまとめるか、場合によっては `ignore_bins` で計測対象から外すことを検討します。トレードオフを意識することが重要です。

*   **条件付きサンプリングの活用:**
    *   `@(posedge clk iff (enable && valid))` のように、自動サンプリングで `iff` を使って本当に意味のあるデータや状態が発生した時だけサンプリングすることで、不要な評価処理を削減します。
    *   **注意点:** `iff` 条件に使う信号は、サンプリングイベント (`posedge clk` など) の前後で安定している必要があります。イベントのエッジ近辺で変化する信号を使うと、意図しないタイミングで評価されたり、グリッチの影響を受けたりして、サンプリングが期待通りに行われない可能性があります。安定した信号（例：パイプラインステージの有効信号など）を使うか、必要ならサンプリング用の信号を別途生成します。
    *   手動 `.sample()` を使う場合も、呼び出し条件を適切に制御することで、無駄なサンプリングを避けます。

*   **レポート頻度とデータ量の制御:**
    *   シミュレーション中に頻繁に `get_coverage()` や詳細レポート出力を行うと、オーバーヘッドが大きくなります。
    *   通常、カバレッジレポートはシミュレーションの最後、または主要なテストフェーズの区切りでまとめて取得・生成します。
    *   カバレッジデータベースのサイズが大きくなりすぎる場合は、シミュレータのオプションで出力内容をフィルタリングしたり、不要なカバレッジタイプ（例：コードカバレッジの一部）を無効にしたりすることを検討します。

*   **`covergroup type_option` の利用:**
    *   前述の通り、`type_option.weight`, `type_option.goal` などを使うと、その `covergroup` 型から生成される全てのインスタンスに共通のデフォルト設定を適用できます。インスタンスごとに `option` を設定する手間を省けます。

---

## マルチクロックドメインカバレッジ

異なるクロックドメイン間でやり取りされるデータや制御信号のカバレッジを測定するには、それぞれのクロックドメインに適したサンプリングイベントを使用します。

```systemverilog
parameter MAX_LATENCY = 100;

// ドメインA (clk_a) で送信データをサンプリング
covergroup cg_tx @(posedge clk_a iff tx_valid);
  cp_tx_data: coverpoint tx_data;
endgroup

// ドメインB (clk_b) で受信データをサンプリング
covergroup cg_rx @(posedge clk_b iff rx_valid);
  cp_rx_data: coverpoint rx_data;
endgroup

// ドメイン間転送のレイテンシを測定
// (例: tx_valid から rx_valid までの clk_b サイクル数を測定)
logic measure_start_ff;
logic [$clog2(MAX_LATENCY+1)-1:0] latency_cnt; // +1 for MAX_LATENCY inclusive
logic sample_latency;

// measure_start_ff は clk_a ドメインの tx_valid を clk_b ドメインに同期させた信号と仮定
// (実際の CDC 同期回路が必要)
// 例: 2-FF synchronizer
logic tx_valid_b_sync1, tx_valid_b_sync2;
always_ff @(posedge clk_b or negedge rst_n) begin // Use always_ff for clarity
  if (!rst_n) begin
    tx_valid_b_sync1 <= 1'b0;
    tx_valid_b_sync2 <= 1'b0;
    measure_start_ff <= 1'b0;
  end else begin
    // Assuming tx_valid is somehow available in clk_b domain (potentially unsafe if not synchronized)
    // For a real design, tx_valid would need proper synchronization first.
    // Let's assume tx_valid is already synchronized for this example scope.
    tx_valid_b_sync1 <= tx_valid; // This line is conceptually problematic without proper sync
    tx_valid_b_sync2 <= tx_valid_b_sync1;
    measure_start_ff <= tx_valid_b_sync2; // synchronized version of tx_valid in clk_b domain
  end
end


always_ff @(posedge clk_b or negedge rst_n) begin // Use always_ff
  if (!rst_n) begin
    latency_cnt <= '0;
    sample_latency <= 1'b0;
  end else begin
    sample_latency <= 1'b0; // Default to no sample
    if (measure_start_ff && !sample_latency) begin // Start counting only on the rising edge of sync'ed valid
      if (!rx_valid) begin // If not completed yet
        if (latency_cnt < MAX_LATENCY) begin
            latency_cnt <= latency_cnt + 1; // Increment latency counter
        end else begin
             // Max latency potentially exceeded, stop counting or flag error
             latency_cnt <= MAX_LATENCY + 1; // Use an overflow value
        end
      end
    end

    // Sample when rx_valid arrives AND we were measuring
    if (rx_valid && (latency_cnt > 0 || measure_start_ff)) begin // Check if we were measuring
        sample_latency <= 1'b1; // Trigger sampling of the current count
        latency_cnt <= '0; // Reset counter for next measurement
    end else if (!measure_start_ff) begin // Reset if measurement trigger goes low
        latency_cnt <= '0;
    end
  end
end

// Latency covergroup sampling on posedge clk_b when sample_latency is high
covergroup cg_latency @(posedge clk_b iff sample_latency);
  cp_latency: coverpoint latency_cnt {
    bins zero = {0}; // Should not happen if logic is correct, maybe ignore or illegal
    bins fast = { [1:5] };
    bins mid  = { [6:10] };
    bins slow = { [11:MAX_LATENCY] };
    // Values > MAX_LATENCY indicate timeout or overflow
    illegal_bins timeout = { [MAX_LATENCY+1:$] };
  }
endgroup

// Instantiate covergroups
cg_tx cg_tx_inst = new;
cg_rx cg_rx_inst = new;
cg_latency cg_latency_inst = new;
```

*   各ドメインのデータは、そのドメインのクロックと有効信号でサンプリングします。
*   ドメイン間のレイテンシや同期の成功/失敗などを測定するには、カウンターや状態変数を用意し、適切なタイミングでその値をサンプリングする `covergroup` を定義します。上記例では `sample_latency` という信号をサンプリング条件の `iff` で使用しています。
*   **重要**: 実際の CDC (Clock Domain Crossing) 検証では、信号を適切な同期回路 (例: 2-FF シンクロナイザ) を通してから受信側ドメインで使用する必要があります。上記コードの `tx_valid` の扱いは簡略化されており、実際の設計では同期化が必須です。レイテンシ測定ロジックも、連続する転送やエッジケースを考慮してより堅牢にする必要があります。
*   非同期信号のクロスを直接 `cross` で扱うのは難しいため、ドメインを跨るイベント間の時間差や、同期回路の出力状態を測定するアプローチが一般的です。CDC 同期回路の動作自体をカバレッジ対象とすることも有効です。

---

## UVM 環境でのクラス内定義と統合

UVM (Universal Verification Methodology) 環境では、`covergroup` は通常、モニタ (Monitor) やスコアボード (Scoreboard)、あるいは専用のカバレッジコレクタコンポーネント (Subscriber) 内にクラスメンバーとして定義されます。

```systemverilog
import uvm_pkg::*;
`include "uvm_macros.svh"

// トランザクションクラス (例)
class my_transaction extends uvm_sequence_item;
  // Define transaction members
  typedef enum logic [3:0] { K_READ=4'h1, K_WRITE=4'h2, K_IDLE=4'h0, K_OTHER=4'hF } kind_e;
  rand kind_e kind;
  rand logic [7:0] addr;
  rand logic [31:0] data;
  // UVM field automation needs valid types for enums
  // `uvm_field_enum requires the type, not just the enum literal
  typedef logic [7:0] addr_t;
  typedef logic [31:0] data_t;

  // Constraints (example)
  constraint c_kind { kind dist { K_READ := 40, K_WRITE := 40, K_IDLE := 10, K_OTHER := 10 }; }
  constraint c_addr { addr inside {[0:255]}; }

  // UVM field automation
  `uvm_object_utils_begin(my_transaction)
    `uvm_field_enum(kind_e, kind, UVM_ALL_ON)
    `uvm_field_int(addr, UVM_ALL_ON | UVM_HEX) // Use addr directly
    `uvm_field_int(data, UVM_ALL_ON | UVM_HEX) // Use data directly
  `uvm_object_utils_end

  function new(string name = "my_transaction");
    super.new(name);
  endfunction
endclass

// カバレッジ収集用 Subscriber クラス
class my_coverage extends uvm_subscriber #(my_transaction);
  `uvm_component_utils(my_coverage)

  // Transaction を受け取る Analysis Imp
  uvm_analysis_imp #(my_transaction, my_coverage) analysis_imp;

  // Covergroup定義 (クラス内で定義, with function sample を使用)
  covergroup cg_trans with function sample(my_transaction tr);
    // --- Type Options (型定義時に設定) ---
    type_option.comment = "Transaction Coverage"; // グループコメント
    type_option.weight = 1;

    // --- Instance Options (インスタンスごと、またはグループ定義内で設定) ---
    option.per_instance = 1; // インスタンスごとにカバレッジ計算
    option.name = get_full_name(); // UVMの階層名を使う (new時に設定も可)

    // --- Coverpoints ---
    cp_kind: coverpoint tr.kind { // 引数 tr のメンバを参照
      bins READ  = { my_transaction::K_READ };
      bins WRITE = { my_transaction::K_WRITE };
      bins IDLE  = { my_transaction::K_IDLE };
      // Use default to catch unspecified values explicitly if needed, or define OTHER bin
      bins OTHER = { my_transaction::K_OTHER };
      ignore_bins idle_ignore = { my_transaction::K_IDLE }; // 例: IDLEはカバレッジ計算から無視する場合
    }
    cp_addr: coverpoint tr.addr {
      bins low  = { [0:127] };
      bins high = { [128:255] };
    }
    cp_data_zero: coverpoint tr.data {
        bins zero = {32'h0};
        bins non_zero = default;
    }

    // --- Cross Coverage ---
    // kind と addr のクロス (READ/WRITE の場合のみ)
    // ラベル 'x_kind_addr' を付与
    x_kind_addr: cross cp_kind, cp_addr {
      // IDLE と OTHER は無視 (cp_kind で ignore_bins を使った場合は不要になることもある)
      ignore_bins ignore_non_rw = binsof(cp_kind).IDLE || binsof(cp_kind).OTHER || binsof(cp_kind).idle_ignore;
      // READ と low addr の組み合わせ
      bins read_low = binsof(cp_kind).READ && binsof(cp_addr).low;
      // WRITE と high addr の組み合わせ
      bins write_high = binsof(cp_kind).WRITE && binsof(cp_addr).high;
      // 特定のクロスビンのゴールを設定
      option.goal = 90; // このクロス全体のゴール
      bins read_low { option.goal = 95; } // この特定のビンだけゴール95%
    }
  endgroup : cg_trans

  // Covergroup インスタンスハンドル
  cg_trans cg_inst;

  function new(string name = "my_coverage", uvm_component parent = null);
    super.new(name, parent);
    analysis_imp = new("analysis_imp", this);
  endfunction

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    // インスタンス生成 (引数なし、with function sample を使うため)
    // covergroup 定義で引数を要求していないため、new() は引数なし
    cg_inst = new();
    // インスタンスオプションの設定例 (build_phase で option を設定)
    cg_inst.option.goal = 98; // このインスタンスの全体のゴールを98%に設定
    // cg_inst.cp_kind.option.goal = 95; // 個別 coverpoint のゴール設定も可能
    cg_inst.option.name = get_full_name(); // option.name で設定済みだが、ここで上書きも可
  endfunction

  // Analysis Port から Transaction を受け取り、sample メソッドを呼び出す
  virtual function void write(my_transaction tr);
    // トランザクションが null でないことを確認 (防御的プログラミング)
    if (tr == null) begin
        `uvm_warning(get_type_name(), "Received null transaction pointer in write method.")
        return;
    end
    `uvm_info(get_type_name(), $sformatf("Sampling transaction: %s", tr.sprint()), UVM_HIGH)
    // covergroup の sample 関数を呼び出し, トランザクションオブジェクトを渡す
    // cg_inst が null でないことも確認
    if (cg_inst != null) begin
        cg_inst.sample(tr);
    end else begin
        `uvm_error(get_type_name(), "Covergroup instance cg_inst is null during sampling!")
    end
  endfunction

  // レポートフェーズでカバレッジをチェック
  function void report_phase(uvm_phase phase);
    super.report_phase(phase);
    // cg_inst が生成されているか確認
    if (cg_inst == null) begin
        `uvm_error(get_type_name(), "Covergroup instance cg_inst was not created.")
        return;
    end
    real cov = cg_inst.get_coverage();
    int goal = cg_inst.option.goal; // 設定したゴール値を取得
    string cg_name = cg_inst.option.name; // 設定した名前を取得

    `uvm_info(get_type_name(), $sformatf("Final Coverage for %s = %0.2f %% (Goal: %0d %%)",
                                         cg_name, cov, goal), UVM_LOW)
    if (cov < goal) begin
      `uvm_error(get_type_name(), $sformatf("Coverage (%0.2f %%) is below goal (%0d %%) for %s",
                                            cov, goal, cg_name))
    end else begin
       `uvm_info(get_type_name(), $sformatf("Coverage goal met for %s.", cg_name), UVM_LOW)
    end
  endfunction

endclass

// 使い方:
// 1. エージェントや環境クラスで my_coverage をインスタンス化する:
//    my_coverage cov_collector;
//    cov_collector = my_coverage::type_id::create("cov_collector", this);
//
// 2. モニタの analysis_port と接続する:
//    monitor.analysis_port.connect(cov_collector.analysis_imp);
```

*   **定義場所:** モニタ、スコアボード、または専用の `uvm_subscriber` 内に定義するのが一般的です。`uvm_subscriber` を使うと、カバレッジ収集のロジックを他のコンポーネントから分離できます。
*   **サンプリングトリガ:**
    *   モニタがトランザクションをブロードキャストする `analysis_port.write(tr)` を受け取る `write` メソッド内で `.sample(tr)` を呼び出すのが最も一般的です。
    *   `covergroup cg @(some_event);` のように SystemVerilog イベントを使うことも可能ですが、トランザクションオブジェクトを直接渡す `with function sample(...)` の方が柔軟性が高いことが多いです。
*   **`with function sample(...)`:** `covergroup` 定義時に `with function sample(type arg, ...)` を付けると、`.sample(arg, ...)` が呼び出されたときに引数を受け取り、その引数を `coverpoint` の式で直接参照できます（例：`coverpoint tr.kind`）。クラスベースの検証環境では非常に便利です。
*   **UVM フェーズとの連携:**
    *   `build_phase` で `covergroup` を `new()` します。インスタンスオプションもここで設定できます。
    *   `connect_phase` でモニタの Analysis Port と Subscriber の Analysis Imp を接続します。
    *   `run_phase` 中にモニタから `write` が呼ばれ、Subscriber の `write` メソッド内で `.sample()` が実行されデータが収集されます。
    *   `report_phase` で `get_coverage()` を呼び出し、結果をレポートしたり、目標値と比較して `uvm_error` / `uvm_warning` を発行したりします。

---

## covergroup の内部処理フロー (概念図)
### 1. サンプリングトリガーと初期判定
```mermaid
flowchart TD
    subgraph Simulation Time
        A[サンプリングイベント発生<br>or .sample 呼び出し]
    end

    A --> B{Covergroup 全体の<br>iff 条件は満たされるか？<br>iff があれば}
    B -- Yes / No Iff --> C[次のステップへ<br>Coverpoint/Cross評価]
    B -- No --> D[サンプリングスキップ]

```

説明: まず、@(event) や .sample() でトリガーがかかります。covergroup 全体に iff 条件があれば、それが評価され、条件を満たさない場合はここで処理が終了します。iff がなければ C へ進みます。

### 2. Coverpoint 評価とカウント

```mermaid
flowchart TD
    C --> SubCP[各 Coverpoint を評価]
    SubCP --> E{Coverpoint 個別の<br>iff 条件は<br>満たされるか？ iff があれば}
    E -- Yes / No Iff --> G[Coverpoint<br>の式/関数を評価]
    E -- No --> H[この Coverpoint<br>はスキップ]

    G --> I{定義されたビンに<br>マッチするか？<br>ignore/illegal チェック含む}
    I -- Illegal Match --> K[エラー/警告<br>カウントされるかは設定次第]
    I -- Ignore Match --> L[カウントせず終了]
    I -- Match (Not Ignored) --> J[対応するビンの<br>カウントを増やす]
    I -- No Match --> Def{Default bin あるか？}
    Def -- Yes --> J_Def[Default Bin Count ++]
    Def -- No --> L_NoMatch[カウントせず終了]

    subgraph Bin Counters
        J --> M(Bin Count ++)
        J_Def --> M
    end
```

説明: グループ全体の条件を満たした場合、各 coverpoint が評価されます。個別の iff 条件、式の評価、ビンとの照合が行われ、illegal_bins にマッチするとエラー、ignore_bins にマッチすると無視されます。有効なビンにマッチすれば、対応するビンのカウントが更新されます。どのビンにもマッチせず default ビンがあればそれがカウントされます。

### 3. Cross 評価とカウント
```mermaid
flowchart TD
    C --> SubCross[各 Cross を評価]
    SubCross --> L{関連する Coverpoint の<br>値/ビンは有効か？<br>Ignore/Illegalでないか}
    L -- Yes --> N[クロス積を計算し<br>組み合わせ値を特定]
    L -- No --> Q[この Cross 評価<br>はスキップ]

    N --> O{定義されたクロスビンに<br>マッチするか？<br>ignore/illegal チェック含む}
    O -- Illegal Match --> R[エラー/警告<br>カウントされるかは設定次第]
    O -- Ignore Match --> S[カウントせず終了]
    O -- Match (Not Ignored) --> P[対応するクロスビンの<br>カウントを増やす]
    O -- No Match --> DefCross{Default Cross Bin あるか？}
    DefCross -- Yes --> P_Def[Default Cross Bin Count ++]
    DefCross -- No --> S_NoMatch[カウントせず終了]

    subgraph Cross Bin Counters
        P --> T(Cross Bin Count ++)
        P_Def --> T
    end
```

説明: coverpoint と同様に、各 cross も評価されます。関連する coverpoint の値に基づいて組み合わせが計算され、定義されたクロスビンと照合されます。Illegal/Ignore ビンは同様に扱われ、マッチすればクロスビンのカウントが更新されます。

### 4. カバレッジデータベース更新

```mermaid
flowchart TD
    subgraph Counters Updated
        M(Bin Count)
        T(Cross Bin Count)
    end

    M & T --> U[内部カバレッジ<br>データベースが更新される]

```
説明: ビンやクロスビンのカウントが更新されると、内部的なカバレッジデータベースの状態が変わります。

### 5. レポート
```mermaid
flowchart TD

    subgraph 要求時またはSim終了時
        V[get_coverage など<br>メソッド呼び出し] --> W[内部DBから<br>ヒット数/総ビン数を取得]
        X[レポート生成ツール<br>例: urg, Questa Cover] --> Y[保存されたDB<br>例: UCDB を読み込み]

        W --> Z[カバレッジ率 % を計算<br>重み、Goal考慮]
        Y --> Z

        Z --> AA[結果を返す/<br>詳細レポート生成<br>ホール情報など]
    end
```

説明: シミュレーション中や終了後に get_coverage() が呼ばれたり、外部ツールがデータベースを読み込んだりすると、その時点でのヒット数と総ビン数（無視ビンを除く）からカバレッジ率が計算され、結果が表示されます。

**フロー概要:**
1.  サンプリングイベント発生 または `.sample()` 呼び出し。
    `covergroup` の `iff` 条件が評価され、真なら続行。
2.  各 `coverpoint` が評価される:
    *   `coverpoint` の `iff` 条件が評価される。
    *   式が評価され、値が計算される。
    *   定義された `bins` と照合される (`ignore`/`illegal` もチェック)。
    *   マッチした有効なビンのカウントが増加する。
3.  各 `cross` が評価される:
    *   関連する `coverpoint` の現在の値（またはヒットしたビン）に基づいてクロス積が計算される。
    *   定義されたクロスビン (`bins` や `ignore_bins` など) と照合される。
    *   マッチした有効なクロスビンのカウントが増加する。
4.  内部のデータベースが更新される。
5.  レポート要求時 (`get_coverage()` やツール) に、データベースからヒット数と総ビン数を読み出し、カバレッジ率が計算される。

---

## メソッド／オプション一覧 (主要なもの)

| カテゴリ             | メソッド／オプション                 | スコープ     | 説明                                                                                           |
| :------------------- | :----------------------------------- | :----------- | :--------------------------------------------------------------------------------------------- |
| **インスタンス化**   | `new(...)`                           | インスタンス | `covergroup` インスタンスを生成するコンストラクタ。`covergroup` 定義時の引数リスト `()` に対応する引数を渡せる。 |
| **サンプリング**     | `sample(...)`                        | インスタンス | 手動でサンプリングを実行。`with function sample()` で定義された引数を渡す。                      |
|                      | `@(event) [iff (cond)]`              | グループ定義 | サンプリングイベントと条件を定義。イベント発生かつ条件成立時に自動サンプリング。                    |
|                      | `with function sample(...)`          | グループ定義 | `.sample()` 呼び出し時に引数を受け取る関数シグネチャを定義。引数を `coverpoint` で参照可能。     |
| **制御**             | `reset()`                            | インスタンス | インスタンスの全てのビンカウントを 0 にリセットする。                                              |
|                      | `start()`                            | インスタンス | カバレッジ収集を開始する (デフォルトで開始状態)。`stop()` で停止後のみ有効。                     |
|                      | `stop()`                             | インスタンス | カバレッジ収集を一時停止する。`start()` で再開可能。                                           |
| **情報取得**         | `get_coverage()`                     | インスタンス | インスタンス全体のカバレッジ率 (%) を返す。引数でヒット数/総ビン数も取得可能。                     |
|                      | `get_inst_coverage()`                | ポイント/クロス | `coverpoint` または `cross` 個別のカバレッジ率 (%) を返す。引数でヒット数/総ビン数も取得可能。 |
|                      | `get_num_bins(type)`                 | インスタンス | 指定タイプのビン (例: `UVM_CVR_ALL_BINS`) の数を返す。                                        |
|                      | `get_num_hit_bins(type)`             | インスタンス | 指定タイプのヒットしたビン数を返す。                                                            |
| **グループオプション** | `option.per_instance = 0/1;`     | グループ/インスタンス | 1 ならインスタンス毎、0 なら同じ型の全インスタンスで集計してカバレッジ計算 (デフォルト 0)。   |
|                      | `option.goal = N;`                   | グループ/インスタンス | グループ全体のカバレッジ目標値 (%)。インスタンスごとに設定可能。                                |
|                      | `option.weight = W;`                 | グループ/インスタンス | グループ全体の重み。インスタンスごとに設定可能。個別の重みと合わせて計算される。                 |
|                      | `option.comment = "string";`         | グループ/インスタンス | レポート用のコメント。インスタンスごとに設定可能。                                               |
|                      | `option.name = "string";`            | グループ/インスタンス | インスタンス名。レポートや識別に利用。                                                         |
|                      | `option.auto_bin_max = N;`           | グループ/インスタンス | 自動生成されるビンの最大数を制限。                                                              |
|                      | `option.cross_auto_bin_max = N;`     | グループ/インスタンス | `cross` で自動生成されるクロスビンの最大数を制限。                                              |
|                      | `type_option.goal = N;`              | 型           | **型定義時**に設定。この型の全インスタンスのデフォルトの `option.goal` 値となる。                   |
|                      | `type_option.weight = W;`            | 型           | **型定義時**に設定。この型の全インスタンスのデフォルトの `option.weight` 値となる。                 |
|                      | `type_option.comment = "string";`    | 型           | **型定義時**に設定。この型の全インスタンスのデフォルトの `option.comment` 値となる。               |
|                      | `type_option.per_instance = 0/1;`    | 型           | **型定義時**に設定。この型の全インスタンスのデフォルトの `option.per_instance` 値となる。         |
| **ポイント/クロスオプション** | `option.goal = N;`       | ポイント/クロス/ビン | `coverpoint`/`cross`/ビン 固有のカバレッジ目標値 (%)。                                       |
|                      | `option.weight = W;`             | ポイント/クロス/ビン | `coverpoint`/`cross`/ビン 固有の重み。                                                       |
|                      | `option.comment = "string";`     | ポイント/クロス/ビン | `coverpoint`/`cross`/ビン 固有のコメント。                                                   |
|                      | `option.at_least = N;`           | ポイント/クロス/ビン | ビンが少なくとも N 回ヒットしないとカバーされたとみなさない。                                     |
|                      | `option.detect_overlap = 0/1;`   | ポイント/クロス | 1 なら重複するビン定義を検出して警告。                                                          |
| **ビン定義**         | `bins name = value_set;`           | ポイント/クロス | 値の集合 (単一、リスト、範囲、遷移) を持つビンを定義。                                           |
|                      | `bins name[] = value_set;`         | ポイント/クロス | 配列ビンを定義。                                                                               |
|                      | `bins name = default;`             | ポイント/クロス | 他のビンでカバーされなかった値を集めるデフォルトビン。                                           |
|                      | `ignore_bins name = value_set;`    | ポイント/クロス | 指定した値をカバレッジ計算から除外する。                                                        |
|                      | `illegal_bins name = value_set;`   | ポイント/クロス | 指定した値が発生したらエラー/警告を出す。                                                        |
|                      | `with (expr)`                      | ビン定義内   | ビン定義の条件を指定 (`coverpoint` 式は `item` で参照)。                                        |
| **クロス定義**       | `cross cp1, cp2, ... { bins ... }` | グループ定義 | `coverpoint` や変数の組み合わせを定義。                                                         |
|                      | `binsof(cp)`                       | クロスビン定義内 | `cross` のビン定義内で、`coverpoint` `cp` のビン集合を参照する。                                |

*   **スコープ:**
    *   **型:** `type_option` で指定。型定義時に記述し、その型から生成される全インスタンスのデフォルト値。
    *   **グループ/インスタンス:** `option` で指定。グループ定義内、またはインスタンスハンドル経由で設定。`type_option` を上書き可能。
    *   **ポイント/クロス/ビン:** `coverpoint` / `cross` / `bins` の定義内で `option` や `at_least` を指定。その要素固有の設定。
*   *注意:* 全てのオプションやメソッドが全てのツールで完全にサポートされているとは限りません。詳細は使用するシミュレータのマニュアルを参照してください。

---

## 参考文献

1.  IEEE Std 1800™‑2017, **IEEE Standard for SystemVerilog—Unified Hardware Design, Specification, and Verification Language** (特に Section 19. Functional Coverage)
2.  Spear, Chris, and Greg Tumbush. *SystemVerilog for Verification: A Guide to Learning the Testbench Language Features*. Springer, 3rd ed., 2012. (定番の解説書)
3.  Mehta, Puneet Kumar, and Yan Zhang. *Functional Verification Coverage Measurement and Analysis*. Springer, 2018. (カバレッジ戦略と分析に特化)
4.  Accellera Systems Initiative, **Universal Verification Methodology (UVM) 1.2 User's Guide** (UVM 環境での適用例)
5.  各 EDA ベンダー (Synopsys, Cadence, Siemens EDA (Mentor)) の SystemVerilog および UVM リファレンスマニュアル、カバレッジツール (VCS/Verdi, Xcelium/Indago, Questa/Questa Cover) のドキュメント

---

## Q&A

**Q1. ビン数が爆発的に増える場合の対策は？**
A: クロスカバレッジの定義を見直します。
*   本当に必要な組み合わせだけを `binsof().with()` を使って明示的に定義します。
*   `ignore_bins` を使って、意味のない組み合わせや "don't care" の組み合わせを除外します。
*   `coverpoint` のビン定義自体をより粗い粒度にします (例: アドレスを個別値でなく範囲で定義)。
*   `option.cross_auto_bin_max` で自動生成されるクロスビンの数を制限します。

**Q2. クロスカバレッジでのサンプリング制御は？**
A: `covergroup` 全体の `@(…) iff (…)` や、`coverpoint` 個別の `iff (...)` を使って、クロス評価自体が行われるタイミングを限定します。手動サンプリング `.sample()` を使う場合は、呼び出し条件を適切に制御します。クロス内の `ignore_bins` でも条件を指定できます (`binsof().with()` を使う)。

**Q3. カバレッジレポートを外部ツールに渡すには？**
A: シミュレータが生成するカバレッジデータベースファイル (例: UCDB, `*.db`) を利用するのが一般的です。
*   シミュレーション実行時にデータベース出力オプションを指定します (例: `xrun -cov -covoverwrite -covtest mytest -covworkdir cov_db`)。
*   生成されたデータベースを、カバレッジユーティリティ (urg, Questa Cover, Verdi Coverage など) や、カスタムスクリプト (Tcl, Python などで DB を読むライブラリがあれば) で読み込み、解析・レポート生成します。
*   単純なテキスト情報が必要な場合は、`$display()` や `get_coverage_message()` (ツール依存) の結果をファイルにリダイレクトすることも可能ですが、情報量は限られます。

**Q4. 動的にパラメータを変えて複数グループを作る手順は？**
A: `covergroup` をパラメータ化し (`covergroup CG #(parameter WIDTH = 8) ...`)、クラス内やモジュール内で `new #(WIDTH_VALUE)` のようにパラメータを指定してインスタンス化します。「動的カバレッジとリセット」セクションの例を参照してください。

**Q5. 複数シミュレーション結果をマージするには？**
A: ほとんどのシミュレータ/カバレッジツールには、複数のカバレッジデータベースをマージする機能があります。
*   **コマンドライン例 (Xcelium/Questa):**
    ```bash
    # Xcelium
    xcrg -merge -out merged_covdb run1/cov_db run2/cov_db test*/cov_db
    # Questa
    vcover merge merged_covdb.ucdb run1.ucdb run2.ucdb test*.ucdb
    ```
*   マージされたデータベースをカバレッジユーティリティで読み込み、総合的なカバレッジレポートを生成します。

**Q6. リセット期間中のサンプリングを除外する方法は？**
A: いくつか方法があります。
*   `covergroup CG @(posedge clk iff rst_n);` のように、自動サンプリングの `iff` でリセットが解除されていることを条件にします (最も一般的)。
*   `coverpoint cp_data iff (rst_n) { ... }` のように、特定の `coverpoint` だけリセット中にサンプリングしないようにします。
*   手動サンプリング (`.sample()`) を使う場合は、テストベンチ側で `if (rst_n)` のような条件を付けて `.sample()` を呼び出します。（「サンプルコードの改善：カバレッジ定義のパッケージ化」の例を参照）
*   `ignore_bins reset_values = { value_during_reset } with (!rst_n);` のように、リセット中の特定の値を `ignore_bins` で定義することも可能ですが、通常は `iff` や手動サンプリングの呼び出し条件で制御する方が確実です。

**Q7. UVM でカバレッジしきい値をテスト判定に使うには？**
A: UVM の `report_phase` で `get_coverage()` を呼び出し、カバレッジ率を取得します。その値と `option.goal` や期待する閾値を比較し、満たない場合は `uvm_error` や `uvm_warning` を発行してテスト失敗または注意喚起を行います。UVM の `set_report_severity_action` などで、エラー発生時の動作（シミュレーション停止など）を制御できます。「UVM 環境でのクラス内定義と統合」セクションの例を参照してください。

**Q8. バースト転送の長さのカバレッジを取るには？**
A: バースト長を保持する変数 (例: `burst_length`) を用意し、それを `coverpoint` でサンプリングします。
```systemverilog
logic [$clog2(MAX_BURST_LEN):0] current_burst_length; // バースト長を保持する変数

covergroup cg_burst @(posedge clk iff burst_end); // バースト完了時にサンプリング
  cp_burst_len: coverpoint current_burst_length {
    bins single = {1};
    bins short  = { [2:4] };
    bins medium = { [5:8] };
    bins long   = { [9:16] };
    bins longer = { [17:MAX_BURST_LEN] };
    illegal_bins zero = {0}; // 長さ0は不正
    // $ はここでは使えないため、最大値をパラメータ等で指定
  }
endgroup
```
バースト転送が完了したタイミング（例: `burst_end` 信号が立つ時）でこの `covergroup` をサンプリングします。バースト長 `current_burst_length` は、テストベンチ側で転送中にカウント/保持しておく必要があります。

**Q9. カバレッジデータを永続化して後で分析するには？**
A: Q3 と同様に、シミュレータの機能を使ってカバレッジデータベース (UCDB など) をファイルに保存します。
```bash
# 例: Xcelium
xrun <options> -cov -access rw -covworkdir ./cov_db -covtest test_name
# 例: Questa
vsim <options> -coverage -cvgdb cov_db/test_name.ucdb
```
生成されたデータベースファイル (`./cov_db` ディレクトリ内など) は、シミュレーション後も残り、いつでもカバレッジユーティリティで読み込んで分析やレポート生成が可能です。

**Q10. 特定のビンだけを個別にリセットする方法は？**
A: SystemVerilog の標準 API では、`covergroup` インスタンス全体の `reset()` しか提供されていません。特定のビンだけを 0 に戻す直接的な方法はありません。代替策としては、
1.  より細かい粒度で `covergroup` を複数定義し、必要なグループだけ `reset()` する。
2.  カバレッジレポートツール側で、特定の期間や条件でフィルタリングしてレポートを表示する (データ自体はリセットされない)。
3.  非常に高度な使い方として、カバレッジデータベースを直接操作する API (ツール依存) があれば可能かもしれませんが、一般的ではありません。

**Q11. 複数カバレッジデータをマージする際の重複ビンの扱いは？**
A: 標準的なマージ処理では、各ビンのヒットカウントは単純に**加算**されます。同じテストケースを誤って2回実行してマージした場合、ヒットカウントは2倍になります。
重複サンプル（全く同じ刺激によるヒット）を排除したい場合は、マージツールやレポートツールが持つオプションを確認するか、マージ前に実行ログなどで重複実行がないかを確認する必要があります。単純なカウント加算が基本動作ですが、**ツールによっては、テスト名やタイムスタンプなどの情報を用いて重複ヒットを除外するオプションを持つ場合もあります。**

**Q12. マルチスレッド／マルチプロセス環境でのカバレッジ収集は可能？**
A: シミュレータが分散実行や並列実行をサポートしている場合、各プロセス/スレッドで個別にカバレッジデータを収集し、最後にそれらをマージすることで、並列環境全体のカバレッジを取得できます。設定方法はシミュレータに依存します (例: Xcelium の `-parallel` とカバレッジDBのマージ)。SystemVerilog 言語自体はスレッドセーフなカバレッジ収集を直接規定していません。

**Q13. コンストレイントカバレッジ（constraint coverage）とは？**
A: これは機能カバレッジの一種で、特にランダム検証において、定義した**制約 (constraint)** のどの部分がどの程度機能して、どのような値の組み合わせが生成されたかを測定するものです。例えば、`constraint c { addr inside {[0:255]}; kind dist {READ:=40, WRITE:=60}; }` がある場合、`addr` の値が全範囲カバーされたか、`kind` の分布が意図通りか、などを `covergroup` を使って測定します。UVM ではトランザクションクラス内で直接カバレッジを定義したり (`uvm_object::coverage()` フックが関連する場合もある)、Subscriber でトランザクションの値をカバーしたりします。

**Q14. サンプリングの遅延（サンプル漏れ）を検知するには？**
A: 直接的な検知機能は標準にはありませんが、以下の方法で間接的に確認できます。
*   **期待値との比較:** テストシナリオから期待されるヒット回数を予測し、実際の結果と比較する。大幅に少ない場合は漏れが疑われます。
*   **関連イベントとのクロス:** サンプリングすべきイベント (例: `valid`信号がHigh) と、実際にサンプリングされたかどうかを示す内部フラグなどをクロスし、「`valid`がHighなのにサンプリングされなかった」組み合わせが発生しないか確認する。
*   **手動サンプリングへの切り替え:** `@(event)` をやめ、期待するタイミングで必ず `.sample()` を呼び出すロジックを記述し、そのロジックが正しく動作しているかデバッグする。
*   **Assertion の併用:** サンプリング条件が成立した際に、次のクロックなどで必ずサンプリング処理が行われることを SVA (SystemVerilog Assertion) でチェックする。

**Q15. 機能カバレッジ 100% なら検証完了ですか？**
A: **いいえ、必ずしもそうとは言えません。機能カバレッジ 100% は、検証完了の十分条件ではなく、必要条件の一つと考えるべきです。** 機能カバレッジ 100% は、「定義されたカバレッジ項目が全てテストで実行された」ことを意味しますが、以下の点が保証されるわけではありません。
*   **カバレッジモデルの完全性:** 定義した `covergroup` が、設計仕様の全ての機能やコーナーケースを網羅しているとは限りません。重要な項目がモデルから漏れていれば、100% でも検証漏れになります。カバレッジモデル自体のレビューが重要です。
*   **バグの不在:** カバレッジはあくまで「実行されたか」を示すもので、実行結果が正しかったか（設計が仕様通りに動作したか）は保証しません。これはアサーションやセルフチェック、スコアボード、波形確認などで別途検証する必要があります。
*   **コードカバレッジ:** 機能カバレッジが 100% でも、RTL コード内に実行されていない箇所が残っている可能性があります（デッドコード、到達不能な分岐など）。コードカバレッジも合わせて確認することが推奨されます。
機能カバレッジ 100% は重要なマイルストーンですが、検証完了の判断は、コードカバレッジ、アサーション結果、テスト合否、バグ収束状況などを総合的に見て行う必要があります。

**Q16. `covergroup` 内で関数を呼び出して `coverpoint` の対象にできますか？**
A: はい、可能です。`coverpoint my_func_result: my_calc(arg1, arg2)` のように、`coverpoint` の式として関数呼び出しを含めることができます。
```systemverilog
function automatic int classify_addr(logic [15:0] addr);
  if (addr < 100) return 0; // Low
  else if (addr < 1000) return 1; // Mid
  else return 2; // High
endfunction

covergroup cg @(posedge clk);
  // current_address は covergroup のスコープから見える変数と仮定
  cp_addr_class: coverpoint classify_addr(current_address) {
    bins low = {0};
    bins mid = {1};
    bins high = {2};
  }
endgroup
```
ただし、注意点があります。
*   **パフォーマンス:** サンプリングのたびに関数が評価されるため、複雑な関数はシミュレーション速度に影響を与える可能性があります。
*   **純粋関数 (Pure Function):** サンプリングに使われる関数は、副作用（グローバル変数の変更など）を持たない方が望ましいです。また、同じ入力に対して常に同じ出力を返す決定的な関数であるべきです。SystemVerilog 2012 以降では `pure function` を宣言できます。
*   **デバッグ:** カバレッジがヒットしない場合、関数自体のデバッグも必要になることがあります。

**Q17. `cover` プロパティとの違いは何ですか？**
A: `cover property` と `covergroup` はどちらも機能カバレッジを収集しますが、得意な領域が異なります。
*   **`cover property (@(posedge clk) sequence_or_property);`**
    *   SystemVerilog Assertion (SVA) の構文に基づいています。
    *   **時間的なシーケンス**や、特定の**プロパティ（条件）**が満たされたかどうか（そのシーケンスが**発生したかどうか、何回発生したか**）をカバーするのに適しています。
    *   例：「リクエスト `req` の後に、3サイクル以内に `ack` が返る」というシーケンスが発生した回数をカバーする。
    *   複雑な値の組み合わせや分布をカバーするのは苦手です。
    *   SVA の `assert property` がシーケンスの**正当性（仕様通りか、Pass/Fail）**を検証するのに対し、`cover property` はシーケンスの**発生有無や頻度**を測定する点が主な違いです。
*   **`covergroup ... { coverpoint ...; cross ...; }`**
    *   特定の時点での**変数の値**や、複数の変数の**値の組み合わせ**、値の**分布**をカバーするのに適しています。
    *   ビン定義により、値の範囲やリストを柔軟に指定できます。
    *   時間的なシーケンスを直接記述するのは苦手です（状態変数などを介して間接的にカバーすることは可能）。

使い分けとしては、**データ値や状態の組み合わせ・分布は `covergroup`**、**時間的なイベントシーケンスやプロトコル遵守の発生頻度は `cover property`** を使うのが一般的です。両方を組み合わせて使うことも有効です。

---
## 用語集

| 用語                          | 説明                                                                                                                               | 英語                       |
| :---------------------------- | :--------------------------------------------------------------------------------------------------------------------------------- | :------------------------- |
| **カバレッジ**                | 設計が仕様通りに動作するかを検証するために、テストが設計の機能やコードをどれだけ網羅したかを測定する指標。                             | Coverage                   |
| **カバレッジ除外**            | 設計上到達不能、テスト不要などの理由で、特定のカバレッジ項目を測定対象から除外すること。理由の記録と管理が重要。                       | Coverage Exclusion / Waiver |
| **カバレッジドリブン検証**    | カバレッジ測定結果に基づき、テストベンチの制約やテストシナリオを修正・追加し、効率的にカバレッジ向上を目指す検証手法。                 | Coverage Driven Verification (CDV) |
| **カバレッジホール**          | 機能カバレッジ測定において、まだヒットしていない（値が観測されていない）ビンのこと。検証が不十分な箇所を示す。                         | Coverage Hole              |
| **カバレッジマージ**          | 複数のシミュレーション結果（カバレッジデータベース）を結合し、総合的なカバレッジレポートを生成する機能。                           | Coverage Merge             |
| **カバレッジモデル**          | `covergroup`, `coverpoint`, `cross`, `bins` などを使って、何をどのようにカバーするかを SystemVerilog で記述したもの。             | Coverage Model             |
| **コードカバレッジ**          | RTL コードの記述（文、分岐、条件、トグルなど）が、テスト実行によってどれだけ網羅されたかを測定するカバレッジ。                         | Code Coverage              |
| **クロス (Cross)**            | `covergroup` 内で、複数の `coverpoint` や変数の値の組み合わせを評価するカバレッジ項目。                                              | Cross                      |
| **クロスビン**                | `cross` で定義された、特定の組み合わせ条件に合致した場合にカウントされるビン。                                                     | Cross Bin / Cross Bucket     |
| **機能カバレッジ**            | 設計仕様に基づいて定義された機能、動作モード、トランザクション、値の組み合わせなどが、テストによってどれだけ網羅されたかを測定するカバレッジ。 | Functional Coverage        |
| **サンプリングイベント**      | `covergroup` が値をサンプリングするトリガとなるイベント。`@(posedge clk)` などで指定。                                             | Sampling Event             |
| **サンプリング修飾子 (iff)**  | サンプリングイベントが発生しても、指定した条件が真の時のみサンプリングを実行するための `iff (condition)` 構文。                      | Sampling Qualifier (iff)   |
| **シーケンスアイテム**        | UVM において、シーケンサからドライバへ、またはモニタからスコアボードへ渡されるトランザクションデータを表現するオブジェクト。             | Sequence Item              |
| **静的カバレッジグループ**    | モジュールやインターフェース内に直接定義され、コンパイル時にインスタンス化される `covergroup`。                                      | Static Covergroup          |
| **動的カバレッジグループ**    | クラス内やタスク/関数内で `new()` を使って生成・破棄できる `covergroup`。パラメータ化や配列化が可能。                                | Dynamic Covergroup         |
| **トランザクション**          | 検証対象との間でやり取りされる、意味のある一連のデータや制御信号のまとまり (例: バス Read/Write、パケット送受信)。                    | Transaction                |
| **ビン (Bin)**                | `coverpoint` や `cross` で定義される、観測対象の値を分類・カウントするための「箱」。値の範囲、リスト、単一値などで定義される。         | Bin                        |
| **ビン演算子 (`binsof`, `with`)** | `cross` のビン定義などで、特定の `coverpoint` (`binsof(cp)`) のビン集合を、条件 (`with(expr)`) に基づいて選択・フィルタリングする演算子。 | Bin Operators (`binsof`, `with`) |
| **検証計画書**                | 設計仕様に基づき、何をどのように検証するか（検証項目、手法、環境、カバレッジ目標など）を定義した文書。                               | Verification Plan          |
| **違法ビン (`illegal_bins`)** | `coverpoint` や `cross` で定義される、設計仕様上、発生してはならない値や組み合わせ。検出時にエラーや警告を出すことができる。         | Illegal Bins               |
| **無視ビン (`ignore_bins`)**  | `coverpoint` や `cross` で定義される、カバレッジ計算の対象から除外する値や組み合わせ（例：リセット中、Don't Care）。                  | Ignore Bins                |
| **Analysis Port/Imp**       | UVM で、コンポーネント間でトランザクションをブロードキャスト/受信するための TLM (Transaction Level Modeling) ポート。モニタからカバレッジコレクタへのデータ送信などに使う。 | Analysis Port / Analysis Implementation Port |
| **Covergroup**              | 機能カバレッジ項目 (`coverpoint`, `cross`) をグループ化し、サンプリングイベントやオプションを定義する SystemVerilog の構文。        | Covergroup                 |
| **Covergroup Handle**       | `new()` によって生成された `covergroup` インスタンスを指す変数（オブジェクトハンドル）。`.sample()`, `.reset()` などのメソッド呼び出しに使う。 | Covergroup Handle          |
| **Coverpoint**              | `covergroup` 内で、単一の変数や式の値を監視し、ビンに分類してカバレッジを測定する項目。                                             | Coverpoint                 |
| **Package**                 | SystemVerilog で、関連する定義（パラメータ、型、クラス、関数、タスク、`covergroup` など）をまとめて名前空間を提供する構文。           | Package                    |
| **UCDB**                      | Unified Coverage Database。主要な EDA ツールがサポートする標準的なカバレッジデータベースフォーマット。マージやレポート生成に利用される。   | Unified Coverage Database (UCDB) |
| **UVM (Universal Verification Methodology)** | 再利用性の高い検証環境を構築するための標準的な手法論と SystemVerilog ベースのクラスライブラリ。                                | Universal Verification Methodology (UVM) |
| **UVM Subscriber**          | UVM で、Analysis Port からトランザクションを受け取ることに特化したコンポーネント。カバレッジ収集やスコアボードによく使われる。           | UVM Subscriber             |

---
<a id="##-8活用例"></a>
## 活用例

<details>
<summary>インターフェース/バスプロトコル関連</summary>

- プロトコルの各トランザクション種別（Read/Write/Idleなど）の発生頻度とパラメータの組み合わせ
- `AXI (Advanced eXtensible Interface)` バースト転送長（ビート数）の分布
- クロックドメイン間ハンドシェイクの成功/失敗パターン
- `AHB (Advanced High-performance Bus)`/`APB (Advanced Peripheral Bus)` バス内のビート数と転送サイズの分布
- `AMBA (Advanced Microcontroller Bus Architecture)` インターコネクトにおけるクロスバー利用パターンと帯域利用率の分布
- `PCIe (Peripheral Component Interconnect Express)` トランザクションレイヤーパケット (`TLP`) の種類と完了コードの組み合わせ
- `USB (Universal Serial Bus)` パケットタイプ（`SOF`, `IN`, `OUT`, `DATA`, `ACK`, `NAK`, `STALL`）の発生比率
- Ethernet フレーム長の分布と`VLAN`タグの有無の組み合わせ
- `I2C`/`SPI` マスター/スレーブ通信の`NACK`発生頻度と再送パターン
- プロトコル違反/エラーレスポンス（`AXI` `DECERR`/`SLVERR`）の発生パターンと要因の組み合わせ
- 特定のアドレスマップ領域へのアクセス頻度とアクセス種別の分布
- トランザクションIDやタグの利用パターンと重複/枯渇状況の観測
- バス/インターコネクトリソース競合による性能劣化パターン（例: レイテンシ増加）

</details>

<details>
<summary>メモリシステム関連</summary>

- メモリアクセスパターン（連続読み出し/ランダム読み出し）の比率
- キャッシュヒット/ミスの組み合わせ
- キャッシュラインの置換アルゴリズム（`LRU (Least Recently Used)`, `FIFO (First-In First-Out)`, ランダム）の選択パターン
- `DDR (Double Data Rate)` メモリのリフレッシュタイミングと他コマンドの衝突パターン
- `NAND`フラッシュのページライト/ブロックイレーズ回数の分布
- ウェアレベリングアルゴリズムによるブロック消去回数の分布
- メモリバンク/ランク/チャネル間のアクセス分散パターン
- ページヒット/ミス/コンフリクトの発生比率
- プリフェッチ機構のヒット/ミスと発動条件の組み合わせ
- メモリコントローラのコマンドキュー深度とスループットの関係
- 共有キャッシュにおける競合パターンとヒット率への影響

</details>

<details>
<summary>エラー検出/回復関連</summary>

- エラー検出動作（パリティエラー検出、タイムアウト発生）の発生パターン
- フォールトトレラントシステムにおけるフェイルオーバー遷移パターン
- 多重化モジュールにおける一致/不一致検出の発生パターン
- チェックポイント/ロールバック機構の発動条件と成功率
- `ECC (Error Correction Code)` メモリのシングルビット/マルチビットエラー発生と修復結果の組み合わせ
- エラー注入シナリオ（注入箇所、注入タイミング、エラータイプ）の網羅度
- 冗長化構成における不一致検出とリカバリシーケンスの実行パターン

</details>

<details>
<summary>割り込み/タイミング制御関連</summary>

- 割り込み要因と優先度レベルの組み合わせ
- 割り込みネスト深度別の処理遅延分布
- マルチクロックドメイン間転送のレイテンシ分布
- エンドツーエンド遅延 ($t_{\mathrm{end2end}}$) の分布
- 非同期信号の同期化段数別の遅延分布
- `CDC (Clock Domain Crossing)` プロトコルの状態遷移パターン
- 非同期`FIFO (First-In First-Out)`のポインタ同期ロジックの動作パターン
- タイミング検証シナリオにおけるコーナーケースとマージン設定値の組み合わせ

</details>

<details>
<summary>データフロー制御関連</summary>

- `FIFO` の Full/Empty/AlmostFull/AlmostEmpty 状態遷移
- データストリームのフロー制御バースト数とサイズの組み合わせ
- `QoS (Quality of Service)` スケジューラにおける優先度ごとのスループット分布
- 複数マスター環境でのバス競合発生パターン
- `DMA (Direct Memory Access)`転送のチャネル競合とスケジューリング結果の関係
- `TCP (Transmission Control Protocol)` フロー制御におけるウィンドウサイズの推移パターン
- パケットドロップの理由（バッファオーバーフロー、`QoS`違反、`TTL (Time To Live)`切れ）の分類と発生頻度
- クレジットベースフロー制御におけるクレジット送受信パターン

</details>

<details>
<summary>電源管理/クロック関連</summary>

- 電源管理ドメインの ON/OFF 切り替え頻度と期間の分布
- 動作周波数スケーリング (`DVFS (Dynamic Voltage and Frequency Scaling)`) における電圧/周波数ペアの選択パターン
- パワーゲーティング制御信号の状態（Enable/Disable）と期間の分布
- クロックゲーティングの適用パターンとパワー状態の相関
- スリープ/ウェイクアップシーケンスの遷移時間分布
- バッテリー充電プロファイルの定電流/定電圧フェーズ遷移パターン

</details>

<details>
<summary>システム初期化/状態遷移関連</summary>

- リセットシーケンス中のステートマシン遷移パターン
- システム起動シーケンス各フェーズの到達有無
- マルチコアにおけるコヒーレンシプロトコル (`MESI (Modified, Exclusive, Shared, Invalid)`, `MOESI (Modified, Owned, Exclusive, Shared, Invalid)`) の状態遷移

</details>

<details>
<summary>プロセッサ/アーキテクチャ関連</summary>

- CPUの命令タイプ（算術、論理、分岐、メモリアクセス）の使用頻度分布
- 投機的実行の成功/失敗パターン
- `SIMD (Single Instruction, Multiple Data)`/ベクトル演算ユニットの並列度活用パターン
- パイプラインハザード（データ、制御、構造）の発生タイプと頻度
- 分岐予測のヒット/ミスと分岐タイプ（条件付き、無条件、直接、間接）の組み合わせ
- `TLB (Translation Lookaside Buffer)` ヒット/ミスとアクセス権限（Read/Write/Execute）の組み合わせ
- 演算ユニットや実行ポートの利用率分布

</details>

<details>
<summary>ネットワーク/パケット処理関連</summary>

- パケット分類エンジンのルールヒット率と処理経路の分布
- `IPsec (Internet Protocol Security)` トンネルモードにおける`ESP (Encapsulating Security Payload)`/`AH (Authentication Header)` プロトコルの使用パターン
- `QoS`マーキング (`DSCP (Differentiated Services Code Point)` 値）ごとのパケット遅延分布
- `NAT (Network Address Translation)` 変換テーブルのエントリ使用パターンとタイムアウト発生パターン
- ヘッダフィールド（IPアドレス、ポート番号、`VLAN ID`）の値範囲の組み合わせ
- フラグメント化/再構成処理の発生とパケットサイズの組み合わせ

</details>

<details>
<summary>画像処理/マルチメディア関連</summary>

- `H.264`/`HEVC (High Efficiency Video Coding)` エンコーダの予測モード（Intra/Inter）選択分布
- 画像処理パイプラインの各ステージ処理時間の分布
- オーディオサンプリングレートとビット深度の組み合わせ
- `HDMI (High-Definition Multimedia Interface)` リンクトレーニングの成功/リトライパターン

</details>

<details>
<summary>セキュリティ/暗号関連</summary>

- `AES (Advanced Encryption Standard)` 暗号処理のキー長（128/192/256ビット）とモード（`ECB (Electronic Codebook)`, `CBC (Cipher Block Chaining)`, `CTR (Counter Mode)`）の組み合わせ
- ランダム数生成器のエントロピー源の有効活用パターン
- セキュアブート時の各ファームウェアイメージの検証結果分布
- サイドチャネル攻撃対策機構（マスキング、シャッフリング）の有効/無効パターン
- 対策機構に関連する乱数値の分布
- アクセス制御機構 (`MPU (Memory Protection Unit)`/`MMU (Memory Management Unit)`) によるアクセス違反検出パターン
- セキュアエレメント/トラステッドゾーンへのアクセス要求パターン

</details>

<details>
<summary>デバッグ/診断関連</summary>

- `JTAG (Joint Test Action Group)`/`SWD (Serial Wire Debug)` インターフェースのアクセスパターン分布
- トレースデータの圧縮率とバッファ溢れイベントの発生パターン
- 自己診断テスト (`BIST (Built-in Self-Test)`) のカバレッジ達成パターンと実行時間の関係
- メモリダンプ機能のアドレス範囲カバレッジ分布

</details>

<details>
<summary>アナログ/ミックスシグナル (`AMS`) 連携</summary>

- `ADC (Analog-to-Digital Converter)`/`DAC (Digital-to-Analog Converter)` の動作モード（解像度、サンプリングレート）と入力レンジの組み合わせ
- `PLL (Phase-Locked Loop)` のロック/アンロック状態遷移と周波数切り替えシーケンス
- デジタル制御ループによるアナログパラメータ（ゲイン、バイアス）の調整パターン

</details>

<details>
<summary>FPGA特有</summary>

- 部分再構成 (`Partial Reconfiguration`) の実行とコンフィグレーション領域/モジュールの組み合わせ
- 高速トランシーバー (`SerDes (Serializer/Deserializer)`) の動作モード（レート、エンコーディング、イコライゼーション設定）の組み合わせ
- 特定リソース（`BRAM (Block RAM)`, `DSP (Digital Signal Processor)`, `LUT (Look-Up Table)`) の使用パターンと競合状態

</details>

<details>
<summary>ソフトウェア連携 / システムレベル</summary>

- ハードウェアアクセラレータへのタスクオフロード種別とパラメータの組み合わせ
- ドライバからのレジスタアクセスシーケンス（初期化、通常動作、エラーハンドリング）のパターン
- 共有メモリ/リソースへの複数マスター（CPUコア、`DMA`）からのアクセス競合パターン
- OSレベルのイベント（タスクスイッチ、割り込み処理）とハードウェア状態の相関
- 特定ユースケースシナリオにおける主要機能ブロックの活性化パターン
- 特定OSブートシーケンスにおける主要HWブロックのアクセス/活性化パターン
- 特定アプリケーションシナリオ（例: 動画エンコード、AI推論）実行時のリソース（CPU、アクセラレータ、メモリ帯域）利用パターンとボトルネック箇所の観測
- 仮想化環境におけるゲストOSとハイパーバイザー間のHWリソースアクセス競合パターン

</details>

<details>
<summary>コンフィギュレーション / レジスタ設定</summary>

- 主要な動作モードと関連するコンフィギュレーション設定値の組み合わせ網羅
- 特定モードにおける設定レジスタ値の組み合わせ
- 設定レジスタの予約ビット/フィールドへの書き込み試行パターン
- 複数の設定が相互に影響する機能における設定値の依存関係の組み合わせ

</details>

<details>
<summary>Low Power Intent (`UPF`/`CPF` 関連)</summary>

- `UPF (Unified Power Format)`/`CPF (Common Power Format)` で定義されたパワーダウン/リテンション/アイソレーション制御シーケンスの実行パターン
- パワーモード遷移（Active -> Retention -> Shutdown -> Activeなど）のシーケンス網羅
- Always-onドメインとスイッチ可能ドメイン間の通信プロトコルの状態遷移

</details>

<details>
<summary>リセットドメイン</summary>

- 複数のリセットドメイン間のリセット解除シーケンスのタイミングパターン
- 特定のリセットドメインのみがアサート/デアサートされるシナリオ
- 異なるリセット源（パワーオンリセット、ウォッチドッグリセット、ソフトウェアリセット等）からのリセット発生パターン

</details>

---

以上