UVM——虚序列器与虚序列(virtual sequencer与virtual sequence)


   对于顶层的测试环境, 测试序列所要协调的不再只是面向一个sequencer的sequence群,而是要面向多个sequencer的sequence群面向不同sequencer的sequence群如何挂载到不同的sequencer上呢这就需要用到virtual sequence和virtual sequencer来解决。对于单一的sequencer下的sequence群,其挂接较为简单,即通过uvm_sequence::start()来挂载root sequence,而在内部的child sequence可以通过宏`uvm_do()来实现。

一、virtual sequence与virtual sequencer

  • virtual sequence:承载不同目标sequencer的sequence群落,实现sequence同步;virtual sequence一般只会挂载到virtual sequencer上,且没有自己的sequence_item,只用于控制其他的sequence执行顺序,起统一调度作用
  • virtual sequencer:桥接其它sequencer,即连接所有底层sequencer的句柄(指针),是一个中心化的路由器。virtual sequencer本身并不传送item数据对象,因此不需要与driver进行TLM连接。所以用户需在顶层的connect阶段做好virtual sequencer中各个sequencer句柄与sequencer实体对象的一一连接,避免句柄悬空。

在验证环境中或测试案例中,使用virtual sequence可以来同步不同接口之间的数据和时序。

二、virtual sequence and sequencer的产生

2.1.嵌入序列器

  • 在virtual sequencer中定义指向其他真实sequencer句柄指针
    在这里插入图片描述
class virtual_sequencer extends uvm_sequencer;
   bfm_sequencer   bfm0_sqr;            //1.插入虚序列器句柄,指向真实sequencer
   bfm_sequencer   bfm1_sqr;  
   function new(string name, uvm_component parent);
      super.new(name,parent);
   endfunction
endclass

2.2.嵌入序列,控制序列

  • 在virtual sequence中定义sequence句柄,在body( )任务中控制这些序列
  • 通过宏`uvm_declare_p_sequencer( )来绑定virtual sequencer同时声明p_sequencer,并操作virtual sequencer中的内容;
  • 通过宏`uvm_do_on( )将虚序列器句柄与虚序列句柄相连接
  • 注意区别:virtual_sequence中嵌套的sequence和普通sequence中嵌套sequence普通sequence中嵌套的sequence都在同一个sequencer上启动(通过sequencer仲裁决定);而在virtual sequence中嵌套的sequence可以在不同sequencer实体上同时启动
    在这里插入图片描述
class virtual_sequence extends uvm_sequence;
   `uvm_object_utils(virtual_sequence)
   `uvm_declare_p_sequencer(virtual_sequencer)         //1.声明p_sequencer,操作virtual sequencer中的内容
   bfm_sequence   bfm0_seq;                            //2.插入序列句柄
   bfm_sequence   bfm1_seq;                            //序列seq可由不同的seqr启动
   virtual task body();
      `uvm_do_on(bfm0_seq,p_sequencer.bfm0_sqr);       //3. 将虚序列器句柄与虚序列句柄相连接
      `uvm_do_on(bfm1_seq,p_sequencer.bfm1_sqr);
   endfunction
endclass

  在使用uvm_do_on宏的情况下,虽然bfm_seq是在virtual_sequence上启动,但他们最终会被交给p_sequencer.bfm_sqr,也即env.bfm_agt.bfn_sqr。这也就是virtual sequence和virtual sequencer中virtual的来源。他们各自不产生transaction,只是控制其他sequence为相应的sequencer产生transaction。

  • 关于p_sequencer的说明
       sequence类里有一个uvm_sequencer_base类型m_sequencer指针,当sequence和sequencer关联后,m_sequencer会自动指向该sequencer,但通过m_sequencer不能直接使用seqr里的变量,否则会出现编译错误只能使用cast强制向子类转换后,才能通过m_sequencer.xxx来访问该seqr内的xxx变量

   UVM引入p_sequencer,可以自动的实现上面所述的cast动作,从而可以在sequence中自由使用关联sequencer内的变量。

   p_sequencer并不是UVM自动地在sequence的创建的,需要用户使用uvm_declare_p_sequencer宏声明,之后UVM会自动实现指向seqr及cast的动作

2.3.在环境/测试用例中连接sequencer到virtual sequencer

  • 在build_phase阶段创建并例化virtual sequencer;将不同agt场景下的sqr发送的default sequence设置为null,关闭相应的sequence;
  • 在connect_phase阶段,将被控制的sequencers与virtual sequencer关联一起
  • `在env或test中配置virtual_sequence为default sequence,在需要的phase阶段执行virtual sequence;

