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验证环境中组件间的通信拓扑:
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桥接实现软硬件协同验证。