多通道整形器模块验证 V2.2_UVM寄存器模型2,常规方法,使用场景 - 知乎
一、前门访问 & 后门访问
- 定义
- 通过总线在寄存器模型上进行读写操作UVC实现总线物理时序访问
- 物理时序协议耗时, 真实的物理操作
- 两种访问寄存器前门的方式write, write_reg
- 第一种方法。
/************************一:reg方法***************************/ virtual task write( output uvm_status_e status, input uvm_reg_data_t value, input uvm_path_e path = UVM_DEFAULT_PATH, input uvm_reg_map map = null, input uvm_sequence_base parent = null, input int prior = -1, input uvm_object extension = null, input string fname = "", input int lineno = 0 ) /************************二:uvm_reg_sequence方法***************************/ virtual task write_reg( input uvm_reg rg, output uvm_status_e status, input uvm_reg_data_t value, input uvm_path_e path = UVM_DEFAULT_PATH, input uvm_reg_map map = null, input int prior = -1, input uvm_object extension = null, input string fname = "", input int lineno = 0 )
2、后门访问
- 定义:
- 通过仿真器提供的可直接访问信号的手段
- UVM DPI,uvm_hdl_read(),uvm_hdl_deposit()
- 功能
- 读取信号路径中某个值value
- force某个值
- 实现后门访问
class mcdf_rgm extends uvm_reg_block; `uvm_object_utils(mcdf_rgm) rand ctrl_reg chnl0_ctrl_reg; rand ctrl_reg chnl1_ctrl_reg; uvm_reg_map map; function new(string name = "mcdf_rgm"); super.new(name, UVM_NO_COVERAGE); endfunction ... // specify HDL path,②各寄存器成员及HDL一侧地址映射 chnl0_ctrl_reg.add_hdl_path_slice($sformatf("mem[ ]", `SLV0_RW_REG), 0, 32); chnl1_ctrl_reg.add_hdl_path_slice($sformatf("mem[ ]", `SLV1_RW_REG), 0, 32); //①关联寄存器模型DUT一端 add_hdl_path("tb.dut.ctrl_regs_inst"); //③最后以lock_model()结束地址映射关系 lock_model(); endfunction endclass
要点:
- 后门访问比前门访问更方便、更快,但不能仅仅依靠后门。
- 前门和后门的混合访问有助于寄存器验证的完整性
- 大型寄存器测试方法:前门检查物理通道,后期节省时间
- quiry 寄存器:寄存器只能写一次,建议物理访问,以确保硬件行为反映真实性
- 随机模拟寄存器值不可预测的硬件配置先后门,然后前门
- 排除地址映射错误,前门写,后门读
- 状态寄存器的触发器延迟
二、寄存器模型常规方法
- mirrored value:表示当前硬件的已知状态值
- desired value:首先用寄存器模型修改软件的对象值(set),然后用该值更新硬件值(update)
通过update保持三个值相同
- actual value:硬件的真实值
- 自动预测
- 定义:
- 自动记录每个寄存器的读写值,并在后台自动调用predict()方法
- 适用场景:
- 验证环境的rgm中缺少mon or predictor
- 使用后门访问时
- 不适用场景
- 其他的sequence直接在总线层面操作寄存器(跳过寄存器级别)write()/read())
- 定义:
- 显示预测
- 定义
- 依赖于monitor从物理总线捕获总线事务,并将捕获的事务传递给外部例化predictor
- 预测步骤
- 拿到monitor监控总线bus_trans,其内容与bus_seq_item内容完全一致
- predictor能够拿到adapter的句柄,bus2reg函数将被读回bus_trans通过adapter转化为RGM可以识别的uvm_reg_item类型
class mcdf_env extends uvm_env; ... //UVC monitor能够监控需要具备捕捉事务的功能和相应性analysis port,并连接到predictor的bus_in ap端口 reg_agt.monitor.mon_ana_port.connect(predictor.bus_in); //predictor拿到adapter和map句柄 predictor.map = rgm.map; predictor.adapter = adapter; virt_sqr.rgm = rgm; endfunction endclass: mcdf_env
- 最后,结合map中的reg名称,转换后的数据更新到每个数据reg field内部的值
-
- UVC monitor能够监控需要具备捕捉事务的功能和相应性analysis port,并连接到predictor的bus_in ap端口
- predictor拿到adapter和map句柄
- reset()/get_reset():_复位对象:寄存器模型
- 按照寄存器的描述实现复位值吗?
- 读取寄存器模型的复位值
- 前门访问获得的寄存器复位值
- mirror
- 前门可以是后门。在修改镜像值之前,您还可以选择是否将读回值与模型中的原始镜像值进行比较。act和mir一致
rg.chnl0_ctrl_reg.mirror(status, UVM_CHECK, UVM_BACKDOOR);
- set()/update()_对象:寄存器模型
- 通过该方法可以修改期望值,而在寄存器配置时先对其随机化,再配置个别域或者域。若寄存器的期望值与镜像值不同时,可以通过update()方法来将不同的(DUT)寄存器通过前门或后门访问的方式做全部修改。
- 优点
- 较write()和poke()的写寄存器方式更为灵活
- 实现随机化寄存器配置值(随机值结合某些域的指定值写入到寄存器)
- 模拟更多不可预知的寄存器应用场景
- update()强大的批量操作
对某个域作操作
void'(rgm.chnl0_ctrl_reg.randomize());
rgm.chnl0_ctrl_reg.pkt_len.set('h3);
rgm.update(status, UVM_FRONTDOOR, .parent(this));
4、mem与reg的联系和差别
- 寄存器模型(rgm)内建sequence
- 禁止域名:uvm_resource_db :对状态寄存器的保留位禁止掉。
- 内建sequences目的
- 测试寄存器模型,寄存器的写入值可以准确地反映到硬件中地寄存器
- 实现前提
class mcdf_reg_builtin_virtual_sequence extends mcdf_base_virtual_sequence;
`uvm_object_utils(mcdf_reg_builtin_virtual_sequence)
...
task do_reg();
// ① sequences创建
uvm_reg_hw_reset_seq reg_rst_seq = new();
uvm_reg_bit_bash_seq reg_bit_bash_seq = new();
uvm_reg_access_seq reg_acc_seq = new();
// wait reset asserted and release② 复位信号的声明与释放
@(negedge p_sequencer.intf.rstn);
@(posedge p_sequencer.intf.rstn);
`uvm_info("BLTINSEQ", "register reset sequence started", UVM_LOW)
//③ 将寄存器模型复位
rgm.reset();
//④ 将寄存器句柄与sequence内的model连接
reg_rst_seq.model = rgm;
//⑤ 将seq挂载到virt_sqr内的reg_sqr上
reg_rst_seq.start(p_sequencer.reg_sqr);
`uvm_info("BLTINSEQ", "register reset sequence finished", UVM_LOW)
`uvm_info("BLTINSEQ", "register bit bash sequence started", UVM_LOW)
// reset hardware register and register model
p_sequencer.intf.rstn <= 'b0;
repeat(5) @(posedge p_sequencer.intf.clk);
p_sequencer.intf.rstn <= 'b1;
rgm.reset();
reg_bit_bash_seq.model = rgm;
reg_bit_bash_seq.start(p_sequencer.reg_sqr);
`uvm_info("BLTINSEQ", "register bit bash sequence finished", UVM_LOW)
`uvm_info("BLTINSEQ", "register access sequence started", UVM_LOW)
// reset hardware register and register model
p_sequencer.intf.rstn <= 'b0;
repeat(5) @(posedge p_sequencer.intf.clk);
p_sequencer.intf.rstn <= 'b1;
rgm.reset();
reg_acc_seq.model = rgm;
reg_acc_seq.start(p_sequencer.reg_sqr);
`uvm_info("BLTINSEQ", "register access sequence finished", UVM_LOW)
endtask
endclass: mcdf_reg_builtin_virtual_sequence
三、
- 使用寄存器模型地场景
- 全局的影子寄存器(LMU(LOCAL MEMORY UNIT))
- 定义: 类似寄存器模型镜像值的方法
- 功能
- 暂存当时写入寄存器的值
- 非易失,省略读取寄存器的步骤,LMU代替
- 响应迅速——无需经过物理总线
- 全局的影子寄存器(LMU(LOCAL MEMORY UNIT))
-
- 对硬件数据通路作数据比对 :_常规用法
- 利用寄存器模型的镜像值可以实现实时读取
- 对硬件数据通路作数据比对 :_常规用法
- 内部自动收集模式
- 例化,采样
- cg自动生成,寄存器有成千上万个时,合理例化以及使能采样。验证前期无需例化cg,后期需要采集功能覆盖率时,再考虑例化、使能采样
- 调用has_coverage()来判断uvm_reg::m_has_cover的值
- 例化,采样
/*****************uvm_coverage_model_e*********************/
UVM_NO_COVERAGE
UVM_CVR_REG_BITS
UVM_CVR_ADDR_MAP
UVM_CVR_FIELD_VALS
UVM_CUR_ALL
-
-
- sample()
- read(), write()方法的回调函数,保证自动采样数据
- sample_value()
- 供外部调用的方法,在特定事件触发时调用, 通过get_coverage()方法判断是否允许进行覆盖率采样
- sample()
- 缺点
- 不灵活,
- 默认采样所有的域包括如保留域
- 一个位宽很大的域
- 不够智能
- 无法使用交叉覆盖率组合出更多有意义的运用场景
- 不同chnl的
- 不灵活,
-
class ctrl_reg extends uvm_reg;
`uvm_object_utils(ctrl_reg)
uvm_reg_field reserved;
rand uvm_reg_field pkt_len;
rand uvm_reg_field prio_level;
rand uvm_reg_field chnl_en;
covergroup value_cg;
//将覆盖率信息保存于cg database中并打印报告
option.per_instance = 1;
//应该去掉保留域的采样
reserved: coverpoint reserved.value[25:0];
//关系的len.value为一个范围,不够灵活,无法指定每个bin的值
pkt_len: coverpoint pkt_len.value[2:0];
prio_level: coverpoint prio_level.value[1:0];
chnl_en: coverpoint chnl_en.value[0:0];
endgroup
function new(string name = "ctrl_reg");
//默认的UVM_CVR_ALL代表包含所有覆盖率类型
super.new(name, 32, UVM_CVR_ALL);
//设定可用或需要的覆盖模型,此处为field_value
void'(set_coverage(UVM_CVR_FIELD_VALS));
//检查是否具备对应的cg
if(has_coverage(UVM_CVR_FIELD_VALS)) begin
value_cg = new();//例化cg
end
endfunction
virtual function void build();
reserved = uvm_reg_field::type_id::create("reserved");
pkt_len =...
reserved.configure(this, 26, 6, "RO", 0, 26'h0, 1, 0, 0);
pkt_len.configure ...
endfunction
//uvm_reg预定义的函数,参数保持一致
function void sample(
uvm_reg_data_t data,
uvm_reg_data_t byte_en,
bit is_read,
uvm_reg_map map
);
super.sample(data, byte_en, is_read, map);
sample_values();
endfunction
function void sample_values();
super.sample_values();
//只有顶层允许例化cg时,,才能允许cg进行采样;
if (get_coverage(UVM_CVR_FIELD_VALS)) begin
value_cg.sample();
end
endfunction
endclass
类uvm_reg_field的成员value,区别于desire val 和mirror val,成员value为rand属性,而desire val和mirror val是local属性,类uvm_reg在指定cg时只能对非local成员采样,在恰当的时刻,value的值与act的值是一致的
- 事件触发外部收集模式__参考书本
- 目的:采取自定义cg会更加贴合实际,贴合覆盖率验收标准
- cg的创建:
- 继承于uvm_subscriber,订阅从其他地方(mon)传来的信息。
- 发送信息方,mcdf_bus_monitor::uvm_analysis_port。
- 监听对象:前门访问读写事件。
- 通过write()发往cg::uvm_analysis_export。
- cg定义
- 指定各个寄存器感兴趣的域或值范围。
- 将各个相关的coverpoint进行cross,构成更复杂的场景实现要求
- sample_value()的触发事件。
- monitor监听到的前门访问读写事件。