(六)UVM的sequence、sequencer及启动

一、sequencer和sequence

        sequencer是在sequence和driver之间传递数据的桥梁,这个数据信息就是sequence_item(可理解为my_transcation),sequence_item是一个子弹,sequence是弹夹,它的作用是装子弹,sequencer是一把枪,它的作用是把子弹射出去。sequencer是一个uvm_component,是验证平台运行过程中始终存在的,sequence是object组件,与my_transaction一样,sequence有其存在周期,比my_transaction要更长一些,当其中的transaction全部发送完毕后,它的存在周期也就结束了。

 说明:

  • export、port是TLM组件之间通信的通道

1、sequencer

sequencer就是充当激励环节的路由器的作用,即管理sequence,在某一个验证环境中 uvm_sequencer管理多个sequence,仲裁某一时刻传递哪个sequence的数据。

1、继承关系

 说明:

  1. 所有的自定义sequencer都继承于uvm_sequencer#(REQ,RSP),(在源码中REQ=RSP,可以理解成AXI读操作,请求与响应在一个通道上面),uvm_push_sequence#(REQ,RSP)很少使用。
  2. 在其他父类中定义了库里面自带的一些变量、函数等操作。
  3. sequencer承载了sequence,sequence挂载在sequencer上才能发挥作用。

2、virtual sequencer

Virtual sequencer作用: 控制其他的sequencer,把多个sequener绑定起来,也是为了方便sequence的调度。Virtual sequencer并不和任何driver相连,Virtual sequencer本身并不处理item。

2、squence

1、transcation:就是要发送的数据和其他的一些信息,和UVM库里的uvm_sequence_item作用类似。

包含:域传输给DUT的数据和验证平台用到的一些控制信息等、约束、field_automation等其他的一些内容。

继承关系:

说明:

  • 所有的自定义transaction(user_transaction)都继承于uvm_sequence_item。

2、sequence就是装transaction的容器,所有的自定义sequence都继承于uvm_sequence#(user_trans)。

说明:

  • 由于sequence、transaction都是属于object类,存在周期较短,为了让他们能够在component组件之间传递,需要将sequence挂载在sequencer上才能发送给driver,再传给DUT。

3、virtual sequence

virtual sequence的作用就是负责对不同的sequence(可相同)去挂载到不同sequencer(可相同)上的顺序进行调度。

 3、sequence的启动与挂载

启动:指就是通过哪种方式调用uvm_sequence中的body()函数,也可以理解为start函数调用。

sequence的挂载:它需要挂载在一个sequencer上,在这个sequencer的phase中被调用,同时uvm_sequence可以操作所挂载的sequencer的成员变量(比如:在virtual sequence中调用 virtual sequcner中其他 sequcner 句柄 )。

transaction的挂载:对于transaction,挂载的意思就是将transaction发送给所挂载的sequencer,sequencer再发送给连接的driver。

无论哪种启动方式最终目的是要把transaction传递给sequencer,主要是要传递信息。

一、sequence的启动有三种方式

1、default_sequence

`uvm_config_db#(uvm_object_wrapper)::set(this,"v_sqr.main_phase","default_sequence",virtual_sequence::type_id::get());

说明:

  • 使用default_sequence启动sequence,会隐式得调用start函数,自动执行sequence的body、pre_body与post_body任务等,然后会把transcation自动传给sequencer。
  • 验证平台的component组件运行,是按照phase机制运行的
  • 通过default_sequence将virtual sequence指向那些实例化sequence挂载到了v_sqr并在其main_phase里面执行,v_sqr是virtual sequencer的实例化对象。
  • default_sequence有两种定义方式,上述是常用的一种,另外一种方式是先实例化要启动的sequence,之后再通过default_sequence启动
function void my_case0::build_phase(uvm_phase phase);
    case0_sequence cseq;
    super.build_phase(phase);
    cseq = new("cseq");
    uvm_config_db(uvm_sequence_base)::set(this,"env.i_agt.sqr.main_phase","default_sequence",cseq);
endfunction
  • 当通过default_sequence启动sequence时,uvm1.1中会自动给starting_phase赋值(uvm1.2使用了default_sequence,starting_phase也是空)starting_phase主要用于控制验证平台的运行在sequence中控制仿真时间因为sequence里面是发送的数据,当要发送的信息消耗完成后,就可以结束仿真了。

2、用start任务来启动sequence

class case_0 extends base_test;
	`uvm_component_utils(case_0)
	
function new(string name = "case_0",uvm_component parent = null);
	super.new ( name, parent);
endfunction

