4. UVM中的配置数据库使用

任务目标

在UVM测试平台中,使用uvm_config_db完成三类典型配置的传递:接口(virtual interface)、整型变量、类对象,并在组件中正确读取,最终通过UVM报告机制验证配置内容与预期一致。

环境依赖

本案例基于标准UVM库(UVM-1.2或更高),需要已安装支持UVM的仿真器(如VCS、QuestaSim、Xcelium)。无需额外IP或外部库。

实现方案

构建一个最小测试平台:顶层模块tb_top中实例化被测接口my_if,在initial块中通过uvm_config_db#(virtual my_if)::set传递接口;在测试类my_test的build_phase中通过uvm_config_db#(int)::set传递整型参数,通过uvm_config_db#(my_object)::set传递类对象。环境类my_env在build_phase中通过对应的get调用读取全部三项配置,并在end_of_elaboration_phase中打印读取结果,使用`uvm_info宏输出。测试类在run_phase中通过uvm_config_db#(int)::get再次读取整型参数,验证跨层级读取一致性。

关键完整代码

// 文件: config_db_demo.sv
`include "uvm_macros.svh"
import uvm_pkg::*;

// 被测接口
interface my_if(input logic clk);
  logic rst_n;
  logic [7:0] data;
endinterface

// 用于配置传递的简单类对象
class my_object extends uvm_object;
  string name_str;
  int    value;
  `uvm_object_utils_begin(my_object)
    `uvm_field_string(name_str, UVM_ALL_ON)
    `uvm_field_int(value, UVM_ALL_ON)
  `uvm_object_utils_end
  function new(string name = "my_object");
    super.new(name);
  endfunction
endclass

// 环境组件:读取全部三项配置
class my_env extends uvm_env;
  `uvm_component_utils(my_env)
  virtual my_if vif;
  int cfg_int;
  my_object cfg_obj;

  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if (!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
      `uvm_fatal("NOVIF", "无法从config_db获取virtual interface")
    if (!uvm_config_db#(int)::get(this, "", "cfg_int", cfg_int))
      `uvm_fatal("NOINT", "无法从config_db获取整型配置")
    if (!uvm_config_db#(my_object)::get(this, "", "cfg_obj", cfg_obj))
      `uvm_fatal("NOOBJ", "无法从config_db获取对象配置")
  endfunction

  function void end_of_elaboration_phase(uvm_phase phase);
    `uvm_info("CFG_CHECK", $sformatf("接口句柄有效: %0d, 整型配置: %0d, 对象名: %s, 对象值: %0d",
              (vif != null), cfg_int, cfg_obj.name_str, cfg_obj.value), UVM_LOW)
  endfunction
endclass

// 测试类:设置整型与对象配置,并在run_phase中验证读取
class my_test extends uvm_test;
  `uvm_component_utils(my_test)
  my_env env;

  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    env = my_env::type_id::create("env", this);
    // 设置整型配置
    uvm_config_db#(int)::set(this, "env", "cfg_int", 42);
    // 设置对象配置
    my_object obj = my_object::type_id::create("obj");
    obj.name_str = "demo_obj";
    obj.value = 100;
    uvm_config_db#(my_object)::set(this, "env", "cfg_obj", obj);
  endfunction

  task run_phase(uvm_phase phase);
    int readback_int;
    phase.raise_objection(this);
    #10ns;
    // 从测试层级读取整型配置,验证跨层级可见性
    if (uvm_config_db#(int)::get(this, "env", "cfg_int", readback_int))
      `uvm_info("TEST_READ", $sformatf("测试层读取整型配置: %0d", readback_int), UVM_LOW)
    else
      `uvm_error("READFAIL", "测试层无法读取整型配置")
    phase.drop_objection(this);
  endtask
endclass

// 顶层模块
module tb_top;
  logic clk = 0;
  always #5 clk = ~clk;

  my_if u_if(clk);

  initial begin
    // 设置接口配置
    uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.env", "vif", u_if);
    run_test("my_test");
  end

  initial begin
    #200ns;
    $finish;
  end
endmodule

运行方式

# 使用QuestaSim示例(其他仿真器命令类似)
vlib work
vlog +incdir+$UVM_HOME/src $UVM_HOME/src/uvm_pkg.sv config_db_demo.sv
vsim -c -do "run -all; quit" work.tb_top

若使用VCS:vcs -sverilog +incdir+$UVM_HOME/src $UVM_HOME/src/uvm_pkg.sv config_db_demo.sv -R

验证方法与判定标准

仿真运行后,观察终端输出。判定通过的充分条件:

  • 仿真器报告UVM_ERROR : 0,UVM_FATAL : 0;
  • 出现来自my_env的CFG_CHECK信息,内容为接口句柄有效: 1, 整型配置: 42, 对象名: demo_obj, 对象值: 100;
  • 出现来自my_test的TEST_READ信息,内容为测试层读取整型配置: 42。

以上输出由代码逻辑直接唯一推出,为预期输出而非实测结果。若三项配置任一读取失败,仿真将以UVM_FATAL终止,据此可定位配置传递链路中的断点。

常见问题

  • 接口获取失败:确认set中第一个参数为null且第二个参数为"uvm_test_top.env",与UVM顶层实例路径严格一致;
  • 整型/对象获取失败:检查set的第二个参数(相对路径)是否与get的第二个参数匹配,本案例中均为"env";
  • 对象字段打印为空:确认对象已通过create分配内存并完成字段赋值,且uvm_object_utils_begin宏已正确声明字段。