UVM实验4

1. 实验目的

generatordrivertest的关系最终移植为sequencesequencerdrivertest的关系,聚焦于sequencesequencer的使用。

2.实验过程

2.1 driver与sequencer的改建

1. 验证结构框图
在这里插入图片描述2. 实际代码
以chnl_pkg为例:

	class chnl_driver extends uvm_driver #(chnl_trans);
//driver通过端口得到req,并通过端口返回rsp,返回rsp前用rsp.set_sequence_id(req.get_sequence_id())方法给rsp贴标签
		local virtual chnl_intf intf;
		
		`uvm_component_utils(chnl_driver)
		
		function new (string name = "chnl_driver", uvm_component parent);
			super.new(name, parent);
		endfunction
		
		function void set_interface(virtual chnl_intf intf);
			if(intf = null)
				$error("interface handle is NULL, please check if target interface has been intantiated");
			else
				this.intf = intf;
		endfunction
		
		task run_phase(uvm_phase phase);
			fork
				this.do_drive();
				this.do_reset();
			join
		endtask
		
		task do_reset();
			forever begin
				@(negedge intf.rstn);
				intf.ch_valid <= 0;
				intf.ch_data <= 0;
			end
		endtask
		
		task do_drive();
			chnl_trans req, rsp;
			@(posedge intf.rstn);
			forever begin	
				seq_item_port.get_next_item(req);
				this.chnl_write(req);
				void'($cast(rsp, req.clone()));
				rsp.rsp = 1;
				rsp.set_sequence_id(req.get_sequence_id());
				seq_item_port.item_done(rsp);
			end
		endtask
		
		task chnl_write(input chnl_trans t);
			foreach(t.data[i]) begin
				@(posedge intf.clk);
				intf.drv_ck.ch_valid <= 1;
				intf.drv_ck.ch_data <= t.data[i];
				@(negedge intf.clk);
				wait(intf.ch_ready === 'b1);
				`uvm_info(get_type_name(), $sformatf("send data 'h%8x", t.data[i]),UVM_HIGH)
				repeat(t.data_nidles) chnl_idle();
			end
		endtask
		
		task chnl_idle();
			@(posedge intf.clk);
			intf.drv_ck.ch_valid <= 0;
			intf.drv_ck.ch_data <= 0;
		endtask
	endclass:chnl_driver
	
	class chnl_sequencer extends uvm_sequencer #(chnl_trans);//sequencer类的声明,uvm_sequencer已经内置了端口与方法
		`uvm_component_utils(chnl_sequencer)
		function new(string name = "chnl_sequencer", uvm_component parent);
			super.new(name, parent);
		endfunction
	endclass: chnl_sequencer
	class chnl_agent extends uvm_agent;//在agent中完成driver与sequencer的创建和端口的连接
		chnl_driver driver;
		chnl_monitor monitor;
		chnl_sequencer sequencer;
		local virtual chnl_intf vif;
		
		`uvm_component_utils(chnl_agent)
		
		function new(string name = "chnl_agent", uvm_component parent);
			super.new(name parent);
		endfunction
		
		function void build_phase(uvm_phase phase);
			super.build_phase(phase);
			driver = chnl_driver::type_id::create("driver", this);
			monitor = chnl_monitor::type_id::create("monitor", this);
			sequencer = chnl_sequencer::type_id::create("sequencer", this);
		endfunction
		
		function void connect_phase(uvm_phase phase);
			super.connect_phase(phase);
			driver.seq_item_port.connect(sequencer.seq_item_export);
		endfunction
		
		function void set_interface(virtual chnl_intf vif);
			this.vif = vif;
			driver.set_interface(vif);
			monitor.set_interface(vif);
		endfunction
		
		task run_phase(uvm_phase phase);//调用子类的run时省略,使用自己的方法时不能省略
			//NOTE::No more needs to call run manually
			//fork
			//	drive.run();
			//	monitor.run();
			//join
		endtask
	endclass:chnl_agent

3. 代码分析与理解
driversequencer都是组件,通过TLM端口进行通信,并且为了便于item传输,UVM专门定义了匹配的TLM端口供sequencerdriver使用;

