天津企悦在线网站建设,网站建设方案与报价,中国企业信用信息网官网,手绘动画制作软件UVM TLM Analysis Port#xff1a;一对多的广播电台
你已经掌握了点对点的Put/Get通信#xff0c;现在我们来学习 UVM TLM Analysis Port —— 这是一种特殊的广播式通信机制。它就像一个电台广播#xff0c;发射塔#xff08;发送者#xff09;…UVM TLM Analysis Port一对多的广播电台你已经掌握了点对点的Put/Get通信现在我们来学习UVM TLM Analysis Port—— 这是一种特殊的广播式通信机制。它就像一个电台广播发射塔发送者只管发送信号不在乎有多少收音机接收者在听甚至不在乎有没有人在听。 核心比喻电台广播 vs 电话通话想象两种通信方式电话通话Put/Get Port一对一必须有人接听才能通话电台广播Analysis Port一对多不管有没有听众照常广播Analysis Port就是UVM的广播电台解决了Monitor需要广播数据给多个监听者Scoreboard、Coverage Collector等的需求。⚙️ 工作原理广播模式 vs 点对点模式下图清晰展示了Analysis Port与传统Put/Get Port在通信模式上的根本区别 Analysis Port 的核心特性1. 非阻塞通信// Analysis Port使用function不是task立即返回virtual functionvoidwrite(T t);// 在同一个仿真delta周期内完成// 不会阻塞发送者endfunction2. 零到多个接收者// 可以连接到0个、1个或多个接收者// 如果没有连接调用write()不会出错只是什么都不做ap.write(pkt);// 即使没有subscriber也不会报错3. 内置广播机制// 内部自动循环调用所有连接的接收者的write()方法// 发送者只需调用一次write()所有接收者都会收到 完整示例深度解析让我们详细分析你提供的例子理解Analysis Port如何工作第一步定义事务类simple_packetclass simple_packet extends uvm_object;rand bit[7:0]addr;rand bit[7:0]data;bit rwb;// read/write bituvm_object_utils_begin(simple_packet)uvm_field_int(addr,UVM_ALL_ON)uvm_field_int(data,UVM_ALL_ON)uvm_field_int(rwb,UVM_ALL_ON)uvm_object_utils_end functionnew(string namesimple_packet);super.new(name);endfunction endclass第二步创建广播者componentB这是广播电台只管发送不管接收class componentB extends uvm_component;uvm_component_utils(componentB)// 1. 声明Analysis Port广播端口uvm_analysis_port #(simple_packet)ap;// 2. 传统Put接口用于接收componentA的数据uvm_blocking_put_imp #(simple_packet,componentB)put_export;functionnew(string namecomponentB,uvm_component parentnull);super.new(name,parent);endfunction virtual functionvoidbuild_phase(uvm_phase phase);super.build_phase(phase);// 创建Analysis Port广播端口apnew(analysis_port,this);endfunction// 3. 实现Put接口接收componentA的数据virtual taskput(simple_packet pkt);uvm_info(COMPB,从CompA收到Packet,UVM_LOW)pkt.print();// 关键收到数据后立即广播给所有订阅者ap.write(pkt);// 广播endtask// 4. 也可以主动生成数据广播可选virtual taskrun_phase(uvm_phase phase);// 这里可以主动生成数据广播// 但示例中是通过put()接收数据后广播endtask endclass第三步创建订阅者sub这是收音机接收广播信号注意继承自uvm_subscriber基类它已经内置了analysis_export// UVM提供的订阅者基类已经实现了大部分功能virtual class uvm_subscriber #(type Tint)extends uvm_component;typedefuvm_subscriber #(T)this_type;// 内置的analysis_export我们不需要自己声明uvm_analysis_imp #(T,this_type)analysis_export;// 纯虚函数子类必须实现pure virtual functionvoidwrite(T t);endclass// 我们的具体订阅者类class sub #(type Tsimple_packet)extends uvm_subscriber #(T);uvm_component_utils(sub)functionnew(string namesub,uvm_component parentnull);super.new(name,parent);endfunction// 必须实现的write()函数// 注意参数名必须是t这是UVM的约定virtual functionvoidwrite(T t);uvm_info(get_full_name(),订阅者收到事务,UVM_MEDIUM)// 这里可以进一步处理数据比如// - 发送给Scoreboard检查// - 收集覆盖率信息// - 记录日志endfunction endclass第四步创建发送者componentA这是数据的原始来源class componentA extends uvm_component;uvm_component_utils(componentA)// Put端口发送数据给componentBuvm_blocking_put_port #(simple_packet)put_port;functionnew(string namecomponentA,uvm_component parentnull);super.new(name,parent);endfunction virtual functionvoidbuild_phase(uvm_phase phase);super.build_phase(phase);put_portnew(put_port,this);endfunction virtual taskrun_phase(uvm_phase phase);for(inti0;i5;i)begin simple_packet pktsimple_packet::type_id::create(pkt);pkt.randomize();uvm_info(COMPA,发送Packet给CompB,UVM_LOW)pkt.print();// 发送给componentBput_port.put(pkt);end endtask endclass第五步环境连接my_env这是连接电台和收音机的地方class my_env extends uvm_env;uvm_component_utils(my_env)componentA compA;componentB compB;sub #(simple_packet)sub1,sub2,sub3;// 三个订阅者functionnew(string namemy_env,uvm_component parentnull);super.new(name,parent);endfunction virtual functionvoidbuild_phase(uvm_phase phase);super.build_phase(phase);// 创建所有组件compAcomponentA::type_id::create(compA,this);compBcomponentB::type_id::create(compB,this);sub1sub#(simple_packet)::type_id::create(sub1,this);sub2sub#(simple_packet)::type_id::create(sub2,this);sub3sub#(simple_packet)::type_id::create(sub3,this);endfunction virtual functionvoidconnect_phase(uvm_phase phase);// 1. 点对点连接A - BcompA.put_port.connect(compB.put_export);// 2. 广播连接B - 所有订阅者关键compB.ap.connect(sub1.analysis_export);compB.ap.connect(sub2.analysis_export);compB.ap.connect(sub3.analysis_export);endfunction endclass 数据流分析看看广播如何工作从输出日志可以看到清晰的广播模式1. ComponentA发送第一个Packet [COMPA] Packet sent to CompB pkt: { addr: h2f, data: h64, rwb: h0 } 2. ComponentB收到并广播 [COMPB] Packet received from CompA 同时广播给三个订阅者... 3. 所有订阅者同时收到 [sub1] Sub got transaction ← 同一时间 [sub2] Sub got transaction ← 同一时间 [sub3] Sub got transaction ← 同一时间 4. 重复5次每个Packet都被3个订阅者收到关键发现所有订阅者都在**同一仿真时间0ns**收到了事务因为write()是函数在同一个delta周期完成 Analysis Port 的典型应用场景场景1Monitor广播事务最经典的应用class monitor extends uvm_component;uvm_analysis_port #(bus_transaction)ap_mon;virtual taskrun_phase(uvm_phase phase);forever begin bus_transaction tr;// 监控总线捕获事务capture_transaction(tr);// 广播给所有监听者ap_mon.write(tr);// Scoreboard、Coverage等都会收到end endtask endclass场景2配置信息广播class config_manager extends uvm_component;uvm_analysis_port #(config_packet)ap_config;virtual taskupdate_config(config_packet cfg);// 更新配置current_configcfg;// 广播新配置给所有组件ap_config.write(cfg);// 所有组件立即收到新配置endtask endclass场景3事件通知系统class event_notifier extends uvm_component;uvm_analysis_port #(event_notification)ap_event;virtual tasknotify_event(string event_name,uvm_object datanull);event_notification evtnew(event_name,data);ap_event.write(evt);// 所有监听事件的组件都会收到endtask endclass⚠️ Analysis Port 的独特特性特性1零连接也正常工作// 即使没有连接任何订阅者也不会出错ap.write(pkt);// ✅ 安全不会崩溃// 这与Put/Get Port不同// put_port.put(pkt); // ❌ 如果没有连接会阻塞或出错特性2函数 vs 任务// Analysis Port使用function非阻塞virtual functionvoidwrite(T t);// ✅ 立即返回// Put/Get使用task可能阻塞virtual taskput(T t);// ❌ 可能被接收方阻塞特性3自动广播循环// 发送者只需调用一次write()ap.write(pkt);// 内部自动执行类似这样的操作foreach(subscribers[i])begin subscribers[i].write(pkt);// 自动调用每个订阅者end 实际应用构建完整监控系统让我们看一个更实际的例子Monitor监控DUT并广播给多个组件// 1. 事务定义class bus_transaction extends uvm_sequence_item;rand bit[31:0]addr;rand bit[31:0]data;rand bit write;// ... 其他字段endclass// 2. Monitor监控DUT并广播class bus_monitor extends uvm_component;uvm_component_utils(bus_monitor)uvm_analysis_port #(bus_transaction)ap;virtual bus_if vif;functionnew(string name,uvm_component parent);super.new(name,parent);endfunction virtual functionvoidbuild_phase(uvm_phase phase);super.build_phase(phase);apnew(ap,this);// 获取虚拟接口if(!uvm_config_db#(virtual bus_if)::get(this,,vif,vif))uvm_fatal(NOVIF,未找到虚拟接口)endfunction virtual taskrun_phase(uvm_phase phase);forever begin (posedge vif.clk);if(vif.validvif.ready)begin bus_transaction trbus_transaction::type_id::create(tr);tr.addrvif.addr;tr.datavif.data;tr.writevif.write;// 关键广播事务ap.write(tr);end end endtask endclass// 3. Scoreboard检查功能正确性class scoreboard extends uvm_subscriber #(bus_transaction);uvm_component_utils(scoreboard)// 内置了analysis_export我们只需实现write()virtual functionvoidwrite(bus_transaction t);// 检查事务的正确性check_transaction(t);endfunction virtual functionvoidcheck_transaction(bus_transaction t);// 具体检查逻辑...uvm_info(SCOREBOARD,检查事务,UVM_MEDIUM)endfunction endclass// 4. Coverage Collector收集覆盖率class coverage_collector extends uvm_subscriber #(bus_transaction);uvm_component_utils(coverage_collector)covergroup bus_cg;addr_cp:coverpoint tr.addr{bins low{[0:32hFF]};bins mid{[32h100:32hFFF]};bins high{[32h1000:32hFFFF]};}data_cp:coverpoint tr.data;write_cp:coverpoint tr.write;endgroup virtual functionvoidwrite(bus_transaction t);bus_cg.sample();// 收集覆盖率endfunction endclass// 5. Logger记录日志class transaction_logger extends uvm_subscriber #(bus_transaction);uvm_component_utils(transaction_logger)virtual functionvoidwrite(bus_transaction t);// 记录到日志文件$fdisplay(log_file,Time: %0t, Addr: 0x%h, Data: 0x%h, Write: %b,$time,t.addr,t.data,t.write);endfunction endclass// 6. 环境连接所有组件class my_env extends uvm_env;bus_monitor monitor;scoreboard sb;coverage_collector cov;transaction_logger logger;virtual functionvoidconnect_phase(uvm_phase phase);// Monitor广播给所有订阅者monitor.ap.connect(sb.analysis_export);monitor.ap.connect(cov.analysis_export);monitor.ap.connect(logger.analysis_export);// 可以轻松添加更多订阅者...endfunction endclass⚡ Analysis Port 的高级用法用法1使用analysis_fifo缓冲广播数据// 当订阅者处理速度较慢时可以使用analysis_fifoclass my_env extends uvm_env;bus_monitor monitor;uvm_tlm_analysis_fifo #(bus_transaction)fifo;scoreboard sb;virtual functionvoidconnect_phase(uvm_phase phase);// Monitor - FIFO缓冲monitor.ap.connect(fifo.analysis_export);// FIFO - ScoreboardScoreboard按自己速度读取sb.get_port.connect(fifo.get_export);endfunction endclass用法2选择性广播// 根据条件决定是否广播class smart_monitor extends uvm_component;uvm_analysis_port #(bus_transaction)ap;virtual taskrun_phase(uvm_phase phase);forever begin bus_transaction trcapture_transaction();// 只广播特定类型的事务if(should_broadcast(tr))begin ap.write(tr);end end endtask virtual function bitshould_broadcast(bus_transaction tr);// 只广播写操作或地址在特定范围内的事务return(tr.write||(tr.addr inside{[32h1000:32h1FFF]}));endfunction endclass用法3多Analysis Port广播// 一个组件有多个Analysis Port广播不同类型的数据class advanced_monitor extends uvm_component;// 广播完整事务uvm_analysis_port #(bus_transaction)ap_full;// 只广播地址信息轻量级uvm_analysis_port #(addr_info)ap_addr;// 广播错误信息uvm_analysis_port #(error_packet)ap_error;virtual taskrun_phase(uvm_phase phase);forever begin bus_transaction trcapture_transaction();// 广播完整事务ap_full.write(tr);// 广播地址信息给只需要地址的订阅者addr_info addrnew(tr.addr);ap_addr.write(addr);// 如果有错误广播错误信息if(has_error(tr))begin error_packet errnew(总线错误,tr);ap_error.write(err);end end endtask endclass Analysis Port vs Put/Get Port 对比总结特性Analysis PortPut/Get Port通信模式广播一对多点对点一对一连接要求0-N个接收者必须有1个接收者阻塞性非阻塞function阻塞task方法类型write()函数put()/get()任务典型应用Monitor广播Generator→Driver内部实现循环调用所有订阅者直接调用接收者错误处理无连接也不报错无连接会阻塞或报错 实战练习建议练习1基础广播系统创建一个Monitor每100ns生成一个随机事务创建3个不同的订阅者Scoreboard、Coverage、Logger观察所有订阅者是否同时收到相同事务练习2选择性广播修改Monitor只广播特定条件的事务如写操作观察订阅者是否只收到符合条件的事务练习3带缓冲的广播使用uvm_tlm_analysis_fifo缓冲广播数据创建慢速Scoreboard每200ns处理一个事务观察FIFO如何缓冲数据练习4实际场景模拟实现一个完整的Monitor-Scoreboard-Coverage系统添加事务过滤功能实现多级广播Monitor→多个分析组件 核心思想总结UVM TLM Analysis Port是只管广播不问接收的通信模式广播特性一次发送多个接收零依赖没有接收者也能正常工作非阻塞立即返回不影响发送者灵活扩展轻松添加/移除订阅者记住这个黄金法则一对多用Analysis广播数据最方便写用函数非阻塞零个订阅也不怕Monitor广播最常见Scoreboard收数据。掌握了Analysis Port你就能够构建高效、灵活的数据广播系统让验证平台各个组件能够协同工作现在尝试在你的测试平台中添加一个Monitor用它来广播事务给所有感兴趣的组件吧