task main_phase( uvm_phase phase);
	apb_sequence	seq;
	super.main_phase(phase);
	seq =apb_sequence::type_id::create("seq");
	seq.starting_phase = phase;
	seq.start(apb_env.mst_agt.sqr);
	`uvm_info(get_full_name(),$sformatf("end_case" ),UVM_INFO);
endtask
endclass

说明:

  • 在sequence中显示调用strat()函数,第一个参数是需要挂载的sequencer;第二个是parent_sequence,一般传入this或者不传入;第三个是优先级;第四个call_pre_post默认为1,则自动执行pre_body/ post_body()函数。调用完这些函数用已经启动了sequence。
  • 在start()函数中,首先调用函数set_item_context(),给成员变量m_sequencer, m_parent_sequence赋值
  • starting_phase需要手动赋值。
  • 这里seq传入了apb_env.mst_agt.sqr,调用set_sequencer()函数完成挂载,并给m_sequencer赋值,m_sequencer就指向了此时传入的sqr。

宏 uvm_declare_p_sequencer

为什么要使用p_sequencer,为了在启动sequence、transaction时能够去访问sequencer里面的变量,因为sequence是object类,sequencer是component组件

举例:`uvm_declare_p_sequencer(apb_sequencer)

内部做了一个向下类型转换,m_sequencer,p_sequencer在库内部已经定义好了,用到了cast,m_sequencer是uvm_sequencer_base类型,它是uvm_sequencer的基类,但此时m_seuencer会指向类型为uvm_sequencer的实际sequencer(即apb_sequencer),此时p_sequencer就可以通过cast指向真正的squencer了,p_sequencer是m_sequencer的子类,p_sequencer的类型是uvm_sequencer;所以在使用start函数启动sequence时要保证start()函数传入的sequencer应该和宏 uvm_declare_p_sequencer声明的类型一致,在使用uvm_declare_p_sequencer后,就可以在sequence中调用挂载sequencer的成员函数和成员变量了。

3、用uvm_do宏来启动sequence

uvm_do系列所有宏都是由uvm_do_on_pri_with宏实现的

例如:

`define uvm_do(SEQ_OR_ITEM) `uvm_do_on_pri_with(SEQ_OR_ITEM, m_sequencer, -1, {})

`uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS)

说明:

  • SEQ_OR_ITEM:第一个参数可以sequence也可以是item
  • SEQR:指要挂载的sequencer
  • PRIORITY:第三个是优先级
  • CONSTRAINTS:第四个是约束
  • 当在sequence中使用uvm_do等宏时,对于uvm_do宏而言,它默认的sequencer就是调用uvm_do宏的这个sequence在启动时指定的sequencer,当在sequence中使用uvm_do等宏时,他会去调用start函数,其默认的sequencer就是此sequence启动时为其指定的sequencer,最终会把ransaction传递给sequencer。
  • 如果uvm_do宏传入的第一个参数不是sequence,就是transaction, 则调用start_item, finish_item函数,而不是调用start函数,start_item()三个参数,第一个是传入的transaction, 第二个是优先级,第三个是指定该transaction发挂载在哪一个sequencer上,如果之前没有给transaction的m_sequencer赋值,此处sequcner仍未null
  • start_item用于获取sequencer的授权许可,finish_item将item发送至sequencer,进而完成与driver之间的交互。
    
  • class case0_sequence extends uvm_sequence #(my_transaction);
       my_transaction m_trans;
    
       function  new(string name= "case0_sequence");
          super.new(name);
       endfunction 
       
       virtual task body();
          if(starting_phase != null) 
             starting_phase.raise_objection(this);
          repeat (10) begin
             `uvm_do(m_trans)
             `uvm_info("seq", $sformatf("get information from driver: %0s", m_trans.frm_drv), UVM_MEDIUM)
          end
          #100;
          if(starting_phase != null) 
             starting_phase.drop_objection(this);
       endtask
    
       `uvm_object_utils(case0_sequence)
    endclass
    
    
    class my_case0 extends base_test;
    
       function new(string name = "my_case0", uvm_component parent = null);
          super.new(name,parent);
       endfunction 
       extern virtual function void build_phase(uvm_phase phase); 
       `uvm_component_utils(my_case0)
    endclass
    
    
    function void my_case0::build_phase(uvm_phase phase);
       super.build_phase(phase);
    
       uvm_config_db#(uvm_object_wrapper)::set(this, 
                                               "env.i_agt.sqr.main_phase", 
                                               "default_sequence", 
                                               case0_sequence::type_id::get());
    endfunction

    说明:

  • 在case0_sequence类body函数中使用了`uvm_do(m_trans),这是一个item,此时并没有挂载,它的sequencer是null的,当后面default_sequence时,才去挂载到sqr上面的,并且在sqr的main_phase执行,然后把m_trans传递给sequencer。

  • 下面是uvm_do宏参数是sequence或者sequence_item库内部所执行的操作

4、关系:

 说明:

  • 通过seq_item_port发送数据请求,seuquencer通过seq_item_export接收请求,再反馈给sequence,然后sequence收到请求后,创建req,req是源码默认创建例化好的类型是my_transcation类型或者uvm_sequence_iteme类型;此时sequence还要等待sequencer把其他发送数据都仲裁完了,到你了,sequencer再反馈给sequence,然后再进行req随机化,然后把数据依次传递给sequencer、driver,过程是通过TLM端口,然后driver收到数据再按协议等要求发送给DUT完成之后,就会发送item_done信号给sequence,sequence最后等到了这个已经完成的信号,就可以开始下一次的传输了
  • 0
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值