driver:uvm_seq_item_pull_port(类型) #(REQ, RSP) seq_item_port(句柄) 常用
        uvm_analysis_port #(RSP) rsp_port

sequencer:uvm_seq_item_pull_imp(类型) #(REQ, RSP) seq_item_export(句柄) 常用
           uvm_analysis_port #(RSP) rsp_port

具体步骤:
a. 由于driversequencer自身在创建时已经例化了TLM端口,所以我们只需要在agent的build_phase阶段创建driver和sequencer,在connect_phase阶段连接driversequencer的port端口即可,不需要在组件driversequencer中声明端口并例化端口。

b. 作为target的sequencer内置的方法有:task item get_next_item(REQ)(常用,采取blocking的方式等待从sequencer获取下一个item)和 function void item_done(RSP or null)(常用,用来通知sequence当前的sequence item已经消化完毕,可以选择性的传递RSP参数),如果driver返回了RSP参数,则sequence需要在uvm_do发送item后用sequencer里的方法get_response(rsp)得到rsp。

补充:rsp.set_sequence_id(req.get_sequence_id())方法是指给返回的rsp贴上一个标签,让读者明白rsp是谁返回的,一般在用item_done()返回rsp时都要加上

2.2 底层sequence的提取

1. 验证结构框图如上
2. 实际代码

	class chnl_data_sequence extends uvm_sequence #(chnl_trans);
		rand int pkt_id = 0;
		rand int ch_id = -1;
		rand int data_nidles = -1;
		rand int pkt_nidles = -1;
		rand int data_size = -1;
		rand int ntrans = 10;
		
		
		constraint cstr{
			soft ch_id == -1;
			soft pkt_id == 0;
			soft data_size == -1;
			soft data_nidles == -1;
			soft pkt_nidles == -1;
			soft ntrans ==10;
		}
		
		`uvm_component_utils_begin(chnl_generator)
			`uvm_filed_int(pkt_id, UVM_ALL_ON)
			`uvm_filed_int(ch_id, UVM_ALL_ON)
			`uvm_filed_int(data_nidles, UVM_ALL_ON)
			`uvm_filed_int(pkt_nidles, UVM_ALL_ON)
			`uvm_filed_int(data_size, UVM_ALL_ON)
			`uvm_filed_int(ntrans, UVM_ALL_ON)
		`uvm_component_utils_end
		`uvm_declare_p_sequencer(chnl_sequencer)
		
		function new(string name = "chnl_data_sequence");
			super.new(name, parent);
		endfunction
		
		task body();
			repeat(ntrans) send_trans();
		endtask
		
		task send_trans();
			chnl_trans req, rsp;
			`uvm_do_with(req, {local::ch_id >= 0 -> ch_id == local::ch_id;
							   local::pkt_id >= 0 -> pkt_id ==local::pkt_id;
							   local::data_nidles >= 0 -> data_nidles ==local::data_nidles;
							   local::pkt_nidles >= 0 -> pkt_nidles ==local::pkt_nidles;
							   local::data_size >= 0 -> data.size ==local::data_size;
							   })
			this.pkt_id++;
			`uvm_info(get_type_name(), req.sprint(), UVM_HIGH)
			get_response(rsp);
			`uvm_info(get_type_name(), rsp.sprint(), UVM_HIGH)
			assert(rsp.rsp)
				else $error("[RSPERR] %0t error response received!", $time);
		endtask
		
		function string sprint();
			string s;
			s = {s, $sformatf("======================================\n")};
			s = {s, $sformatf("chnl_generator object content is as below: \n")};
			s = {s, super.sprint()};
			s = {s, $sformatf("======================================\n")};
			return s;
		endfunction
		
		function void post_randomize();
			string s;
			s = {"AFTER RANDOMIZATION \n", this.sprint()};
			`uvm_info(get_type_name(), s, UVM_HIGH)
		endfunction
	endclass:chnl_data_sequence

3. 代码分析与理解

strat( )方法:
1.创建item
2.通过start_item()方法获得sequencer的授权许可,
3.对item进行随机化处理
4.finish_item(),在sequencer关卡前等候发送

`uvm_do宏:
包含了以上过程,创建,sequencer授权,随机化,等待发送。

