4. 实现UVM寄存器模型集成
任务目标
为RISC-V处理器验证环境中的CSR(控制状态寄存器)建立UVM寄存器模型,并将其集成到现有UVM验证平台中,使测试序列能够通过前门(总线协议访问)和后门(直接内存/层次路径访问)两种方式读写CSR。
环境依赖
本案例基于以下环境实现:
- UVM-1.2(或更高)
- RISC-V处理器RTL模型(含CSR接口,支持前门访问协议)
- 验证环境已具备:uvm_agent(含sequencer/driver/monitor)、uvm_scoreboard
CSR寄存器模型定义
以RISC-V中三个典型CSR为例:mstatus(机器状态)、mtvec(机器陷阱向量基址)、mepc(机器异常PC)。前门访问通过RISC-V的CSR读写指令(csrrw/csrrs)经由指令总线完成;后门访问通过层次路径直接操作RTL内部寄存器变量。
关键完整代码
// 文件: riscv_csr_reg_model.sv
// CSR寄存器模型:定义单个CSR寄存器及寄存器块
class riscv_csr_reg extends uvm_reg;
`uvm_object_utils(riscv_csr_reg)
rand uvm_reg_field csr_field;
function new(string name = "riscv_csr_reg");
super.new(name, 32, UVM_NO_COVERAGE);
endfunction
virtual function void build();
csr_field = uvm_reg_field::type_id::create("csr_field");
// 参数: parent, size, lsb_pos, access, volatile, reset, has_reset, is_rand, individually_accessible
csr_field.configure(this, 32, 0, "RW", 0, 'h0, 1, 1, 0);
endfunction
endclass
class riscv_csr_reg_block extends uvm_reg_block;
`uvm_object_utils(riscv_csr_reg_block)
rand riscv_csr_reg mstatus_reg;
rand riscv_csr_reg mtvec_reg;
rand riscv_csr_reg mepc_reg;
function new(string name = "riscv_csr_reg_block");
super.new(name, UVM_NO_COVERAGE);
endfunction
virtual function void build();
// 创建寄存器实例
mstatus_reg = riscv_csr_reg::type_id::create("mstatus_reg");
mtvec_reg = riscv_csr_reg::type_id::create("mtvec_reg");
mepc_reg = riscv_csr_reg::type_id::create("mepc_reg");
// 配置寄存器并添加到块中
mstatus_reg.configure(this);
mtvec_reg.configure(this);
mepc_reg.configure(this);
mstatus_reg.build();
mtvec_reg.build();
mepc_reg.build();
// 地址映射(前门地址)
mstatus_reg.add_map("csr_map", 'h300, UVM_LITTLE_ENDIAN);
mtvec_reg.add_map("csr_map", 'h305, UVM_LITTLE_ENDIAN);
mepc_reg.add_map("csr_map", 'h341, UVM_LITTLE_ENDIAN);
// 默认映射
default_map = get_map("csr_map");
// 后门访问配置:指定RTL层次路径
// 假设DUT顶层为 dut,CSR模块实例名为 csr_unit
mstatus_reg.set_backdoor(riscv_csr_backdoor::type_id::create("mstatus_bd"));
mstatus_reg.get_backdoor().set_hdl_path("dut.csr_unit.mstatus");
mtvec_reg.set_backdoor(riscv_csr_backdoor::type_id::create("mtvec_bd"));
mtvec_reg.get_backdoor().set_hdl_path("dut.csr_unit.mtvec");
mepc_reg.set_backdoor(riscv_csr_backdoor::type_id::create("mepc_bd"));
mepc_reg.get_backdoor().set_hdl_path("dut.csr_unit.mepc");
lock_model();
endfunction
endclass
// 后门访问实现(HDL路径直接读写)
class riscv_csr_backdoor extends uvm_reg_backdoor;
`uvm_object_utils(riscv_csr_backdoor)
function new(string name = "riscv_csr_backdoor");
super.new(name);
endfunction
virtual task read(uvm_reg_item rw);
uvm_reg reg = rw.element;
string path;
reg.get_backdoor().get_hdl_path(path);
// 使用UVM的HDL路径读取(需仿真器支持)
rw.value[0] = uvm_hdl_read(path);
endtask
virtual task write(uvm_reg_item rw);
uvm_reg reg = rw.element;
string path;
reg.get_backdoor().get_hdl_path(path);
uvm_hdl_deposit(path, rw.value[0]);
endtask
endclass
// 集成到验证环境:在env中创建并连接
class riscv_env extends uvm_env;
`uvm_component_utils(riscv_env)
riscv_csr_reg_block reg_model;
riscv_adapter csr_adapter; // 前门适配器(需实现uvm_reg_adapter)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
reg_model = riscv_csr_reg_block::type_id::create("reg_model");
reg_model.build();
reg_model.lock_model();
csr_adapter = riscv_adapter::type_id::create("csr_adapter");
// 将寄存器模型默认映射连接到sequencer(前门)
reg_model.default_map.set_sequencer(env.agent.sequencer, csr_adapter);
endfunction
endclass
前门适配器实现要点
// 文件: riscv_adapter.sv(前门适配器关键代码)
class riscv_adapter extends uvm_reg_adapter;
`uvm_object_utils(riscv_adapter)
function new(string name = "riscv_adapter");
super.new(name);
supports_byte_enable = 0;
provides_responses = 1;
endfunction
virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
// 将寄存器操作转换为RISC-V CSR指令序列项
riscv_csr_seq_item item = riscv_csr_seq_item::type_id::create("item");
item.csr_addr = rw.addr;
item.write = (rw.kind == UVM_WRITE);
item.data = rw.data;
return item;
endfunction
virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
riscv_csr_seq_item item;
if (!$cast(item, bus_item))
`uvm_fatal("ADAPTER", "Bus item type mismatch")
rw.kind = item.write ? UVM_WRITE : UVM_READ;
rw.addr = item.csr_addr;
rw.data = item.data;
rw.status = UVM_IS_OK;
endfunction
endclass
运行与调用方式
- 在测试用例中通过
uvm_reg_hw_reset_seq或自定义序列执行前门访问:
// 测试序列中前门访问示例
class csr_access_test_seq extends uvm_sequence;
`uvm_object_utils(csr_access_test_seq)
virtual task body();
uvm_status_e status;
uvm_reg_data_t value;
// 前门写
p_sequencer.reg_model.mstatus_reg.write(status, 32'h00000001);
// 前门读
p_sequencer.reg_model.mstatus_reg.read(status, value);
// 后门写(直接修改RTL内部值)
p_sequencer.reg_model.mtvec_reg.set(32'h80000000);
p_sequencer.reg_model.mtvec_reg.update(status, UVM_BACKDOOR);
// 后门读
p_sequencer.reg_model.mepc_reg.peek(status, value);
endtask
endclass
- 编译运行(以VCS为例):
vcs -sverilog -ntb_opts uvm-1.2 -f filelist.f -o simv
./simv +UVM_TESTNAME=csr_access_test
验证方法与通过条件
- 前门验证:在测试序列中执行CSR写后立即读回,比较读回值与写入值一致;同时通过monitor观察总线上的csr指令序列与预期地址/数据匹配。
- 后门验证:使用
peek读取RTL内部寄存器值,与通过前门写入的期望值比对;或先使用poke直接修改RTL内部值,再通过前门读回确认值已生效。 - 回归检查:运行包含上述两种访问方式的测试,UVM报告
UVM_TEST_DONE且无uvm_reg_prediction错误,即判定通过。
常见问题
- 后门路径需与DUT层次严格一致,否则
uvm_hdl_read返回X态;可通过uvm_hdl_check_path预检查。 - 前门适配器需正确实现
reg2bus/bus2reg,否则寄存器操作无法正确转换为总线事务。 - 若CSR支持非32位访问(如部分字段只读),需在
uvm_reg_field中设置正确的access策略(如"RO"),并在adapter中处理掩码。