搭建寄存模型时使用add_hdl_path和add_hdl_path_slice
在UVM(Universal Verification Methodology)中,add_hdl_path_slice是用于将HDL(硬件描述语言)中的信号路径映射到UVM寄存器模型(uvm_reg_model)中的一种方法。它通常在寄存器模型构建过程中使用,以便在寄存器读写操作时能够通过前门访问(front-door access)直接访问硬件信号。
具体来说,add_hdl_path_slice方法用于将寄存器模型中的某个寄存器或字段与HDL路径中的特定信号片段(slice)关联起来。这样,当通过寄存器模型进行读写操作时,UVM可以找到对应的HDL信号路径,从而进行硬件级别的读写。
函数原型:
systemverilog
function void add_hdl_path_slice(string name, int offset, int size, string kind = "RTL");
参数说明:
name:HDL路径中信号的名字。通常是一个字符串,表示从顶层开始的路径,但这里只是信号名,完整的路径由之前调用add_hdl_path时指定。
offset:该信号片段在寄存器中的起始位偏移。
size:该信号片段的位宽。
kind:可选的字符串,用于指定HDL路径的类型,默认为"RTL"。可以是"RTL"或"Gate"等,用于区分不同的设计层次。
使用步骤:
首先,在寄存器模型中,为每个寄存器或寄存器块调用add_hdl_path来指定顶层的HDL路径。
然后,对于寄存器中的每个字段或整个寄存器,调用add_hdl_path_slice来指定该字段或寄存器对应的信号在HDL路径中的具体位置。
示例:
假设我们有一个寄存器模块,其中包含一个32位的寄存器status_reg,该寄存器由两个字段组成:fifo_empty(位0)和fifo_full(位1)。在HDL中,该寄存器的路径为top.dut.status_reg。
在UVM寄存器模型中,我们可以这样映射:
systemverilog
class status_reg extends uvm_reg;
`uvm_object_utils(status_reg)
uvm_reg_field fifo_empty;
uvm_reg_field fifo_full;
function new(string name = "status_reg");
super.new(name, 32, UVM_NO_COVERAGE);
endfunction
virtual function void build();
fifo_empty = uvm_reg_field::type_id::create("fifo_empty");
fifo_empty.configure(this, 1, 0, "RO", 0, 1'b0, 1, 0, 0);
fifo_full = uvm_reg_field::type_id::create("fifo_full");
fifo_full.configure(this, 1, 1, "RO", 0, 1'b0, 1, 0, 0);
endfunction
endclass
class reg_block extends uvm_reg_block;
`uvm_object_utils(reg_block)
status_reg status;
function new(string name = "reg_block");
super.new(name, UVM_NO_COVERAGE);
endfunction
virtual function void build();
// 创建寄存器
status = status_reg::type_id::create("status");
status.configure(this, null, "");//此寄存器所在block的指针,reg_file的指针,此寄存器后门访问的路径
status.build();
// 指定默认的HDL路径(相对路径)
this.add_hdl_path("top.dut");
// 为status寄存器添加HDL路径片段
// 假设status_reg在HDL中是32位,我们将其映射到top.dut.status_reg
// 注意:这里我们使用add_hdl_path_slice将整个寄存器映射到一个32位的信号
// 实际上,也可以为每个字段单独映射,但通常整个寄存器映射一次即可。
status.add_hdl_path_slice("status_reg", 0, 32); // 从第0位开始,32位宽
// 或者,如果寄存器中的字段分散在不同的HDL信号中,我们可以为每个字段单独映射:
// status.fifo_empty.add_hdl_path_slice("fifo_empty", 0, 1);
// status.fifo_full.add_hdl_path_slice("fifo_full", 1, 1);
endfunction
endclass
注意事项:
add_hdl_path_slice通常用于前门访问(front-door access)的映射。如果只使用后门访问(back-door access),则不一定需要。
在调用add_hdl_path_slice之前,通常需要先调用add_hdl_path来设置基路径。
对于寄存器模型中的每个寄存器或字段,可以多次调用add_hdl_path_slice,以映射到不同的HDL路径(例如,RTL级和门级)。
使用add_hdl_path_slice时,需要确保偏移和位宽与HDL中的信号位置一致。
通过这种方式,UVM寄存器模型就能够知道如何通过前门访问来读写硬件寄存器,从而在仿真中实现寄存器的硬件访问。
uvm_reg::add_hdl_path_slice() 是 UVM 寄存器模型(RGM)中用于建立寄存器与硬件信号路径映射的关键方法,主要用于前门访问(front-door access)。
基本功能
将寄存器/字段映射到 HDL 中的具体信号路径,使得寄存器模型可以通过层次化路径直接访问硬件信号。
方法原型
function void add_hdl_path_slice(
string name, // 信号名称
int offset, // 位偏移
int size, // 位宽
bit first = 0, // 是否为首个slice
string kind = "RTL" // 路径类型
);
使用场景
1. 单个寄存器映射
class my_reg extends uvm_reg;
`uvm_object_utils(my_reg)
uvm_reg_field data;
virtual function void build();
data = uvm_reg_field::type_id::create("data");
data.configure(this, 32, 0, "RW", 0, 32'h0, 1, 1, 0);
endfunction
function new(string name = "my_reg");
super.new(name, 32, UVM_NO_COVERAGE);
endfunction
endclass
// 在寄存器块中配置
function void my_reg_block::build();
my_reg = my_reg::type_id::create("my_reg");
my_reg.configure(this, null, "");
my_reg.build();
// 添加HDL路径
my_reg.add_hdl_path("reg_file.reg1"); // 根路径
my_reg.add_hdl_path_slice("data", 0, 32, 1); // 32位数据信号
endfunction
2. 寄存器分片映射
当寄存器分散在多个硬件信号中时:
// 假设64位寄存器分在两个32位信号中
my_reg.add_hdl_path("reg_file.complex_reg");
my_reg.add_hdl_path_slice("low_word", 0, 32, 1); // 低32位
my_reg.add_hdl_path_slice("high_word", 32, 32, 0); // 高32位
3. 字段级映射
class status_reg extends uvm_reg;
uvm_reg_field error;
uvm_reg_field busy;
uvm_reg_field done;
virtual function void build();
error = uvm_reg_field::type_id::create("error");
busy = uvm_reg_field::type_id::create("busy");
done = uvm_reg_field::type_id::create("done");
error.configure(this, 1, 0, "RO", 0, 1'b0, 1, 0, 0);
busy.configure(this, 1, 1, "RO", 0, 1'b0, 1, 0, 0);
done.configure(this, 1, 2, "RO", 0, 1'b0, 1, 0, 0);
endfunction
function new(string name = "status_reg");
super.new(name, 3, UVM_NO_COVERAGE);
endfunction
endclass
// 为每个字段单独映射
status_reg.add_hdl_path("top.status");
status_reg.error.add_hdl_path_slice("error_bit", 0, 1, 1);
status_reg.busy.add_hdl_path_slice("busy_bit", 1, 1, 0);
status_reg.done.add_hdl_path_slice("done_bit", 2, 1, 0);
关键参数详解
offset 和 size
- offset: 信号在寄存器中的起始位
- size: 信号位宽
- 示例:
add_hdl_path_slice("field2", 8, 4)表示映射到位[11:8]
kind 参数
// 支持多种设计表示
reg.add_hdl_path("design.reg", "RTL"); // RTL级路径
reg.add_hdl_path("gate_design.reg", "GATES"); // 门级路径
// 使用时指定
reg.set_hdl_path_root("TB.dut", "RTL"); // 使用RTL路径
reg.set_hdl_path_root("TB.dut_gates", "GATES"); // 使用门级路径
完整示例
class ral_block_sys extends uvm_reg_block;
`uvm_object_utils(ral_block_sys)
rand control_reg ctrl;
rand status_reg stat;
virtual function void build();
// 创建寄存器实例
ctrl = control_reg::type_id::create("ctrl");
stat = status_reg::type_id::create("stat");
// 配置寄存器
ctrl.configure(this, null, "ctrl_reg");
stat.configure(this, null, "stat_reg");
ctrl.build();
stat.build();
// 设置默认路径前缀
set_hdl_path_root("tb.dut");
// 映射control寄存器
ctrl.add_hdl_path("ctrl_reg");
ctrl.enable.add_hdl_path_slice("en", 0, 1, 1);
ctrl.mode.add_hdl_path_slice("mode", 1, 2, 0);
// 映射status寄存器
stat.add_hdl_path("stat_reg");
stat.add_hdl_path_slice("status", 0, 8); // 整个寄存器映射
// 锁定模型
lock_model();
endfunction
endclass
注意事项
- 层级关系:先调用
add_hdl_path()设置根路径,再调用add_hdl_path_slice()添加具体信号 - 位对齐:确保 offset 和 size 与硬件设计一致
- 多次调用:一个寄存器可以映射到多个 HDL 路径(不同 abstraction level)
- 验证环境集成:
// 在base_test中集成
virtual function void connect_phase(uvm_phase phase);
// 设置适配器
reg2adapter = reg2bus_adapter::type_id::create("reg2adapter");
predictor = uvm_reg_predictor#(bus_transaction)::type_id::create("predictor");
// 设置寄存器模型HDL路径
reg_model.set_hdl_path_root("tb.dut");
// 连接predictor
predictor.map = reg_model.default_map;
predictor.adapter = reg2adapter;
bus_monitor.item_collected_port.connect(predictor.bus_in);
endfunction
调试技巧
// 1. 检查映射关系
reg_model.print_hdl_paths();
// 2. 使用UVM_INFO查看路径
`uvm_info("HDL_PATH",
$sformatf("Path for %s: %s",
reg.get_full_name(), reg.get_hdl_path()),
UVM_MEDIUM)
// 3. 运行时验证
if (!reg.has_hdl_path()) begin
`uvm_error("NO_HDL_PATH", "HDL path not configured")
end
正确使用 add_hdl_path_slice() 可以实现精确的寄存器-硬件映射,是前门访问(通过总线接口访问寄存器)的基础。
浙公网安备 33010602011771号