具体步骤: 通过宏uvm_declare_p_sequencer(chnl_sequencer),chnl_data_sequence可以定位到chnl_sequencer,通过宏uvm_do_with创建item(req),授权item(req),随机化item(req)并等待发送,task body()会自动执行。

2.3 添加顶层的virtual sequencer

1. 验证结构框图
在这里插入图片描述2. 实际代码

	class mcdf_virtual_sequencer extends uvm_sequencer;//定义virtual sequencer类
		reg_sequencer reg_sqr;
		fmt_sequencer fmt_sqr;
		chnl_sequencer chnl_sqr[3];
		`uvm_component_utils(mcdf_virtual_sequencer)
		function new(string name = "mcdf_virtual_sequencer", uvm_component parent);
			super.new(name, parent);
		endfunction
	endclass
class mcdf_env extends uvm_env;
//将定义的virtual sequencer类在mcdf_env中声明,例化,并且完成其与底层sequencer的句柄连接
		chnl_agent chnl_agts[3];
		reg_agent reg_agts;
		fmt_agent fmt_agts;
		mcdf_checker chker;
		mcdf_coverage cvrg;
		mcdf_virtual_sequencer virt_sqr;
		
		`uvm_component_utils(mcdf_env)
		
		function new(string name = "mcdf_env", uvm_component parent);
			super.new(name, parent);
		endfunction
		
		function void build_phase(uvm_phase phase);
			super.build_phase(phase);
			this.chker = mcdf_checker::type_id::create("chker", this);
			foreach(chnl_agts[i]) begin
				this.chnl_agts[i] = chnl_agent::type_id::create($sformatf("chnl_agts[%0d]", i), this);
			end
			this.reg_agts[i] = reg_agent::type_id::create("reg_agts", this);
			this.fmt_agts[i] = fmt_agent::type_id::create("fmt_agts", this);
			this.cvrg = mcdf_coverage::type_id::create("cvrg", this);
			virt_sqr = mcdf_virtual_sequencer::type_id::create("virt_sqr", this);
		endfunction
		
		function void connect_phase(uvm_phase phase);
			super.connect_phase(phase);
			chnl_agts[0].monitor.mon_bp_port.connect(chker.chnl0_bp_imp);
			chnl_agts[1].monitor.mon_bp_port.connect(chker.chnl1_bp_imp);
			chnl_agts[2].monitor.mon_bp_port.connect(chker.chnl2_bp_imp);
			reg_agt.monitor.mon_bp_port.connect(chker.reg_bp_imp);
			fmt_agt.monitor.mon_bp_port.connect(chker.fmt_bp_imp);
			virt_sqr.reg_sqr = reg_agt.sequencer;
			virt_sqr.fmt_sqr = fmt_agt.sequencer;
			foreach(virt_sqr.chnl_sqrs[i]) vir_sqr.chnl_sqrs[i] = chnl_agts[i].sequencer;
		endfunction
		
		task run_phase(uvm_phase phase);

		endtask
		
		function void report_phase(uvm_phase phase);
			super.report_phase(phase);

		endfunction
	endclass:mcdf_env

3. 代码分析与理解

virtual sequencer起到了桥接其他sequencer的作用,即virtual sequencer是一个连接所有底层sequencer句柄的地方,它是一个中心化的路由器。我们只需做好virtual sequencer中各个sequencer句柄与底层sequencer实体对象的一一对接,避免句柄悬空即可。

具体步骤: 定义一个virtual sequencer的类,在virtual sequencer类里声明各个底层sequencer的句柄。然后在顶层环境env里例化virtual sequencer类,并完成其与底层sequencer句柄的连接。

2.4 重构mcdf_base_test

