UVM m_sequencer 和 p_sequencer

m_sequencer:

class uvm_sequence extends uvm_sequence_item;    // uvm_sequence 继承于 uvm_sequence_item
// case属于sequence类型,case本质是个sequence
// case0_sequence 在 my_sequencer上启动:case0_sequence.start(my_sequencer)

class case0_sequence extends uvm_sequence #(my_transaction);
	my_trasaction m_trans;
	`uvm_object_utils(case0_squence)
	...
	
	virtual task body();
	...
	repeat(10) 
		begin
		... //如何得到dmac和smac?
		end
	...
endclass

在这里插入图片描述

  • m_sequencer 是继承于 uvm_transaction 的 uvm_sequence_item 中,定义为 uvm_sequencer_base 类型的变量,即是个定义在 sequence 里的 sequencer。
  • uvm_sequence_item 中的变量,默认情况下在每个sequence中都可用
  • uvm_sequence 继承于 uvm_sequence_item
  • uvm_sequence 和 uvm_sequence_item都继承于 uvm_object

p_sequencer:

方法一

// 创建继承于 uvm_sequencer 的 my_sequencer 

在这里插入图片描述

`uvm_do_with 宏,这个宏完成了三个步骤:
•    sequence 或 item 的创建;
•    sequence 或 item 的随机化;
•    sequence 或 item 的传送

