はい、承知いたしました。「サンプルコードの改善:カバレッジ定義のパッケージ化」の章を元の「サンプルコード」セクションの直後に挿入し、修正後の記事全体を出力します。
はじめに
LSI や SoC の検証において、機能カバレッジ (functional coverage) は、テストが設計仕様をどれだけ網羅しているかを定量的に評価するための重要な指標です。検証の抜け漏れを防ぎ、設計が意図通りにテストされたことを客観的に示すために不可欠な要素となります。
SystemVerilog の covergroup
を用いることで、テストシナリオに対する値の分布や組み合わせ(これらを「カバレッジ項目」と呼びます)を定義・集計し、未検証のパターン(「カバレッジホール」)を明示できます。
通常、どのような機能カバレッジ項目を測定するかは、設計仕様に基づいて作成される検証計画書 (Verification Plan) で定義されます。covergroup
は、この検証計画書で定義された項目を検証環境に実装するための具体的な手段となります。
本記事では、主に検証の初心者に向けて、covergroup
の基本構文から、クロスカバレッジやマルチクロックドメイン対応、UVM 統合、最適化テクニック、そしてカバレッジ結果の分析といった実践的な内容までを踏まえて解説します。
カバレッジの種類
まず前提として、カバレッジには大きく分けて以下の様に、コードカバレッジ (code coverage)と、機能カバレッジ (functional coverage)の2種類があります。
この内、SystemVerilog の covergroup
は 機能カバレッジ (functional coverage) を定義・収集するための仕組みであり、テストベンチ側で観測したい入力パターンや状態の組み合わせを網羅的に評価できます。
-
コードカバレッジ (code coverage)
- 目的:RTL コードそのものの網羅度を測る
-
主な指標:
- 命令網羅 (statement coverage)
- 分岐網羅 (branch coverage)
- 条件網羅 (condition coverage)
- トグルカバレッジ (toggle coverage)
- FSM カバレッジ (Finite State Machine coverage)
-
ツール:シミュレータオプション(例:
-cover
/-cov
)で自動取得
-
機能カバレッジ (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 の基本構文
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
は、単一の変数や式の値を監視し、定義されたビンに分類してカウントします。
基本形
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
で参照)に対する条件でビンを定義できます。
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回ヒットしないとカバーされたとみなさない設定。
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
(または変数) の値の組み合わせ(クロス積)を評価します。組み合わせ爆発を起こしやすいため、定義には注意が必要です。
全組み合わせ評価 (非推奨な場合が多い)
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
を満たすビンに絞り込むことができます。
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
の例を示します。
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
を利用することで、これを実現できます。
パッケージ化のメリット:
- 再利用性: 同じカバレッジ定義を複数のテストベンチや検証コンポーネントで容易に共有できます。
- 関心の分離: カバレッジ定義のロジックをテストベンチの刺激生成やチェックロジックから分離し、コードの見通しを良くします。
- 保守性: カバレッジ定義の修正が必要になった場合、パッケージファイルを変更するだけで、それを利用する全ての箇所に反映されます。
以下に、元のサンプルコードのカバレッジグループ定義をパッケージ化する手順とコード例を示します。ここでは、with function sample
を使用して、サンプリングするデータを covergroup
に渡す方法を採用します。これにより、サンプリングイベント (@
) を covergroup
定義から分離でき、より柔軟な制御が可能になります。
1. カバレッジ定義パッケージ (coverage_pkg.sv
)
まず、covergroup
定義を含むパッケージを作成します。
// --- 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
) の修正
次に、テストベンチモジュールがこのパッケージを利用するように修正します。
// --- 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
が設定されている場合は、重みを考慮した計算になります。
ベストプラクティス
効果的な機能カバレッジを定義・運用するためのヒントです。
-
検証計画との連携:
- 必ず検証計画書に基づいてカバレッジ項目を定義します。「何を検証したいのか」が不明確なまま
covergroup
を書いても意味がありません。 - 検証計画書とカバレッジモデル (
covergroup
のコード) のトレーサビリティを確保します。
- 必ず検証計画書に基づいてカバレッジ項目を定義します。「何を検証したいのか」が不明確なまま
-
意味のあるビン定義とビン数の制御:
- 仕様上の意味のある境界値、代表値、コーナーケースを中心にビンを定義します。
-
cross
で組み合わせ爆発を起こさないように、本当に重要な組み合わせだけを定義します。ignore_bins
やbinsof().with()
を駆使して不要なクロスビンを除外します。 -
option.auto_bin_max
で意図しない自動ビン生成を抑制します。
-
Illegal/Ignore ビンの積極的な活用:
-
illegal_bins
: 仕様に反する値や状態を定義し、早期にバグを発見します。 -
ignore_bins
: リセット中、未定義状態、"don't care" な条件など、カバレッジ計算に含めるべきでない値を明確に除外します。
-
-
サンプリングポイントと条件 (
@
,iff
, 手動.sample()
) の最適化:- 自動サンプリング (
@(event)
) を基本とし、サンプリング漏れを防ぎます。 -
iff (condition)
を使って、意味のあるタイミング(例:トランザクションが有効な時、特定のモードの時)でのみサンプリングします。 -
iff
条件に使う信号は、サンプリングイベントに対して安定しているものを選び、グリッチによる誤サンプリングを避けます。 - 複雑な条件やクラスベース環境では、手動
.sample()
やwith function sample()
を使う方が柔軟性が高い場合があります。手動サンプリングの場合、呼び出し条件を適切に制御することで、無駄なサンプリングを避けます。
- 自動サンプリング (
-
カバレッジホール分析の実施:
- カバレッジ率が 100% に満たない場合、単に数値を見るだけでなく、「どのビンが埋まっていないか(カバレッジホール)」を特定します。
- レポートツールを活用してホールを特定し、その原因を分析します(テスト不足、制約の問題、到達不能な設計、仕様バグ、カバレッジモデルの誤りなど)。
-
カバレッジドリブン検証 (CDV) の導入:
- カバレッジホールの分析結果に基づき、テストを追加したり、ランダム制約を調整したりして、効率的にカバレッジを向上させるアプローチ(CDV)を実践します。
-
カバレッジ除外 (Waiver) の適切な管理:
- 設計上到達不能、テスト不要、あるいは意図的に未検証とするカバレッジ項目を除外 (Waiver) する場合は、必ずその理由を明確に記録し、チーム内でレビュー・承認プロセスを経て管理します。安易な Waiver は検証漏れのリスクを高めます。ツールが提供する Waiver 機能を利用することが一般的です。
-
命名規則とコメント:
-
covergroup
,coverpoint
,cross
,bins
には、その目的がわかるような一貫性のある名前を付けます。 - なぜそのビンを定義したのか、なぜその組み合わせをクロスしたのかなど、意図をコメントで残します。
-
-
コードの構造化(パッケージ化):
- 関連する
covergroup
定義はpackage
にまとめることで、再利用性を高め、テストベンチコードの見通しを良くします。(「サンプルコードの改善:カバレッジ定義のパッケージ化」参照)
- 関連する
動的カバレッジとリセット
covergroup
はクラス内で定義したり、配列として生成したりすることで、動的にインスタンス化・管理できます。
// パラメータ化された 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
を設定する手間を省けます。
- 前述の通り、
マルチクロックドメインカバレッジ
異なるクロックドメイン間でやり取りされるデータや制御信号のカバレッジを測定するには、それぞれのクロックドメインに適したサンプリングイベントを使用します。
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) 内にクラスメンバーとして定義されます。
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. サンプリングトリガーと初期判定
説明: まず、@(event) や .sample() でトリガーがかかります。covergroup 全体に iff 条件があれば、それが評価され、条件を満たさない場合はここで処理が終了します。iff がなければ C へ進みます。
2. Coverpoint 評価とカウント
説明: グループ全体の条件を満たした場合、各 coverpoint が評価されます。個別の iff 条件、式の評価、ビンとの照合が行われ、illegal_bins にマッチするとエラー、ignore_bins にマッチすると無視されます。有効なビンにマッチすれば、対応するビンのカウントが更新されます。どのビンにもマッチせず default ビンがあればそれがカウントされます。
3. Cross 評価とカウント
説明: coverpoint と同様に、各 cross も評価されます。関連する coverpoint の値に基づいて組み合わせが計算され、定義されたクロスビンと照合されます。Illegal/Ignore ビンは同様に扱われ、マッチすればクロスビンのカウントが更新されます。
4. カバレッジデータベース更新
説明: ビンやクロスビンのカウントが更新されると、内部的なカバレッジデータベースの状態が変わります。
5. レポート
説明: シミュレーション中や終了後に get_coverage() が呼ばれたり、外部ツールがデータベースを読み込んだりすると、その時点でのヒット数と総ビン数(無視ビンを除く)からカバレッジ率が計算され、結果が表示されます。
フロー概要:
- サンプリングイベント発生 または
.sample()
呼び出し。
covergroup
のiff
条件が評価され、真なら続行。 - 各
coverpoint
が評価される:-
coverpoint
のiff
条件が評価される。 - 式が評価され、値が計算される。
- 定義された
bins
と照合される (ignore
/illegal
もチェック)。 - マッチした有効なビンのカウントが増加する。
-
- 各
cross
が評価される:- 関連する
coverpoint
の現在の値(またはヒットしたビン)に基づいてクロス積が計算される。 - 定義されたクロスビン (
bins
やignore_bins
など) と照合される。 - マッチした有効なクロスビンのカウントが増加する。
- 関連する
- 内部のデータベースが更新される。
- レポート要求時 (
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
を指定。その要素固有の設定。
-
型:
- 注意: 全てのオプションやメソッドが全てのツールで完全にサポートされているとは限りません。詳細は使用するシミュレータのマニュアルを参照してください。
参考文献
- IEEE Std 1800™‑2017, IEEE Standard for SystemVerilog—Unified Hardware Design, Specification, and Verification Language (特に Section 19. Functional Coverage)
- Spear, Chris, and Greg Tumbush. SystemVerilog for Verification: A Guide to Learning the Testbench Language Features. Springer, 3rd ed., 2012. (定番の解説書)
- Mehta, Puneet Kumar, and Yan Zhang. Functional Verification Coverage Measurement and Analysis. Springer, 2018. (カバレッジ戦略と分析に特化)
- Accellera Systems Initiative, Universal Verification Methodology (UVM) 1.2 User's Guide (UVM 環境での適用例)
- 各 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):
# 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
でサンプリングします。
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 など) をファイルに保存します。
# 例: 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 に戻す直接的な方法はありません。代替策としては、
- より細かい粒度で
covergroup
を複数定義し、必要なグループだけreset()
する。 - カバレッジレポートツール側で、特定の期間や条件でフィルタリングしてレポートを表示する (データ自体はリセットされない)。
- 非常に高度な使い方として、カバレッジデータベースを直接操作する 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
の式として関数呼び出しを含めることができます。
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 |
活用例
インターフェース/バスプロトコル関連
- プロトコルの各トランザクション種別(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やタグの利用パターンと重複/枯渇状況の観測
- バス/インターコネクトリソース競合による性能劣化パターン(例: レイテンシ増加)
メモリシステム関連
- メモリアクセスパターン(連続読み出し/ランダム読み出し)の比率
- キャッシュヒット/ミスの組み合わせ
- キャッシュラインの置換アルゴリズム(
LRU (Least Recently Used)
,FIFO (First-In First-Out)
, ランダム)の選択パターン -
DDR (Double Data Rate)
メモリのリフレッシュタイミングと他コマンドの衝突パターン -
NAND
フラッシュのページライト/ブロックイレーズ回数の分布 - ウェアレベリングアルゴリズムによるブロック消去回数の分布
- メモリバンク/ランク/チャネル間のアクセス分散パターン
- ページヒット/ミス/コンフリクトの発生比率
- プリフェッチ機構のヒット/ミスと発動条件の組み合わせ
- メモリコントローラのコマンドキュー深度とスループットの関係
- 共有キャッシュにおける競合パターンとヒット率への影響
エラー検出/回復関連
- エラー検出動作(パリティエラー検出、タイムアウト発生)の発生パターン
- フォールトトレラントシステムにおけるフェイルオーバー遷移パターン
- 多重化モジュールにおける一致/不一致検出の発生パターン
- チェックポイント/ロールバック機構の発動条件と成功率
-
ECC (Error Correction Code)
メモリのシングルビット/マルチビットエラー発生と修復結果の組み合わせ - エラー注入シナリオ(注入箇所、注入タイミング、エラータイプ)の網羅度
- 冗長化構成における不一致検出とリカバリシーケンスの実行パターン
割り込み/タイミング制御関連
- 割り込み要因と優先度レベルの組み合わせ
- 割り込みネスト深度別の処理遅延分布
- マルチクロックドメイン間転送のレイテンシ分布
- エンドツーエンド遅延 ($t_{\mathrm{end2end}}$) の分布
- 非同期信号の同期化段数別の遅延分布
-
CDC (Clock Domain Crossing)
プロトコルの状態遷移パターン - 非同期
FIFO (First-In First-Out)
のポインタ同期ロジックの動作パターン - タイミング検証シナリオにおけるコーナーケースとマージン設定値の組み合わせ
データフロー制御関連
-
FIFO
の Full/Empty/AlmostFull/AlmostEmpty 状態遷移 - データストリームのフロー制御バースト数とサイズの組み合わせ
-
QoS (Quality of Service)
スケジューラにおける優先度ごとのスループット分布 - 複数マスター環境でのバス競合発生パターン
-
DMA (Direct Memory Access)
転送のチャネル競合とスケジューリング結果の関係 -
TCP (Transmission Control Protocol)
フロー制御におけるウィンドウサイズの推移パターン - パケットドロップの理由(バッファオーバーフロー、
QoS
違反、TTL (Time To Live)
切れ)の分類と発生頻度 - クレジットベースフロー制御におけるクレジット送受信パターン
電源管理/クロック関連
- 電源管理ドメインの ON/OFF 切り替え頻度と期間の分布
- 動作周波数スケーリング (
DVFS (Dynamic Voltage and Frequency Scaling)
) における電圧/周波数ペアの選択パターン - パワーゲーティング制御信号の状態(Enable/Disable)と期間の分布
- クロックゲーティングの適用パターンとパワー状態の相関
- スリープ/ウェイクアップシーケンスの遷移時間分布
- バッテリー充電プロファイルの定電流/定電圧フェーズ遷移パターン
システム初期化/状態遷移関連
- リセットシーケンス中のステートマシン遷移パターン
- システム起動シーケンス各フェーズの到達有無
- マルチコアにおけるコヒーレンシプロトコル (
MESI (Modified, Exclusive, Shared, Invalid)
,MOESI (Modified, Owned, Exclusive, Shared, Invalid)
) の状態遷移
プロセッサ/アーキテクチャ関連
- CPUの命令タイプ(算術、論理、分岐、メモリアクセス)の使用頻度分布
- 投機的実行の成功/失敗パターン
-
SIMD (Single Instruction, Multiple Data)
/ベクトル演算ユニットの並列度活用パターン - パイプラインハザード(データ、制御、構造)の発生タイプと頻度
- 分岐予測のヒット/ミスと分岐タイプ(条件付き、無条件、直接、間接)の組み合わせ
-
TLB (Translation Lookaside Buffer)
ヒット/ミスとアクセス権限(Read/Write/Execute)の組み合わせ - 演算ユニットや実行ポートの利用率分布
ネットワーク/パケット処理関連
- パケット分類エンジンのルールヒット率と処理経路の分布
-
IPsec (Internet Protocol Security)
トンネルモードにおけるESP (Encapsulating Security Payload)
/AH (Authentication Header)
プロトコルの使用パターン -
QoS
マーキング (DSCP (Differentiated Services Code Point)
値)ごとのパケット遅延分布 -
NAT (Network Address Translation)
変換テーブルのエントリ使用パターンとタイムアウト発生パターン - ヘッダフィールド(IPアドレス、ポート番号、
VLAN ID
)の値範囲の組み合わせ - フラグメント化/再構成処理の発生とパケットサイズの組み合わせ
画像処理/マルチメディア関連
-
H.264
/HEVC (High Efficiency Video Coding)
エンコーダの予測モード(Intra/Inter)選択分布 - 画像処理パイプラインの各ステージ処理時間の分布
- オーディオサンプリングレートとビット深度の組み合わせ
-
HDMI (High-Definition Multimedia Interface)
リンクトレーニングの成功/リトライパターン
セキュリティ/暗号関連
-
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)
) によるアクセス違反検出パターン - セキュアエレメント/トラステッドゾーンへのアクセス要求パターン
デバッグ/診断関連
-
JTAG (Joint Test Action Group)
/SWD (Serial Wire Debug)
インターフェースのアクセスパターン分布 - トレースデータの圧縮率とバッファ溢れイベントの発生パターン
- 自己診断テスト (
BIST (Built-in Self-Test)
) のカバレッジ達成パターンと実行時間の関係 - メモリダンプ機能のアドレス範囲カバレッジ分布
アナログ/ミックスシグナル (`AMS`) 連携
-
ADC (Analog-to-Digital Converter)
/DAC (Digital-to-Analog Converter)
の動作モード(解像度、サンプリングレート)と入力レンジの組み合わせ -
PLL (Phase-Locked Loop)
のロック/アンロック状態遷移と周波数切り替えシーケンス - デジタル制御ループによるアナログパラメータ(ゲイン、バイアス)の調整パターン
FPGA特有
- 部分再構成 (
Partial Reconfiguration
) の実行とコンフィグレーション領域/モジュールの組み合わせ - 高速トランシーバー (
SerDes (Serializer/Deserializer)
) の動作モード(レート、エンコーディング、イコライゼーション設定)の組み合わせ - 特定リソース(
BRAM (Block RAM)
,DSP (Digital Signal Processor)
,LUT (Look-Up Table)
) の使用パターンと競合状態
ソフトウェア連携 / システムレベル
- ハードウェアアクセラレータへのタスクオフロード種別とパラメータの組み合わせ
- ドライバからのレジスタアクセスシーケンス(初期化、通常動作、エラーハンドリング)のパターン
- 共有メモリ/リソースへの複数マスター(CPUコア、
DMA
)からのアクセス競合パターン - OSレベルのイベント(タスクスイッチ、割り込み処理)とハードウェア状態の相関
- 特定ユースケースシナリオにおける主要機能ブロックの活性化パターン
- 特定OSブートシーケンスにおける主要HWブロックのアクセス/活性化パターン
- 特定アプリケーションシナリオ(例: 動画エンコード、AI推論)実行時のリソース(CPU、アクセラレータ、メモリ帯域)利用パターンとボトルネック箇所の観測
- 仮想化環境におけるゲストOSとハイパーバイザー間のHWリソースアクセス競合パターン
コンフィギュレーション / レジスタ設定
- 主要な動作モードと関連するコンフィギュレーション設定値の組み合わせ網羅
- 特定モードにおける設定レジスタ値の組み合わせ
- 設定レジスタの予約ビット/フィールドへの書き込み試行パターン
- 複数の設定が相互に影響する機能における設定値の依存関係の組み合わせ
Low Power Intent (`UPF`/`CPF` 関連)
-
UPF (Unified Power Format)
/CPF (Common Power Format)
で定義されたパワーダウン/リテンション/アイソレーション制御シーケンスの実行パターン - パワーモード遷移(Active -> Retention -> Shutdown -> Activeなど)のシーケンス網羅
- Always-onドメインとスイッチ可能ドメイン間の通信プロトコルの状態遷移
リセットドメイン
- 複数のリセットドメイン間のリセット解除シーケンスのタイミングパターン
- 特定のリセットドメインのみがアサート/デアサートされるシナリオ
- 異なるリセット源(パワーオンリセット、ウォッチドッグリセット、ソフトウェアリセット等)からのリセット発生パターン
以上