# [[DV筆記] Systemverilog - Covergroup](/lMQnyoF6SlKDumL9sEksVQ)
## 前言
驗證通常都會需要加一些covergroup 去特別看要驗的 code 是不是都有覆蓋到,或是把一些function 寫進來去證明真的有 cover到
## 使用情境
Covergroup 可以定義在 package, module, program, interface, or class中
## Covergroup 基本語法
直接看code
```
module tb;
bit [1:0] mode;
bit [2:0] cfg;
//define clk
bit clk;
always #10 clk = ~clk;
//define reset
bit reset=0;
intital begin
#30;
reset=1;
end
covergroup cg (@posedge clk iff (reset)); // 可以在covergroup 在 iff
coverpoint mode iff (reset);//coverpoint 可以用 iff 添加要sample的條件,通常會讓 reset 期間不 sample
endgroup
//實例化covergroup
cg cg_inst;
//randomize variable
initial begin
cg_inst = new();
#30;//after reset
for (int i=0; i<5; i++) begin
mode=$random;
cfg=$random;
end
end
initial begin
#500 $display ("coverage = %0.2f%%", cfg_inst.get_inst_coverage());//%%: 表示百分比%, %0.2f 保留小數點後2位的浮點數
$finish;
end
endmodule
```
另外 covergroup 也可以有傳入的參數,但是只能是 input 或是 ref 類型,input類型的在 instantiate 的時候就傳入,之後不會變動,所以如果要收集coverage的變數要用 ref 類型,這樣的好處是可以重複使用這個 covergroup,跟 function 一樣
```
covergroup address_cov (reg logic [7:0] address, input int low, int high) @(posedge clk); //default 是 input 類型
ADDRESS: coverpoint address {
bins low = {0,low};
bins high = {low,high};
}
endgroup
address_cov acov_low = new(addr,0,10);
address_cov acov_mid = new(adrr,11,20);
address_cov acov_high = new(addr,21,30);
```
補充一種寫法是在 new 的時候不需要傳入參數,在sample的時候才要傳入參數: (雖然好像不常見)
```
covergroup address_cov with function sample(reg logic [7:0] address, input int low, int high) @(posedge clk); //default 是 input 類型
ADDRESS: coverpoint address {
bins low = {0,low};
bins high = {low,high};
}
endgroup
address_cov acov_low = new();
address_cov acov_mid = new();
address_cov acov_high = new();
acov_low.sample(addr,0,10);
acov_mid.sample(adrr,11,20);
acov_high.sample(addr,21,30);
```
常用covergroup 方法:
```
bit [1:0] mode;
covergoup cg;
a: coverpoint mode {bins a = {[0:1]};
bins b = {[2:3]};
}
endcgroup
cg cg_inst;
initial begin
cg_inst = new();
cg_inst.sample(); //如果 covergroup 沒有 觸發條件,就需要用 smaple() 來啟動收集 coverage
cg_inst.get_coverage(); //或是 cg_inst.get_inst_coverage()
//$get_coverage(); 可以得到總體coverage
cg_inst.start(); //enable coverage
cg_inst.stop(); //disable coverage
end
```
## Coverpoints 介紹
### implicity bins
如果沒有特別將 coverpoints 的 bins 標出來,會自動產生 2^n 個 bins:
```
bit [1:0] mode;
bit [2:0] cfg;
bit clk;
always #20 clk = ~clk;
covergroup cg @(posedge clk);
coverpoint mode;
endgroup
cg cg_inst;
intial begin
cg_inst = new();
end
```
上面如果沒有特別把 bins 列出來,則會自動創建:
mode[0]
mode[1]
mode[2]
mode[3]
這四個 bin
### explicity bins
#### 指定coverpoint範圍
可以顯式的把 bins 寫出來,方便確認那些區間是否有 cover 到:
```
covergroup cg @(posedge clk);
covpoint1: coverpoint mode {bins mode_0 = {[0:1]};
bins mode_1 = {[2:3]};
default bin; //default 表示其他值,不會被算進 coverage!
}
endgroup: cg
```
如此就可以明確規範我們要cover的範圍
#### 指定coverpoint的sequence
##### 值的變化
也可以指定特定 bins 變化的 sequence //如果要很精確驗某些 function 感覺很實用!
sequence coverpoint 是用 (),而如果是指定 bins 值是用 {}
```
covergroup cg @(posedge clk);
covpoint1: coverpoint mode {bins mode_0 = (0 => 1);
bins mode_1[] = (1 => 2), (2 => 1);//會有兩個 bins mode_1[0] 和 mode_1[1]
bins other = default sequence; //default 表示其他值,不會被算進 coverage!
}
endgroup: cg
```
值的變化也可以是從範圍到範圍:
```
bins mode_0 = ([0:1] => [2:3]);
...
```
#### 出現多次
如果是需要某個值出現很多次,可以寫: (這邊的語法其實跟 assertion 很類似,之後再來整理一篇assertion)
```
bins mode_0 = (0[*2]); //0連續出現2次
bins mode_1 = (1[*1:2]); //1 連續出現1~2次
//如果要求不需要連續出現
bins mode_2 = (1 => 2[->2] =>0); //1變成2,2出現2次(不需要連續),再變成0
bins mode_3 = (2[=2]); //2 至少出現2次,不要求連續
...
```
#### Wildcard
要使用 wildcard bins,可以用 x,z,? 來表示某一bit 可以為任意
```
wildcard bins mode_4 = {2'b1?}; //cover 11,10
...
```
#### Ignore bins
可以排除一些值
```
ignore_bins b1 = {1}; //1不被計算到 coverage中
...
```
#### Illegal bins
如果出現 illegal bins 了話, simulation 會報錯
```
illegal_bins b1 = {1}; //出現1,simulation 報錯
...
```
### Cross Coverage
指定2個 coverpoints 或是 variable 的交叉點覆蓋率
```
bit [1:0] a,b;
covergroup cg @(posedge clk);
c1: coverpoint a;
c2 coverpoint b;
c1xc2: cross a,b;
endgroup: cg
//或是可以寫
covergroup cov @(posedge clk);
axb: cross a,b;
endgroup: cov
```
a和b各會有4個 bins ,所以 cross 出來的結股會有 16個 bins
user 可以自己定義 cross 後的 bins 的數目,這時候需要用到 binsof 和 intersect:
```
covergroup address_cov () @ (posedge ce);
ADDRESS : coverpoint addr {
bins addr0 = {0};
bins addr1 = {1};
}
CMD : coverpoint cmd {
bins READ = {0};
bins WRITE = {1};
bins IDLE = {2};
}
CRS_USER_ADDR_CMD : cross ADDRESS, CMD {
bins USER_ADDR0_READ = binsof(CMD) intersect {0};//bins本来應該是2*3=6个,這邊定義後結果變成只有2個 bins
}
CRS_AUTO_ADDR_CMD : cross ADDRESS, CMD {
ignore_bins AUTO_ADDR_READ = binsof(CMD) intersect {0};
ignore_bins AUTO_ADDR_WRITE = binsof(CMD) intersect {1} && binsof(ADDRESS) intersect{0};
}
endgroup
```
### Coverage Option 功能
option 主要分為
1. 針對 covergroup instance
2. 針對 covergroup type
#### covergroup instance
語法:
```
option.<option_name> = <expression>;
```
option_name:
| Ooption Name | Description | Allowed in Synatic level |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
| Weight (default =1) | 1. If it is set at the covergroup syntactic level, then it specifies the weight of this covergroup instance for computing the overall instance coverage of the simulation. 2. If it is set at coverpoint or cross syntactic level, then it specifies the weight of a coverpoint or a cross for computing the instance coverage of the enclosing covergrouult =1) | covergroup, coverpoint, cross |
| name=string | set instance name, 如果沒有, tool 會自動給 unique 名字 | covergroup |
| per_instance = boolean(Default value = False/0) | set 1,這樣每個 Instance 的 coverage 才會被列出,不然只會是這個 covergroup average 的結果,通常用在這個 covergroup 重複使用的時候 | covergroup |
| goal = number(Default value = 100) | 設定coverage goal (一般都是100%) | covergroup, coverpoint, cross |
| comment = string | 這個 comment 會出現在 report 中 | covergroup, coverpoint, cross |
| at_least = number (Default value = 1) | 設定 bins 至少需要被cover 幾次才算 cover | covergroup, coverpoint, cross |
| detect_overlap=boolean (Default value = False/0) | 如果 set 1,bins 之間的 range 如果有重疊,tool 會報 warning | covergroup, coverpoint |
| auto_bin_max = number (Default value = 64) | 設定自動 create 最多的 bins數目 | covergroup, coverpoint |
| cross_auto_bin_max = number | 定自動 create 最多的 cross_bins數目 | covergroup cross |
| cross_num_print_missing = number (Default value = 0) | uncovered cross_bins 會 include 在 coverage report中 | covergroup, cross |
example:
```
module func_coverage;
bit [7:0] addr, data;
covergroup c_group;
option.per_instance = 1;
option.comment = "This is the comment";
cp1: coverpoint addr {
option.weight = 2;
option.auto_bin_max = 32;
}
cp2: coverpoint data;
cp1_X_cp2: cross cp1, cp2 {
option.cross_auto_bin_max = 32;
}
endgroup : c_group
c_group cg = new();
initial begin
forever begin
cg.sample();
#5;
end
end
initial begin
$monitor("At time = %0t: addr = %0d, data = %0d", $time, addr, data);
repeat(5) begin
addr = $random;
data = $random;
#5;
end
$display("Coverage = %f", cg.get_coverage());
$finish;
end
endmodule
```
#### covergroup type
類似於 covergroup 的 static member,即所以 covergroup 都看的見這個 member
語法:
```
type_option <option_name> = <expression>;
```
option name:
| Option Name | Description | Allowed in Synatic level |
| -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
| Weight (default =1) | 1. If it is set at the covergroup syntactic level, then it specifies the weight of this covergroup instance for computing the overall instance coverage of the simulation. 2. If it is set at coverpoint or cross syntactic level, then it specifies the weight of a coverpoint or a cross for computing the instance coverage of the enclosing covergrouult =1) | covergroup, coverpoint, cross |
| goal = number(Default value = 100) | 設定coverage goal (一般都是100%) | covergroup, coverpoint, cross |
| comment = string | 這個 comment 會出現在 report 中 | covergroup, coverpoint, cross |
| strobe = constant_number (default value = 0) | Similar to the $strobe system task, if it sets to 1, sampling is done at the end of the time slot. | covergroup |
example:
```
module func_coverage;
bit [7:0] addr, data;
covergroup c_group;
option.per_instance = 1;
type_option.comment = "This is the comment";
type_option.strobe = 1;
cp1: coverpoint addr {
type_option.weight = 2;
}
cp2: coverpoint data;
cp1_X_cp2: cross cp1, cp2;
endgroup : c_group
c_group cg = new();
initial begin
forever begin
cg.sample();
#5;
end
end
initial begin
$monitor("At time = %0t: addr = %0d, data = %0d", $time, addr, data);
repeat(5) begin
addr = $random;
data = $random;
#5;
end
$display("Coverage = %f", cg.get_coverage());
$finish;
end
endmodule
```
## 結語
Coverage 的語法真的滿雜的,整理起來以後要用的時候應該方便很多,真的要把coverage 寫的很全面感覺也是不小功夫,邊作筆記又學到了很多東西!感覺會寫 coverage也是 DV獨特且重要的技能。