UVM中uvm_analysis_imp与uvm_tlm_analysis_fifo的区别、适用场景及替代疑问
问题1:uvm_analysis_imp与uvm_tlm_analysis_fifo的区别及适用场景
核心区别
| 特性 | uvm_analysis_imp | uvm_tlm_analysis_fifo |
|---|---|---|
| 本质 | 被动TLM端口,需用户实现write回调方法 | 封装了uvm_analysis_imp和FIFO的组件,自带存储 |
| 数据存储 | 无内置存储,仅做转发/即时处理 | 内置FIFO队列,可缓存事务 |
| 连接支持 | 支持多个uvm_analysis_port连接(一对多) | 通常一对一连接(发送端→FIFO,接收端从FIFO取数) |
| 处理时机 | 事务到达时立即执行write方法(同步处理) | 接收端可异步从FIFO取数,无需实时响应 |
示例代码
多监视器→单记分板(用uvm_analysis_imp)
// 记分板实现imp及write方法 class scoreboard extends uvm_scoreboard; uvm_analysis_imp#(transaction, scoreboard) analysis_imp; function new(string name = "scoreboard", uvm_component parent=null); super.new(name, parent); analysis_imp = new("analysis_imp", this); endfunction // 必须实现的write回调 virtual function void write(transaction tr); `uvm_info(get_type_name(), $sformatf("Received trans: data=0x%0h", tr.data), UVM_MEDIUM) // 此处做数据比对、统计等逻辑 endfunction endclass // 监视器(多个实例可连接到同一记分板) class monitor extends uvm_monitor; uvm_analysis_port#(transaction) analysis_port; function void build_phase(uvm_phase phase); super.build_phase(phase); analysis_port = new("analysis_port", this); endfunction task run_phase(uvm_phase phase); forever begin transaction tr = transaction::type_id::create("tr"); // 总线采集逻辑... analysis_port.write(tr); // 发送事务到记分板 end endtask endclass // 环境中连接多监视器到单记分板 class env extends uvm_env; monitor mon1, mon2; scoreboard sb; function void connect_phase(uvm_phase phase); super.connect_phase(phase); mon1.analysis_port.connect(sb.analysis_imp); mon2.analysis_port.connect(sb.analysis_imp); endfunction endclass
监视器→记分板异步处理(用uvm_tlm_analysis_fifo)
适用于记分板处理速度慢,需要缓存事务的场景:
// 带FIFO的记分板 class scoreboard extends uvm_scoreboard; uvm_tlm_analysis_fifo#(transaction) analysis_fifo; function new(string name = "scoreboard", uvm_component parent=null); super.new(name, parent); analysis_fifo = new("analysis_fifo", this); endfunction task run_phase(uvm_phase phase); transaction tr; forever begin analysis_fifo.get(tr); // 阻塞等待FIFO中有数据 `uvm_info(get_type_name(), $sformatf("Fetched trans from FIFO: data=0x%0h", tr.data), UVM_MEDIUM) // 耗时处理逻辑... end endtask endclass // 环境中连接 class env extends uvm_env; monitor mon; scoreboard sb; function void connect_phase(uvm_phase phase); super.connect_phase(phase); mon.analysis_port.connect(sb.analysis_fifo.analysis_export); endfunction endclass
问题2:是否可以用uvm_analysis_imp替代uvm_tlm_analysis_fifo?
可以,但需要自行实现缓存逻辑。uvm_analysis_imp本身没有存储功能,若要模拟FIFO的缓存效果,需在write方法中手动维护队列或其他存储结构,并在接收端线程中异步取数。
示例(手动实现缓存):
class scoreboard extends uvm_scoreboard; uvm_analysis_imp#(transaction, scoreboard) analysis_imp; transaction tr_queue[$]; // 手动维护缓存队列 function new(string name = "scoreboard", uvm_component parent=null); super.new(name, parent); analysis_imp = new("analysis_imp", this); endfunction virtual function void write(transaction tr); tr_queue.push_back(tr); // 事务到来时存入队列 endfunction task run_phase(uvm_phase phase); transaction tr; forever begin wait(tr_queue.size() > 0); tr = tr_queue.pop_front(); // 处理事务... end endtask endclass
这种方式等价于uvm_tlm_analysis_fifo的核心功能,但uvm_tlm_analysis_fifo已经封装了get/peek/try_get等方法,以及满/空状态判断,无需重复造轮子。
问题3:如何在两者间做选择?
按以下优先级判断:
- 多发送端场景:必须用
uvm_analysis_imp,因为它支持多个analysis_port同时连接,而uvm_tlm_analysis_fifo通常只适配一对一连接。 - 需要异步/缓存处理:优先选
uvm_tlm_analysis_fifo,它自带FIFO存储,省去手动维护缓存的代码,且支持灵活的取数时机(如peek查看数据不删除、try_get非阻塞取数)。 - 一对一实时处理:两种都可,若只需即时处理事务,
uvm_analysis_imp更轻量;若后续可能需要缓存扩展,uvm_tlm_analysis_fifo更具扩展性。
内容的提问来源于stack exchange,提问作者Kiran Kumar
相关产品推荐
相关产品推荐

