uvm_config_db的使用说明

举例说明:在tc_test和rm之间传递一个cfg句柄

在 UVM 中,test(测试用例)与rm(Register Model,寄存器模型)之间通过uvm_config_db传递cfg句柄(配置对象),核心是利用uvm_config_db的 “路径 + 名称” 索引机制,将test中配置好的cfg对象写入数据库,再在rm的构建阶段读取该句柄。以下是标准流程 + 完整代码示例,覆盖关键步骤与避坑要点:

一、前提定义:先明确cfg类与rm

首先定义通用的配置类(xxx_cfg)和寄存器模型类(xxx_rm),作为传递的基础:

systemverilog

// 1. 定义配置类(含寄存器模型所需的参数:基地址、时钟周期、访问模式等)
class axi_cfg extends uvm_object;
  `uvm_object_utils(axi_cfg)
  
  // 寄存器模型核心配置参数
  bit [31:0]  reg_base_addr = 32'h1000_0000;  // 寄存器基地址
  int         clk_period    = 10;              // 时钟周期(ns)
  bit         reg_coverage  = 1;               // 是否开启寄存器覆盖率
  
  function new(string name = "axi_cfg");
    super.new(name);
  endfunction
endclass

// 2. 定义寄存器模型类(需接收cfg句柄)
class axi_rm extends uvm_reg_block;
  `uvm_object_utils(axi_rm)
  
  axi_cfg cfg;  // 本地存储cfg句柄
  uvm_reg status_reg;  // 示例:状态寄存器
  uvm_reg ctrl_reg;    // 示例:控制寄存器

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

  // 构建阶段:读取cfg句柄 + 初始化寄存器
  virtual function void build();
    super.build();
    // 步骤1:从uvm_config_db读取cfg句柄(核心)
    if (!uvm_config_db#(axi_cfg)::get(this, "", "axi_cfg_h", cfg)) begin
      `uvm_fatal("RM_GET_CFG_ERR", "寄存器模型未读取到cfg句柄!")
    end
    // 步骤2:使用cfg参数初始化寄存器(示例)
    status_reg = uvm_reg::type_id::create("status_reg");
    status_reg.configure(this, 32, 0);  // 32位,非可配置
    ctrl_reg   = uvm_reg::type_id::create("ctrl_reg");
    ctrl_reg.configure(this, 32, 0);
    
    // 步骤3:基于cfg的基地址创建寄存器映射
    default_map = create_map("default_map", cfg.reg_base_addr, 4, UVM_LITTLE_ENDIAN);
    default_map.add_reg(status_reg, 32'h00, "RW");  // 偏移0x00
    default_map.add_reg(ctrl_reg,   32'h04, "RW");  // 偏移0x04
    
    `uvm_info("RM_CFG_LOAD", $sformatf(
      "寄存器模型加载cfg成功:基地址=0x%0h, 时钟周期=%0dns",
      cfg.reg_base_addr, cfg.clk_period), UVM_MEDIUM)
  endfunction
endclass

二、核心流程:Test 中 Set → RM 中 Get

步骤 1:Test 中创建并配置 cfg,写入 uvm_config_db

test是验证环境的顶层控制者,需先实例化cfg并配置参数,再通过uvm_config_db传递给rm

systemverilog

class axi_base_test extends uvm_test;
  `uvm_component_utils(axi_base_test)
  
  axi_cfg    cfg;    // 配置对象
  axi_rm     rm;     // 寄存器模型
  uvm_env    env;    // 验证环境(可选)

  function new(string name = "axi_base_test", uvm_component parent = null);
    super.new(name, parent);
  endfunction

  // 构建阶段:创建cfg → 配置参数 → set到uvm_config_db → 创建rm
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    
    // 步骤1:实例化并配置cfg
    cfg = axi_cfg::type_id::create("cfg");
    cfg.reg_base_addr = 32'h2000_0000;  // 自定义基地址(覆盖默认值)
    cfg.clk_period    = 20;             // 自定义时钟周期
    cfg.reg_coverage  = 1;              // 开启覆盖率
    
    // 步骤2:将cfg句柄写入uvm_config_db(核心)
    // 关键:路径指向rm的实例路径,确保rm能读取到
    uvm_config_db#(axi_cfg)::set(
      this,             // 上下文:当前test组件
      "rm",             // 目标路径:test下的rm实例(相对路径)
      "axi_cfg_h",      // 配置项名称(需与rm中get的名称一致)
      cfg               // 要传递的cfg句柄
    );

    // 步骤3:创建寄存器模型实例(自动触发rm的build_phase)
    rm = axi_rm::type_id::create("rm", this);
    rm.build();  // 显式调用build(或由UVM自动调用)
  endfunction

  // 运行阶段:验证cfg传递结果
  virtual task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    `uvm_info("TEST_CFG_CHECK", $sformatf(
      "Test中cfg参数:基地址=0x%0h, RM中cfg基地址=0x%0h",
      cfg.reg_base_addr, rm.cfg.reg_base_addr), UVM_MEDIUM)
    phase.drop_objection(this);
  endtask
endclass
步骤 2:RM 中读取 cfg 句柄(已嵌入上述axi_rmbuild函数)

核心代码回顾:

systemverilog

// 在axi_rm的build函数中
if (!uvm_config_db#(axi_cfg)::get(this, "", "axi_cfg_h", cfg)) begin
  `uvm_fatal("RM_GET_CFG_ERR", "寄存器模型未读取到cfg句柄!")
end

三、关键细节与避坑指南

1. 路径匹配原则(最易出错)
  • setinst_name需指向rm实例路径
    • rmtest下实例化为rm,则inst_name = "rm"
    • rmenv.agent下,需写inst_name = "env.agent.rm"
    • 若用绝对路径,可写"/uvm_top/axi_base_test/rm"(不推荐,降低可重用性)。
  • getinst_name填空字符串"":表示 “从当前组件(rm)的路径下读取”。
2. 类型严格一致

setget的模板参数必须完全匹配(如axi_cfg不能写成uvm_object):

systemverilog

// 错误示例:类型不匹配(set是axi_cfg,get是uvm_object)
uvm_config_db#(uvm_object)::get(this, "", "axi_cfg_h", cfg); // 编译/运行错误
3. 执行顺序:先 Set 后 Get
  • set必须在rmbuild_phase之前执行(testbuild_phase先于rmbuild_phase,符合 UVM 的 phase 执行顺序);
  • 禁止在testconnect_phaseset(此时rmbuild_phase已执行,读取失败)。
4. 全局传递(可选:跨层级传递)

rm不在test直接子层级(如在env内部),可通过通配符*批量传递:

systemverilog

// Test中:给所有路径下的rm传递cfg
uvm_config_db#(axi_cfg)::set(this, "*rm", "axi_cfg_h", cfg);

四、扩展场景:RM 在 Env 中时的传递

rm实例化在env中,而非直接在test中,只需调整set的路径:

systemverilog

// Test的build_phase
virtual function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  cfg = axi_cfg::type_id::create("cfg");
  // 路径改为:test → env → rm
  uvm_config_db#(axi_cfg)::set(this, "env.rm", "axi_cfg_h", cfg);
  env = axi_env::type_id::create("env", this); // 创建env(内部包含rm)
endfunction

// Env的build_phase
class axi_env extends uvm_env;
  `uvm_component_utils(axi_env)
  axi_rm rm;
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    rm = axi_rm::type_id::create("rm", this); // rm在env中实例化
  endfunction
endclass

五、验证传递成功的方法

  1. 日志打印:在rmbuild函数中打印cfg的参数(如上述示例中的RM_CFG_LOAD日志);
  2. 断言检查:在rm中对cfg的关键参数做断言,确保未使用默认值:

    systemverilog

    assert(cfg.reg_base_addr == 32'h2000_0000) else begin
      `uvm_error("RM_CFG_ERR", "cfg参数未正确传递!")
    end
    
  3. UVM 打印层级:通过+UVM_VERBOSITY=UVM_HIGH查看uvm_config_db的读写日志。

总结

testrm之间传递cfg句柄的核心步骤:

  1. 定义:创建包含 RM 所需参数的cfg类;
  2. Set:在testbuild_phase中实例化并配置cfg,通过uvm_config_db#(cfg类型)::set写入(路径指向 RM 实例);
  3. Get:在rmbuild函数中通过uvm_config_db#(cfg类型)::get读取,做容错处理;
  4. 使用:基于cfg参数初始化 RM 的寄存器、映射等。

关键原则:路径匹配、类型一致、执行顺序(先 Set 后 Get),这是确保传递成功的核心。

`uvm_config_db` 是 UVM(Universal Verification Methodology)提供的配置类,用于在仿真环境中实现配置信息的传递和管理,其使用方法主要包括设置和获取配置信息。 ### 设置配置信息 使用 `uvm_config_db::set()` 函数将配置信息写入数据库,函数原型如下: ```systemverilog uvm_config_db#(type T = int)::set(uvm_component cntxt, string inst_name, string field_name, T value); ``` - `cntxt`:指定配置信息的上下文组件。 - `inst_name`:指定目标组件的实例名称。 - `field_name`:指定配置信息的字段名称。 - `value`:指定要设置的配置值。 示例代码如下: ```systemverilog uvm_config_db#(int)::set(uvm_root::get(), "uvm_test_top.env.agent", "data_width", 32); ``` ### 获取配置信息 使用 `uvm_config_db::get()` 函数从数据库中获取配置信息,函数原型如下: ```systemverilog uvm_config_db#(type T = int)::get(uvm_component cntxt, string inst_name, string field_name, inout T value); ``` - `cntxt`:指定配置信息的上下文组件。 - `inst_name`:指定目标组件的实例名称。 - `field_name`:指定配置信息的字段名称。 - `value`:用于存储获取到的配置值。 示例代码如下: ```systemverilog int data_width; if (!uvm_config_db#(int)::get(this, "", "data_width", data_width)) begin `uvm_fatal("CONFIG_ERROR", "Failed to get data_width configuration") end ``` ### 检查配置信息是否存在 使用 `uvm_config_db::exists()` 函数检查配置信息是否存在,函数原型如下: ```systemverilog uvm_config_db#(type T = int)::exists(uvm_component cntxt, string inst_name, string field_name, bit spell_chk=0); ``` - `cntxt`:指定配置信息的上下文组件。 - `inst_name`:指定目标组件的实例名称。 - `field_name`:指定配置信息的字段名称。 - `spell_chk`:是否进行拼写检查。 示例代码如下: ```systemverilog if (uvm_config_db#(int)::exists(this, "", "data_width")) begin // 配置信息存在 end else begin // 配置信息不存在 end ``` ### 在 `uvm_object` 中使用 `uvm_config_db` 在 `uvm_object` 类中也可以使用 `uvm_config_db`,但需要使用 `get_full_name()` 函数获取路径。例如,在 sequence 中使用 `get` 方法的示例如下: ```systemverilog int data_width; string path = get_full_name(); if (!uvm_config_db#(int)::get(null, path, "data_width", data_width)) begin `uvm_fatal("CONFIG_ERROR", "Failed to get data_width configuration in sequence") end ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值