即使听起来很简单,但在实际实现中,在UVM agent中处理reset也不是那么简单。
在本文中,我将介绍一种处理reset的通用机制,该机制可以在任何UVM agent中重复使用。
让我们考虑一下,我们有一个具有以下架构的UVM agent:

步骤#1:处理agent组件中的reset
因为agent是最重要的组件,所以我们可以在其中实现一些逻辑,该逻辑可以检测到reset何时变为活动状态,然后通知其所有子组件,它们应该reset其逻辑(包括driver,monitor,sequencer等)。
class cfs_agent extends uvm_agent;
...
virtual task run_phase(uvm_phase phase);
forever begin
wait_reset_start();
if(agent_config.get_should_handle_reset() == 1) begin
handle_reset(phase, "HARD");
end
wait_reset_end();
end
endtask
...
endclass
通知所有子组件,它们应该重新reset相应逻辑,其实很简单:
class cfs_agent extends uvm_agent;
...
virtual function void handle_reset(uvm_phase phase, string kind = "HARD");
monitor.handle_reset(kind);
if(driver != null) begin
driver.handle_reset(kind);
end
if(sequencer != null) begin
sequencer.handle_reset(phase, kind);
end
if(coverage != null) begin
coverage.handle_reset(kind);
end
//add here any other component which might need to be reset
endfunction
...
endclass
在agent配置类中,我们声明用于控制reset处理的开关:
class cfs_agent_config extends uvm_component;
...
protected bit should_handle_reset;
function new(string name = "");
super.new(name);
should_handle_reset = 1;
endfunction
virtual function bit get_should_handle_reset();
return should_handle_reset();
endfunction
virtual function void set_should_handle_reset(bit should_handle_reset);
this.should_handle_reset = should_handle_reset;
endfunction
endclass
关于此切换背后的原因,请看一下本文的第2部分。
如果您想找到我们如何更好地抽象该agent逻辑,请阅读SystemVerilog中的“多重继承”。
步骤#2:处理monitor组件中的复位
从最基本的角度来看,monitor程序逻辑是一个连续的循环,它监视某些物理总线并收集所有传输。
基于此,我们可以说复位逻辑应停止该循环(无论复位来时其状态如何),清除所有临时信息并在复位完成后重新启动监视循环。
当然,无论agnet处理的物理协议如何,都必须这样做。
class cfs_monitor extends uvm_monitor;
...
//process for collect_transactions() task
protected process process_collect_transactions;
//task for collecting all transactions
virtual task collect_transactions();
fork
begin
process_collect_transactions = process::self();
forever begin
collect_transaction();
end
end
join
endtask
virtual task run_phase(uvm_phase phase);
forever begin
fork
begin
wait_reset_end();
collect_transactions();
disable fork;
end
join
end
endtask
//function for handling reset
virtual function void handle_reset(string kind = "HARD");
if(process_collect_transactions != null) begin
process_collect_transactions.kill();
end
//clear here any temporary information from the monitor
endfunction
...
endclass
步骤#3:处理driver组件中的复位
我们在monitor中实现的相同逻辑可以适用于driver组件。最后,driver组件的逻辑只是一个循环,等待sequencer的sequence并将它们放在物理总线上。
class cfs_driver extends uvm_driver;
...
//process for drive_transactions() task
protected process process_drive_transactions;
//task for driving all transactions
virtual task drive_transactions();
fork
begin
process_drive_transactions = process::self();
forever begin
cfs_item_drv_master transaction;
seq_item_port.get_next_item(transaction);
drive_transaction(transaction);
seq_item_port.item_done();
end
end
join
endtask
task run_phase(uvm_phase phase);
forever begin
fork
begin
wait_reset_end();
drive_transactions();
disable fork;
end
join
end
endtask
//function for handling reset
virtual function void handle_reset(string kind = "HARD");
if(process_drive_transactions != null) begin
process_drive_transactions.kill();
end
//clear here any temporary information, initialize some interface signals etc
endfunction
...
endclass
步骤4:在sequencer组件中处理重置
复位sequencer非常简单。我们只需要确保丢弃所有待处理的项目,以便sequencer可以在重置后处理新项目:
class cfs_sequencer extends uvm_sequencer;
...
virtual function void handle_reset(uvm_phase phase, string kind = "HARD");
uvm_objection objection = phase.get_objection();
int objections_count;
stop_sequences();
objections_count = objection.get_objection_count(this);
if(objections_count > 0) begin
objection.drop_objection(this, $sformatf("Dropping %0d objections at reset", objections_count), objections_count);
end
start_phase_sequence(phase);
endfunction
...
endclass
步骤5:处理Coverage组件中的复位
复位coverage组件更多地取决于物理协议,因为没有上述组件必须执行的“标准”逻辑。
因此,您可以使用handle_reset()函数在复位期间进行一些覆盖率采样,并清除所有临时信息:
class cfs_coverage extends uvm_component;
...
virtual function void handle_reset(string kind = "HARD");
//sample coverage groups related to reset
//clear some temporary information
endfunction
...
endclass
就是这样!
该技术非常通用,因此可以用于任何agent。
如果您想了解有关如何将此技术集成到通用agent中的更多信息,汉密尔顿·卡特(Hamilton Carter)曾在2015年写过两篇关于此类通用agent的文章:
- The Ecstasy and the Agony of UVM Abstraction and Encapsulation Featuring the AMIQ APB VIP: Part I
- Part II: The Ecstasy and the Agony of UVM Abstraction and Encapsulation Featuring the AMIQ APB VIP
希望这可以帮助?
在本文的第2部分中,您可以阅读有关如何在验证环境中处理重置的信息:SystemVerilog:如何在UVM中处理复位(第2部分)