本記事はSystem Verilogのcovergroupの説明シリーズです。全体でかなりボリュームがあるため、以下に分割しています。上から順番に読んでいただくことをお勧めします。
本記事ではSystem Verilogのcovergroupのcross binについて説明します。
本機能については、シミュレータがどこまでサポートしているかまちまちのため、主要なシミュレータがサポートしている基本的な機能のみについて説明します。
cross binの作り方
crossの後に対象となる変数やbinを記述するだけで、cross binが生成されます。下記例ではそれぞれall_dats, all_bins, dat_binsという名前で3つのcross binを生成しています。
logic [1:0] dat1;
logic [1:0] dat2;
covergroup cg;
bin1: coverpoint dat1 {
bins s = {[0:1]};
bins l = {[2:3]};
}
bin2: coverpoint dat2 {
bins s = {[0:1]};
bins l = {[2:3]};
}
all_dats: cross dat1, dat2; // All combinations of dat1 x dat2, that is 16 combinations.
all_bins: cross bin1, bin2; // All combinations of bin1 x bin2, that is 4 combinations.
dat_bin: cross dat1, bin2; // variable x bin, 8 combinations.
endcovergroup
binsof
cross binでは、binsofによりbinを集約して総数を減らすことができます。
binsofの機能
binsofにbinを指定した場合、そのbinにマッチするものは全てを一つのbinとして扱います。下記例では、bin1.sにマッチする組み合わせは全てをbin_sとしています。dat2の値にかかわらず、bin1.sにマッチするものが全て一つのbinになります。この時cross binのbinsでカバーされない組み合わせについてはbinが自動生成されます。この点はcoverpointと挙動が違いますので注意してください。coverpointではbinsで指定していない範囲はbinが自動生成されることはありません。
logic [1:0] dat1;
logic [1:0] dat2;
covergroup cg;
bin1: coverpoint dat1 {
bins s = {[0:1]};
bins l = {[2:3]};
}
cbins_v: cross bin1, dat2 {
bins bin_s = binsof(bin1.s); // A bin covers all combinations below:
// <s, 0>, <s, 1>, <s, 2>, <s, 3>
// Bins will be automatically created for the combinations below
// <l, 0>, <l, 1>, <l, 2>, <l, 3>
}
endcovergroup
##binsof同士の論理演算
binsof同士で論理演算を取ったものをcross binとすることが可能です。&&, ||, !, ()が使用可能です。
logic [1:0] dat1;
logic [1:0] dat2;
covergroup cg;
option.per_instance = 1;
bin1: coverpoint dat1 {
bins s = {[0:1]};
bins l = {[2:3]};
}
bin2: coverpoint dat2 {
bins s = {[0:1]};
bins l = {[2:3]};
}
useOfBinsof: cross bin1, bin2 {
bins bin1_is_s = binsof(bin1.s); // <s, s>, <s.l>
bins bin_s_and_s = binsof(bin1.s) && binsof(bin2.s); // <s, s>
bins bin_s_or_s = binsof(bin1.s) || binsof(bin2.s); // <s, s>, <s, l>, <l, s>
bins bin_not_l = !binsof(bin1.l); // <s, s>, <s, l>
bins bin_paren = (binsof(bin1.s) || binsof(bin2.s)) && binsof(bin2.l); // <s, l>
// Bins for the combinations that are not specified will be generated automatically.
// <l, l>
}
intersect
上記の例はcoverpointのbinを対象にcross binを作成しましたが、値を直接指定してcross binを作ることも可能です。その機能がintersectです。
intersectの対象がcoverpointのbinの場合
coverpointのbinでなく、値でcross binを定義することができます。以下の書式になります。
bins bin_name = binsof (bin_name) intersect(range);
この場合まず_range_に対応するcoverpoint binが抽出され、それに対して集約されたcross binが生成されます。以下の例のcbin_b_0の場合、bin1ではintersectで0が指定されていますが、dat1が0となるcoverpoint bin名はsとなります。従ってbin1がsの時の全ての組み合わせが集約され、{s, s}と{s, l}の組み合わせが対象になります。cbin_b_1の場合でも対象となるbin1のbinはsのみなので同じ結果となります。一方cbin_b_2の場合は対象となるbin1のbinがs, l両方になるので全ての組み合わせが一つのbinに集約されます。
covergroup cg;
bin1: coverpoint dat1 {
bins s = {[0:1]};
bins l = {[2:3]};
}
bin2: coverpoint dat2 {
bins s = {[0:1]};
bins l = {[2:3]};
}
cbins_b_0: cross bin1, bin2 {
bins bin0 = binsof(bin1) intersect {0}; // <s, s>, <s, l>
// <l, s>, <l, l>
}
cbins_b_1: cross bin1, bin2 {
bins bin0 = binsof(bin1) intersect {[0:1]}; // <s, s>, <s, l>
// <l, s>, <l, l>
}
cbins_b_2: cross bin1, bin2 {
bins bin0 = binsof(bin1) intersect {[0:2]}; // <s, s>, <s, l>, <l, s>, <l, l>
// No auto bin
}
endgroup
intersectの対象が変数や信号、functionの戻り値の場合
bins bin_name = binsof (variable) intersect(range);
全組み合わせのうち、_variable_で指定した変数(または信号、functionの戻り値等)が_range_を一つのbinとして集約します。
logic [1:0] dat1;
logic [1:0] dat2;
covergroup cg;
cbins_v: cross dat1, dat2 {
bins bin1_0 = binsof(dat1) intersect {[0:2]}; // A bin covers all combinations below:
// <0, 0>, <0, 1>, <0, 2>, <0, 3>
// <1, 0>, <1, 1>, <1, 2>, <1, 3>
// <2, 0>, <2, 1>, <2, 2>, <2, 3>
// Bins will be automatically created for the combinations below
// <3, 0>, <3, 1>, <3, 2>, <3, 3>
}
endgroup
ignore_bin
不必要なbinはignore_binに指定することで、coverageのカウントから外すことができます。
useOfIgn: cross dat1, dat2 {
ignore_bins ign = binsof (dat1) intersect {[0:2]} || //<0, 0>, <0, 1>, <0, 2>, <0, 3>,
binsof (dat2) intersect {[0:1]}; //<1, 0>, <1, 1>, <1, 2>, <1, 3>,
//<2, 0>, <2, 1>, <2, 2>, <2, 3>,
//<3, 0>, <3, 1>
// Automatically Created cross bins
// <3, 2>, <3, 3>
}
条件に一致した時のみサンプリング
coverpointと同様にcross binでもiffを使用して、cross binまたはその中の個々のbinに対して、条件に一致した時のみカバレッジのサンプリングを行うように指定できます。
cond1: cross bin1, bin2 iff (face == front); // Collect coverage only when face == front
cond2: cross bin1, bin2 {
bins bin1s = binsof(bin1.s) iff (face == front); // Collect coverage only when face == front
// Other bins are always collected
}
以下の動作はスペックに記述が見つかりませんでしたが、crossの要素となるcoverpointにiffが使用されている場合、crossの要素となっているいずれかのcoverpointがサンプリングされない時はそのcrossカバレッジもサンプリングされないようです。調べた限りどのシミュレーターでも同じ動作でした。
cond3はbins_cndのサンプリングが行われない時は (face != frontの時は)サンプリングが行われません。
cond4はbins_cnd2のbin zeroのサンプリングが行われ無い時は (dat1 == 0 && face != front の時は)サンプリングが行われません。
logic [1:0] dat1;
logic [1:0] dat2;
rand face_t face;
covergroup cg;
bins_cnd1: coverpoint dat1 iff (face == front);
bins_cnd2: coverpoint dat1 {
bins zero = {0} iff (face == front);
bins int_num[] = {[1:$]};
}
cond3: cross bins_cnd1, dat2;
cond4: cross bins_cnd2, dat2;
endgroup
サンプルプログラム
以下が今までの説明をまとめたサンプルプログラムです。
class MyTest;
typedef enum logic {front, back} face_t;
logic [1:0] dat1;
logic [1:0] dat2;
rand face_t face;
covergroup cg;
option.per_instance = 1;
bin1: coverpoint dat1 {
bins s = {[0:1]};
bins l = {[2:3]};
}
bin2: coverpoint dat2 {
bins s = {[0:1]};
bins l = {[2:3]};
}
bins_cnd1: coverpoint dat1 iff (face == front);
bins_cnd2: coverpoint dat1 {
bins zero = {0} iff (face == front);
bins int_num[] = {[1:$]};
}
all_dats: cross dat1, dat2; // All combinations of dat1 x dat2, that is 16 combinations.
all_bins: cross bin1, bin2; // All combinations of bin1 x bin2, that is 4 combinations.
dat_bin: cross dat1, bin2; // Combination of variable x bin
useOfBinsof: cross bin1, bin2 {
bins bin1_is_s = binsof(bin1.s); // <s, s>, <s.l>
bins bin_s_and_s = binsof(bin1.s) && binsof(bin2.s); // <s, s>
bins bin_s_or_s = binsof(bin1.s) || binsof(bin2.s); // <s, s>, <s, l>, <l, s>
bins bin_not_l = !binsof(bin1.l); // <s, s>, <s, l>
bins bin_paren = (binsof(bin1.s) || binsof(bin2.s)) && binsof(bin2.l); // <s, l>
// Bins for the combinations that are not specified will be generated automatically.
// <l, l>
}
cbins_v: cross dat1, dat2 {
bins bin1_0 = binsof(dat1) intersect {[0:2]}; // A bin covers all combinations below:
// <0, 0>, <0, 1>, <0, 2>, <0, 3>
// <1, 0>, <1, 1>, <1, 2>, <1, 3>
// <2, 0>, <2, 1>, <2, 2>, <2, 3>
// Bins will be automatically created for the combinations below
// <3, 0>, <3, 1>, <3, 2>, <3, 3>
}
cbins_b_0: cross bin1, bin2 {
bins bin0 = binsof(bin1) intersect {0}; // Equivalent to binsof(bin1.s)
// <s, s>, <s, l>
// <l, s>, <l, l>
}
cbins_b_1: cross bin1, bin2 {
bins bin0 = binsof(bin1) intersect {[0:1]}; // Equivalent to binsof(bin1.s)
// <s, s>, <s, l>
// <l, s>, <l, l>
}
cbins_b_2: cross bin1, bin2 {
bins bin0 = binsof(bin1) intersect {[0:2]}; // Equivalent to binsof(bin1.s) || binsof(bin1.l)
// <s, s>, <s, l>, <l, s>, <l, l>
// No auto bin
}
useOfIgn: cross dat1, dat2 {
ignore_bins ign = binsof (dat1) intersect {[0:2]} || //<0, 0>, <0, 1>, <0, 2>, <0, 3>,
binsof (dat2) intersect {[0:1]}; //<1, 0>, <1, 1>, <1, 2>, <1, 3>,
//<2, 0>, <2, 1>, <2, 2>, <2, 3>,
//<3, 0>, <3, 1>
// Automatically Created cross bins
// <3, 2>, <3, 3>
}
cond1: cross bin1, bin2 iff (face == front); // Collect coverage only when face == front
cond2: cross bin1, bin2 {
bins bin1s = binsof(bin1.s) iff (face == front); // Collect coverage only when face == front
// Other bins are always collected
}
cond3: cross bins_cnd1, dat2; //bins_cnd1 has iff
cond4: cross bins_cnd2, dat2; //bins_cnd2 has a bin with iff
endgroup
function new();
cg = new;
endfunction
function void run();
for (int i = 0; i < 2**$size(dat1); i++) begin
for (int j = 0; j < 2**$size(dat2); j++) begin
for (int k = 0; k < 2**$size(face); k++) begin
dat1 = i;
dat2 = j;
face = face_t'(k);
cg.sample();
end
end
end
endfunction
endclass
program top;
initial begin
MyTest myTest;
myTest = new;
myTest.run();
end
endprogram
以下がカバレッジレポートの抜粋となります。
CLASS - /MyTest : work.MyTest
SUMMARY
=============================================
| Coverage Type | Weight | Hits/Total |
=============================================
| Covergroup Coverage | 1 | 100.000% |
|---------------------|--------|------------|
| Types | | 1 / 1 |
=============================================
WEIGHTED AVERAGE LOCAL: 100.000%
COVERGROUP COVERAGE
=====================================================================
| Covergroup | Hits | Goal / | Status |
| | | At Least | |
=====================================================================
| TYPE /MyTest/cg | 100.000% | 100.000% | Covered |
=====================================================================
| INSTANCE <UNNAMED1> | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| COVERPOINT <UNNAMED1>::bin1 | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin s | 16 | 1 | Covered |
| bin l | 16 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| COVERPOINT <UNNAMED1>::bin2 | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin s | 16 | 1 | Covered |
| bin l | 16 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| COVERPOINT <UNNAMED1>::bins_cnd1 | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin auto[0] | 4 | 1 | Covered |
| bin auto[1] | 4 | 1 | Covered |
| bin auto[2] | 4 | 1 | Covered |
| bin auto[3] | 4 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| COVERPOINT <UNNAMED1>::bins_cnd2 | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin zero | 4 | 1 | Covered |
| bin int_num[1] | 8 | 1 | Covered |
| bin int_num[2] | 8 | 1 | Covered |
| bin int_num[3] | 8 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| COVERPOINT <UNNAMED1>::dat1 | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin auto[0] | 8 | 1 | Covered |
| bin auto[1] | 8 | 1 | Covered |
| bin auto[2] | 8 | 1 | Covered |
| bin auto[3] | 8 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| COVERPOINT <UNNAMED1>::dat2 | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin auto[0] | 8 | 1 | Covered |
| bin auto[1] | 8 | 1 | Covered |
| bin auto[2] | 8 | 1 | Covered |
| bin auto[3] | 8 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| CROSS <UNNAMED1>::all_dats | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin <auto[0],auto[0]> | 2 | 1 | Covered |
| bin <auto[0],auto[1]> | 2 | 1 | Covered |
| bin <auto[0],auto[2]> | 2 | 1 | Covered |
| bin <auto[0],auto[3]> | 2 | 1 | Covered |
| bin <auto[1],auto[0]> | 2 | 1 | Covered |
| bin <auto[1],auto[1]> | 2 | 1 | Covered |
| bin <auto[1],auto[2]> | 2 | 1 | Covered |
| bin <auto[1],auto[3]> | 2 | 1 | Covered |
| bin <auto[2],auto[0]> | 2 | 1 | Covered |
| bin <auto[2],auto[1]> | 2 | 1 | Covered |
| bin <auto[2],auto[2]> | 2 | 1 | Covered |
| bin <auto[2],auto[3]> | 2 | 1 | Covered |
| bin <auto[3],auto[0]> | 2 | 1 | Covered |
| bin <auto[3],auto[1]> | 2 | 1 | Covered |
| bin <auto[3],auto[2]> | 2 | 1 | Covered |
| bin <auto[3],auto[3]> | 2 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| CROSS <UNNAMED1>::all_bins | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin <s,s> | 8 | 1 | Covered |
| bin <s,l> | 8 | 1 | Covered |
| bin <l,s> | 8 | 1 | Covered |
| bin <l,l> | 8 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| CROSS <UNNAMED1>::dat_bin | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin <auto[0],s> | 4 | 1 | Covered |
| bin <auto[0],l> | 4 | 1 | Covered |
| bin <auto[1],s> | 4 | 1 | Covered |
| bin <auto[1],l> | 4 | 1 | Covered |
| bin <auto[2],s> | 4 | 1 | Covered |
| bin <auto[2],l> | 4 | 1 | Covered |
| bin <auto[3],s> | 4 | 1 | Covered |
| bin <auto[3],l> | 4 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| CROSS <UNNAMED1>::useOfBinsof | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin <l,l> | 8 | 1 | Covered |
| bin bin1_is_s | 16 | 1 | Covered |
| bin bin_s_and_s | 8 | 1 | Covered |
| bin bin_s_or_s | 24 | 1 | Covered |
| bin bin_not_l | 16 | 1 | Covered |
| bin bin_paren | 8 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| CROSS <UNNAMED1>::cbins_v | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin <auto[3],auto[0]> | 2 | 1 | Covered |
| bin <auto[3],auto[1]> | 2 | 1 | Covered |
| bin <auto[3],auto[2]> | 2 | 1 | Covered |
| bin <auto[3],auto[3]> | 2 | 1 | Covered |
| bin bin1_0 | 24 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| CROSS <UNNAMED1>::cbins_b_0 | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin <l,s> | 8 | 1 | Covered |
| bin <l,l> | 8 | 1 | Covered |
| bin bin0 | 16 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| CROSS <UNNAMED1>::cbins_b_1 | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin <l,s> | 8 | 1 | Covered |
| bin <l,l> | 8 | 1 | Covered |
| bin bin0 | 16 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| CROSS <UNNAMED1>::cbins_b_2 | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin bin0 | 32 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| CROSS <UNNAMED1>::useOfIgn | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin <auto[3],auto[2]> | 2 | 1 | Covered |
| bin <auto[3],auto[3]> | 2 | 1 | Covered |
| ignore bin ign | 28 | - | Occurred |
|----------------------------------|----------|----------|----------|
| CROSS <UNNAMED1>::cond1 | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin <s,s> | 4 | 1 | Covered |
| bin <s,l> | 4 | 1 | Covered |
| bin <l,s> | 4 | 1 | Covered |
| bin <l,l> | 4 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| CROSS <UNNAMED1>::cond2 | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin <l,s> | 8 | 1 | Covered |
| bin <l,l> | 8 | 1 | Covered |
| bin bin1s | 8 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| CROSS <UNNAMED1>::cond3 | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin <auto[0],auto[0]> | 1 | 1 | Covered |
| bin <auto[0],auto[1]> | 1 | 1 | Covered |
| bin <auto[0],auto[2]> | 1 | 1 | Covered |
| bin <auto[0],auto[3]> | 1 | 1 | Covered |
| bin <auto[1],auto[0]> | 1 | 1 | Covered |
| bin <auto[1],auto[1]> | 1 | 1 | Covered |
| bin <auto[1],auto[2]> | 1 | 1 | Covered |
| bin <auto[1],auto[3]> | 1 | 1 | Covered |
| bin <auto[2],auto[0]> | 1 | 1 | Covered |
| bin <auto[2],auto[1]> | 1 | 1 | Covered |
| bin <auto[2],auto[2]> | 1 | 1 | Covered |
| bin <auto[2],auto[3]> | 1 | 1 | Covered |
| bin <auto[3],auto[0]> | 1 | 1 | Covered |
| bin <auto[3],auto[1]> | 1 | 1 | Covered |
| bin <auto[3],auto[2]> | 1 | 1 | Covered |
| bin <auto[3],auto[3]> | 1 | 1 | Covered |
|----------------------------------|----------|----------|----------|
| CROSS <UNNAMED1>::cond4 | 100.000% | 100.000% | Covered |
|----------------------------------|----------|----------|----------|
| bin <zero,auto[0]> | 1 | 1 | Covered |
| bin <zero,auto[1]> | 1 | 1 | Covered |
| bin <zero,auto[2]> | 1 | 1 | Covered |
| bin <zero,auto[3]> | 1 | 1 | Covered |
| bin <int_num[1],auto[0]> | 2 | 1 | Covered |
| bin <int_num[1],auto[1]> | 2 | 1 | Covered |
| bin <int_num[1],auto[2]> | 2 | 1 | Covered |
| bin <int_num[1],auto[3]> | 2 | 1 | Covered |
| bin <int_num[2],auto[0]> | 2 | 1 | Covered |
| bin <int_num[2],auto[1]> | 2 | 1 | Covered |
| bin <int_num[2],auto[2]> | 2 | 1 | Covered |
| bin <int_num[2],auto[3]> | 2 | 1 | Covered |
| bin <int_num[3],auto[0]> | 2 | 1 | Covered |
| bin <int_num[3],auto[1]> | 2 | 1 | Covered |
| bin <int_num[3],auto[2]> | 2 | 1 | Covered |
| bin <int_num[3],auto[3]> | 2 | 1 | Covered |
=====================================================================
EDA Playgroundにソースコードがありますので、WEB browserから各自実行して結果を確かめることができます。実行後にダウンロードされるファイルの中のcov.txtがカバレッジリポートになります。
[covergroup cross coverage samlpe] (https://www.edaplayground.com/x/2xD8)
参考文献
"19 Functional coverage". 1800-2017 - IEEE Standard for SystemVerilog--Unified Hardware Design, Specification, and Verification Language. pp.553-590.