| |
MonitorComponent
Overview
测试平台的analysis部分的第一项任务是监视DUT上的活动。Monitor,如Driver一样,是agent的组成部分。monitor组件类似于driver组件,因为它们都在实际信号活动和该活动的抽象表示之间执行转换。Monitor和Driver之间的关键区别在于Monitor始终是被动的。它不会驱动接口上的任何信号。当agent处于被动模式时,Monitor将继续执行。
Monitor通过虚拟接口与DUT信号通信,并包含识别信号活动中的协议模式的代码。一旦识别出协议模式,Monitor就会构建一个表示该活动的抽象事务模型,并将事务传输到任何感兴趣的组件。
Construction
Monitor应该扩展于uvm_monitor。它们应该有一个analysis端口和一个指向DUT接口的虚拟接口句柄。
class wb_bus_monitor extends uvm_monitor;
`uvm_component_utils(wb_bus_monitor)
uvm_analysis_port #(wb_txn) wb_mon_ap;
virtual wishbone_bus_syscon_if m_v_wb_bus_if;
wb_config m_config;
// Standard component constructor
function new(string name, uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase( uvm_phase phase );
super.build_phase( phase );
wb_mon_ap = new("wb_mon_ap", this);
m_config = wb_config::get_config(this); // get config object
endfunction
function void connect_phase( uvm_phase phase );
super.connect_phase( phase );
m_v_wb_bus_if = m_config.v_wb_bus_if; // set local virtual if property
endfunction
// run_phase not shown...
endclass
Passive Monitoring
就像在科学实验中,观察行为不应影响观察到的活动,monitor组件应该是被动的。它们不应将任何活动注入DUT信号。实际上,这意味着monitor代码在与DUT信号交互时应该是完全只读的。
Recognizing Protocols
监视器必须具有协议代码,以便检测信号活动中的可识别模式。可以通过在monitor的run()任务中编写特定于协议的状态机代码来完成检测。此代码通过虚拟接口句柄观察等待关键信号活动的模式。
Building Transaction Objects
一旦识别出模式,monitors就会构建一个或多个抽象地表示信号活动的事务。这可以通过调用函数并将特定于事务的属性(例如数据值和地址值)作为函数的参数传递,或者通过在检测到现有事务时设置事务属性来完成。
Copy-on-Write Policy
由于SystemVerilog中的对象是基于句柄的,因此当Monitor将事务句柄写入其analysis端口时,只会将句柄复制并传输给subscribers。每次Monitor在run()任务中运行其正在进行的协议识别循环时,都会执行此写操作。为防止在循环的下一次迭代中覆盖相同的对象内存,传输的句柄应指向Monitor创建的事务对象的单独副本。
这可以通过两种方式实现:
Broadcasting the Transaction
一旦建立了新的或克隆的事务,就应该通过写入analysis端口向所有感兴趣的观察者传输。
Example Monitor
task run_phase( uvm_phase phase );
wb_txn txn, txn_clone;
txn = wb_txn::type_id::create("txn"); // Create once and reuse
forever @ (posedge m_v_wb_bus_if.clk)
if(m_v_wb_bus_if.s_cyc) begin // Is there a valid wb cycle?
txn.adr = m_v_wb_bus_if.s_addr; // get address
txn.count = 1; // set count to one read or write
if(m_v_wb_bus_if.s_we) begin // is it a write?
txn.data[0] = m_v_wb_bus_if.s_wdata; // get data
txn.txn_type = WRITE; // set op type
while (!(m_v_wb_bus_if.s_ack[0] | m_v_wb_bus_if.s_ack[1]|m_v_wb_bus_if.s_ack[2]))
@ (posedge m_v_wb_bus_if.clk); // wait for cycle to end
end
else begin
txn.txn_type = READ; // set op type
case (1) //Nope its a read, get data from correct slave
m_v_wb_bus_if.s_stb[0]: begin
while (!(m_v_wb_bus_if.s_ack[0])) @ (posedge m_v_wb_bus_if.clk); // wait for ack
txn.data[0] = m_v_wb_bus_if.s_rdata[0]; // get data
end
m_v_wb_bus_if.s_stb[1]: begin
while (!(m_v_wb_bus_if.s_ack[1])) @ (posedge m_v_wb_bus_if.clk); // wait for ack
txn.data[0] = m_v_wb_bus_if.s_rdata[1]; // get data
end
endcase
end
$cast(txn_clone, txn.clone()); // Clone txn to protect from next loop iteration overwriting
wb_mon_ap.write(txn_clone); // broadcast the cloned txn
end
endtask
(在http://verificationacademy.com/uvm-ovm上在线下载源代码示例)。