1. 验证结构框图
在这里插入图片描述2. 实际代码

	class mcdf_base_virtual_sequence extends uvm_sequence;
	//将原有test里发送激励的功能移植到新定义的mcdf_base_virtual_sequence一侧
		idle_reg_sequence idle_reg_seq;
		write_reg_sequence write_reg_seq;
		read_reg_sequence read_reg_seq;
		chnl_data_sequence chnl_data_seq;
		fmt_config_sequence fmt_config_seq;
		
		`uvm_object_utils(mcdf_base_virtual_sequence)
		`uvm_declare_p_sequencer(mcdf_virtual_sequencer)
		
		function new(string name = "mcdf_base_virtual_sequence");
			super.new(name);
		endfunction
		
		virtual task body();
			`uvm_info(get_type_name(), "======================STARTED====================", UVM_LOW)
			this.do_reg();
			this.do_formatter();
			this.do_data();
			`uvm_info(get_type_name(), "======================FINISHED====================", UVM_LOW)
			endtask
			
		// do register configuration
		virtual task do_reg();
			
		endtask
			
		// do external formatter down stream slave configuration
		virtual task do_formatter();
			
		endtask
			
		// do data transition from 3 channel slaves
		virtual task do_data();
			
		endtask	
		
		virtual function bit diff_value(int val1, int val2, string id = "value_compare");
			if(val1 != val2) begin
				`uvm_error("[CMPERR]", $sformatf("ERROR! %s val1 %8x != val2 %8x", id, val1, val2))
				return 0;
			end
			else begin
				`uvm_info("[CMPSUC]", $sformatf("SUCCESS! %s val1 %8x != val2 %8x", id, val1, val2), UVM_LOW)
				return 1;
			end
		endfunction
	endclass
	class mcdf_base_test extends uvm_test;
	//test一侧只需要在run_phase里例化sequence,并将其挂载到对应的顶层virtual sequencer即可。
		mcdf_env env;
		virtual chnl_intf ch0_vif;
		virtual chnl_intf ch1_vif;
		virtual chnl_intf ch2_vif;
		virtual reg_intf reg_vif;
		virtual arb_intf arb_vif;
		virtual fmt_intf fmt_vif;
		virtual mcdf_intf mcdf_vif;
		
		`uvm_component_utils(mcdf_base_test)
		
		function new(string name = "mcdf_base_test", uvm_component parent);
			super.new(name, parent);
		endfunction
		
		function void build_phase(uvm_phase);
			super.build_phase(phase);
			// get virtual interface from top TB
			if(!uvm_config_db#(virtual chnl_intf)::get(this, "", "ch0_vif", ch0_vif)) begin
				`uvm_fatal("GETVIF", "cannot get vif handle from config DB")
			end
			if(!uvm_config_db#(virtual chnl_intf)::get(this, "", "ch1_vif", ch1_vif)) begin
				`uvm_fatal("GETVIF", "cannot get vif handle from config DB")
			end
			if(!uvm_config_db#(virtual chnl_intf)::get(this, "", "ch2_vif", ch2_vif)) begin
				`uvm_fatal("GETVIF", "cannot get vif handle from config DB")
			end
			if(!uvm_config_db#(virtual reg_intf)::get(this, "", "reg_vif", reg_vif)) begin
				`uvm_fatal("GETVIF", "cannot get vif handle from config DB")
			end
			if(!uvm_config_db#(virtual arb_intf)::get(this, "", "arb_vif", arb_vif)) begin
				`uvm_fatal("GETVIF", "cannot get vif handle from config DB")
			end
			if(!uvm_config_db#(virtual fmt_intf)::get(this, "", "fmt_vif", ch2_vif)) begin
				`uvm_fatal("GETVIF", "cannot get vif handle from config DB")
			end
			if(!uvm_config_db#(virtual mcdf_intf)::get(this, "", "mcdf_vif", mcdf_vif)) begin
				`uvm_fatal("GETVIF", "cannot get vif handle from config DB")
			end
			
			this.env = mcdf_env::type_id::create("env", this);
			foreach(this.chnl_gen[i]) begin	
				this.chnl_gens[i] = chnl_generator::type_id::create($sformatf("chnl_gens[%0d]", i), this);
				end
				this.reg_gen = reg_generator::type_id::create("reg_gen", this);
				this.fmt_gen = fmt_generator::type_id::create("fmt_gen", this);
				
				// rpt_pkg::logname = {this.m_name, "_check.log"};
				// rpt_pkg::clean_log();
			endfunction
			
			function void connect_phase(uvm_phase phase);
				super.connect_phase(phase);
				// After get virtual interface from config_db, and then set them to
				// child components 
				this.set_interface(ch0_vif, ch1_vif, ch2_vif, reg_vif, arb_vif, fmt_vif, mcdf_vif);
				
				
			endfunction
			
			function void end_of_elaboration_phase(uvm_phase phase);
				super.end_of_elaboration_phase(phase);
				uvm_root::get().set_report_verbosity_level_hier(UVM_HIGH);
				uvm_root::get().set_report_max_quit_count(1);
				uvm_root::get().set_timeout(10ms);
			endfunction
				
			task run_phase(uvm_phase phase);				
				// NOTE:: raise objection to prevent simulation stopping 
				phase.raise_objection(this);
				
				this.run_top_virtual_sequence();
				
				// Note::drop objection to request simulation stopping
				phase.drop_objection(this);
			endtask
			
			virtual task run_top_virtual_sequence();
			endtask
			
			virtual function void set_interface(virtual chnl_intf ch0_vif
											   ,virtual chnl_intf ch1_vif
											   ,virtual chnl_intf ch2_vif
											   ,virtual reg_intf reg_vif
											   ,virtual arb_intf arb_vif
										       ,virtual fmt_intf fmt_vif
										       ,virtual mcdf_intf mcdf_vif
										   );
			this.env.chnl_agts[0].set_interface(ch0_vif);
			this.env.chnl_agts[1].set_interface(ch1_vif);
			this.env.chnl_agts[2].set_interface(ch2_vif);
			this. env.reg_agt.set_interface(reg_vif);
			this. env.fmt_agt.set_interface(fmt_vif);
			this.env.chker.set_interface(mcdf_vif, '{ch0_vif, ch1_vif, ch2_vif}, arb_vif);
			this.env.cvrg.set_interface('{ch0_vif, ch1_vif, ch2_vif}, reg_vif, arb_vif, fmt_vif, mcdf_vif);
		endfunction
		
	endclass:mcdf_base_test

3. 代码分析与理解
将原先run_phase发送序列的功能移植到新定义的mcdf_base_virtual_sequence一侧,mcdf_base_test::run_phase( )只需要挂载对应的顶层virtual_sequence即可,即在run_phase里例化配置好的virtual sequence,然后sequence.start(env.virt_sqr)挂载sequence。

具体步骤: 定义mcdf_base_virtual_sequence,声明各个sequence的句柄,利用宏uvm_declare_p_sequencer(mcdf_virtual_sequencer),使mcdf_base_virtual_sequence定位到mcdf_virtual_sequencer,将原先test里的配置方法移植到mcdf_base_virtual_sequence中。而在test里只需要例化sequence,并挂载sequence.start(env.virt_sqr)即可。

2.5 重构mcdf_data_consistence_basic_test

1. 验证框图如上
2. 实际代码

	class mcdf_data_consistence_basic_virtual_sequence extends mcdf_base_virtual_sequence;
	//通过do_reg配置寄存器,do_formatter配置fmt,do_data配置chnl
		`uvm_object_utils(mcdf_data_consistence_basic_virtual_sequence)
		function new(string name = "mcdf_data_consistence_basic_virtual_sequence");
			super.new(name);
		endfunction
		
		task do_reg();
			bit[31:0] wr_val, rd_val;
			// slv0 with len=8, prio=0, en=1
			wr_val = (1<<3) + (0<<1) + 1;
			`uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV0_RW_ADDR; data == wr_val;})
			`uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV0_RW_ADDR;})
			rd_val = read_reg_seq.data;
			void'(this.diff_value(wr_val, rd_val, "SLV0_WR_REG"));
			
			// slv1 with len=16, prio=1, en=1
			wr_val = (2<<3) + (1<<1) + 1;
			`uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV1_RW_ADDR; data == wr_val;})
			`uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV1_RW_ADDR;})
			rd_val = read_reg_seq.data;
			void'(this.diff_value(wr_val, rd_val, "SLV1_WR_REG"));
			
			// slv2 with len=32, prio=2, en=1
			wr_val = (3<<3) + (2<<1) + 1;
			`uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV2_RW_ADDR; data == wr_val;})
			`uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV2_RW_ADDR;})
			rd_val = read_reg_seq.data;
			void'(this.diff_value(wr_val, rd_val, "SLV2_WR_REG"));
			
			// send IDLE command
			`uvm_do_on(idle_reg_seq, p_sequencer.reg_sqr)
		endtask
		
		task do_formatter();
			`uvm_do_on(fmt_config_seq, p_sequencer.fmt_sqr, {fifo == LONG_FIFO; bandwidth == HIGH_WIDTH;})
		endtask
		
		task.do_data();
			fork
				`uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[0], {ntrans==100; ch_id==0; data_nidles ==0;pkt_nidles==1;data_size==8;})
				`uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[1], {ntrans==100; ch_id==1; data_nidles ==1;pkt_nidles==4;data_size==16;})
				`uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[2], {ntrans==100; ch_id==2; data_nidles ==2;pkt_nidles==8;data_size==32;})
			join
			#10us; // wait until all data haven been transfered through MCDF
		endtask
	endclass: mcdf_data_consistence_basic_virtual_sequence
	class mcdf_data_consistence_basic_test extends mcdf_base_test;
		
		`uvm_component_utils(mcdf_data_consistence_basic_test)
		
		function new(string name = "mcdf_data_consistence_basic_test", uvm_component parent);
			super.new(name, parent);
		endfunction
		
		task run_top_virtual_sequence();
			mcdf_data_consistence_basic_virtual_sequence top_seq = new();
			top_seq.start(env.virt_sqr);
		endtask
	endclass:mcdf_data_consistence_basic_test

3. 代码分析与理解
uvm_do_with(item, {constraint}): 所有item只对应一个顶层sequencer时可以使用。
例如,对于chnl_sequence和chnl_sequencer,如果没有宏uvm_declare_p_sequencer(chnl_sequencer),则使用宏uvm_do_with时,所有item发送默认定位的是m_sequence即uvm_sequence。

uvm_do_on_with(item, p_sequencer.SQR, {constraint} ): 所有item可通过改变p_sequencer.SQR里的SQR让item定位到对应的SQR上,同样,在定义sequence类时,需声明宏 uvm_declare_p_sequencer(mcdf_virtual_sequencer),那么item定位到的sequencer就是mcdf_virtual_sequencer的句柄p_sequencer。

3. 理解从sequencer到driver的item传输类型转换

uvm_sequence,uvm_driver,uvm_sequencer都是参数化的类,在数据句柄传递时要注意数据类型的转换。

3.1 讲义里使用默认类型传输时

讲义p169

	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;
			tmp = create_item(bus_trans::get_type(), m_sequencer, "req");
			//使用create_item创建item时返回的是父类句柄(子类对象),所以需要声明一个uvm_sequence_item tmp去指向新创建的item。
			//不能直接用子类bus_trans req去指向该item
			void'($cast(req, tmp));
			req.randomize with {data == 10;};
			`uvm_info("SEQ", $sformatf("send 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
	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)
	class sequencer extends uvm_sequencer;
		`uvm_component_utils(sequencer)
		...
	endclass

driver,sequence,sequencer都是参数化的类,在不指定数据类型时均为uvm_sequence_item类型。
对于class flat_seq extends uvm_sequence类来说,未指定数据参数,那么在使用create_item创建item时返回的是父类句柄,指向的是子类对象,所以需要声明一个uvm_sequence_item tmp去指向新创建的item。不能直接用子类bus_trans req去指向该item。

tmp = create_item(bus_trans::get_type(), m_sequencer, "req")
1.sequence未指定参数,默认返回的是父类句柄;
2.bus_trans::get_type()指的是创建的对象为bus_trans类型(子类);
3.m_sequencer指的是默认挂载到父类uvm_sequencer上;
4.“req”指的是创建的对象句柄字符串名字为req。

sequence同理。

3.2 uvm实验使用参数的类时

	class chnl_driver extends uvm_driver #(chnl_trans);
	...
	endclass
	class chnl_sequencer extends uvm_sequencer #(chnl_trans);
	...
	endclass
	class chnl_data_sequence extends uvm_sequence #(chnl_trans);
	...
	endclass

使用参数化的类,就不需要句柄的转换了。

  • 28
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值