本文转载自https://blog.youkuaiyun.com/zhajio/article/details/79612388,感谢原作者。
上一篇文章集中讨论了 jelly-bean系统的transaction和sequence。本文将深入解释验证环境中的验证组件。
interface
在这一部分,将提供接口(jelly_bean_if)的一般解释及其绑定验证组件和jelly-bean(DUT)的作用。
下图显示了jelly_bean_if的内容。实质上,jelly_bean_if已包含从jelly_bean_transaction中的属性转换而来的信号。
interface jelly_bean_if(input bit clk);
logic [2:0] flavor;
logic [1:0] color;
logic sugar_free;
logic sour;
logic [1:0] taste;
clocking master_cb @ (posedge clk);
default input #1step output #1ns;
output flavor, color, sugar_free, sour;
input taste;
endclocking: master_cb
clocking slave_cb @ (posedge clk);
default input #1step output #1ns;
input flavor, color, sugar_free, sour;
output taste;
endclocking: slave_cb
modport master_mp(input clk, taste, output flavor, color, sugar_free, sour);
modport slave_mp(input clk, flavor, color, sugar_free, sour, output taste);
modport master_sync_mp(clocking master_cb);
modport slave_sync_mp(clocking slave_cb);
endinterface: jelly_bean_if
各个信号的时序由时钟块定义。 master_cb从总线master的角度定义时序,而slave_cb从总线slave的角度定义时序。
该接口还有modport列表,它定义了接口内信号的方向。我们定义了四个modport列表:
DUT使用异步modport列表(master_mp和slave_mp),而testbench使用同步modport列表(master_sync_mp和slave_sync_mp)。
更新(2014年4月2日):我们注意到有些仿真器不支持#1步骤(第9和15行)。如果是这种情况,您可以将其更改为#1ns。
PS:为避免竞争冒险,testbench需要使用同步后的信号,clocking时钟块即实现的同步功能,DUT不需要同步。
DUT
下面的代码显示了jelly_bean_taster的一个简单结构。第1行指定了我们刚刚定义的jelly_bean_if,以及slave_mp为接口信号选择适当的方向信息。品尝师只会对酸味巧克力口味产生负面影响(即有酸味的巧克力)!
module jelly_bean_taster( jelly_bean_if.slave_mp jb_slave_if );
import jelly_bean_pkg::*;
always @ ( posedge jb_slave_if.clk ) begin
if ( jb_slave_if.flavor == jelly_bean_transaction::CHOCOLATE &&
jb_slave_if.sour ) begin
jb_slave_if.taste <= jelly_bean_transaction::YUCKY;
end else begin
jb_slave_if.taste <= jelly_bean_transaction::YUMMY;
end
end
endmodule: jelly_bean_taster
或者,您可以在模块实例的端口连接中指定modport列表。
module jelly_bean_taster( jelly_bean_if jb_slave_if ); // no modport specified
// ...
endmodule
module top;
reg clk;
jelly_bean_if jb_slave_if( clk );
jelly_bean_taster jb_taster( jb_slave_if.slave_mp ); // modport specified
// ...
endmodule
您可以在模块声明和模块实例中指定modport列表,但如果您这样做,它们必须相同。如果完全没有指定modport列表,则接口中的信号被假定为无法访问。
PS:实际使用中,一般不这么用,dut不会使用interface,老老实实的在top中使用intf.xxx连接dut。
调用class中的成员:jelly_bean_transaction::YUCKY,YUCKY是class中定义的enum变量。::类似于使用extern 方法时的操作。
Sequencer
jelly-bean sequence由sequencer处理。 uvm_sequencer按原样使用,因为 jelly-bean sequencer不涉及任何类型的扩展功能。
typedef uvm_sequencer#(jelly_bean_transaction) jelly_bean_sequencer;
Driver
driver通过22行中的seq_item_port接收jelly_bean_transaction,然后驱动interface上的信号。driver使用driver和DUT之间的interface来驱动信号。该interface存储在uvm_config_db数据库中。
class jelly_bean_driver extends uvm_driver#(jelly_bean_transaction);
`uvm_component_utils(jelly_bean_driver)
virtual jelly_bean_if jb_vi;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction: new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
assert( uvm_config_db#( virtual jelly_bean_if )::get( this,"","jelly_bean_if",jb_vi ) ) );
endfunction: build_phase
task run_phase(uvm_phase phase);
jelly_bean_transaction jb_tx;
forever begin
@jb_vi.master_cb;
jb_vi.master_cb.flavor <= jelly_bean_transaction::NO_FLAVOR;
seq_item_port.get_next_item(jb_tx);
@jb_vi.master_cb;
jb_vi.master_cb.flavor <= jb_tx.flavor;
jb_vi.master_cb.color <= jb_tx.color;
jb_vi.master_cb.sugar_free <= jb_tx.sugar_free;
jb_vi.master_cb.sour <= jb_tx.sour;
seq_item_port.item_done();
end
endtask: run_phase
endclass: jelly_bean_driver
第20和23是所谓的时钟块事件。它们相当于@(posedge jb_vi.clk)
PS:interface相当于硬件,静态的,一直存在,class是动态的,class中是不能直接例化interface的,所以使用virtual,相当于取了interface的句柄。也可以直接使用top.intf_inst,但移植性会差些。
drv驱动的信号flavor--sour都是用的master_cb中的信号,为output型!主动产生激励的才是master,dut接受激励,为slave。
Monitor
monitor中的数据流向与driver中相反,但与驱动程序类似。 DUT的interface(jelly_bean_if)位于uvm_resource_db(第14行)。monitor密切监视jelly_bean_if,并获取信号的值。我们的monitor监视一个非NO_FLAVOR果冻豆(第23行)并创建一个jelly_bean_transaction(第24行)。创建的transaction通过analysis port发送给31行的用户。
class jelly_bean_monitor extends uvm_monitor;
`uvm_component_utils(jelly_bean_monitor)
uvm_analysis_port#(jelly_bean_transaction) jb_ap;
virtual jelly_bean_if jb_vi;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction: new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
assert(uvm_config_db#(virtual jelly_bean_if)::get(this,"","jelly_bean_if",jb_vi));
jb_ap = new(.name("jb_ap"), .parent(this));
endfunction: build_phase
task run_phase(uvm_phase phase);
forever begin
jelly_bean_transaction jb_tx;
@jb_vi.slave_cb;
if (jb_vi.slave_cb.flavor != jelly_bean_transaction::NO_FLAVOR) begin
jb_tx = jelly_bean_transaction::type_id::create(.name("jb_tx"), .contxt(get_full_name()));
//ATTENTION
jb_tx.flavor = jelly_bean_transaction::flavor_e'(jb_vi.slave_cb.flavor);
jb_tx.color = jelly_bean_transaction::color_e'(jb_vi.slave_cb.color);
jb_tx.sugar_free = jb_vi.slave_cb.sugar_free;
jb_tx.sour = jb_vi.slave_cb.sour;
@jb_vi.master_cb;
jb_tx.taste = jelly_bean_transaction::taste_e'(jb_vi.master_cb.taste);
jb_ap.write(jb_tx);
end
end
endtask: run_phase
endclass: jelly_bean_monitor
PS: 注意类型转换的操作,将flavor转换为枚举型值:jelly_bean_transaction::flavor_e'(jb_vi.slave_cb.flavor)。
注意mon中,采样的值flavor、color、sugar_free、sour用的是slave_cb中的信号,input型。taste则是用的master_cb中的信号,也是input型,平台不能对intf中的output型采样,因为这些值刚赋值完就采样,会引起竞争冒险。
Agent
sequencer,driver,monitor - 全部例化在在agent中。这些组件在build_phase中创建,创建的组件在connect_phase中连接。由于subscriber没有例化在agent,但是monitor要向subscriber发送trans,所以创建analysis port以与subscriber进行通信。agent和monitor中的analysis port在26行相互连接。然后,agent中的analysis port又和subscriber中的analysis imp在env中连接。
class jelly_bean_agent extends uvm_agent;
`uvm_component_utils(jelly_bean_agent)
uvm_analysis_port#(jelly_bean_transaction) jb_ap;
jelly_bean_sequencer jb_seqr;
jelly_bean_driver jb_drvr;
jelly_bean_monitor jb_mon;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction: new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
jb_ap = new(.name("jb_ap"), .parent(this));
jb_seqr = jelly_bean_sequencer::type_id::create(.name("jb_seqr"), .parent(this));
jb_drvr = jelly_bean_driver::type_id::create(.name("jb_drvr"), .parent(this));
jb_mon = jelly_bean_monitor::type_id::create(.name("jb_mon"), .parent(this));
endfunction: build_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
jb_drvr.seq_item_port.connect(jb_seqr.seq_item_export);
jb_mon.jb_ap.connect(jb_ap);
endfunction: connect_phase
endclass: jelly_bean_agent
PS:drv需要和sqr通过端口进行连接,虽然seq_item_port和seq_item_export是内建的。