【UVM】sequence 的启动方式

本文深入探讨了UVM中Sequence的启动机制,包括直接实例化、default_sequence设置及`uvm_do宏的使用。解析了Sequence在不同Sequencer上的启动方式,以及如何在Sequence中控制仿真时间和交易项的调度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

该篇文章描述不清楚的地方建议参考:UVM设计模式 (七)命令模式、三种sequence启动方式、start_item/finish_item、中介模式、virtual sequence_Holden_Liu的博客-CSDN博客_uvm的body函数

第一种:直接在tc中例化sequence,通过调用star函数指定sequencer启动。

my_sequence my_seq;
my_seq = my_sequence::type_id::create("my_seq");
my_seq.start(sequencer); ## 括号中是sequencer的例化路径,也可以使用m_sequencer(m_sequencer为sequence的启动sequencer). 如果sequence例化在sequencer中,可以用this.

第二种:采用default_sequence

未直接例化sequence:

uvm_config_db#(uvm_object_wrapper)::set(this,"env.i_agt.sqr.main_phase","default_sequence",my_sequence::type_id::get());

未例化时,如何在seqr中启动seq?可以通过在test_base中uvm_config_db将seq set到sequencer中。

在使用 `uvm_do宏时,会默认选择seq启动的seqr上,seq中创建的tr会发送给seqr, seqr负责tr的调度,发送给driver.

`uvm_do_on可以显示将seq中的tr发送给哪个seqr。

uvm_do系列宏不仅仅适用于tr, 也适合seq。如果要在vseq中调用seq,`uvm_do(seq)可以自动调用seq的start函数,同时seq中的tr自动发送给vseq启动的seqr上。使用`uvm_do_on(seq, p_sequencer.p_sqr1)则将seq中的tr发送给vseqr中的p_sqr1这个seqr上。

class my_sequence extends uvm_sequence;

    my_config cfg;

    `uvm_declare_p_sequencer(my_sequencer) 
    
    virtual task body();
        cfg = p_sequencer.cfg;
    endtask

endclass

直接例化sequence:

my_sequence my_seq;
my_seq = my_sequence::type_id::create("my_seq",this);
uvm_config_db#(uvm_sequence_base)::set(this,"env.i_agt.sqr.main_phase","default_sequence",my_seq);

通过例化的方法,uvm_object_wrapper要改成uvm_sequence_base;sequence也可以放在env中例化;如果要在tc中向sequence传入handle,就不需要p_sequencer了,因为sequence已例化,可以直接将句柄相连:

seq.tr_h = this.tr_h; #seq例化在tc中
env.seq.tr_h = this.tr_h;#seq例化在env中

seq,seqr,还是 vseq,vseqr,最关键的是搞明seq的启动方式(1. default_sequence启动 2. start启动 3. vseq中调用uvm_do宏启动seq),seq在哪个seqr上启动,挂载。启动的意思就是调用seq的body函数,因为seq不是component,不属于验证组件,没有phase机制,所以必须挂载到一个seqr上启动。第二个需要搞明白seq中的tr发送给哪个seqr调度(1. uvm_do宏(封装了start_item) 2. start_item形式),seq启动后创建的tr需要发送给seqr,seqr调度tr通过TLM发送给对应的dvier。一种是默认的使用启动时的seqr, 一种是显示指明seqr,这种一般是指定vseqr中的seqr。

seq挂载到seqr上时,成员变量m_sequencer就指向了该seqr。

所以uvm_do宏即适用seq,也适用tr。 尽量少用宏

每个sequence中都有一个m_sequencer的句柄,指向seq启动的seqr,如果要引用seqr中的参数,可以声明p_sequencer(其实就是m_sequencer cast转化过来的)

关键是seq在哪个seqr上启动。

在sequence中控制仿真时间:

default_sequence启动方式其实隐式调用start函数:

task my_sequencer::main_phase(phase);

    seq.starting_phase = phase;
    seq.start(this);

endtask
  • 采用default_sequence启动方式,要在sequence中控制仿真时间,通过starting_phase的raise和drop。
task my_sequence::body();

    if(starting_phase != null)
        starting_phase.raise_objection(this);

        tr = new();
        start_item(tr);
        finish_item(tr);

    if(starting_phase != null)
        starting_phase.drop_objection(this);

endtask
  • 不采用default_sequence启动方式,但是也通过starting_phase的raise和drop。
