1.传输方式
sequencer和driver之间采用TLM传输,数据传送机制采用get模式
,即driver从sequencer获取item。
选择get模式原因是:
- 从效率上看,不需要收到返回值,item从sequence产生,穿过sequencer到达driver时,就可以结束该传输
- 从仲裁特性看,更符合工学设计,sequencer拥有仲裁特性,可以使得多个sequence同时挂载到sequencer上,driver作为initiator,一旦发出get请求,它会先通过sequencer,继而获得仲裁后的item
2.TLM端口和方法
为了便于item传输,UVM专门定义了匹配的TLM端口
供sequencer和driver使用
- driver是
请求发起端
,所以在driver一侧例化了下面两种端口
uvm_seq_item_pull_port #(REQ, RSP) seq_item_port
uvm_analysis_port #(RSP) rsp_port
- sequencer是
请求的相应端
,在sequencer一侧例化了对应的下面两种端口
uvm_seq_item_pull_imp #(REQ, RSP) seq_item_export
uvm_analysis_export rsp_export
- 用户可以通过
匹配第一对TLM端口完成item的完整传送
driver::seq_item_port.connect(sequencer::seq_item_export)
常用TLM端口方法 | |
---|---|
task get_next_item(output REQ req_arg) | 采用blocking的方式等待从sequence获取下一个item |
function void item_done(input RSP rsp_arg=null) | 通知sequence当前sequence item已经消化完毕 |
3.事务传输实例
class bus_trans extends uvm_sequence_item;
...
endclass
class flat_seq extends uvm_sequence;
...
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;};
finish_item(req);
void'($cast(rsp, tmp));
endtask
endclass
flat_seq::body()做了如下几件事:
create_item()
创建request item对象start_item()
准备发送item- 在完成发送item之前对
item进行随机处理
- 调用
finish_item()
完成item发送
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));
void'($cast(req, req.clone()));
rsp.set_sequence_id(req.get_sequence_id);
seq_item_port.item_done(rsp);
endtask
endclass
driver::run_phase()做如下处理:
seq_item_port.get_next_item(REQ)
从sequencer获取有效的request item- 从request item 中获取数据,进而产生数据激励
- 对request item进行克隆生成新的对象response item
- 修改response item 中的数据成员,最终通过
seq_item_port.item_done(RSP)
将response item 对象返回给sequence
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
在高层环境,env::connect_phase()完成driver到sequencer的TLM端口连接:
drv.seq_item_port.connect(sqr.seq_item_export)
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
test1层:
- 考虑挂起objection防止提前退出
- 利用
uvm_sequence类的方法
,uvm_sequence::start(sequencer)
来实现sequence到sequencer的挂载