需要注意的几个重点:
driver同sequencer之间的TLM通信采取了get模式,即由driver发起请求,从sequencer一端获得item,再由sequencer将其传递至driver。
作为driver,只要它可以从sequencer获取item,它就可以一直工作下去。
sequencer和item只应该在合适的时间点产生需要的数据,而至于怎么处理数据,则会由driver来实现。
flat_seq作为动态创建的数据生成载体,它的主任务flat_seq::body()做了如下的几件事情:
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 flat_seq extends uvm_sequence;
`uvm_object_utils(flat_seg)
...
task body();
uvm_sequence_item tmp;
bus_trans req,rsp;
tmp=create_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);
void'($cast(rsp, tmp));
`uvm_info("SEQ",$sformatf("got a item \n %s", rsp.sprint()), UVM_LOW)
endtask
endclass
在定义driver时,它的主任务driver::run_phase()也应通常做出如下处理:
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 a 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 a item \n %s", rsp.sprint()), UVM_LOW)
endtask
endclass
对于uvm_sequence::get_response(RSP)和uvm_driver::item_done(RSP)这种成对的操作,是可选的而不是必须的,即用户可以选择uvm_driver不返回response item,同时sequence也无需获取response item。
在完成了flat_seq、sequencer、driver和env的定义之后,到了test1层,除了需要考虑挂起objection防止提前退出,便可以利用uvm_sequence类的方法uvm_sequence::start(SEQUENCER)
来实现sequence到sequencer的挂载。
seq.start(e.sqr);实现了seq和对应sqr的挂载。
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);
phase.drop_objection(phase);
endtask
endclass
输出结果:
UVM_INFO @ 0:uvm_test_top.e.sqr@@flat_seq [SEQ] sent a item
...
UVM_INFO @ 0:uvm test top.e.drv [DRV] got a item
...
UVM_INFO @ 0:uvm test top.e.drv [DRV] sent a item
...
UVM_INFO @ 0:uvm_test_top.e.sqr@@flat_seq [SEQ] got a item
...
其中seq_item_export的定义、start_item()等都是内部定义的,虽然对应模块已写好,但却像run_phase一样看不见摸不着。