引子:Transaction 不会自己变成波形
在 UVM 验证平台中,sequence 负责产生 transaction 对象,sequencer 负责调度这些 transaction,但真正驱动 DUT 引脚、产生时序波形的是谁?答案是 driver。
然而,driver 本身通常并不直接操作信号,它通过调用BFM (Bus Functional Model)提供的信号级任务来完成实际的总线时序。transaction 是抽象的“数据包”,BFM 是“物理层驱动”,driver 则是连接两者的“调度器”。理解这三者的分工,是构建高效、可复用验证环境的核心。
Driver 与 BFM 的分工
Driver —— 从 Sequencer 到 BFM 的搬运工
uvm_driver是一个 UVM 组件,它通过seq_item_port从 sequencer 获取 transaction,然后将其转换为对 BFM 的调用。Driver 的核心任务是:
- 从 sequencer 获取下一个 transaction(
get_next_item)。 - 解析 transaction 中的抽象字段(如地址、数据、读写方向)。
- 调用 BFM 提供的信号级 task,驱动 DUT 接口。
- 完成传输后,调用
item_done()通知 sequencer。
重点:Driver 不应该直接操作vif信号,除非没有 BFM 或波形非常简单。将信号级操作封装在 BFM 中,可以让 driver 保持协议无关性,提高复用度。
BFM —— 信号级的“黑盒”封装
BFM (Bus Functional Model) 是对某一种总线协议(如 AHB、AXI、APB)的信号级行为封装。它以 task/function 的形式提供类似drive_write(addr, data)、drive_read(addr, data)这样的接口。
一个典型的 BFM 可能包含:
interface my_bfm ( input logic clk, input logic rst_n, output logic [31:0] addr, output logic [31:0] wdata, input logic [31:0] rdata, output logic write, output logic valid, input logic ready ); // BFM 信号级任务:发起一次写操作 task drive_write(input logic [31:0] a, input logic [31:0] d); @(posed