1. 搭建最小UVM验证环境

搭建最小UVM验证环境 学习卡片

任务目标

搭建一个可编译、可运行的最小UVM验证环境,包含uvm_test、uvm_env、uvm_agent、uvm_driver、uvm_sequencer、uvm_monitor、uvm_scoreboard七个核心组件,并通过一个简单测试用例验证组件间的连接与数据通路。

环境依赖

  • 仿真工具:VCS 或 QuestaSim(本案例以VCS为例)
  • UVM库:UVM-1.2(随仿真工具发布)
  • 文件结构:所有文件置于同一目录,编译顺序由文件列表控制

最小UVM环境实现

以下代码将全部组件定义在单个文件中,便于最小化编译与运行。核心数据通路为:sequencer产生事务 → driver驱动到接口 → monitor采样 → scoreboard比对。

// min_uvm_env.sv
`include "uvm_macros.svh"
import uvm_pkg::*;

// 简单事务
class simple_item extends uvm_sequence_item;
  rand bit [7:0] data;
  `uvm_object_utils_begin(simple_item)
    `uvm_field_int(data, UVM_ALL_ON)
  `uvm_object_utils_end
  function new(string name = "simple_item");
    super.new(name);
  endfunction
endclass

// 接口
interface simple_if(input bit clk);
  logic [7:0] data;
  logic valid;
endinterface

// 驱动器
class simple_driver extends uvm_driver #(simple_item);
  virtual simple_if vif;
  `uvm_component_utils(simple_driver)
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  task run_phase(uvm_phase phase);
    forever begin
      seq_item_port.get_next_item(req);
      @(posedge vif.clk);
      vif.data <= req.data;
      vif.valid <= 1;
      seq_item_port.item_done();
    end
  endtask
endclass

// 监视器
class simple_monitor extends uvm_monitor;
  virtual simple_if vif;
  uvm_analysis_port #(simple_item) mon_ap;
  `uvm_component_utils(simple_monitor)
  function new(string name, uvm_component parent);
    super.new(name, parent);
    mon_ap = new("mon_ap", this);
  endfunction
  task run_phase(uvm_phase phase);
    forever begin
      @(posedge vif.clk);
      if (vif.valid) begin
        simple_item item = simple_item::type_id::create("item");
        item.data = vif.data;
        mon_ap.write(item);
      end
    end
  endtask
endclass

// 序列发生器
class simple_sequencer extends uvm_sequencer #(simple_item);
  `uvm_component_utils(simple_sequencer)
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
endclass

// 代理
class simple_agent extends uvm_agent;
  simple_driver driver;
  simple_sequencer sequencer;
  simple_monitor monitor;
  `uvm_component_utils(simple_agent)
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    monitor = simple_monitor::type_id::create("monitor", this);
    if (get_is_active() == UVM_ACTIVE) begin
      driver = simple_driver::type_id::create("driver", this);
      sequencer = simple_sequencer::type_id::create("sequencer", this);
    end
  endfunction
  function void connect_phase(uvm_phase phase);
    if (get_is_active() == UVM_ACTIVE)
      driver.seq_item_port.connect(sequencer.seq_item_export);
  endfunction
endclass

// 计分板
class simple_scoreboard extends uvm_scoreboard;
  uvm_analysis_imp #(simple_item, simple_scoreboard) sb_export;
  int count;
  `uvm_component_utils(simple_scoreboard)
  function new(string name, uvm_component parent);
    super.new(name, parent);
    sb_export = new("sb_export", this);
  endfunction
  function void write(simple_item item);
    count++;
    `uvm_info("SCB", $sformatf("Received item, data=0x%0h, count=%0d", item.data, count), UVM_LOW)
  endfunction
endclass

// 环境
class simple_env extends uvm_env;
  simple_agent agent;
  simple_scoreboard scoreboard;
  `uvm_component_utils(simple_env)
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    agent = simple_agent::type_id::create("agent", this);
    scoreboard = simple_scoreboard::type_id::create("scoreboard", this);
  endfunction
  function void connect_phase(uvm_phase phase);
    agent.monitor.mon_ap.connect(scoreboard.sb_export);
  endfunction
endclass

// 测试
class simple_test extends uvm_test;
  simple_env env;
  `uvm_component_utils(simple_test)
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    env = simple_env::type_id::create("env", this);
  endfunction
  task run_phase(uvm_phase phase);
    simple_item item;
    phase.raise_objection(this);
    repeat (3) begin
      item = simple_item::type_id::create("item");
      assert(item.randomize());
      env.agent.sequencer.start_item(item);
      env.agent.sequencer.finish_item(item);
    end
    #100;
    phase.drop_objection(this);
  endtask
endclass

// 顶层模块
module top;
  logic clk = 0;
  always #5 clk = ~clk;
  simple_if if0(.clk(clk));

  initial begin
    uvm_config_db#(virtual simple_if)::set(null, "uvm_test_top.env.agent.*", "vif", if0);
    run_test("simple_test");
  end
endmodule

编译与运行

# 编译(VCS)
vcs -sverilog -ntb_opts uvm-1.2 -timescale=1ns/1ps min_uvm_env.sv -o simv

# 运行
./simv +UVM_TESTNAME=simple_test

验证方法与通过条件

  • 编译无错误,仿真退出码为0。
  • 日志中出现3条来自scoreboard的Received item信息,且count依次为1、2、3。
  • 无UVM_ERROR或UVM_FATAL报告。

满足以上条件即表示最小UVM环境搭建成功,组件连接正确,数据通路完整。