uvm_do_with(sequencer, {sequencer.seq_item = values}
class case0_sequence extends uvm_sequence #(my_transaction);
	my_trasaction m_trans;
	`uvm_object_utils(case0_squence)
	...
	
	virtual task body();
		my_sequencer x_sequencer;   // class my_sequencer extends uvm_sequencer #(my_transaction); 声明uvm_sequencer类型变量x_sequencer
		...
		$cast(x_sequencer, m_sequencer); // 将m_sequencer转换为x_sequencer
		...
	endtask: body
	
	repeat(10) 
		begin
		`uvm_do_with(m_trans,{m_trans.dmac==x_sequencer.dmac;
							  m_trans.smac==x_sequencer.smac;}) // `uvm_do_with宏创建item,并调用item.randomize()对item进行约束,(item.randomize with {m_trans.dmac==x_sequencer.dmac; m_trans.smac==x_sequencer.smac;})
		end
	...
endclass
  • sequencer 是继承于 uvm_sequencer,uvm_sequencer 是 uvm_component 类型;uvm_component 可以通过树形组织结构管理,可以很方便的通过 uvm_config_db 实现对其类成员的参数设置
  • sequence 属于 uvm_object,不属于UVM结构中,sequence 属于 uvm_component,在UVM结构中。sequence 必须挂到 sequencer,才能获得顶层的配置和更多信息
  • case 属于 sequence 类型,uvm_sequence 是 uvm_sequence_item 类型,sequence(子弹) 从 sequencer(弹夹) 发送,如何得到 sequencer(弹夹) 的 dmac 和 smac?
  • sequence 中变量 m_sequencer 类型是 uvm_sequencer_base(uvm_sequencer的基类),而不是 my_sequencer 类型,sequence 如何通过自己的成员变量 m_sequencer,拿到 sequencer 的 dmac 和 smac?
  • 方法一:在 case0_sequence 的 body 中创建 my_sequencer 类型变量 x_sequencer,再 $cast(x_sequencer, m_sequencer),m_sequencer 通过 cast 转换成 x_sequencer,相当于 my_sequencer m_sequencer? sequence 通过自己的成员变量挂载在 sequencer上?

  • m_sequencer 可作为媒介,用于从 sequence 中访问组件层次结构中的配置信息和其他资源。可以通过调用m_sequencer.get_full_name() 来获取 sequencer 的完整层次名称

方法二 UVM内建宏 `uvm_declare_p_sequencer(SEQUENCER)

// 使用宏定义 声明一个 my_sequencer 类型的成员变量 p_sequencer 

class case0_sequence extends uvm_sequence #(my_transaction);
	my_trasaction m_trans;
	`uvm_object_utils(case0_squence)
	`uvm_declare_p_sequencer(my_sequencer) // UVM内建宏`uvm_declare_p_sequencer(SEQUENCER),UVM会自动将m_sequencer通过$cast() 转换成 my_sequencer 类型的 p_sequencer,在pre_body() 之前完成
	...
	
	virtual task body();
		...
	repeat(10) 
		begin
		`uvm_do_with(m_trans,{m_trans.dmac==p_sequencer.dmac;
		                      m_trans.smac==p_sequencer.smac;})
		end
	...
endclass

`uvm_declare_p_sequencer(my_sequencer)宏的作用:

  • 声明了一个my_sequencer类型的句柄p_sequencer
  • 将 m_sequencer 句柄通过 $cast(p_sequencer,m_sequencer) 转化为 p_sequencer 类型的句柄。
  • uvm_sequencer_base -> uvm_sequencer_param_base #(REQ,RSP) -> uvm_sequencer -> my_sequencer
  • uvm_sequencer_base m_sequencer
  • uvm_sequencer p_sequencer
  • m_sequencer 是 p_sequencer 的父类
  • $cast(p_sequencer, m_sequencer) ,向下类型转换?
  • case0_sequence.start(my_sequencer),则 start() 任务将分配 case0_sequence.m_sequencer 作为my_sequencer,case0_sequence 可以使用 m_sequencer 访问组件层次结构。例如通过调用m_sequencer.get_full_name() 来获取 sequencer 的完整层次名称。请注意,m_sequencer的类型是uvm_sequencer_base

equence/item一旦“挂载”到某一个sequencer上,该sequencer的句柄即被赋值于m_sequencer(uvm_sequencer_base类);而p_sequencer通常需要通过在定义sequence类使,通过宏`uvm_declare_p_sequencer(SEQUENCER)声明,间接定义p_sequencer成员变量。m_sequencer与p_sequencer均指向同一个挂载的sequencer句柄,只是前者使父类句柄,后者往往是所挂载sequencer句柄(子类句柄)

cast

对于两个具有继承关系的class,若对应父类的instance为father_tr,而子类的instance为child_tr,那么​如果只是让子类的指针指向父类,有以下几种操作方法:

1、简单赋值:fathrer_tr = child_tr;​
2、使用copy函数:father_tr = child_tr.copy();
3、使用cast函 数:cast(father_tr, child_tr);​

以上3种方法均可实现数据的传递,但有本质区别:(1)通过简单赋值操作,使两个handle father_tr和child_tr指向了同一块memory,因此,father_tr的类型也会变成子类的类型。(2)使用copy函数​,是将数值进行简单的copy,即将child_tr对应的memory中的数据放入father_tr对应的memory中,这种数据的copy方式,不会带来类型的变化,因此,father_tr仍然是父类的类型,但使用copy函数要求father_tr得先new一块memory, 如果没有memory,则需要使用clone函数。(3)此处的$cast操作与(1)中的简单赋值很类似,father_tr的类型也会变为子类的类型。

上面子类向父类进行数据传递时,显示不出cast操作向下类型转换的优势,但父类向子类传递数据时,无法使用child_tr = father_tr,则必须要使用$cast操作。

直接使用cast(child_tr, father_tr)是非法的,此时则要求基类的handle必须指向派生类的对象,即father_tr必须指向child_tr类型的对象​,因此一般会有如下几步操作:

1、定义一个派生类类型的对象:child1_tr = new;
2、​father_tr = child1_tr;
3、$cast(child_tr, father_tr);

以上第(3)步,$cast会做类型检查,若类型兼容返回1,否则返回0。


m_sequencer是uvm_sequencer_base类型的句柄,默认情况下在每个sequence中都可用。要访问正在运行sequence 的真实sequencer ,我们需要将m_sequencer类型转化为真实sequencer ,通常称为p_sequencer。

// 下面是一个简单的示例,sequence 希望访问sequencer的 clock monitor组件

class test_sequencer_c extends uvm_sequencer;         
    clock_monitor_c clk_monitor;
endclass
 
class test_sequence_c extends uvm_sequence;
    test_sequencer_c p_sequencer;    // sequencer/monitor在sequence中声明
    clock_monitor_c my_clock_monitor;
    task pre_body()                      //Typecast the m_sequencer base type to p_sequencer
	    if(!$cast(p_sequencer, m_sequencer)) begin   // m_sequencer转p_sequencer,sequence挂载sequencer
	        `uvm_fatal("Sequencer Type Mismatch:", " Worng Sequencer");
    	end
		//get access to clock monitor
    	my_clock_monitor = p_sequencer.clk_monitor;  // sequence中声明的monitor连接sequencer的monitor
    endtask
endclass

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值