• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

SOC/IP验证工程师

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

uvm中搭建寄存器模型时,使用add_hdl_path和add_hdl_path_slice进行后门访问

在UVM中,寄存器模型的后门访问允许直接通过层次路径访问硬件寄存器,而不通过总线。这可以用于在仿真中快速读取或写入寄存器的值,而不依赖于前门访问(即通过总线序列)。为了使用后门访问,我们需要在寄存器模型中为每个寄存器和其域指定HDL路径。

add_hdl_path和add_hdl_path_slice是用于在UVM寄存器模型中设置后门访问路径的两个重要方法。

1. add_hdl_path方法
add_hdl_path方法用于为寄存器模型中的块(uvm_reg_block)或寄存器(uvm_reg)添加HDL路径。这个路径是一个字符串,指定了在硬件设计中该块或寄存器的层次路径。

2. add_hdl_path_slice方法
add_hdl_path_slice方法用于为寄存器中的每个域(uvm_reg_field)指定其在寄存器中的位置(即位的范围)以及可选的HDL路径片段。如果寄存器的所有域都位于同一个层次路径下,那么可以为整个寄存器指定一个路径,然后为每个域指定位的范围。但是,有时一个寄存器的不同域可能分散在不同的层次路径中,这时就需要为每个域分别指定HDL路径片段。

使用步骤
步骤1: 在寄存器块中设置根路径
通常在顶层寄存器块中,使用add_hdl_path来设置根路径。然后,在块中的每个寄存器可以使用相对路径。

步骤2: 为寄存器添加HDL路径
对于每个寄存器,使用add_hdl_path来设置该寄存器的路径。这个路径可以是绝对的(从设计顶层开始)或相对的(相对于所在块的路径)。

步骤3: 为寄存器的每个域添加路径切片
对于寄存器中的每个域,使用add_hdl_path_slice来指定该域在寄存器中的位范围,以及可选的路径。如果寄存器的所有域都在同一个路径下,那么可以只指定一次寄存器的路径,然后为每个域指定位范围,而不需要指定路径。

示例
假设我们有一个设计,其中有一个寄存器块my_block,它包含一个寄存器my_reg,该寄存器有两个域:field1(位[7:0])和field2(位[15:8])。并且,这个寄存器在硬件中的层次路径为:top.dut.reg_block.my_reg。

在寄存器模型中,我们可以这样设置后门访问路径:

