• UVM m_sequencer 和 p_sequencer


    m_sequencer:

    class uvm_sequence extends uvm_sequence_item;    // uvm_sequence 继承于 uvm_sequence_item
    
    • 1
    // 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    • 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 
    
    • 1

    在这里插入图片描述

    `uvm_do_with 宏,这个宏完成了三个步骤:
    •    sequence 或 item 的创建;
    •    sequence 或 item 的随机化;
    •    sequence 或 item 的传送
    
    uvm_do_with(sequencer, {sequencer.seq_item = values}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    `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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

  • 相关阅读:
    ShardingSphere笔记(一): 经验和踩坑总结
    aggregate和annotate方法使用
    VINS学习(二)IMU预积分原理与实现
    GEE遥感云大数据林业应用典型案例实践及GPT模型应用
    自动化运维?看看Python怎样完成自动任务调度⛵
    Casper Network 构建企业级区块链生态的野望
    2.基本指令
    linux卸载jdk方法
    TypeScript 笔记:基础类型
    1.读dubbo spi机制源码
  • 原文地址:https://blog.csdn.net/qq_40456702/article/details/126373808