1. 概述
在基于UVM(Universal Verification Methodology)的验证平台上,Driver(驱动器)是一个至关重要的动态组件。它扮演着"执行者"的角色,专门负责将事务级(Transaction-Level)的激励数据,按照目标接口的物理时序协议,转换为引脚级的信号驱动。简单来说,Driver是连接验证平台抽象事务与待测设计(DUT)具体物理接口的桥梁。没有Driver,抽象的测试场景就无法施加到DUT上。
1.1 数据流转换中心
systemverilog
// Driver在UVM数据流中的位置
Sequence Item (抽象事务) → uvm_driver → DUT Signals (具体波形)
1.2 主要职责
- 事务获取:从sequencer获取序列项
- 协议转换:将事务转换为DUT接口时序
- 信号驱动:按照协议要求驱动物理信号
- 响应处理:可选地向sequencer返回响应
将uvm部分验证环境看成一个餐厅出菜系统,方便我们理解transaction、sequence、sequencer、driver、dut的关系。

2. 只有driver的uvm验证环境
2.1 搭建环境
如下图搭建了一个只有driver的UART验证环境,将uart的发送与接收回环,根据发送的数据与接收的数据对比,判断数据是否正常:

my_driver的实现如下,直接在driver中驱动信号:
systemverilog
`ifndef MY_DRIVER_SV
`define MY_DRIVER_SV
`include "uvm_macros.svh" //uvm宏定义文件
import uvm_pkg::*; //导入uvm包
class my_driver extends uvm_driver; //继承自uvm_driver
`uvm_component_utils(my_driver) //注册到工厂
function new(string name="my_driver",uvm_component parent = null);
super.new(name,parent);
endfunction
function void end_of_elaboration_phase (uvm_phase phase);
uvm_root::get().print_topology(); //在end_of_elaboration_phase 打印uvm验证环境拓扑
endfunction
virtual task run_phase(uvm_phase phase);
phase.raise_objection(this); //objection机制
while(!top_tb.rst_n) //等待复位完成
@(posedge top_tb.clk);
`uvm_info("my_driver","system reset finish!!!",UVM_LOW)
for(int i=0; i<10; i++)begin
wait(top_tb.tx_busy==1'b0);
top_tb.tx_en <= 1'b1; //发送数据
top_tb.tx_data <= $urandom_range(0,255);
#10;
top_tb.tx_en <= 1'b0;
wait(top_tb.tx_done); //等待发送完成,打印发送数据
`uvm_info("my_driver",$sformatf("uart tx_data is 0x%0X",top_tb.tx_data),UVM_LOW)
wait(top_tb.rx_valid); //等待接收数据有效,打印接收到的数据
`uvm_info("my_driver",$sformatf("uart rx_data is 0x%0X",top_tb.rx_data),UVM_LOW)
#10;
end
phase.drop_objection(this);
endtask
endclass
`endif
再在顶层testbenc中例化dut(uart_top):
systemverilog
module top_tb;
import uvm_pkg::*;
`include "uvm_macros.svh"
reg clk, rst_n;
reg tx_en;
reg [7:0] tx_data;
wire tx_busy, tx_done, tx_out;
wire rx_in;
wire rx_valid;
wire [7:0] rx_data;
wire rx_error, rx_busy;
// UART实例化
uart_top #(
.CLK_FREQ(100_000_000),
.BAUD_RATE(115200),
.DATA_BITS(8),
.STOP_BITS(1),
.PARITY(0)
) dut (
.clk(clk),
.rst_n(rst_n),
.tx_en(tx_en),
.tx_data(tx_data),
.tx_busy(tx_busy),
.tx_done(tx_done),
.tx_out(tx_out),
.rx_in(rx_in),
.rx_valid(rx_valid),
.rx_data(rx_data),
.rx_error(rx_error),
.rx_busy(rx_busy)
);
assign rx_in = tx_out;
// 时钟生成
initial begin
clk = 0;
forever #5 clk = ~clk; // 100MHz时钟
end
initial begin
// 初始化
rst_n = 0;
tx_en = 0;
tx_data = 8'h00;
// 复位
#100 rst_n = 1;
end
initial begin
run_test("my_driver"); //启动uvm
end
initial begin
$fsdbDumpfile("wave.fsdb"); //dump fsdb波形
$fsdbDumpvars(0,top_tb);
end
endmodule
仿真结果如下图:

仿真环境下载:一个只有driver的UART简单验证环境
2.2 当前环境的显著劣势
虽然上述环境能运行,但这与verilog中的仿真基本没有任何区别,并不能体现uvm环境的优势。 全局路径硬编码 - 可重用性差
systemverilog
// 问题代码:直接引用顶层模块信号
wait(top_tb.tx_busy==1'b0);
top_tb.tx_en <= 1'b1;
top_tb.tx_data <= $urandom_range(0,255);
- Driver与特定的测试平台绑定,无法在其他项目中重用
- 修改顶层模块名称或信号名称需要修改Driver代码
- 违反了UVM的封装原则
激励生成与驱动逻辑耦合
systemverilog
// 问题代码:激励生成和驱动逻辑混合在一起
top_tb.tx_data <= $urandom_range(0,255); // 激励生成
top_tb.tx_en <= 1'b1; // 驱动逻辑
- 无法实现激励的重用和组合
- 难以创建复杂的测试场景
- 无法实现约束随机验证
缺乏配置机制
systemverilog
// 问题:没有配置接口,所有参数硬编码
for(int i=0; i<10; i++)begin // 固定10次传输
- 无法在测试用例中动态配置Driver行为
- 无法实现不同测试用例的不同配置需求
- 调试和验证灵活性受限
同步机制原始
systemverilog
// 问题:使用原始的时序等待
#10;
wait(top_tb.tx_done);
- 时序控制不精确,容易产生竞争条件
- 无法适应不同时钟频率的配置
- 代码可读性和维护性差
3. 通用Driver实现
3.1 最简单的Driver示例
systemverilog
class basic_driver extends uvm_driver #(basic_transaction);
`uvm_component_utils(basic_driver)
virtual interface dut_if vif; //定义虚拟接口,用于与dut的连接
virtual task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req); //使用get_next_item方法获取一个事务
drive_transaction(req); //自定义方法,驱动dut
seq_item_port.item_done(); //item_done方法告知sequence,当前事务已经处理完成
end
endtask
endclass
通用driver事务来源一般为sequencer,seq_itme_port是driver与sequencer通信的TLM prot。关于TLM可查看UVM验证入门(4)-TLM1.0)
这个最简单的Driver示例体现了UVM驱动器的三个基本职责:
- 通信机制:通过seq_item_port与Sequencer建立标准TLM通信通道
- 事务获取:使用get_next_item(req)从Sequencer获取激励事务
- 完成确认:通过item_done()通知Sequencer当前事务处理完成
工作流程详解:
- get_next_item(req):阻塞方法,等待Sequencer发送下一个事务对象
- drive_transaction(req):自定义的驱动方法,将事务级数据转换为信号级时序
- item_done():关键的回调方法,允许Sequencer发送下一个事务
3.2 虚拟接口连接
systemverilog
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
// 获取虚拟接口
if (!uvm_config_db#(virtual dut_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "Virtual interface not set")
endfunction
配置数据库机制: 虚拟接口连接是UVM验证环境与DUT物理接口的桥梁,通过UVM配置数据库实现:
- 接口设置端(通常在测试平台顶层):
systemverilog
// 在top_tb中将物理接口注册到config_db
uvm_config_db#(virtual dut_if)::set(null, "uvm_test_top.env.agent.driver", "vif", dut_if_inst);
- 接口获取端(在Driver的build_phase中):
systemverilog
// 使用相同的路径和标识符获取接口
uvm_config_db#(virtual dut_if)::get(this, "", "vif", vif);
4. Driver与Sequencer的通信机制
4.1 端口连接
systemverilog
class test_env extends uvm_env;
virtual function void connect_phase(uvm_phase phase);
// Driver与Sequencer的关键连接
driver.seq_item_port.connect(sequencer.seq_item_export);
endfunction
endclass
TLM端口连接机制:
这是UVM组件间通信的核心基础设施,建立了Driver与Sequencer之间的标准通信通道:
- seq_item_port:Driver的TLM拉取端口,主动请求事务
- seq_item_export:Sequencer的TLM导出接口,提供事务流控制
连接时机与位置:
- 在connect_phase中执行,确保所有组件已完成实例化
- 通常在环境的connect_phase中完成此关键连接
- 遵循UVM的phase执行顺序:build_phase → connect_phase → run_phase
通信模式:
- 采用拉取(pull)模式,Driver主动从Sequencer获取事务
- Sequencer负责事务的仲裁、选择和流控制
- 支持复杂的序列调度和优先级管理
4.2 完整的通信流程
systemverilog
virtual task get_and_drive();
forever begin
// 1. 请求下一个事务
seq_item_port.get_next_item(req);
// 2. 处理事务
process_transaction(req);
// 3. 可选:返回响应
if (req.need_response) begin
rsp = advanced_transaction::type_id::create("rsp");
rsp.status = SUCCESS;
seq_item_port.put_response(rsp);
end
// 4. 标记事务完成
seq_item_port.item_done();
end
endtask
事务请求阶段
- get_next_item(req):阻塞调用,等待Sequencer提供有效事务
- 在此期间,Sequencer可以执行序列调度、仲裁和优先级处理
事务处理阶段
- process_transaction(req):将事务级数据转换为信号级时序
- 实现具体的协议驱动逻辑,如握手、时序控制等
响应返回阶段(可选)
- 创建响应对象并填充状态信息
- 通过put_response(rsp)将响应返回给原始序列
- 支持请求-响应通信模式
完成确认阶段
- item_done():关键的非阻塞调用,通知Sequencer可以发送下一事务
- 必须在事务处理完成后调用,否则会阻塞序列执行
5. 高级Driver特性
5.1 复位处理机制
在真实的验证环境中,复位处理是确保验证可靠性的关键特性。正确的复位处理能够:
- 避免复位期间的竞态条件
- 确保复位后信号和内部状态正确初始化
- 防止事务丢失或重复处理
systemverilog
class simple_driver extends uvm_driver;
`uvm_component_utils(simple_driver)
virtual dut_if vif;
virtual task run_phase(uvm_phase phase);
// 等待复位完成
wait(!vif.rst_n);
// 开始驱动事务
forever begin
seq_item_port.get_next_item(req);
drive_item(req);
seq_item_port.item_done();
end
endtask
virtual task drive_item(uvm_sequence_item item);
// 简单的驱动逻辑
@(posedge vif.clk);
vif.data <= item.data;
vif.valid <= 1'b1;
@(posedge vif.clk);
vif.valid <= 1'b0;
endtask
endclass
5.2 可配置Driver
可配置性是UVM验证环境的重要特性,它使得同一个Driver组件能够适应不同的测试需求和工作模式,大大增强了代码的可重用性和验证的灵活性。
- 参数化行为:通过外部配置控制Driver的内部行为,如时序延迟、工作模式等
- 测试场景适配:不同的测试用例可以配置不同的Driver参数,无需修改Driver代码
- 调试便利性:通过调整配置参数快速定位问题,提高调试效率
systemverilog
class config_driver extends uvm_driver;
`uvm_component_utils(config_driver)
int delay = 1;
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
// 从配置获取参数
uvm_config_db#(int)::get(this, "", "delay", delay);
endfunction
virtual task drive_item(uvm_sequence_item item);
repeat(delay) @(posedge vif.clk);
vif.data <= item.data;
vif.valid <= 1'b1;
@(posedge vif.clk);
vif.valid <= 1'b0;
endtask
endclass
//在test配置
class my_test extends uvm_test;
`uvm_component_utils(my_test)
virtual function void build_phase(uvm_phase phase);
// 设置driver延迟
uvm_config_db#(int)::set(this, "env.driver", "delay", 5);
endfunction
endclass
6. 总结
UVM Driver作为验证平台的核心组件,承担着事务级到信号级转换的关键桥梁作用。从简单的信号驱动器到具备复位处理、动态配置等高级特性的智能组件,Driver的设计质量直接影响验证环境的可重用性和效率。掌握Driver的通信机制、配置方法和高级特性,是构建标准化、可扩展UVM验证环境的基础,为复杂SoC验证提供坚实保障。