class sequence1 extends uvm_sequence #(my_transaction);

virtual task body();
      if(starting_phase != null) 
         starting_phase.raise_objection(this);
      repeat (5) begin
         `uvm_do_with(m_trans, {m_trans.pload.size < 500;})
         `uvm_info("sequence1", "send one transaction", UVM_MEDIUM)
      end
      #100;
      if(starting_phase != null) 
         starting_phase.drop_objection(this);
   endtask

没有set  default_sequence, 所以starting_phase 为 null。 但是可以像下面那样seq0.starting_phase = phase 赋值为非空,间接通过sequence中的starting_phase 控制 objection。

task my_case0::main_phase(uvm_phase phase);
   sequence0 seq0;
   sequence1 seq1;

   seq0 = new("seq0");
   seq0.starting_phase = phase;
   seq1 = new("seq1");
   seq1.starting_phase = phase;
   fork
      seq0.start(env.i_agt.sqr);
      seq1.start(env.i_agt.sqr);
   join
endtask
  • 不采用default_sequence, 通过testcase中的phase的raise和drop。
task my_case0::main_phase(uvm_phase phase);
   sequence0 seq0;
   sequence1 seq1;
   
   phase.raise_objection(this);
   seq0 = new("seq0");
   
   seq1 = new("seq1");

   fork
      seq0.start(env.i_agt.sqr);
      seq1.start(env.i_agt.sqr);
   join
   phase.drop_objection(this);
endtask

此时sequence中的starting_phase = null ; 

starting phase的赋值发生的机制是1.run_test()->excute_phases()->traverse->excute()->sqr.start_phase_sequence();
2.start_phase_sequence()中会通过uvm_config_db::get 得到default_sequence的名字,如果get 到了default sequence的名字就会create default_sequence,并且将当前phase(uvm_main_phase或者uvm_run_phase)的句柄赋值给starting phase,如果没有get 到就会直接return退出当前函数;
3.由于uvm_config_db::set default sequence只针对的是virtual sequencer,当执行你调用的子sequencer的时候由于没有uvm_config_db::get到default sequence的名字,所以会直接退出return;4.所以如果使用了default_sequence机制,并且default sequence中有子sequence,这个时候要在子sequence使用starting_phase.raise_object要非常小心;4.这个跟pre body,post body貌似没有多大关系;
4.具体代码请见uvm1.1 中文件 uvm_sequencer_base.svh

================================================================================================================================================================================================================================================================================================

`uvm_do_on(tr, this.m_sequencer)
第一个是transaction指针,第二个是sequencer指针。m_sequencer默认为启动(显式或者隐式)sequence的sequencer.

p_sequencer:

 class case0_sequence extends uvm_sequence #(my_transaction);
    my_transaction m_trans;
    `uvm_object_utils(case0_sequence)
    `uvm_declare_p_sequencer(my_sequencer)
endclass

此时sequence的默认启动m_sequencer指向p_sequencer,可以引用p_sequencer中的变量和方法。

在sequence中获得sequencer的object ( config class ,interface, TLM port etc.)

第一种方式:在base sequence中的pre_start中,当执行start函数时,会自动调用pre_start函数。

class sys_base_seq extends uvm_sequence;
......
    `uvm_declare_p_sequencer(sys_vseqr)

    sys_cfg m_cfg_h;
    xxxx port;
    virtual sys_if sys_vif;

    task pre_start();
        this.m_cfg_h      = p_sequencer.m_cfg_h;
        this.sys_vif      = p_sequencer.sys_vif;
        this.port         = p_sequencer.port;
    endtask

第二种方式: 在base sequence中的pre_body中,当执行body函数时,会自动调用pre_body函数。 (建议放在pre_start中)

class sys_base_seq extends uvm_sequence;
......
    `uvm_declare_p_sequencer(sys_vseqr)

    sys_cfg m_cfg_h;
    xxxx port;
    virtual sys_if sys_vif;

    task pre_body();
        this.m_cfg_h      = p_sequencer.m_cfg_h;
        this.sys_vif      = p_sequencer.sys_vif;
        this.port         = p_sequencer.port;
    endtask

除了直接句柄的赋值,也可以采用config_db的形式:

uvm_config_db#(virtual sys_if)::get(m_sequencer,"","vif",sys_vif);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

劲仔小鱼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值