学习目标
UVM入门和进阶部分7
学习内容
.
2.uvm_sequence_item和uvm_sequence都是基于uvm_object;uvm_sequencer和driver都是基于uvm_component
3.如果sequence一旦活动起来,它必须挂载到一个sequencer上,这样sequence可以依赖sequencer的结构关系,间接通过sequencer来获取顶层的配置和更多信息
4.sequencer作为一个组件,它可以通过TLM端口与driver传送至item对象
sequencer在面向多个并行sequence时,它有充分的仲裁机制来合理分配和传送item,继而实现并行item数据传送至driver的测试环境
5.数据传送机制采用的是get模式
6.对于激励生成和场景控制,是由sequence来编织的,而对于激励所需要的具体数据和控制要求,则是对item的成员数据得来的
7.item通常具备的数据成员:
控制类—譬如总线协议上的读写类型、数据长度、传送模式等
负载类—一般指数据总线上的数据包
配置类—用来控制driver的驱动行为,例如命令driver的发送间隔或者有无错误插入
调试类—用来标记一些额外信息方便调试,例如该对象的实例序号、创建事件、被driver解析的时间始末
8.一个sequence可以包含一些有序组织起来的item实例,考虑到item在创建后需要被随机化,sequence在声明时也需要预留一些可供外部随机化的变量,这些随机变量一部分是用来通过层级传递约束来最终控制item对象的随机变量,一部分是用来对item对象之间加以组织和时序控制的
9.几种常见的sequence定义方式:
扁平类—只用来组织item实例 Flatsequence
层次类—由更高层的sequence组织底层的sequence,让其有序的挂载到同一个sequencer Hierarchical Sequence
虚拟类—鉴于整个环境中往往存在不同种类的sequencer和其对应的sequence,我们需要一个虚拟的sequence来协调顶层的测试环境
10.事务传输实例
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_seq)
...
task body();
uvm_sequence_item tmp;
bus_trans req,rsp;
//调用函数,创建item,m_sequencer是uvm_sequence的成员变量,sequence要挂载的sequencer,默认情况下item和sequence挂载到同一sequencer上;用new创建虽然没有挂载,但是会自动挂载到此uvm_sequence类挂载的sequencer上
tmp=create_item(bus_trans::get_type(),m_sequencer,"req");
//create_item只会返回一个父类的uvm_sequence_item句柄,需要将其转化为子类的bus_trans句柄,因为要调用子类的成员变量
void'($cast(req,tmp));
start_item(req); //货车停在sequencer门口,要想sequencer放行,得driver发送请求,要货,sequencer才开始仲裁
req.randomize with {data==10;}; //调用子类成员变量做randomize,在放行之前做随机化
'uvm_info("SEQ",#sformatf("sent a item \n %s",req.sprint()),UVM_LOW)
finish_item(req); //等待仲裁
get_response(tmp); //可有可无,看drv的item_done有没有rsp;get_response函数原型就是父类句柄
void'($cast(rsp,tmp)); //转化为子类句柄,后面要打印子类
'uvm_info("SEQ",#sformatf("got 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); //拿到第一个item
void'($cast(req,tmp));
'uvm_info("DRV",#sformatf("got a item \n %s",req.sprint()),UVM_LOW)
void'($cast(rsp,req.clone()); //克隆之后返回的是父类句柄,克隆不会克隆sequence_id,因为sequence_id没用进行域的自动化
rsp.set_sequence_id(req.get_sequence_id()); //给rsp标记sequence_id,返回时返回到正确的item;sequence_id在发送的时候就送过去了
rsp.data+=100;
seq_item_port.item_done(rsp); //drv消化了item返回item_done
'uvm_info("DRV",#sformatf("sent a item \n %s",rsp.sprint()),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
11.