在covergroup中使用阻塞表达式时,是否仍需调用.sample()指令?
Covergroup触发方式的疑问
Covergroup既可以通过过程代码中的.sample()采样指令触发,也可以通过其内部的@(clk)或@(signal)这类阻塞表达式触发。如果在covergroup中已经实现了阻塞表达式,还需要调用.sample()采样指令吗?
用户提供的示例代码:
class func_cov extends uvm_subscriber #(seq_item); covergroup cg @(posedge clk); option.per_instance = 1; // Per instance coverage option.auto_bin_max = 256; // Set maximum number of bins option.type_option = UVM_UNSIGNED; // Set coverage type to unsigned option.weight = 1; // Set coverage weight // Add coverage points to the covergroup coverpoint req.addr { bins range[] = {0, 255, 512, 1023}; } coverpoint req.data { bins data_range[] = {[0:255], [256:511], [512:767], [768:1023]}; } endgroup function new(string name = "func_cov", uvm_component parent = null); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); cg = new("cg", this); endfunction function void write(seq_item req); // Collect coverage data cg.sample(); endfunction endclass
解答
不需要再调用.sample(),两种触发方式二选一即可,同时使用会导致重复采样,干扰覆盖统计结果。
两种触发方式的逻辑差异
- 带事件触发的covergroup:当定义时指定了
@(posedge clk)这类触发事件,每当事件发生时,covergroup会自动对内部coverpoint的变量进行采样,无需额外调用.sample()。这种方式适合需要严格对齐时钟沿的采样场景。 - 显式调用
.sample()的covergroup:如果covergroup定义时没有指定触发事件,必须通过主动调用.sample()来触发采样,通常在数据更新完成后执行(比如UVM subscriber拿到新的事务时)。
针对示例代码的修正
示例代码同时使用了时钟触发和.sample(),属于重复触发,需要调整:
方案1:保留时钟触发,移除.sample()
需要把传入的事务存到类的成员变量中,让covergroup在时钟沿到来时采样这个变量:
class func_cov extends uvm_subscriber #(seq_item); seq_item req; // 定义成员变量存储事务 covergroup cg @(posedge clk); option.per_instance = 1; // 每个实例独立统计覆盖 option.auto_bin_max = 256; // 设置自动分箱最大数量 option.type_option = UVM_UNSIGNED; // 覆盖类型设为无符号 option.weight = 1; // 设置覆盖权重 // 覆盖点定义 coverpoint req.addr { bins range[] = {0, 255, 512, 1023}; } coverpoint req.data { bins data_range[] = {[0:255], [256:511], [512:767], [768:1023]}; } endgroup function new(string name = "func_cov", uvm_component parent = null); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); cg = new("cg", this); endfunction function void write(seq_item t); // 将传入事务赋值给成员变量,供时钟沿触发采样 req = t; endfunction endclass
方案2:移除时钟触发,保留.sample()
适合需要在拿到事务时立即采样的场景:
class func_cov extends uvm_subscriber #(seq_item); covergroup cg; // 移除时钟触发事件 option.per_instance = 1; // 每个实例独立统计覆盖 option.auto_bin_max = 256; // 设置自动分箱最大数量 option.type_option = UVM_UNSIGNED; // 覆盖类型设为无符号 option.weight = 1; // 设置覆盖权重 // 覆盖点定义 coverpoint req.addr { bins range[] = {0, 255, 512, 1023}; } coverpoint req.data { bins data_range[] = {[0:255], [256:511], [512:767], [768:1023]}; } endgroup function new(string name = "func_cov", uvm_component parent = null); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); cg = new("cg", this); endfunction function void write(seq_item req); // 拿到事务后立即触发采样 cg.sample(); endfunction endclass
总结
根据采样时机需求选择一种触发方式即可:
- 若需对齐时钟沿采样:使用事件触发,不要调用
.sample() - 若需在数据更新时立即采样:移除事件触发,显式调用
.sample()
内容的提问来源于stack exchange,提问作者bu-ral
相关产品推荐
相关产品推荐

