2. SV验证组件基础:Driver、Monitor、Sequencer、Agent、Scoreboard、Environment的职责与通信需求

在UVM验证方法学中,验证组件被划分为若干具有明确职责的模块。理解每个组件的核心职责以及它们之间的通信需求,是构建可复用、可扩展验证环境的前提。本章将逐一剖析六大基础组件的功能边界与交互契约。

2.1 组件职责速览

下表总结了每个组件的核心职责、典型实现方式以及主要通信对象:

组件 核心职责 典型实现 主要通信对象
Driver 将事务级激励转换为DUT接口时序信号 扩展 uvm_driver,实现 run_phase Sequencer(获取item)、DUT(驱动信号)
Monitor 采集DUT接口信号并重构为事务级数据 扩展 uvm_monitor,实现 run_phase DUT(采样信号)、Agent/Scoreboard(发送item)
Sequencer 管理激励序列,仲裁并分发事务item 扩展 uvm_sequencer,参数化item类型 Driver(TLM端口)、Sequence(产生item)
Agent 封装Driver、Monitor、Sequencer,提供统一接口 扩展 uvm_agent,配置active/passive模式 Environment(配置与连接)、外部组件
Scoreboard 比对预期结果与实际结果,报告验证状态 扩展 uvm_scoreboard,实现比较逻辑 Monitor(接收item)、Reference Model(获取预期)
Environment 构建、配置、连接所有验证组件,控制验证流程 扩展 uvm_env,在build_phase中实例化子组件 所有子组件(配置与连接)、Test(接收配置)

2.2 组件通信需求分析

验证组件的通信需求可归纳为三类:事务级TLM通信、配置通信和事件同步通信。下图展示了典型UVM验证环境中组件间的通信拓扑:

UVM验证环境组件通信拓扑 Environment Agent (Active Mode) Sequencer seq_item_export Driver seq_item_port Monitor ap (analysis_port) DUT (Interface) 信号级连接 TLM get 驱动时序 采样信号 Scoreboard imp_export Reference Model imp_export analysis analysis 预期数据 通信类型说明 • TLM通信:Sequencer↔Driver, Monitor→Scoreboard • 配置通信:Environment→Agent→子组件 • 事件同步:通过uvm_event或uvm_barrier

2.3 Driver:激励驱动者

Driver 是验证环境中唯一直接与DUT接口信号交互的组件。其核心职责包括:

  • 事务到信号的转换:从Sequencer获取事务级item,解析其字段,按照协议时序驱动到DUT接口。
  • 时序控制:处理时钟同步、握手信号、延迟等时序细节。
  • 错误注入:在驱动过程中可选择性注入协议违例或错误条件。
