UVM学习笔记(四)sequence与sequencer

一、概述

1.1 类的继承

- uvm_object->uvm_transaction->**uvm_sequence_item**->uvm_sequence_base->**uvm_sequence**

1.2 数据传送机制

- get模式:driver从sequencer获取item
- 优势:1. driver获取到item即可结束传输,put需要收到返回值才发起下一次传输,效率会低一些;2. driver作为initiator能更好的实现sequence的仲裁特性

二、uvm_sequence_item

2.1 功能与数据成员

- 功能:生成item
- 数据成员类型
	- 控制类:总线协议上的读写类型,数据长度,传送模式
	- 负载类:数据总线上的数据包
	- 配置类:控制driver的驱动行为,命令driver的发送间隔等
	- 调试类:标记格外信息

2.2 示例

1.声明
2.注册与域的自动化
3.test中构建,用create具有可以覆盖,建立层次化关系的优点
4.随机化t.randomize();
class bus_trans extends uvm_sequence_item;
	rand bit write ;
	rand int data ;
	rand int addr ;
	rand int delay;
	static int id_num;
	`uvm_object_utils_begin(bus_trans)
		`uvm_field_int...
	`uvm_object_utils_end
endclass
class test1 extends uvm_test ;
	`uvm_component_utils(test1)
	task run_phase(uvm_phase phase) ;
		bus_trans t1,t2 ;
		phase.raise_objection(phase) ;
		#100ns;
		t1 = new("t1") ;
		t1.print() ;
		#200ns;
		t2 = new("t2") ;
		void'(t2.randomize()) ;
		t2.print() ;
		phase.drop_objection(phase) ;
	endtask
endclass

三、uvm_sequence

3.1 功能与分类

- flat sequence:item实例构成
- hierarchical sequence:高层的sequence组织底层的sequence,让这些sequence按照顺序或并行挂载到同一个sequencer上
- virtual sequence:自身不挂载,将内部不同类型sequence挂载到不同的目标sequencer上

3.2 flat sequence

sequence被挂载后,自动执行**body**内容
class bus_trans extends uvm_sequence_item;
	rand bit write;
	rand int data[];
	rand int length;
	rand int addr;
	rand int delay;
	static int id_num;
	constrint cstr{
		data.size() == length;
 		soft addr == 'h10;
		soft write == 1;
		delay inside{[1:5]};
	}//1.尽量将一段完整发生的数据传输中的、更长的的数据囊括在trans类中,可以使sequence不考虑数据内容,只考虑数据长度与地址等
	`uvm_object_utils_begin(bus_trans)
		uvm_field_int...
	`uvm_object_utils_end
endclass

