UVM——sequence机制(数据激励的产生、配置方式)

一、sequence的执行流程

  • uvm_sequence_item包装数据):只能对数据进行封装,不存在自动执行的函数;
  • uvm_sequence生产数据):具有可自动执行的函数,可通过body()函数进行可执行操作,产生数据激励;
  • uvm_sequencer发送数据):将数据发送给driver

   sequence item是每一次driver与DUT互动的最小粒度内容,在sequence与driver之间起到桥梁作用的是sequencer,sequencer与driver均是component组件,它们之间的通信也是通过TLM端口实现的。UVM序列的连接传送如下图所示:

在这里插入图片描述

  1. sequence对象自身会产生目标数量的sequence item对象。借助于SV的随机化和sequence item对随机化的支持,使得产生的每个sequence item对象中的数据内容都不相同。
  2. 产生的sequence item会经过sequencer再流向driver
  3. driver得到了每一个sequence item,经过数据解析,再将数据按照与DUT的物理接口协议写入到接口上,对DUT形成有效激励
  4. 必要时,driver在每解析并且消化完一个sequence item,也会将最后的状态信息同sequence item对象本身再度返回给sequencer,最终抵达sequence对象一侧。这么做的目的在于,有的时候sequence需要得知driver与DUT互动的状态,这就需要driver仍然有一个回路再将处理了的sequence item对象和状态信息写回到sequence一侧。

二、sequence的启动方式——start()/default_sequence

  UVM中sequence的启动分为显示启动隐式启动两种方式。

  • 显式启动(直接启动)——调用start()方法启动。
  • 隐式启动 ——使用uvm_config_db机制配置default_sequence启动。
//sequence的显式启动
//该方法提起和落下objection,通过phase.raise_objection(this)/phase.drop_objection(this)
my_sequence   seq = my_sequence::type_id::create("seq");
phase.raise_objection(this);
seq.start(sequencer);
phase.drop_objection(this)

//sequence的隐式启动
//该方法可以在sequence中使用starting_phase提起和撤销objection
uvm_config_db#(uvm_object_wrapper)::set(this,"env.i_agt.sqr.main_phase",
                                        "default_sequence",
                                         case0_sequence::get_type());
//在my_sequence中的body任务中
virtual task body;
  if(starting_phase != null)
    starting_phase.raise_objection(this);
  repeat(10)begin
    `uvm_do(req);
  end
  if(starting_phase != null)
    starting_phase.drop_objection(this);
endtask

二、sequence生产数据——body( )

   当一个sequence启动后,会自动执行body()函数生产数据,sequencer会将数据发送给driver,完成数据的发送。sequencer与driver的通信也是通过TLM端口实现的,TLM端口在例化中需要对通信参数进行指定,这里的通信参数即sequence item种类

class tr_sequence extends uvm_sequence#(transaction);
   ...
   virtual task body();
      if(starting_phase != null)
         starting_phase.raise_objection(this,"starting");   //1.启动仿真,生产数据
         `uvm_do(req);                                      //2.通过宏`uvm_do自动随机化产生数据
      if(starting_phase != null)
         starting_phase.drop_objection(this,"done");        //3.结束仿真
   endtask
endclass  

class driver extends uvm_driver#(transaction);
   ...
   virtual task run_phase(uvm_phase phase);
      forever begin
         seq_item_port.get_next_item(req);                 //4.driver申请数据
         send(req);                                        //5.按照物理时序处理接收到的数据
         seq_item_port.item_done();                        //6.数据传输完毕
      end
   endtask
endclass
  • 加粗样式在sequence中,通过objection机制控制仿真时的数据生产;
  • 在driver的run_phase阶段,利用TLM端口seq_item_portget_next_item()和item_done()方法控制数据包的传输;

2.1.宏`uvm_do( )的功能

   当一个sequence启动后,会自动执行sequence中的body任务,在body任务中可以调用`uvm_do系列宏来生产数据
   当同一个sequencer上启动多个sequence时,由于sequencer会依据何种选择启用哪一个sequence的transaction存疑,故引入仲裁机制。使用仲裁机制的相关系列宏如下所指示:(默认仲裁算法是SEQ_ARB_FIFO,遵循先入先出,不考虑优先级)

`uvm_do(SEQ_OR_ITEM)                       //1. 根据sequence_item实例,随机化产生数据
`uvm_do_with(SEQ_OR_ITEM, CONSTRAINTS)     //2. 在随机化数据的基础上,添加约束
`uvm_do_pri(SEQ_OR_ITEM, PRIORITY)
`uvm_do_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS)
`uvm_do_on(SEQ_OR_ITEM, SEQR)               //3. 随机化同时,显式的指定使用哪个sequencer来发送此transaction
`uvm_do_on_pri(SEQ_OR_ITEM, SEQR, PRIORITY)
`uvm_do_on_with(SEQ_OR_ITEM, SEQR, CONSTRAINTS)
`uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS)
  • `uvm_do系列宏其实是将下述动作封装在了一个宏中(start_itemfinish_item运用)。在实际的代码编写中,工程师可以不使用宏uvm_do()处理数据,而是根据实际情况手动执行这些内嵌程序。
       req = my_sequence::type_id::create("req");  \       1. 创建item对象实例;
       start_item(req);      \                   2.获取sequencer的授权许可;
       assert(req.randomzie() with {req.data == 100;}); //assert(req.ranomzie()); 3.**对item进行随机化处理**;
       finish_item(req);     \                   4.将item发送至sequencer,进而完成与driver之间的交互
  • 宏`uvm_do_with (item, { constraint })与 宏 ‘uvm_do( )无本质区别,只是多了约束条件;需要说明的是宏‘uvm_do( )不支持randc类型的随机变量。

