昨天组会时,老师说研二的同学把工作交接一下开始准备找工作。初听时还是很开心的,至少可以光明正大的看点儿uvm。但是细想,每天还得去公司挂机,也得去费尽心思去搞毕设,但是心理上更能接受而已。不过不管怎么样,还是专注把自己手头的工作做好吧,剩下的一半交给天意。
1.uvm_agent![](https://img-blog.csdnimg.cn/77b811ca734448ca972fd7cfef77448a.png)
1.agent 封装了sqr,driver和monitor,并将sqr和driver连接起来;
2.agt有两种模式,active和passive;
3.代码示例
`ifndef _GUARD_HELLO_AGENT_SV_
`define _GUARD_HELLO_AGENT_SV_ //两句连用,防止重复编译(C语言内容)
class hello_agent extends uvm_agent;
hello_sequencer sqr;
hello_driver dri;
hello_monitor mon;
//agt内例化 sqr,dri,moni
extern function new(string name,uvm_component parent);
extern virtual function void build_phase(uvm_phase phase);
extern virtual function void connect_phase(uvm_phase phase);
//agt中需要将dri与sqr连接在一起
uvm_analysis_port#(hello_transaction) ap;
`uvm_component_utils_begin(hello_agent) //uvm 工厂机制 宏注册
`uvm_field_object(sqr,UVM_ALL_ON)
`uvm_field_object(dri,UVM_ALL_ON)
`uvm_field_object(mon,UVM_ALL_ON)
`uvm_conponent_utils_end
endclass
function hello_agent::new(string name,uvm_component parent)
super.new(name,parent);
endfunction
//执行uvm_agent的new函数
function void hello_agent::build_phase(uvm_phase phase)
super.build_phase(phase);
if(is_active == UVM_ACTIVE) begin
sqr = hello_sequencer::type_id::create("sqr",this);
dri = hello_sequencer::type_id::create("sri",this);
mon = hello_sequencer::type_id::create("mon",this);
end
else begin
mon = hello_sequencer::type_id::create("mon",this);
endfunction
function void hello_agent::connect_phase(uvm_phase phase);
super.connect_phase(phase);
if(is_active == UVM_ACTIVE) begin
dri.seq_item_port.connect(sqr.seq_item_export);
this.ap = mon.ap;
end
else begin
this.ap = mon.ap
end
endfunction
2.reference model
1.模拟DUT的行为,计算相应的输出;继承于component(唯一)
输入:iagt_monitor 输出:scoreboard
例如在fifo验证中,就不需要reference model
2.代码示例
`ifndef _GUARD_HELLO_MODEL_SV_
`define _GUARD_HELLO_MODEL_SV_ //两句连用,防止重复编译(C语言内容)
class hello_model extends uvm_component
uvm_blocking_get_port#(hello_transaction) port;//从mon取的激励
uvm_analysis_port #(hello_transaction) ap;
extern function new(string name,uvm_component parent);
extern function void build_phase(uvm_phase phase);
extern task main_phase(uvm_phase phase);
`uvm_component_utils(hello_model) //uvm 工厂机制 宏注册
endclass
function hello_sequencer::new(string name,uvm_component parent)
super.new(name,parent);
endfunction
//执行reference model的new函数
function void hello_model::build_phase(uvm_phase phase)
super.build_phase(phase);
port = new("port",this); //reference model与monitor连接端口
ap = new("ap",this); //reference model与scoreboard连接端口
endfunction
task hello_model::main_phase(uvm_phase phase)
hello_transaction tr;
hello_transaction new_tr;
super.main_phase(phase);
while(1) begin
port.get(tr); //从monitor拿到tr
new_tr = new("new_tr");
new_tr.copy(tr); //复制tr到new_tr
new_tr.print();
ap.write(tr); //把new_tr发给scoreboard,本质上还是从vif获取的tr
end
endtask
3.uvm_scoreboard
1.scoreboard用于比较DUT的输出与reference model是否一致。只有一个构析函数,在component的基础上没有额外增加任何东西
2.代码分析
`ifndef _GUARD_HELLO_SCOREBOARD_SV_
`define _GUARD_HELLO_SCOREBOARD_SV_ //两句连用,防止重复编译(C语言内容)
class hello_scoreboard extends uvm_scoreboard
hello_transaction expect_queue[$];
uvm_blocking_get_port #(hello_transaction) exp_port;
uvm_blocking_get_port #(hello_transaction) act_port;
`uvm_component_utils(hello_scoreboard) //uvm 工厂机制 宏注册
extern function new(string name,uvm_component parent);
extern virtual function void build_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);
//new、build_phase、main_phase是一个component必须的
extern task xxx
//不同的component里面有各自完成独特功能的函数,属于用户自定义
endclass
function hello_monitor::new(string name,uvm_component parent)
super.new(name,parent);
endfunction
//执行uvm_scoreboard的new函数
function void hello_scoreboard::build_phase(uvm_phase phase)
super.build_phase(phase);
exp_port = new("exp_port",this);
act_port = new("act_port",this);
endfunction
task hello_scoreboard::main_phase(uvm_phase phase);
hello_transaction get_export,get_actual,tmp_tran;
bit result;
super.main_phase(phase);
fork
while(1) begin
exp_port.get(get_export);
expect_queue.push_back(get_export);
end
while(1) begin
act_port.get(get_actual);
if(expect_queue.size()>0) begin
tmp_tran = expect_queue.pop_front();
result = get_actual.compare(tmp_tran);
if(result) begin
tmp_tran.print();
end
else begin
`uvm_error("my_scoreboard","compare FAILED");
end
end
join
endtask
4.总结
1.agent的作用是什么?为什么需要agent这个组件?
相较于sv来说,uvm的存在就是为了提高代码的复用性和可维护。agent作为一个uvm_component类,是为了验证环境的复用而存在的。agt只是将dri、mon、sqr封装在一起,在它内部没有其他特殊的函数。封装成mon之后,在env中只需要例化agt而不需要例化dri和moni。dri和mon的代码是高度重复的,因为他们处理的是同一种协议,区别在于方向。把他们封装在一起,不同的agt就代表了不同的协议。
2.is_active的实现有什么好处?若用new创建drv,mon,sqr会怎么样?
is_active的存在是为了模块级的环境复用到更高级别的环境中。在build_phase中,根据is_active变量的值来决定sqr和dri是否要实例化。通常对于slave_agt,只需要监测信号时,可以设为passive,减少代码的冗余。另一方面,在模块级验证中,当模块验证环境被集成到一个更大的模块时,有真正的master模块设计连接着APB总线,,也有slave模块通过APB总线做响应。那这个时候,我就不需要你APB VIP里面的master agent 里面的 driver 和 sequencer 来模拟master去发送激励了,但这个时候,我们仍然想监测APB总线上数据的来来回回,但又不需要发送激励,这时候我们就可以通过对APB VIP的 master agent 和 slave agent 配置UVM_PASSIVE,也就是不例化 driver 和 sequencer ,只例化monitor,实现了模块级环境复用到更高级别的环境中。
UVM推荐使用内置方法 :: type_id :: create() ,而不是直接调用构造函数new()创建组件或事务对象。create方法在内部调用factory机制以查找所请求创建的类型,然后调用构造函数new()以实际创建一个对象而 无需更改任何代码 。