理解UVM中的virtual sequencer和virtual sequence

这周看了Cliff的文章《Using UVM Virtual Sequencers & Virtual Sequences》,本文相当于是一个阅读记录。

一、什么时候需要virtual sequencer?

  • 环境中只有一个driver agent,此时不需要virtual sequencer;
  • 环境中有多个driver_agent,但是这些driver之间不需要同步,此时不需要virtual sequencer;
  • 环境中有多个driver_agent,且这些driver之间需要同步,此时需要virtual sequencer。

一般考虑到环境的可扩展性,我们会在一开始生成环境的时候就把virtual sequencer给加上。即使暂时用不到,也比以后再去加的要好。而且目前的验证环境大部分是脚本生成的,加virtual sequencer其实也不存在什么额外的工作量。

二、为什么叫virtual sequencer / virtual sequence?

  • 使用virtual sequencer时,我们的sequence实际上是运行在对应的subsequencer上的,此时virtual sequencer只是一个容器,所以称之为"virtual"。
  • 同理,virtual sequence上可以包含多种不同的pkt/seq,它同样是一个容器,所以称之为"virtual"。
  • 需要注意,这里的“virtual”是抽象概念上的,并不是关键字的意思。实际上:

        virtual sequencer和(real) sequencer都继承自uvm_sequencer;

        virtual sequence 和(real) sequence 都继承自uvm_sequence。

三、m_sequencer与p_sequencer

3.1 m_sequencer

当我们使用宏`uvm_do或者xxx_seq.start(sqr)方法启动sequence后,sequence内部自有的m_sequencer句柄就自动地指向了对应的sequencer上了。这个操作是start()方法内部实现的,对用户不可见,因此一般我们都不会直接去操作m_sequencer变量。事实上,uvm中直接以'm_'开头的变量都不应该直接被用户使用。

3.2 p_sequencer

与m_sequencer变量作用相反,p_sequencer变量就是为了方便用户而提供的。p_sequencer变量需要用户使用宏`uvm_declare_p_sequencer去定义和设置,该宏的展开如下:

`define uvm_declare_p_sequencer(SEQUENCER) \
  SEQUENCER p_sequencer;\
  virtual function void m_set_p_sequencer();\
    super.m_set_p_sequencer(); \
    if( !$cast(p_sequencer, m_sequencer)) \
      `uvm_fatal("DCLPSQ", \
      $sformatf("%m %s Error casting p_sequencer, please verify that this
      sequence/sequence item is intended to execute on this type of sequencer",
      get_full_name())) \
  endfunction

`uvm_declare_p_sequencer宏一般在sequence的内部使用,主要完成以下两件事情:

  1. 创建了p_sequencer变量;
  2. 将uvm内部的m_sequencer变量赋给了p_sequencer变量;

宏`uvm_declare_p_sequencer的使用可以参考后续4.2.1的代码。或许你存在疑惑,这个宏只是定义了m_set_p_sequencer()函数,并没有直接调用该函数。实际上,m_set_p_sequencer()函数也是在sequence的start()函数内部被调用的(所以这个函数是virtual的)。

在创建和设置好p_sequencer变量后,我们就可以很方便地通过p_sequencer变量去访问sequencer了。比如在4.2.1的代码中,我们在virtual sequence中,通过p_sequencer索引到多个实际的sequencer句柄,并将他们传递给实际的sequence。

四、举例

4.1 virtual sequencer

class vsequencer extends uvm_sequencer;
  `uvm_component_utils(vsequencer)
  tb_ahb_sequencer ahb_sqr;
  tb_eth_sequencer eth_sqr;

  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
endclass
  • virtual sequencer只是一个sequencer的容器。

4.2 virtual sequence

4.2.1 virtual sequence base

class vseq_base extends uvm_sequence;
  `uvm_object_utils(vseq_base)
  `uvm_declare_p_sequencer(vsequencer)

  function new(string name="vseq_base");
    super.new(name);
  endfunction

  tb_ahb_sequencer ahb_sqr;
  tb_eth_sequencer eth_sqr;

  virtual task body();
    ahb_sqr = p_sequencer.ahb_sqr;
    eth_sqr = p_sequencer.eth_sqr;
  endtask
endclass
  • 在virtual sequence base中,我们借助p_sequencer变量的帮助,得到多个sequencer的句柄。

4.2.2 virtual sequence extension

class v_seq1 extends vseq_base;
  `uvm_object_utils(v_seq1)

  function new(string name="v_seq1");
    super.new(name);
  endfunction

  virtual task body();
    ahb_seq1 ahb_seq;
    eth_seq1 eth_pkts;
    //---------------------------------------------------
  super.body();
  `uvm_info("v_seq1", "Executing sequence", UVM_HIGH)
  `uvm_do_on(ahb_seq, ahb_sqr)
  `uvm_do_on(eth_pkts, eth_sqr)
  `uvm_do_on(eth_pkts, eth_sqr)
  `uvm_do_on(ahb_seq, ahb_sqr)
  `uvm_info("v_seq1", "Sequence complete", UVM_HIGH)
  endtask
endclass
  • 在virtual sequence中,将不同sequence和对应的sequencer联系起来。

4.3 environment

class env extends uvm_env;
  `uvm_component_utils(env)

  tb_eth_agent eth_agnt;
  tb_ahb_agent ahb_agnt;
  vsequencer v_sqr;

  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    eth_agnt = tb_eth_agent::type_id::create("eth_agnt", this);
    ahb_agnt = tb_ahb_agent::type_id::create("ahb_agnt", this);
    v_sqr = vsequencer::type_id::create("v_sqr" , this);
  endfunction

  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    v_sqr.ahb_sqr = ahb_agnt.sqr);
    v_sqr.eth_sqr = eth_agnt.sqr);
  endfunction
endclass
  • 显然,我们还需要在env中,将各个sequencer的句柄传递给virtual sequencer。这里是直接赋值的方式,你也可以采用config_db进行配置。 

4.4 testcase

`timescale 1ns/1ns

class test1 extends test_base;
  `uvm_component_utils(test1)

  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction

  task run_phase(uvm_phase phase);
    v_seq1 vseq = v_seq1::type_id::create("vseq");
    uvm_test_done.raise_objection(this);
    `uvm_info("test1 run", "Starting test", UVM_MEDIUM)
    vseq.start(e.v_sqr);
    `uvm_info("test1 run", "Ending test", UVM_MEDIUM)
    uvm_test_done.drop_objection(this);
  endtask
endclass
  • 在testcase中,我们可以通过start()函数来启动virtual sequence。

  • 14
    点赞
  • 110
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值