systemverilog
class my_reg extends uvm_reg;
   rand uvm_reg_field field1;
   rand uvm_reg_field field2;

   function new(string name = "my_reg");
      super.new(name, 16, UVM_NO_COVERAGE);
   endfunction

   virtual function void build();
      field1 = uvm_reg_field::type_id::create("field1");
      field2 = uvm_reg_field::type_id::create("field2");
      // 配置域
      field1.configure(this, 8, 0, "RW", 0, 8'h00, 1, 1, 1);
      field2.configure(this, 8, 8, "RW", 0, 8'h00, 1, 1, 1);
   endfunction

   // 添加后门访问路径
   virtual function void add_hdl_path_slices(string path = "");
      // 为整个寄存器添加路径
      add_hdl_path(path);
      // 为每个域添加路径切片,注意这里的路径为空,表示使用寄存器的路径
      // 位范围由参数指定:field1是位[7:0],field2是位[15:8]
      field1.add_hdl_path_slice("field1", 0, 8);   // 在寄存器的路径下,field1的位范围是0到7
      field2.add_hdl_path_slice("field2", 8, 8);   // 在寄存器的路径下,field2的位范围是8到15
   endfunction
endclass

class my_block extends uvm_reg_block;
   rand my_reg reg1;

   function new(string name = "my_block");
      super.new(name, UVM_NO_COVERAGE);
   endfunction

   virtual function void build();
      // 创建寄存器
      reg1 = my_reg::type_id::create("reg1");
      reg1.configure(this, null, "");
      reg1.build();
      // 设置寄存器的偏移地址(前门访问)这里省略
      // ...

      // 设置后门访问路径
      // 首先为整个块设置根路径
      add_hdl_path("top.dut.reg_block");
      // 然后为寄存器设置路径,这里使用相对路径,因为块已经有根路径
      reg1.add_hdl_path("my_reg");
      // 或者,如果寄存器的路径是绝对的,可以这样:
      // reg1.add_hdl_path("top.dut.reg_block.my_reg");
      // 但是,使用相对路径更灵活,因为如果块的路径改变,只需要改一个地方。

      // 调用寄存器的方法来添加域的路径切片
      reg1.add_hdl_path_slices(); // 这里使用寄存器的路径,已经在上面设置
   endfunction
endclass
在上面的示例中,我们为块my_block设置了根路径"top.dut.reg_block",然后为寄存器reg1设置了相对路径"my_reg"。然后,在my_reg的add_hdl_path_slices方法中,我们为每个域添加了路径切片,指定了位范围。注意,这里我们假设寄存器的两个域都在同一个层次路径下,即top.dut.reg_block.my_reg,并且域在寄存器中的位范围是连续的。

注意事项
后门访问路径必须与设计的层次路径完全匹配,包括大小写。

如果设计的层次结构发生变化,需要更新这些路径。

后门访问通常用于仿真,不能用于硬件综合。

在使用后门访问时,需要确保仿真器支持通过层次路径访问信号。

通过这样的设置,我们就可以在测试中使用后门访问来读取或写入寄存器的值,例如:

systemverilog
reg1.field1.read(status, value, UVM_BACKDOOR);
reg1.field2.write(status, 8'hFF, UVM_BACKDOOR);
这样,寄存器模型就会通过后门路径直接访问硬件信号,而不通过总线。

在UVM中,add_hdl_path和add_hdl_path_slice用于配置寄存器模型的后门访问路径。以下是详细的使用方法:

1. 基本概念

  • add_hdl_path: 为寄存器块或寄存器添加硬件路径
  • add_hdl_path_slice: 为寄存器字段添加具体的位域范围

2. 在寄存器块中的配置

class my_reg_block extends uvm_reg_block;
    `uvm_object_utils(my_reg_block)
    
    rand my_reg reg1;
    rand my_reg reg2;
    
    virtual function void build();
        // 创建寄存器
        reg1 = my_reg::type_id::create("reg1");
        reg1.configure(this, null, "");
        reg1.build();
        
        reg2 = my_reg::type_id::create("reg2");
        reg2.configure(this, null, "");
        reg2.build();
        
        // 为整个块添加硬件路径
        add_hdl_path("top_tb.DUT.reg_block");
        
        // 为每个寄存器添加路径
        reg1.add_hdl_path("reg1");
        reg2.add_hdl_path("reg2");
        
        // 锁定模型
        lock_model();
    endfunction
endclass

3. 在寄存器中的配置

方法一:统一路径

class my_reg extends uvm_reg;
    `uvm_object_utils(my_reg)
    
    rand uvm_reg_field field1;
    rand uvm_reg_field field2;
    rand uvm_reg_field field3;
    
    function new(string name = "my_reg");
        super.new(name, 32, UVM_NO_COVERAGE);
    endfunction
    
    virtual function void build();
        field1 = uvm_reg_field::type_id::create("field1");
        field2 = uvm_reg_field::type_id::create("field2");
        field3 = uvm_reg_field::type_id::create("field3");
        
        // 配置字段
        field1.configure(this, 8, 0, "RW", 0, 8'h00, 1, 1, 1);
        field2.configure(this, 8, 8, "RW", 0, 8'h00, 1, 1, 1);
        field3.configure(this, 16, 16, "RW", 0, 16'h0000, 1, 1, 1);
        
        // 添加硬件路径(整个寄存器)
        add_hdl_path("reg_module");
        
        // 为每个字段添加位域切片
        field1.add_hdl_path_slice("field1", 0, 8);
        field2.add_hdl_path_slice("field2", 8, 8);
        field3.add_hdl_path_slice("field3", 16, 16);
    endfunction
endclass

方法二:分离路径(字段位于不同模块)

class split_reg extends uvm_reg;
    `uvm_object_utils(split_reg)
    
    rand uvm_reg_field field_a;
    rand uvm_reg_field field_b;
    
    function new(string name = "split_reg");
        super.new(name, 32, UVM_NO_COVERAGE);
    endfunction
    
    virtual function void build();
        field_a = uvm_reg_field::type_id::create("field_a");
        field_b = uvm_reg_field::type_id::create("field_b");
        
        field_a.configure(this, 16, 0, "RW", 0, 16'h0000, 1, 1, 1);
        field_b.configure(this, 16, 16, "RW", 0, 16'h0000, 1, 1, 1);
        
        // 字段A位于模块A
        field_a.add_hdl_path_slice("module_a.field_a", 0, 16);
        
        // 字段B位于模块B
        field_b.add_hdl_path_slice("module_b.field_b", 16, 16);
    endfunction
endclass

4. 复杂示例:多层路径

class complex_reg_model extends uvm_reg_block;
    `uvm_object_utils(complex_reg_model)
    
    rand sub_block1 blk1;
    rand sub_block2 blk2;
    
    virtual function void build();
        // 创建子块
        blk1 = sub_block1::type_id::create("blk1");
        blk1.configure(this, "");
        blk1.build();
        blk1.add_hdl_path("sub_system1");
        
        blk2 = sub_block2::type_id::create("blk2");
        blk2.configure(this, "");
        blk2.build();
        blk2.add_hdl_path("sub_system2");
        
        // 设置默认路径
        set_default_hdl_path("top_tb.DUT");
        
        // 锁定模型
        lock_model();
    endfunction
endclass

5. 使用宏简化配置

`define ADD_REG_FIELD_SLICE(reg_name, field_name, offset, width) \
    reg_name.field_name.add_hdl_path_slice(`"field_name`", offset, width)

class my_reg extends uvm_reg;
    // ... 字段声明 ...
    
    virtual function void build();
        // ... 字段配置 ...
        
        // 使用宏添加路径切片
        `ADD_REG_FIELD_SLICE(this, field1, 0, 8)
        `ADD_REG_FIELD_SLICE(this, field2, 8, 8)
        `ADD_REG_FIELD_SLICE(this, field3, 16, 16)
    endfunction
endclass

6. 后门访问的使用

// 在测试序列中使用后门访问
class my_test_seq extends uvm_sequence;
    task body();
        uvm_status_e status;
        uvm_reg_data_t data;
        
        // 后门读取
        reg_model.reg1.field1.read(status, data, .path(UVM_BACKDOOR));
        
        // 后门写入
        reg_model.reg1.field2.write(status, 8'hFF, .path(UVM_BACKDOOR));
        
        // 混合访问:前门写,后门验证
        reg_model.reg2.write(status, 32'h12345678, .path(UVM_FRONTDOOR));
        reg_model.reg2.read(status, data, .path(UVM_BACKDOOR));
        
        if(data == 32'h12345678)
            `uvm_info("CHECK", "Register write successful", UVM_LOW)
    endtask
endclass

7. 注意事项

  1. 路径格式:

    • 使用"."作为层次分隔符
    • 路径必须与实际RTL层次结构匹配
  2. 路径类型:

    add_hdl_path("path", "RTL");    // RTL路径(默认)
    add_hdl_path("path", "GATES");  // 门级网表路径
    add_hdl_path("path", "ALL");    // 所有类型
    
  3. 错误处理:

    • 确保路径在验证环境构建时已存在
    • 使用check_hdl_path()验证路径有效性
  4. 性能考虑:

    • 后门访问比前门访问快,但不利于验证总线协议
    • 建议主要用于初始化和快速检查

8. 调试技巧

// 打印所有HDL路径
reg_model.print_hdl_paths();

// 检查特定路径
if(reg_model.check_hdl_path()) begin
    `uvm_info("PATH", "HDL path is valid", UVM_LOW)
end

// 获取路径信息
string paths[$];
reg_model.get_hdl_paths(paths);

这些配置使得UVM寄存器模型能够通过后门直接访问DUT中的寄存器信号,提高仿真效率。

posted on 2026-01-31 17:17  SOC验证工程师  阅读(2)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3