class flat_seq extends uvm_sequence;
	rand int length;
	rand int addr;
	`uvm_object_utils(flat_seq)
	function new(string name = "flat_seq");
		super.new(name);
	endfunction
	task body();
		bus_trans tmp;
		tmp = new();
		tmp.randomize() with {length == local::length;
							  addr == local::addr;};
		tmp.print();
endclass
class test extends uvm_test;
	`uvm_component_utils(test)
	task run_phase(uvm_phase phase)
		flat_seq seq;
		phase.raise_objection(phase);
		seq = flat_seq::type_id::create("seq");
		seq.randomize() with{addr == 'h20; length = 3;};
		seq.body();
		phase.drop_objection(phase);
	endtask

3.2 hierarchical sequence

1.创建sequence和trans
2.完成随机化
3.发送到sequencer
挂载到同一个sequencer

typedef enum {CLKON, CLKOFF, RESET, WRREG, RDREG} cmd_t;
class bus_trans extends uvm_sequence_item;
	rand cmd_t cmd;
	rand int addr;
	rand int data;
	constraint cstr{
		soft addr == 'h0;
		soft data == 'h0;
	}
endclass
class flat_seq extends uvm_sequence;
	rand int length;
	rand int addr;
	`uvm_object_utils(flat_seq)
	function new(string name = "flat_seq");
		super.new(name);
	endfunction
	task body();
		bus_trans tmp;
		tmp = new();
		tmp.randomize() with {length == local::length;
							  addr == local::addr;};
		tmp.print();
endclass
class hier_seq extends uvm_sequence;
	`uvm_object_utils(hier_seq)
	function new(string name = "hier_seq");
		super.new(name);
	endfunction
	task body();
		bus_trans t1,t2;
		flat_seq s1,s2;
		`uvm_do_with(t1,{length == 2;})//item创建,随机化与发送到sequencer
		fork
			`uvm_do_with(s1,{length == 5})
			`uvm_do_with(s2,{length == 8})
		join
		`uvm_do_with(t2,{length == 3})
	endtask
endclass
class clk_rst_seq extends uvm_sequence;
	rand int freq;
	task body();
		bus_trans req;
		`uvm_do_with(req, {cmd == CLKON, data == freq;})
		`uvm_do_with(req, {cmd == RESET;})
	endtask
endclass
class reg_test_seq extends uvm_sequence;
	rand int chnl;
	task body();
		bus_trans req;
		//读写
		`uvm_do_with(req, {cmd == WRREG, addr == chnl*'h4;})
		`uvm_do_with(req, {cmd == RDREG, addr == chnl*'h4;})
		//读
		`uvm_do_with(req, {cmd == RDREG, addr == chnl*'h4 + 'h10;})
	endtask
endclass
class top_seq extends uvm_sequence;
	task body();
		reg_test_seq regseq0, regseq1, regseq2;
		clk_rst_seq clkseq;
		grab_seq grabs;
		m_sequencer.set_arbitration(UVM_SEQ_ARB_STRICT_FIFO);
		fork
			`uvm_do_with(clkseq, {freq== 150;})//打开时钟150Mhz,reset
			`uvm_do_with(regseq0, {chnl == 0;})
			`uvm_do_with(regseq1, {chnl == 1;})
			`uvm_do_with(regseq2, {chnl == 2;})//优先级比seq1和seq2低
		join
	endtask
endclass	
class reg_master_driver extends uvm_driver;
	task run_phase(uvm_phase phase);
		REQ tmp;
		bus_tranas 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	

3.3 virtual sequence

  1. virtual sequencer定义所有要挂载的sequencer的句柄
  2. env实例化virtual sequencer,将所有sequencer句柄赋值给virtual sequencer
  3. virtual sequence通过uvm_declare_p_sequencer(virtual sequencer)获取所有句柄,通过uvm_do_on将不同的sequence的数据挂载到不同的sequencer上且发送
  4. test中实例化virtual sequence,将virtual sequence挂载到virtual sequencer上
//1.virtual sequencer
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;
	mcdf_virtual_sequencer virt_sqr;
	`uvm_component_utils(mcdf_virtual_sequencer)
	function new(string name, uvm_coponent parent)
		super.new(name,parent);
	endfunction
endclass
//2.env
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(this);
	endfunction
	//创建各个有sequencer的容器
	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_agt0",this);
		chnl_agt1 = chnl_master_agent::type_id::create("chnl_agt1",this);
		chnl_agt2 = chnl_master_agent::type_id::create("chnl_agt2",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);
		virt_sqr.cr_sqr = cr_agt.sqr;
		virt_sqr.reg_sqr = reg_agr.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;
	endfunciton
endclass:mcdf_env
//3.virtual sequence,分属不同的sequencer,clk_rst_seq....分别配置sequencer且发送数据
class mcdf_normal_seq extends uvm_sequence;
	`uvm_object_utils(mcdf_normal_seq)
	`uvm_declare_p_sequencer(mcdf_virtual_sequencer)
	task body();
		clk_rst_seq clk_seq;
		reg_cfg_seq cfg_seq;
		data_trans_seq data_seq;
		fmt_slv_cfg_seq fmt_seq;
		//配置formatter slave agent
		`uvm_do_on(fmt_seq, p_sequencer.fmt_sqr)
		//打开时钟并完成复位
		`uvm_do_on(clk_seq, p_sequencer.cr_sqr)
		//配置MCDF寄存器
		`uvm_do_on(cfg_seq, p_sequencer.reg_sqr)
		//传送channel数据包
		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
//4.test,将virtual sequence挂载到virtual sequencer上
class test1 extends uvm_test;
	mcdf_env e;
	task run_phase(uvm_phase phase);
		mcdf_normal_seq seq;
		phase.raise_objection(phase);
		seq = mcdf_normal_seq::type_id::create("seq",this);
		seq.start(e.virt_sqr);
		phase.drop_objection(phase);
	endtask
endclass:test1

3.4 layering sequence

高抽象的item、中间转换的sequence、低抽象的item

typedef enum {CLKON, CLKOFF, RESET, WRREG, RDREG} phy_cmd_t;
typedef enum {FREQ_LOW_TRANS, FREQ_MID_TRANS, FREQ_HIGH_TRANS} layer_cmd_t;
//1.layer_trans高抽象级item
class layer_trans extends uvm_sequence_item;
	rand layer_cmd_t 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_MID_TRANS -> pkt_idle inside {[100:200]};
		layer_cmd == FREQ_HIGH_TRANS -> pkt_idle inside {[20:40]};
	}
endclass
//2.bus_trans低抽象的item
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;
	}
endclass
//3.packet_seq 低抽象级的item,bus_trans
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;
	}
	task body();
		bus_trans req;
		foreach(data[i])
			`uvm_do_with(req, {cmd == local::cmd;
							   addr == local::addr;
							   data == local::data[i];})
	endtask
endclass
//4.adapter_seq 转化层,从layer获取数据;挂载到phy_sequencer中,产生的为phy_sequence
class adapter_seq extends uvm_sequence;
	`uvm_objecet_utils(adapter_seq)
	`uvm_declare_p_sequencer(phy_master_sequencer)
	task body();
		layer_trans trans;//高抽象
		packet_seq pkt;//低抽象
		forever begin
			p_sequencer.up_sqr.get_next_item(req);//upsqr为更上层的sequencer句柄,从layersequencer中获取layer item;经常在driver中调用,但是这个是sequencer的方法,拿到句柄后可以调用,得到layer_trans;
			void'($cast(trans, req));
			repeat(trans.pkt_len) begin
				`uvm_do(pkt)
				delay(trans.pkt_idle);
			end
			p_sequencer.up_sqr.item_done();//消化掉高抽象级的item
		end
	endtask
	virtual task delay(int delay);
	endtask
endclass
//5.top_seq 更顶层的sequence,连续发送两个layer_trans
class top_seq extends uvm_sequence;
	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
//6.sequencer phy中有up_sqr
class layering_sequencer extends uvm_sequencer;
endclass
class phy_master_sequencer extends uvm_sequencer;
	layering_sequencer up_sqr ;
endclass

class phy_master_driver extends uvm_driver;
	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;
	function void build_phase(uvm_phase phase);
		sqr = phy_master_sequencer::type_id::create("sqr",this);
		drv = phy_maaster_driver::type_id::create("drv",this);
	endfunction
	function void connect_phase(uvm_phasae 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;
	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;
		adaper_seq adapter;
		phase.raise_objection(phase):
		seq = new();
		adapter = new();
		fork
			adapter.start(phy_agt.sqr);//adaper_seq 挂载到phy上面
		join_none
		seq.start(layer_sqr);//top_seq 挂载到layer上面
		phase.drop_objection(phase);
	endtask
endclass

四、uvm_sequencer与uvm_driver

4.1 功能

driver从sequencer通过get模式获取item

uvm_sequencer
	1. component通过TLM端口与driver传送item对象
	2. 仲裁多个并行sequence,路由,sequencer有选择的动态挂载所需的sequence
	
uvm_driver
	驱动激励时序

4.2 端口与方法

uvm_sequencer
	· uvm_seq_item_pull_imp #(REQ,RSP,this_type) seq_item_export
	· uvm_analysis_export#(RSP) rsp_export //analysis一对多端口,与fifo组件连接,fifo内部有imp,所以接收用的export端口;
uvm_driver
	· uvm_seq_item_pull_port#(REQ,RSP) seq_item_port
	· uvm_analysis_port#(RSP) rsp_port
driver常用方法
	· seq_item_port.get_next_item(tmp)
	· seq_item_port.item_done(rsp)
	· seq_item_port.put_rsponse(rsp)//在sequence中get_response(rsp)对应
	· rsp_port.write(RSP)

4.3 传输实例

//1.传输类
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
/*2.sequence类
挂载后通过seq.start自动执行body()内容
req=create_item(bus_trans::get_type(),m_sequencer,"req");创建request item对象
start_item(req);准备发送item
完成发送前对item进行随机处理
finish_item(req);完成item发送
get_response(tmp);从driver获取响应
*/
class flat_seq extends uvm_sequence;
	`uvm_object_utils(flat_seq)
	task body();
		bus_trans req,rsp;
		uvm_sequence_item tmp;//过渡与转换的
		//trans的type,name和要被挂载的sequencer
		tmp = create_item(bus_trans::get_type(),m_sequencer,"req");//类型强制转换了
		void'($cast(req,tmp));
		//可改为req=create_item(bus_trans::get_type(),m_sequencer,"req");
		start_item(req);//立即返回,表示开始等待
		req.randomize with {data == 10;};
		finish_item(req);//阻塞,数据准备好,真实的在等待
		get_response(tmp);//driver::put_response与item_done(rsp)一一对应
		void'($cast(rsp,tmp));
	endtask
endclass
//3.sequencer类
class sequencer extends uvm_sequencer;
	`uvm_component_utils(sequencer)
endclass
//typedef uvm_sequencer#(bus_trans) sequencer;
//4.uvm_driver类
class driver extends uvm_driver;
	`uvm_component_utils(driver)
	task run_phase(uvm_phase phase);
		REQ tmp;//源码的REQ
		bus_trans req, rsp;
		seq_item_port.get_next_item(tmp);//driver开始从sequencer获取数据
		void'($cast(req,tmp));//强制转换,这个类型可以在定义类时将参数传入,默认为uvm_sequence_item
		`uvm_info("DRV",$sformatf("got a item \n %s",req.sprint()),UVM_LOW)
		void'($cast(rsp, req.clone()));//clone返回都是object
		rsp.set_sequence_id(req.get_sequence_id());//id可以在response才知道发送给谁
		rsp.data += 100;
		seq_item_port.item_done(rsp);//done发送了respone,sequence需要获取get_response
		`uvm_info("DRV",$sformatf("got a item \n %s",req.sprint()),UVM_LOW)
	endtask
endclass
//5.env
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
//6.test
class test extends uvm_test;
	env e;
	`uvm_component_utils(test)
	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 = flat_seq::type_id::create("seq");
		seq.start(e.sqr);//挂载,body自动执行,这里sequence还没有随机化
		phase.drop_objection(phase);
	endtask
endclass

五、uvm_sequencer与uvm_sequence

5.1 sequence挂载到sequencer

seq.start(要挂载的sequencer, 上层的sequence可以保留优先级,优先级,是否执行pre_body()和post_body())

5.2 item挂载到sequencer

create_item//创建item
start_item(req);
finish_item(req);
只有item才有优先级

5.3 发送序列的相关宏

只有sequence可以调用这些宏
在这里插入图片描述

class child_seq extends uvm_sequence;
	task body();
		bus_trans req;
		`uvm_create(req)
		`uvm_rand_send_with(req, {data == 10;})
	endtask
endclass
class top_seq extends uvm_sequence;
	task body();
		child_seq cseq;
		bus_trans req;
		`uvm_do(cseq)
		`uvm_do_with(req,{data == 20})
	endtask
endclass

5.4 仲裁模式

uvm_sequencer::set_arbitration(UVM_SEQ_ARB_TYPE val)设置仲裁模式
UVM_SEQ_ARB_FIFO:默认,fifo先入先出一次授权
UVM_SEQ_ARB_WEIGHTED:按优先级权重随机授权
UVM_SEQ_ARB_RANDOM:随机授权
UVM_SEQ_ARB_STRICT_FIFO:按优先级和抵达顺序依次授权

class child_seq extends uvm_sequence;
	rand int base;
	task body();
		bus_trans req;
		repeat(2) `uvm_do_with(req, {data inside {[base: base + 9]};//wait_for_grant才会等待授权
	endtask
endclass
class top_seq extends uvm_sequence;
	task body();
		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发送sequence时可以传递优先级参数
			`uvm_do_pri_with(seq2, 500, {base == 20;})
			`uvm_do_pri_with(seq3, 300, {base == 30;})
		join
	endtask
endclass
class driver extends uvm_driver;
	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 %0d from parent sequence %s", req.data, req.get_parent_sequence().get_name()),UVM_LOW)
			seq_item_port.item_done();
		end
	endtask
endclass
class test extends uvm_test;
	env e;
	task run_phase(uvm_phase phase);
		top_seq seq;
		phase.raise_objection(phase);
		seq = top_seq::type_id::create("seq");
		seq.start(e.sqr);//只有在sequence里面才可以用宏
		phase.drop_objection(phase);
	endtask
endclass

5.5 sequencer的锁定机制

lock() unclock()按优先级获取
grab() ungrab()不按优先级

class lock_seq extends uvm_sequence;
	task body();
		bus_trans req;
		#10ns;
		m_sequencer.lock(this);//等待权限时,lock住
		`uvm_info("LOCK","get exclusive access by lock()"),UVM_LOW)
		repeat(3) #10ns 
		`uvm_do_with(req, {data inside {[100:110]};})
		m_sequencer.unclock(this);
	endtask
endclass
class grab_seq extends uvm_sequence;
	task body();
		bus_trans req;
		#20ns;
		m_sequencer.grab(this);//
		`uvm_info("GRAB","get exclusive access by grab()"),UVM_LOW)
		repeat(3) #10ns 
		`uvm_do_with(req, {data inside {[200:210]};})
		m_sequencer.ungrab(this);
	endtask
endclass
class top_seq extends uvm_sequence;
	task body();
		child_seq seq1, seq2, seq3;
		lock_seq locks;
		grab_seq grabs;
		m_sequencer.set_arbitration(UVM_SEQ_ARB_STRICT_FIFO);
		fork
			`uvm_do_pri_with(seq1, 500, {base == 10;})//同一时间申请发起传送请求,uvm_do_pri_with发送sequence时可以传递优先级参数
			`uvm_do_pri_with(seq2, 500, {base == 20;})
			`uvm_do_pri_with(seq3, 300, {base == 30;})
			`uvm_do_pri(locks,300)//优先级比seq1和seq2低
			`uvm_do(grabs)//没有优先级,不管优先级,20ns才开始获取
		join
	endtask
endclass
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鱼爱学习,每天好心情

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值