2. UVM环境组件层次化连接

任务目标

在UVM验证环境中,按照标准层次结构实例化并连接driver、monitor、agent、env与test组件,通过uvm_config_db完成virtual interface从test到driver/monitor的传递,最终在test中启动sequence以驱动DUT接口信号,验证组件间通信链路完整可用。

环境依赖

  • 仿真器:支持UVM-1.2或UVM-1.1d(如VCS、QuestaSim)
  • UVM库文件:uvm_pkg已编译
  • DUT接口:一个简单的同步接口(时钟+数据+有效信号)

关键完整代码

// 接口定义:simple_bus_if.sv
interface simple_bus_if(input bit clk);
  logic [7:0] data;
  logic       valid;
  clocking drv_cb @(posedge clk);
    output data, valid;
  endclocking
  clocking mon_cb @(posedge clk);
    input data, valid;
  endclocking
  modport DRV(clocking drv_cb);
  modport MON(clocking mon_cb);
endinterface

// 组件定义:uvm_components.sv
`include "uvm_macros.svh"
import uvm_pkg::*;

class driver extends uvm_driver #(uvm_sequence_item);
  `uvm_component_utils(driver)
  virtual simple_bus_if.DRV vif;
  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 simple_bus_if.DRV)::get(this, "", "vif", vif))
      `uvm_fatal("DRV", "virtual interface not found")
  endfunction
  task run_phase(uvm_phase phase);
    vif.drv_cb.data <= 0;
    vif.drv_cb.valid <= 0;
    forever begin
      seq_item_port.get_next_item(req);
      // 驱动接口
      if ($cast(req, req)) begin
        vif.drv_cb.data <= req.get_data();
        vif.drv_cb.valid <= 1;
      end
      seq_item_port.item_done();
      repeat (2) @(vif.drv_cb);
      vif.drv_cb.valid <= 0;
    end
  endtask
endclass

class monitor extends uvm_monitor;
  `uvm_component_utils(monitor)
  virtual simple_bus_if.MON vif;
  uvm_analysis_port #(uvm_sequence_item) ap;
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    ap = new("ap", this);
    if (!uvm_config_db#(virtual simple_bus_if.MON)::get(this, "", "vif", vif))
      `uvm_fatal("MON", "virtual interface not found")
  endfunction
  task run_phase(uvm_phase phase);
    forever begin
      @(vif.mon_cb);
      if (vif.mon_cb.valid) begin
        uvm_sequence_item item = new("item");
        item.set_data(vif.mon_cb.data);
        ap.write(item);
      end
    end
  endtask
endclass

class agent extends uvm_agent;
  `uvm_component_utils(agent)
  driver    drv;
  monitor   mon;
  uvm_sequencer #(uvm_sequence_item) sqr;
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    sqr = uvm_sequencer#(uvm_sequence_item)::type_id::create("sqr", this);
    drv = driver::type_id::create("drv", this);
    mon = monitor::type_id::create("mon", this);
  endfunction
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    drv.seq_item_port.connect(sqr.seq_item_export);
  endfunction
endclass

class env extends uvm_env;
  `uvm_component_utils(env)
  agent agt;
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    agt = agent::type_id::create("agt", this);
  endfunction
endclass

// 简单sequence item(为演示最小化)
class simple_item extends uvm_sequence_item;
  `uvm_object_utils(simple_item)
  rand bit [7:0] data;
  function new(string name = "simple_item");
    super.new(name);
  endfunction
  function bit [7:0] get_data();
    return data;
  endfunction
  function void set_data(bit [7:0] d);
    data = d;
  endfunction
endclass

class simple_seq extends uvm_sequence #(uvm_sequence_item);
  `uvm_object_utils(simple_seq)
  function new(string name = "simple_seq");
    super.new(name);
  endfunction
  task body();
    simple_item item = simple_item::type_id::create("item");
    start_item(item);
    assert(item.randomize());
    finish_item(item);
  endtask
endclass

class test extends uvm_test;
  `uvm_component_utils(test)
  env e;
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    e = env::type_id::create("e", this);
    // 从test层传递virtual interface
    uvm_config_db#(virtual simple_bus_if.DRV)::set(this, "e.agt.drv", "vif", top_if.DRV);
    uvm_config_db#(virtual simple_bus_if.MON)::set(this, "e.agt.mon", "vif", top_if.MON);
  endfunction
  task run_phase(uvm_phase phase);
    simple_seq seq = simple_seq::type_id::create("seq");
    phase.raise_objection(this);
    seq.start(e.agt.sqr);
    #100;
    phase.drop_objection(this);
  endtask
endclass

// 顶层模块:top.sv
module top;
  bit clk;
  always #5 clk = ~clk;
  simple_bus_if bus_if(clk);
  // 将接口连接到DUT(此处用简单逻辑代替)
  // 实际DUT连接省略,仅演示UVM组件连接
  initial begin
    uvm_config_db#(virtual simple_bus_if.DRV)::set(null, "uvm_test_top.e.agt.drv", "vif", bus_if.DRV);
    uvm_config_db#(virtual simple_bus_if.MON)::set(null, "uvm_test_top.e.agt.mon", "vif", bus_if.MON);
    run_test("test");
  end
endmodule

运行方式

# 编译(以QuestaSim为例)
vlog -sv -uvm simple_bus_if.sv uvm_components.sv top.sv
vsim -c -do "run -all; quit" top

# 或使用VCS
vcs -sverilog -ntb_opts uvm simple_bus_if.sv uvm_components.sv top.sv
./simv

验证方法与通过条件

  1. 编译通过:无语法错误,UVM组件类型注册成功。
  2. config_db传递成功:仿真日志中无FATAL级别的"virtual interface not found"报错,说明driver和monitor均成功从config_db获取到virtual interface。
  3. sequence执行:仿真日志显示sequence的body执行完成,driver成功驱动接口信号。
  4. monitor采样:monitor在valid有效时成功采样数据,并通过analysis port写出(可在monitor中加打印验证)。
  5. 无UVM警告/错误:仿真结束时UVM报告无UVM_ERROR或UVM_FATAL。

若以上条件全部满足,说明agent、env、test的层次化实例化与连接正确,config_db的virtual interface传递链路完整,组件间通信正常。