在这里插入图片描述

class top_env extends uvm_env;
   virtual_sequencer       v_sqr;     //and subenvs
   ...
   virtual funvtion void build_phase(uvm_phase phase);
      super.build_phase(phase);
      ...
      v_sqr = virtual_sequencer::type_id::create("v_sqr",this);
      uvm_config_db#(uvm_object_wrapper)::set(this,"subenv0.bfm0_agt.sqr.main_phase","default_sequence",null);
      uvm_config_db#(uvm_object_wrapper)::set(this,"subenv0.bfm1_agt.sqr.main_phase","default_sequence",null);
      uvm_config_db#(uvm_object_wrapper)::set(this,"v_sqr.main_phase","default_sequence",virtual_sequence::get_type());
   endfunction
   
   virtual function void connect_phase(uvm_phase phase);
      v.sqr.bfm0_sqr = bfm_agt0.bfm0_sqr;        //将被控制的真实sequencers赋给virtual sequencer的指针,建立连接
      v.sqr.bfm1_sqr = bfm_agt1.bfm1_sqr;
   endfunction
endclass

三、实例应用

在这里插入图片描述

class simple_virtual_sequencer extends uvm_sequencer;
    `uvm_component_utils(simple_virtual_sequencer)
    eth_sequencer eth_seqr;                            //1. 嵌入序列器
    cpu_sequencer cpu_seqr;                            //1. 嵌入序列器

   function new(input string name="simple_virtual_sequencer",
      input uvm_component parent=null);
      super.new(name, parent);
   endfunction
endclass: simple_virtual_sequencer

class simple_virtual_seq extends uvm_sequence;
    `uvm_declare_p_sequencer(simple_virtual_sequencer) 
    ...
    // A sequence from the cpu sequencer library
    cpu_config_seq conf_seq;                        //2. 嵌入序列
    // A sequence from the ethernet subsequencer library
    eth_large_payload_seq frame_seq;                //2. 嵌入序列
    // A virtual sequence from this sequencer's library
    random_traffic_virt_seq rand_virt_seq; **//嵌套virtual sequence**
    virtual task body();
    // Invoke a sequence in the cpu subsequencer.
        `uvm_do_on(conf_seq, p_sequencer.cpu_seqr)
    // Invoke a sequence in the ethernet subsequencer.
        `uvm_do_on(frame_seq, p_sequencer.eth_seqr)
    // Invoke another virtual sequence in this sequencer.
        `uvm_do(rand_virt_seq)        //在virtual_seq中嵌套另一个virtual sequence
    endtask : body
endclass : simple_virtual_seq

class simple_tb extends uvm_env;
    cpu_env_c cpu0; 
    eth_env_c eth0; 
    simple_virtual_sequencer v_sequencer;
    ... 
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        // Configuration: Set the default sequence for the virtual sequencer.
        uvm_config_db#(uvm_object_wrapper)::set(this,"v_sequencer.run_phase","default_sequence",simple_virtual_seq::get_type());
        // Build envs with subsequencers.
        cpu0 = cpu_env_c::type_id::create("cpu0", this);
        eth0 = eth_env_c::type_id::create("eth0", this);
        // Build the virtual sequencer.
        v_sequencer = simple_virtual_sequencer::type_id::create("v_sequencer",this);
    endfunction : build_phase

    function void connect();                           //3. 连接sequencer与virtual sequencer
        v_sequencer.cpu_seqr = cpu0.cpu_agt.sequencer; // 直接通过指针传递实例化的driver sequencer
        v_sequencer.eth_seqr = eth0.eth_agt.sequencer; // 直接通过指针传递实例化的driver sequencer
        //uvm_config_db#(uvm_sequencer)::set(this,”v_sequencer”,eth_seqr”,eth0.tx_rx_agent.sequencer);通过config_db机制传递实例化的driver sequencer
    endfunction : connect
endclass: simple_tb

参考:1.https://www.cnblogs.com/east1203/p/11592641.html
2.http://www.learnuvmverification.com/index.php/2016/03/03/how-virtual-sequence-works-part-2/
3.https://blog.csdn.net/wonder_coole/article/details/90665876?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-5&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-5

  • 47
    点赞
  • 299
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SD.ZHAI

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

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

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

打赏作者

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

抵扣说明:

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

余额充值