- 13.3.2 事务传输实例
一、sequence body()的四步骤:
1、create_item() //创建request对象
2、start_item() //准备发送item
3、req.randomize with //发送前的随机化处理
4、finish_item() //完成item的发送
二、driver run_phase()的几个步骤
1、seq_item_port.get_next_item(tmp) //从sequencer中获取到有效的item\sequence
2、$ cast(req,tmp) //进行动态句柄转换
3、void’($cast(rep,req.clone())) //若有需要进行clone一份给rsp
4、seq_item_port.item_done(rsp) //最后通过此形式将rsp反馈给sequence
class bus_trans extends uvm_sequence_item;
rand int data;
`uvm_object_utils_begin(bus_trans)
`uvm_field_int(data,UVM_ALL_ON)
`uvm_object_utils_end
//...
endclass
class flas_seq extends uvm_sequence;
`uvm_object_utils(flat_seq)
//...
task body();
uvm_sequence_item tmp;
bud_trans req,rdp;
tmp = creat_item(bus_trans::get_type().m_sequencer,"req");
void'($cast(req,tmp));
start_item(req);
req.randomize with (data == 10);
`uvm_info("SEQ",$sformatf("sent a item \n%s",req.sprint()),UVM_LOW)
finish_item(req);
get_response(tmp);
vod'($cast(rsp,tmp));
`uvm_info("RSP",$sformatf("recived a item \n %s"),rsp.sprint(),UVM_LOW)
endtask
endclass
class sequencer extends uvm_sequencer;
`uvm_component_utils(sequencer);
//...
endclass
class driver extends uvm_driver;
`uvm_component_utils(driver)
//...
task run_phase(uvm_phase phase);
REQ tmp;
bus_trans req,rsp;
seq_item_port.get_next_item(tmp);
void'($cast(req,tmp));
`uvm_info("DRV",$sformatf("got an item \n %s"),req.sprint(),UVM_LOW)
void'($cast(rsp,req.clone()));
rsp.set_sequence_id(req.get_sequence_id());
rsp.data += 100;
seq_item_port.item_done(rsp);
`uvm_info("DRV",$sformatf("sent an item \n %s"),rsp.sprintf(),UVM_LOW)
endtask
endclass
class env extends uvm_env;
sequencer sqr;
driver drv;
`uvm_component_utils(env)
//...
function void build_phase (uvm_phase phase);
sqr = sequencer::type_id::create("sqr",this);
drv = driver::type_id::create("drv",this);
endfunction
function void connect_phase (uvm_phase phase)
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction
endclass
class test1 extends uvm_test;
env e;
`uvm_component_utils(test1)
//...
function void build_phase (uvm_phase phase);
e = env::type_id::create("e",this);
endfunction
task run_phase (uvm_phase phase);
flat_seq seq;
phase.raise_objection(phase);
seq = new();
seq.start(e.sqr); //实现了将sequence挂载到sequencer上
phase.drop_objection(phase);
endtask
endclass
- sequence中发送item跟sequence的区别
1、sequence挂载到sequencer上:HANDLE.start(m_sequencer,this) //若是没有更上层的sequence嵌套时可以省略this,例如在test层调top_seq的时候:HANLE.start(e.start‘“路径”)
2、将item挂载到sequencer上:
create_item(bus_trans::get_type(), m_sequencer, “req”)
finish_item(req)
class top_seq extends uvm_sequence;
`uvm_object_utils(top_seq)
function new(string name = "top_seq");
super.new(name);
endfunction
task body();
uvm_sequence_item tmp;
child_seq cseq;
bus_trans req;
// create child sequence and items
cseq = child_seq::type_id::create("cseq");
tmp = create_item(bus_trans::get_type(), m_sequencer, "req");
// send child sequence via start()
cseq.start(m_sequencer, this);
// send sequence item
void'($cast(req, tmp));
start_item(req);
req.randomize with {data == 20;};
finish_item(req);
endtask
endclass
- sequencer仲裁模式;
child_seq seq1,seq2,seq3;
m_sequencer.set_arbitration(UVM_SEQ_ARB_STRICT_FIFO);
fork
`uvm_do_pri_with(seq1, 500, {base == 10;})
`uvm_do_pri_with(seq1, 500, {base == 10;})
`uvm_do_pri_with(seq1, 300, {base == 10;})
//优先级
join
- layer sequence
module layer_seq;
import uvm_pkg::*;
`include "uvm_macros.svh"
typedef class phy_master_sequencer;
typedef enum {CLKON, CLKOFF, RESET, WRREG, RDREG} phy_cmd_t;
typedef enum {FREQ_LOW_TRANS, FREQ_MED_TRANS, FREQ_HIGH_TRANS} layer_cmd_t;
class bus_trans extends uvm_sequence_item;
rand phy_cmd_t cmd;
rand int addr;
rand int data;
constraint cstr{
soft addr == 'h0;
soft data == 'h0;
}
`uvm_object_utils_begin(bus_trans)
`uvm_field_enum(phy_cmd_t, cmd, UVM_ALL_ON)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "bus_trans");
super.new(name);
endfunction
endclass
class packet_seq extends uvm_sequence;
rand int len;
rand int addr;
rand int data[];
rand phy_cmd_t cmd;
constraint cstr{
soft len inside {[30:50]};
soft addr[31:16] == 'hFF00;
data.size() == len;
}
`uvm_object_utils(packet_seq)
function new(string name = "reg_test_seq");
super.new(name);
endfunction
task body();
bus_trans req;
foreach(data[i])
`uvm_do_with(req, {cmd == local::cmd;
addr == local::addr;
data == local::data[i];})
endtask
endclass
class layer_trans extends uvm_sequence_item;
rand layer_cmd_t layer_cmd;
rand int pkt_len;
rand int pkt_idle;
constraint cstr {
soft pkt_len inside {[10: 20]};
layer_cmd == FREQ_LOW_TRANS -> pkt_idle inside {[300:400]};
layer_cmd == FREQ_MED_TRANS -> pkt_idle inside {[100:200]};
layer_cmd == FREQ_HIGH_TRANS -> pkt_idle inside {[20:40]};
}
`uvm_object_utils(layer_trans)
function new(string name = "layer_trans");
super.new(name);
endfunction
endclass
class adapter_seq extends uvm_sequence;
`uvm_object_utils(adapter_seq)
`uvm_declare_p_sequencer(phy_master_sequencer)
function new(string name = "adapter_seq");
super.new(name);
endfunction
task body();
layer_trans trans;
packet_seq pkt;
forever begin
p_sequencer.up_sqr.get_next_item(req);
void'($cast(trans, req));
repeat(trans.pkt_len) begin
`uvm_do(pkt)
delay(trans.pkt_idle);
end
p_sequencer.up_sqr.item_done();
end
endtask
virtual task delay(int delay);
endtask
endclass
class top_seq extends uvm_sequence;
`uvm_object_utils(top_seq)
function new(string name = "top_seq");
super.new(name);
endfunction
task body();
layer_trans trans;
`uvm_do_with(trans, {layer_cmd == FREQ_LOW_TRANS;})
`uvm_do_with(trans, {layer_cmd == FREQ_HIGH_TRANS;})
endtask
endclass
class layering_sequencer extends uvm_sequencer;
`uvm_component_utils(layering_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class phy_master_sequencer extends uvm_sequencer;
layering_sequencer up_sqr;
`uvm_component_utils(phy_master_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class phy_master_driver extends uvm_driver;
`uvm_component_utils(phy_master_driver)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
REQ tmp;
bus_trans req;
forever begin
seq_item_port.get_next_item(tmp);
void'($cast(req, tmp));
`uvm_info("DRV", $sformatf("got a item \n %s", req.sprint()), UVM_LOW)
seq_item_port.item_done();
end
endtask
endclass
class phy_master_agent extends uvm_agent;
phy_master_sequencer sqr;
phy_master_driver drv;
`uvm_component_utils(phy_master_agent)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
sqr = phy_master_sequencer::type_id::create("sqr", this);
drv = phy_master_driver::type_id::create("drv", this);
endfunction
function void connect_phase(uvm_phase phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction
endclass
class test1 extends uvm_test;
layering_sequencer layer_sqr;
phy_master_agent phy_agt;
`uvm_component_utils(test1)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
layer_sqr = layering_sequencer::type_id::create("layer_sqr", this);
phy_agt = phy_master_agent::type_id::create("phy_agt", this);
endfunction
function void connect_phase(uvm_phase phase);
phy_agt.sqr.up_sqr = layer_sqr;
endfunction
task run_phase(uvm_phase phase);
top_seq seq;
adapter_seq adapter;
phase.raise_objection(phase);
seq = new();
adapter = new();
fork
adapter.start(phy_agt.sqr);
join_none
seq.start(layer_sqr);
phase.drop_objection(phase);
endtask
endclass
initial begin
run_test("test1");
end
endmodule
- virtual sequence
uvm_do_on宏用于显式地指定使用哪个sequencer发送此transaction,其参数形式为`uvm_do_on(SEQ_OR_ITEM,SEQR),第一个参数是transaction的指针,第二个是sequencer的指针。当使用uvm_do时,它实际等价于将uvm_do_on的第二个参数设置为了默认的sequencer,即此sequence启动时为其指定的sequencer。
'uvm_do_on(data_seq, p_sequencer.chnl_sqr0)
module virtual_seq;
import uvm_pkg::*;
`include "uvm_macros.svh"
typedef class mcdf_virtual_sequencer;
class clk_rst_seq extends uvm_sequence;
`uvm_object_utils(clk_rst_seq)
function new(string name = "clk_rst_seq");
super.new(name);
endfunction
endclass
class reg_cfg_seq extends uvm_sequence;
`uvm_object_utils(reg_cfg_seq)
function new(string name = "reg_cfg_seq");
super.new(name);
endfunction
endclass
class data_trans_seq extends uvm_sequence;
`uvm_object_utils(data_trans_seq)
function new(string name = "data_trans_seq");
super.new(name);
endfunction
endclass
class fmt_slv_cfg_seq extends uvm_sequence;
`uvm_object_utils(fmt_slv_cfg_seq)
function new(string name = "fmt_slv_cfg_seq");
super.new(name);
endfunction
endclass
// element sequences definitions above
// which belong to different sequencers/agents
// clk_rst_seq
// reg_cfg_seq
// data_trans_seq
// fmt_slv_cfg_seq
class mcdf_normal_seq extends uvm_sequence;
`uvm_object_utils(mcdf_normal_seq)
`uvm_declare_p_sequencer(mcdf_virtual_sequencer)
function new(string name = "mcdf_normal_seq");
super.new(name);
endfunction
task body();
clk_rst_seq clk_seq;
reg_cfg_seq cfg_seq;
data_trans_seq data_seq;
fmt_slv_cfg_seq fmt_seq;
// virtual sequence is to be attached the
// virtual sequencer, and further attache
// its child sequences via p_sequencer.OBJ_SQR_HANDLE
// configure formatter slave agent
`uvm_do_on(fmt_seq, p_sequencer.fmt_sqr)
// turn on clock and assert reset
`uvm_do_on(clk_seq, p_sequencer.cr_sqr)
// configure mcdf registers
`uvm_do_on(cfg_seq, p_sequencer.reg_sqr)
// transfer data packets
fork
`uvm_do_on(data_seq, p_sequencer.chnl_sqr0)
`uvm_do_on(data_seq, p_sequencer.chnl_sqr1)
`uvm_do_on(data_seq, p_sequencer.chnl_sqr2)
join
endtask
endclass
class cr_master_sequencer extends uvm_sequencer;
`uvm_component_utils(cr_master_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class reg_master_sequencer extends uvm_sequencer;
`uvm_component_utils(reg_master_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class chnl_master_sequencer extends uvm_sequencer;
`uvm_component_utils(chnl_master_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class fmt_slave_sequencer extends uvm_sequencer;
`uvm_component_utils(fmt_slave_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class reg_master_agent extends uvm_agent;
reg_master_sequencer sqr;
// other agents definition/build/connect ignored
`uvm_component_utils(reg_master_agent)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
sqr = reg_master_sequencer::type_id::create("sqr", this);
endfunction
endclass
class cr_master_agent extends uvm_agent;
cr_master_sequencer sqr;
// other agents definition/build/connect ignored
`uvm_component_utils(cr_master_agent)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
sqr = cr_master_sequencer::type_id::create("sqr", this);
endfunction
endclass
class chnl_master_agent extends uvm_agent;
chnl_master_sequencer sqr;
// other agents definition/build/connect ignored
`uvm_component_utils(chnl_master_agent)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
sqr = chnl_master_sequencer::type_id::create("sqr", this);
endfunction
endclass
class fmt_slave_agent extends uvm_agent;
fmt_slave_sequencer sqr;
// other agents definition/build/connect ignored
`uvm_component_utils(fmt_slave_agent)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
sqr = fmt_slave_sequencer::type_id::create("sqr", this);
endfunction
endclass
// element sequencers and agents definition above
// cr_master_sequencer | cr_master_agent
// reg_master_sequencer | reg_master_agent
// chnl_master_sequencer | chnl_master_agent
// fmt_slave_sequencer | fmt_slave_agent
class mcdf_virtual_sequencer extends uvm_sequencer;
cr_master_sequencer cr_sqr;
reg_master_sequencer reg_sqr;
chnl_master_sequencer chnl_sqr0;
chnl_master_sequencer chnl_sqr1;
chnl_master_sequencer chnl_sqr2;
fmt_slave_sequencer fmt_sqr;
`uvm_component_utils(mcdf_virtual_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class mcdf_env extends uvm_env;
cr_master_agent cr_agt;
reg_master_agent reg_agt;
chnl_master_agent chnl_agt0;
chnl_master_agent chnl_agt1;
chnl_master_agent chnl_agt2;
fmt_slave_agent fmt_agt;
mcdf_virtual_sequencer virt_sqr;
`uvm_component_utils(mcdf_env)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
cr_agt = cr_master_agent::type_id::create("cr_agt", this);
reg_agt = reg_master_agent::type_id::create("reg_agt", this);
chnl_agt0 = chnl_master_agent::type_id::create("chnl_agt", this);
chnl_agt1 = chnl_master_agent::type_id::create("chnl_agt", this);
chnl_agt2 = chnl_master_agent::type_id::create("chnl_agt", this);
fmt_agt = fmt_slave_agent::type_id::create("fmt_agt", this);
virt_sqr = mcdf_virtual_sequencer::type_id::create("virt_sqr", this);
endfunction
function void connect_phase(uvm_phase phase);
// virtual sequencer connection
// but no any TLM connection with sequencers
virt_sqr.cr_sqr = cr_agt.sqr;
virt_sqr.reg_sqr = reg_agt.sqr;
virt_sqr.chnl_sqr0 = chnl_agt0.sqr;
virt_sqr.chnl_sqr1 = chnl_agt1.sqr;
virt_sqr.chnl_sqr2 = chnl_agt2.sqr;
virt_sqr.fmt_sqr = fmt_agt.sqr;
endfunction
endclass