通信需求:Driver通过 seq_item_port 与Sequencer的 seq_item_export 建立TLM阻塞通信。Driver调用 get_next_item() 获取item,驱动完成后调用 item_done() 通知Sequencer。
class my_driver extends uvm_driver#(my_transaction);
  virtual my_interface vif;

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(!uvm_config_db#(virtual my_interface)::get(this, "", "vif", vif))
      `uvm_fatal("DRV", "No virtual interface assigned")
  endfunction

  task run_phase(uvm_phase phase);
    my_transaction tr;
    forever begin
      seq_item_port.get_next_item(tr);  // 从Sequencer获取item
      drive_transaction(tr);            // 驱动到DUT接口
      seq_item_port.item_done();        // 通知Sequencer完成
    end
  endtask
endclass

2.4 Monitor:信号采集者

Monitor 负责被动采集DUT接口上的信号,并将其重构为事务级数据对象。关键特性:

  • 被动观察:不驱动信号,只采样,确保不影响DUT行为。
  • 协议解析:根据协议规则将信号波形转换为有语义的事务item。
  • 广播分发:通过analysis_port将采集到的item广播给多个订阅者(如Scoreboard、Coverage Collector)。
设计建议:Monitor应独立于Driver实现,即使两者操作同一接口。这种分离使得Monitor可以在passive agent中独立工作,无需Sequencer和Driver。
class my_monitor extends uvm_monitor;
  virtual my_interface vif;
  uvm_analysis_port#(my_transaction) ap;

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    ap = new("ap", this);
    if(!uvm_config_db#(virtual my_interface)::get(this, "", "vif", vif))
      `uvm_fatal("MON", "No virtual interface assigned")
  endfunction

  task run_phase(uvm_phase phase);
    my_transaction tr;
    forever begin
      // 采样信号并构造事务
      tr = my_transaction::type_id::create("tr");
      @(posedge vif.clk);
      tr.addr = vif.addr;
      tr.data = vif.data;
      tr.op   = vif.op;
      ap.write(tr);  // 广播给所有订阅者
    end
  endtask
endclass

2.5 Sequencer:激励调度者

Sequencer 是激励生成与驱动之间的调度枢纽。其职责包括:

  • item仲裁:管理多个Sequence同时请求发送item时的优先级和仲裁策略。
  • item缓存:维护一个item队列,按序或按优先级分发给Driver。
  • Sequence生命周期管理:控制Sequence的启动、暂停、终止。
常见误区:Sequencer不负责生成item内容,只负责调度。item的具体字段值由Sequence对象通过 body() 任务产生。Sequencer与Sequence之间通过TLM端口通信,Sequence调用 start_item() 和 finish_item() 与Sequencer交互。
class my_sequencer extends uvm_sequencer#(my_transaction);
  // 通常不需要额外实现,继承自uvm_sequencer即可
  // 可在此添加自定义仲裁策略或回调函数
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
endclass

2.6 Agent:组件封装者

Agent 将Driver、Monitor、Sequencer封装为一个逻辑单元,代表一个协议接口的完整验证能力。Agent有两种工作模式:

模式 包含组件 适用场景
Active Driver + Monitor + Sequencer 验证环境主动驱动激励给DUT
Passive 仅Monitor 仅观察DUT行为,不驱动激励
通信需求:Agent负责在build_phase中实例化子组件,在connect_phase中建立Driver与Sequencer之间的TLM连接,并将Monitor的analysis_port暴露给上层Environment。
class my_agent extends uvm_agent;
  my_driver    driver;
  my_monitor   monitor;
  my_sequencer sequencer;
  uvm_analysis_port#(my_transaction) ap;

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    monitor = my_monitor::type_id::create("monitor", this);
    if(get_is_active() == UVM_ACTIVE) begin
      sequencer = my_sequencer::type_id::create("sequencer", this);
      driver    = my_driver::type_id::create("driver", 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);
    ap = monitor.ap;  // 将Monitor的analysis_port向上传递
  endfunction
endclass

2.7 Scoreboard:结果比对者

Scoreboard 是验证环境的“裁判”,负责比对DUT实际输出与预期结果。其核心机制:

  • 数据接收:通过TLM imp端口接收来自Monitor的实际输出和来自Reference Model的预期输出。
  • 数据存储:使用队列、关联数组或FIFO缓存待比对的数据。
  • 比对逻辑:支持精确比对、容差比对、顺序无关比对等多种策略。
  • 错误报告:发现不匹配时,通过uvm_error或自定义报告机制记录。
通信模式:Scoreboard通常使用 uvm_analysis_imp 接收多个数据流。典型实现中,实际输出和预期输出各对应一个imp,在各自的write函数中执行入队和比对操作。
class my_scoreboard extends uvm_scoreboard;
  uvm_analysis_imp#(my_transaction, my_scoreboard) actual_imp;
  uvm_analysis_imp#(my_transaction, my_scoreboard) expected_imp;
  my_transaction expected_queue[$];

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    actual_imp   = new("actual_imp", this);
    expected_imp = new("expected_imp", this);
  endfunction

  function void write_actual(my_transaction tr);
    my_transaction exp;
    if(expected_queue.size() > 0) begin
      exp = expected_queue.pop_front();
      if(!tr.compare(exp))
        `uvm_error("SCOREBOARD", $sformatf("Mismatch: actual=%s, expected=%s", tr.sprint(), exp.sprint()))
    end
    else
      `uvm_error("SCOREBOARD", "Unexpected actual transaction without expected")
  endfunction

  function void write_expected(my_transaction tr);
    expected_queue.push_back(tr);
  endfunction
endclass

2.8 Environment:环境构建者

Environment 是验证环境的顶层容器,负责:

  • 组件实例化:在build_phase中创建所有Agent、Scoreboard、Reference Model等子组件。
  • 配置传递:通过uvm_config_db将接口句柄、配置对象等传递给子组件。
  • 连接建立:在connect_phase中完成跨Agent的TLM连接,如将Monitor的analysis_port连接到Scoreboard。
  • 流程控制:协调验证流程,如设置超时、控制仿真结束条件。
class my_environment extends uvm_env;
  my_agent      agent;
  my_scoreboard scoreboard;
  my_ref_model  ref_model;

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    agent      = my_agent::type_id::create("agent", this);
    scoreboard = my_scoreboard::type_id::create("scoreboard", this);
    ref_model  = my_ref_model::type_id::create("ref_model", this);
    uvm_config_db#(virtual my_interface)::set(this, "agent.*", "vif", vif);
  endfunction

  function void connect_phase(uvm_phase phase);
    // 连接Monitor到Scoreboard和Reference Model
    agent.monitor.ap.connect(scoreboard.actual_imp);
    agent.monitor.ap.connect(ref_model.analysis_imp);
    // 连接Reference Model到Scoreboard
    ref_model.ap.connect(scoreboard.expected_imp);
  endfunction
endclass

2.9 通信机制总结

下表汇总了各组件之间的通信方式与典型端口:

通信对 通信方式 端口/接口 数据方向
Sequencer → Driver TLM阻塞通信 seq_item_port ↔ seq_item_export Sequencer → Driver
Monitor → Scoreboard TLM非阻塞广播 analysis_port ↔ analysis_imp Monitor → Scoreboard
Monitor → Reference Model TLM非阻塞广播 analysis_port ↔ analysis_imp Monitor → Reference Model
Reference Model → Scoreboard TLM非阻塞广播 analysis_port ↔ analysis_imp Reference Model → Scoreboard
Environment → Agent 配置通信 uvm_config_db Environment → Agent
Agent → 子组件 配置通信 uvm_config_db / 直接赋值 Agent → Driver/Monitor/Sequencer
关键设计原则:组件间的通信应尽量通过TLM端口进行,避免直接引用其他组件的内部成员。这种松耦合设计使得每个组件可以独立开发、测试和复用。在原型板部署场景中,这种通信机制还支持将部分组件部署到硬件加速器上,通过TLM桥接实现软硬件协同验证。