2.2.sequence的嵌套启动

   嵌套sequence的启动可以通过start(m_sequencer)来完成,也可以通过uvm_do()系列宏来完成;

  • m_sequencer是base_sequencer启动时所使用的sequencer的指针,也就是说,嵌套的seq启动时所使用的sequencer同所在的sequence所使用的sequencer一致
class base_sequence extends uvm_sequence#(transaction);
  ...
  virtual task body();
    crc_seq    cseq=crc_seq::type_id::create("cseq");
    long_seq       lseq=long_seq:;type_id::create("lseq");
    
    repeat(10)begin
        cseq.start(m_sequencer);             //启动嵌套的seq
        lseq.start(m_sequencer);
    end

  endtask
endclass
  • 采用uvm_do宏启动嵌套的seq,更加简单;
class base_sequence extends uvm_sequence#(transaction);
  ...
  virtual task body();
    crc_seq    cseq;
    long_seq       lseq;
    
    repeat(10)begin
        `uvm_do(cseq);             //启动嵌套seq
        `uvm_do(lseq);
    end

  endtask
endclass

2.3.sequence接收响应rsp

class tr_sequence extends uvm_sequence#(transaction);
   ...
   virtual task body();
      ...
        `uvm_do(req);                                      
         get_response(rsp);                               //3.接收响应信息rsp
   endtask
endclass  

class driver extends uvm_driver#(transaction);
   ...
   virtual task run_phase(uvm_phase phase);
      forever begin
         seq_item_port.get_next_item(req);              
         send(req);      
         rsp = transaction::type_id::create("rsp");       
         rsp.set_id_info(req);                            //1. 创建并配置响应ID
         seq.item.port.item_done(rsp);                    //2. driver返回响应rsp
      end
   endtask
endclass

三、config_db配置sequence

3.1.默认执行的sequence

  默认的测试用例(test_base)执行默认的default sequence,该sequence在验证环境中配置的;

class environment extends uvm_env;       //在初始环境中配置默认的sequence
   ...
   function void build_phase(uvm_phase phase);
      ...
      uvm_config_db #(uvm_object_wrapper)::set(this,"*.seqr.main_phase","default_sequence",transaction_sequence::get_type());
      ...
   endfunciton
endclass   

  默认sequence在main_phase阶段执行,此时也可将null赋给default sequence,不产生数据

3.2.配置sequence——get_full_name() / m_sequencer

  • 通过get_full_name( )获取配置的路径名称,可以有效防止不同的sequence中有相同变量进行配置时产生的冲突
  • get_full_name()在sequence中被调用时,打印的路径为:uvm_test_top.env.agt.seqr.seq
  • 需要说明的是,当sequence在virtual sequence中被启动,调用的get_full_name()方法打印的路径结果:uvm_test_top.v_seqr.*,这是由于virtual sequence不遵循UVM树的路径层次;
class tr_sequence extends base_sequence;        //2.在底层组件捕获sequence配置
   int item_count = 10;
      ...
   virtual task pre_start();
      ...
      uvm_config_db #(int)::get(null, "this.get_full_name()", "item_count", item_count);   //本地变量item_count = 20,配置成功
     
     //uvm_config_db #(int)::get(null, this.get_full_name(), "item_count", item_count);   get_full_name() 不添加引号

    //uvm_config_db #(int)::get(m_sequencer, “”, "item_count", item_count);   m_sequencer 指定路径
   endfunciton
endclass      

class test_20_items extends test_base;        //1.在测试用例中启动sequence配置
   ...
   function void build_phase(uvm_phase phase);
      ...
      uvm_config_db #(int)::set(this,"env.agt.seqr.*","item_count",20);     //item_count = 20 ,启动配置赋值
   endfunciton
endclass      

3.3.配置sequence——get_sequncer()

  • 通过get_sequencer( )获取配置字段的sequencer,可以为sequencer下的所有sequence中的相同变量同时提供配置。
class tr_sequence extends base_sequence;        //2.在底层组件捕获sequence配置
   int item_count = 10;
      ...
   virtual task pre_start();
      ...
      uvm_config_db #(int)::get(this.get_sequencer(),"","item_count",item_count);   //本地变量item_count = 20,配置成功
   endfunciton
endclass      

class test_20_items extends test_base;        //1.在测试用例中启动sequence配置
   ...
   function void build_phase(uvm_phase phase);
      ...
      uvm_config_db #(int)::set(this,"env.agt.seqr.*","item_count",20);     //item_count = 20 ,启动配置赋值
   endfunciton
endclass      
  • 51
    点赞
  • 278
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SD.ZHAI

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

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

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

打赏作者

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

抵扣说明:

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

余额充值