UVM
TLM通讯
class master;
uvm_analysis_port #(lvc_apb_transfer)item_collected_port
function new();
item_collected_port = new("item_collected_port",this);
endfunction
endclass
class slave;
uvm_analysis_port #(lvc_i2c_slave_transaction)xact_observed_port
endclass
`uvm_analysis_imp_decl(_apb_master)
`uvm_analysis_imp_decl(_i2c_slave)
class scoreboard;
uvm_analysis_imp_apb_master #(lvc_apb_transfer,scoreboard) apb_trans_observe_imp;
uvm_analysis_imp_i2c_slave #(lvc_i2c_slave_transaction,scoreboard) i2c_trans_observe_imp;
virtual function void write_apb_master();
endfunction
virtual function void write_i2c_slave();
endfunction
endclass
class cgm;
uvm_analysis_imp_apb_master #(lvc_apb_transfer,scoreboard) apb_trans_observe_imp;
uvm_analysis_imp_i2c_slave #(lvc_i2c_slave_transaction,scoreboard) i2c_trans_observe_imp;
endclass
class env;
virtual void connect_phase(uvm_phase phase);
master.item_collected_port.connect(scoreboard.apb_trans_observe_imp);
slave.xact_observed_port.connect(scoreboard.i2c_trans_observe_imp);
master.item_collected_port.connect(cgm.apb_trans_observe_imp);
slave.xact_observed_port.connect(cgm.i2c_trans_observe_imp);
endfunction
endclass
总结:一个port连接多个import是通过analysis_port解决的,但是一个import被多个port连接,是通过宏定义来解决方法重名的问题。
在这里,由于使用了analysis port,因此方法必然是write函数,宏定义后也是在write函数后加后缀。
1.关于回调函数的使用:
应用1:下图是正向的使用测试用例进行测试
class mcdf_data_consistence_basic_test extends mcdf_base_test;
`uvm_component_utils(mcdf_data_consistence_basic_test)
function new(string name = "mcdf_data_consistence_basic_test", uvm_component parent);
super.new(name, parent);
endfunction
task do_reg();
bit[31:0] wr_val, rd_val;
// slv0 with len=8, prio=0, en=1
wr_val = (1<<3)+(0<<1)+1;
this.write_reg(`SLV0_RW_ADDR, wr_val);
this.read_reg(`SLV0_RW_ADDR, rd_val);
void'(this.diff_value(wr_val, rd_val, "SLV0_WR_REG"));
// slv1 with len=16, prio=1, en=1
wr_val = (2<<3)+(1<<1)+1;
this.write_reg(`SLV1_RW_ADDR, wr_val);
this.read_reg(`SLV1_RW_ADDR, rd_val);
void'(this.diff_value(wr_val, rd_val, "SLV1_WR_REG"));
// slv2 with len=32, prio=2, en=1
wr_val = (3<<3)+(2<<1)+1;
this.write_reg(`SLV2_RW_ADDR, wr_val);
this.read_reg(`SLV2_RW_ADDR, rd_val);
void'(this.diff_value(wr_val, rd_val, "SLV2_WR_REG"));
// send IDLE command
this.idle_reg();
endtask
task do_formatter();
void'(fmt_gen.randomize() with {fifo == LONG_FIFO; bandwidth == HIGH_WIDTH;});
fmt_gen.start();
endtask
task do_data();
void'(chnl_gens[0].randomize() with {ntrans==100; ch_id==0; data_nidles==0; pkt_nidles==1; data_size==8; });
void'(chnl_gens[1].randomize() with {ntrans==100; ch_id==1; data_nidles==1; pkt_nidles==4; data_size==16;});
void'(chnl_gens[2].randomize() with {ntrans==100; ch_id==2; data_nidles==2; pkt_nidles==8; data_size==32;});
fork
chnl_gens[0].start();
chnl_gens[1].start();
chnl_gens[2].start();
join
#10us; // wait until all data haven been transfered through MCDF
endtask
endclass: mcdf_data_consistence_basic_test
下图是使用回调的方式达到和前面的测试用例的相同办法。
class mcdf_base_test extends uvm_test;
`uvm_register_cb(mcdf_base_test, cb_mcdf_base)
task run_phase(uvm_phase phase);
phase.raise_objection(this);
this.do_reg();均是虚任务,每个任务中增加了`uvm_do_callbacks(mcdf_base_test, cb_mcdf_base, cb_do_reg()),以此来添加回调函数
this.do_formatter();
this.do_data();
phase.drop_objection(this);
endtask
endclass
定义一个具体的callback
class cb_mcdf_base extends uvm_callback;
mcdf_base_test test;
virtual task cb_do_reg();
虚任务
endtask
virtual task cb_do_formatter();
虚任务
endtask
virtual task cb_do_data();
虚任务
endtask
endclass
class cb_mcdf_data_consistence_basic extends cb_mcdf_base;
task cb_do_reg();
放具体的内容
endtask
task cb_do_formatter();
具体的内容
endtask
task cb_do_data();
具体的内容
endtask
endclass: cb_mcdf_data_consistence_basic
注意这部分test相当于一个容器的作用,在其中放了具体的回调函数。由于对于回调函数预留的入口在mcdf_base_test中,因此,在这里的绑定实际上也是将mcdf_base_test和具体例化的回调函数cb进行绑定。
class cb_mcdf_data_consistence_basic_test extends mcdf_base_test;
cb_mcdf_data_consistence_basic cb;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
cb = cb_mcdf_data_consistence_basic::type_id::create("cb");
uvm_callbacks#(mcdf_base_test)::add(this, cb);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
cb.test = this;
endfunction
endclass: cb_mcdf_data_consistence_basic_test
回调函数关于pre的用法:
(1)在pre函数中定义相关条件,用于判断这个函数是否发生,典型的例子是uvm_event中的pre_trigger函数中的返回值,返回值为0继续执行相关trigger任务,如果返回值为1,不执行后续的内容。
(2)在发送数据前发送一些报文,用于快速定位数据产生的位置,也可以通过pre函数实现;对发送的数据产生一些约束,而具体的约束就可以通过pre函数定义。
启动sequence中的两种方式:(1)uvm_do_on_with(2)start函数,先进行new,一方面可以在new中给参数,另一方面在new之后可以通过句柄索引的方式赋参数。
package arbitration;
import uvm_pkg::*;
`include "uvm_macros.svh"
class item extends uvm_sequence_item;
`uvm_object_utils(item)
rand int i;
function new(string name = "item");
super.new(name);
endfunction
endclass
class seq extends uvm_sequence#(item);
`uvm_object_utils(seq)
int i;
function new(string name = "seq");
super.new(name);
endfunction
virtual task body();
item req;
//#10;
repeat(5)begin
//#5;
`uvm_do_pri_with(req,1000,{i == local::i; })
//`uvm_do_with(req,{i == local::i; })
i = i+1;
`uvm_info("seq",$sformatf("the value of i is %0d",i),UVM_LOW)
end
endtask
endclass
class seq2 extends uvm_sequence#(item);
`uvm_object_utils(seq)
int i;
function new(string name = "seq2");
super.new(name);
endfunction
virtual task body();
item req;
//#20;
m_sequencer.grab(this);
repeat(5)begin
// #20;
m_sequencer.grab(this);
`uvm_do_pri_with(req,1,{i == local::i; })
//`uvm_do_with(req,{i == local::i; })
i = i+1;
`uvm_info("seq2",$sformatf("the value of i is %0d",i),UVM_LOW)
m_sequencer.ungrab(this);
end
endtask
endclass
class driver extends uvm_driver#(item);
`uvm_component_utils(driver)
function new(string name = "driver",uvm_component parent);
super.new(name,parent);
endfunction
virtual task run_phase(uvm_phase phase);
forever begin
item rsp;
rsp = new();
seq_item_port.get_next_item(rsp);
`uvm_info("driver",$sformatf("the value of i is %0d",rsp.i),UVM_LOW)
seq_item_port.item_done();
end
endtask
endclass
class sequencer extends uvm_sequencer #(item);
`uvm_component_utils(sequencer)
function new(string name = "sequencer",uvm_component parent);
super.new(name,parent);
endfunction
endclass
class env extends uvm_env;
`uvm_component_utils(env)
sequencer sqr;
driver dr;
function new(string name = "env",uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
sqr = sequencer::type_id::create("sqr",this);
dr = driver::type_id::create("dr",this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
dr.seq_item_port.connect(sqr.seq_item_export);
endfunction
endclass
class test extends uvm_test;
`uvm_component_utils(test)
env e;
seq s1;
seq2 s2;
function new(string name = "parent",uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
e = env::type_id::create("e",this);
s1 = new("s1");
s2 = new("s2");
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
e.sqr.set_arbitration(UVM_SEQ_ARB_FIFO);
fork
s1.start(e.sqr,null,100);
s2.start(e.sqr,null,1);
join
phase.drop_objection(this);
endtask
endclass
endpackage
工厂机制和config_db机制
package arbitration;
import uvm_pkg::*;
`include "uvm_macros.svh"
class item extends uvm_sequence_item;
rand int i;
`uvm_object_utils_begin(item)
`uvm_field_int(i,UVM_ALL_ON)
`uvm_object_utils_end
constraint cstr{i inside {[0:10]};};
function new(string name = "item");
super.new(name);
endfunction
endclass
class seq extends uvm_sequence#(item);
`uvm_object_utils(seq)
function new(string name = "seq");
super.new(name);
endfunction
virtual task body();
item req;
req = new("req");
repeat(5)begin
`uvm_do(req)
end
endtask
endclass
class seq2 extends seq#(item);
`uvm_object_utils(seq2)
bit err_on = 0;
function new(string name = "seq2");
super.new(name);
`uvm_info("seq2",$sformatf("%0s",get_full_name()),UVM_LOW)
endfunction
virtual task pre_body();
if(!uvm_config_db#(int)::get(null,get_full_name(),"err_on",err_on))begin
`uvm_error("seq2",$sformatf("the value of err_on is not get"))
end
if(err_on == 1)begin
`uvm_info("seq2",$sformatf("the value of err_on is get"),UVM_LOW)
end
endtask
virtual task body();
item req;
req = new();
req.cstr.constraint_mode(0);
repeat(5)begin
`uvm_do(req)
end
endtask
endclass
class driver3 extends uvm_driver#(item);
`uvm_component_utils(driver3)
function new(string name = "driver3",uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
virtual task run_phase(uvm_phase phase);
item req;
req = new();
forever begin
seq_item_port.get_next_item(req);
if(req.i > 50)
`uvm_info("driver3",$sformatf("the value is error,50"),UVM_LOW)
seq_item_port.item_done();
end
endtask
endclass
class driver2 extends driver3;
`uvm_component_utils(driver2)
bit err_on = 0;
function new(string name = "driver2",uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(int)::get(this,"","err_on",err_on))begin
`uvm_error("driver2",$sformatf("the value of err_on is not get"))
end
`uvm_info("driver2",$sformatf("%s",get_full_name()),UVM_LOW)
if(err_on == 1)begin
`uvm_info("driver2",$sformatf("the value of err_on is get"),UVM_LOW)
end
endfunction
virtual task run_phase(uvm_phase phase);
item req;
req = new();
forever begin
seq_item_port.get_next_item(req);
if(req.i > 10)
`uvm_info("driver2",$sformatf("the value is error,10"),UVM_LOW)
seq_item_port.item_done();
end
endtask
endclass
class driver extends driver2;
`uvm_component_utils(driver)
function new(string name = "driver",uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
virtual task run_phase(uvm_phase phase);
item req;
req = new();
forever begin
seq_item_port.get_next_item(req);
`uvm_info("driver",$sformatf("the value of req after get_item is %0d",req.i),UVM_LOW)
seq_item_port.item_done();
end
endtask
endclass
class sequencer extends uvm_sequencer#(item);
`uvm_component_utils(sequencer)
function new(string name = "sequencer",uvm_component parent);
super.new(name,parent);
endfunction
endclass
class env extends uvm_env;
`uvm_component_utils(env)
sequencer sqr;
driver dr;
driver2 dr2;
driver3 dr3;
function new(string name = "env",uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
sqr = sequencer::type_id::create("sqr",this);
dr = driver::type_id::create("dr",this);
dr2 = driver2::type_id::create("dr2",this);
dr3 = driver3::type_id::create("dr3",this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
dr3.seq_item_port.connect(sqr.seq_item_export);
dr2.seq_item_port.connect(sqr.seq_item_export);
dr.seq_item_port.connect(sqr.seq_item_export);
endfunction
endclass
class test extends uvm_test;
`uvm_component_utils(test)
bit err_on = 1;
bit cov;
env e;
seq s1;
seq2 s2;
function new(string name = "test",uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(int)::get(this,"","cov",cov))begin
`uvm_error("test",$sformatf("the value of cov is not get"))
end
else
`uvm_info("test",$sformatf("the value of cov is get"),UVM_LOW)
`uvm_info("test",$sformatf("right"),UVM_LOW)
if(cov)begin
`uvm_info("driver",$sformatf("the value of err_on is %0d",err_on),UVM_LOW)
set_type_override_by_type(driver3::get_type(),driver2::get_type());
//set_type_override_by_type(seq2::get_type(),seq::get_type());
set_type_override_by_type(driver2::get_type(),driver::get_type());
end
`uvm_info("test",$sformatf("right"),UVM_LOW)
e = env::type_id::create("e",this);
s2 = seq2::type_id::create("s2");
s1 = seq::type_id::create("s1");
`uvm_info("test",$sformatf("right"),UVM_LOW)
uvm_config_db#(int)::set(this,"e.sqr.s2","err_on",err_on);
uvm_config_db#(int)::set(this,"e.dr*","err_on",err_on);
`uvm_info("test",$sformatf("right"),UVM_LOW)
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
`uvm_info("test",$sformatf("right"),UVM_LOW)
s1.start(e.sqr);
`uvm_info("test",$sformatf("right"),UVM_LOW)
s2.start(e.sqr);
`uvm_info("test",$sformatf("right"),UVM_LOW)
phase.drop_objection(this);
endtask
endclass
endpackage
module tb;
import arbitration::*;
import uvm_pkg::*;
`include "uvm_macros.svh"
bit cov = 0;
initial begin
uvm_config_db#(int)::set(null,"uvm_test_top","cov",cov);
run_test("test");
end
endmodule
-------------------------------------------------------------------------
package arbitration;
import uvm_pkg::*;
`include "uvm_macros.svh"
class item extends uvm_sequence_item;
rand integer i;
`uvm_object_utils_begin(item)
`uvm_field_int(i,UVM_ALL_ON)
`uvm_object_utils_end
constraint cstr{i inside {[0:10]};}
function new(string name = "item");
super.new(name);
endfunction
endclass
class seq extends uvm_sequence#(item);
`uvm_object_utils(seq)
function new(string name = "seq");
super.new(name);
endfunction
virtual task body();
item req;
req = new("req");
repeat(5)begin
`uvm_do(req)
end
endtask
endclass
class seq2 extends seq#(item);
`uvm_object_utils(seq2)
bit err_on = 0;
function new(string name = "seq2");
super.new(name);
//`uvm_info("seq2",$sformatf("%0s",get_full_name()),UVM_LOW)
endfunction
virtual task pre_body();
if(!uvm_config_db#(int)::get(null,get_full_name(),"err_on",err_on))begin
`uvm_error("seq2",$sformatf("the value of err_on is not get"))
end
if(err_on == 1)begin
`uvm_info("seq2",$sformatf("the value of err_on is get"),UVM_LOW)
end
endtask
virtual task body();
item req;
req = new();
req.cstr.constraint_mode(0);
repeat(5)begin
`uvm_rand_send_with(req,{req.i>10;})
end
endtask
endclass
class driver3 extends uvm_driver#(item);
`uvm_component_utils(driver3)
function new(string name = "driver3",uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
`uvm_info("driver3",$sformatf("enter the build phase of driver3"),UVM_LOW)
super.build_phase(phase);
endfunction
virtual task run_phase(uvm_phase phase);
item req;
req = new();
forever begin
seq_item_port.get_next_item(req);
`uvm_info("driver3",$sformatf("the value of req after get_item is %0d",req.i),UVM_LOW)
if(req.i > 50)
`uvm_info("driver3",$sformatf("the value is error,50"),UVM_LOW)
seq_item_port.item_done();
end
endtask
endclass
class driver2 extends driver3;
`uvm_component_utils(driver2)
bit err_on = 0;
function new(string name = "driver2",uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
`uvm_info("driver2",$sformatf("enter the build phase of driver2"),UVM_LOW)
super.build_phase(phase);
if(!uvm_config_db#(int)::get(this,"","err_on",err_on))begin
`uvm_error("driver2",$sformatf("the value of err_on is not get"))
end
else begin
`uvm_info("driver2",$sformatf("the value of err_on is get"),UVM_LOW)
end
`uvm_info("driver2",$sformatf("%s",get_full_name()),UVM_LOW)
if(err_on == 1)begin
`uvm_info("driver2",$sformatf("the value of err_on is get"),UVM_LOW)
end
endfunction
virtual task run_phase(uvm_phase phase);
item req;
req = new();
forever begin
seq_item_port.get_next_item(req);
`uvm_info("driver2",$sformatf("the value of req after get_item is %0d",req.i),UVM_LOW)
if(req.i > 10)
`uvm_info("driver2",$sformatf("the value is error,10"),UVM_LOW)
seq_item_port.item_done();
end
endtask
endclass
class driver extends driver2;
`uvm_component_utils(driver)
function new(string name = "driver",uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
`uvm_info("driver",$sformatf("enter the build phase of driver"),UVM_LOW)
super.build_phase(phase);
//`uvm_info("driver2",$sformatf("driver2","enter the build phase of driver"),UVM_LOW)
endfunction
virtual task run_phase(uvm_phase phase);
item req;
req = new();
forever begin
seq_item_port.get_next_item(req);
`uvm_info("driver",$sformatf("the value of req after get_item is %0d",req.i),UVM_LOW)
seq_item_port.item_done();
end
endtask
endclass
class sequencer extends uvm_sequencer#(item);
`uvm_component_utils(sequencer)
function new(string name = "sequencer",uvm_component parent);
super.new(name,parent);
endfunction
endclass
class env extends uvm_env;
`uvm_component_utils(env)
sequencer sqr;
driver dr;
driver2 dr2;
driver3 dr3;
function new(string name = "env",uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
sqr = sequencer::type_id::create("sqr",this);
dr = driver::type_id::create("dr",this);
dr2 = driver2::type_id::create("dr2",this);
dr3 = driver3::type_id::create("dr3",this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
dr3.seq_item_port.connect(sqr.seq_item_export);
dr2.seq_item_port.connect(sqr.seq_item_export);
dr.seq_item_port.connect(sqr.seq_item_export);
endfunction
endclass
class test extends uvm_test;
`uvm_component_utils(test)
bit err_on = 1;
bit cov;
env e;
seq s1;
seq2 s2;
function new(string name = "test",uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
uvm_factory factory = uvm_factory::get();
super.build_phase(phase);
//uvm_factory factory = uvm_factory::get();
if(!uvm_config_db#(int)::get(this,"","cov",cov))begin
`uvm_error("test",$sformatf("the value of cov is not get"))
end
else
`uvm_info("test",$sformatf("the value of cov is get"),UVM_LOW)
//uvm_factory factory = uvm_factory::get();
if(cov)begin
`uvm_info("driver",$sformatf("the value of err_on is %0d",err_on),UVM_LOW)
set_type_override_by_type(driver3::get_type(),driver2::get_type());
set_type_override_by_type(seq::get_type(),seq2::get_type());
set_type_override_by_type(driver2::get_type(),driver::get_type());
end
e = env::type_id::create("e",this);
s2 = seq2::type_id::create("s2");
s1 = seq::type_id::create("s1");
uvm_config_db#(int)::set(this,"e.sqr.s2","err_on",err_on);
uvm_config_db#(int)::set(this,"e.dr*","err_on",err_on);
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
//fork
// begin
`uvm_info("test",$sformatf("start s1"),UVM_LOW)
s1.start(e.sqr);
`uvm_info("test",$sformatf("end s1"),UVM_LOW)
//#20;
// end
// begin
`uvm_info("test",$sformatf("start s2"),UVM_LOW)
s2.start(e.sqr);
`uvm_info("test",$sformatf("end s2"),UVM_LOW)
// end
//join
phase.drop_objection(this);
endtask
endclass
endpackage