UVM学习之sequence启动

,对于default_sequence启动方式不太理解,今天随笔一下

start_phase_sequence

先在tc中set一个seq,set的方式可以是如下几种,可以例化后set也可以是不例化直接set,可以是uvm_config_db,也可以是uvm_resource_db

   myseq_t myseq = new("myseq");
   myseq.randomize() with { ... };
   uvm_config_db #(uvm_sequence_base)::set(null, "top.agent.myseqr.main_phase",
                                           "default_sequence",
                                           myseq);
  
   uvm_config_db #(uvm_object_wrapper)::set(null, "top.agent.myseqr.main_phase",
                                            "default_sequence",
                                            myseq_type::type_id::get());
  
   The uvm_resource_db can similarly be used.
  
   myseq_t myseq = new("myseq");
   myseq.randomize() with { ... };
   uvm_resource_db #(uvm_sequence_base)::set({get_full_name(), ".myseqr.main_phase",
                                             "default_sequence",
                                             myseq, this);
  
   uvm_resource_db #(uvm_object_wrapper)::set({get_full_name(), ".myseqr.main_phase",
                                              "default_sequence",
                                              myseq_t::type_id::get(),
                                              this );

 type_id简单看一下,之前看的也不是很明白

类注册宏:首先myseq_t通过注册,会定义一个uvm_object_registry参数化的类,参数类型即myseq_t,该类的句柄就是type_id,get_type()是每个经过注册的类都有的一个函数。uvm_object_registry直接继承uvm_object_wrapper,其get()函数返回uvm_object_registry实例的句柄,所以set的是子类的句柄,在环境中将该子类句柄会赋值给父类句柄,得到一个指向子类对象的父类句柄wrapper。

`define uvm_object_utils(T) \
  `uvm_object_utils_begin(T) \
  `uvm_object_utils_end

`define uvm_object_utils_begin(T) \
   `m_uvm_object_registry_internal(T,T)  \
   `m_uvm_object_create_func(T) \
   `m_uvm_get_type_name_func(T) \
   `uvm_field_utils_begin(T) 

`define m_uvm_object_registry_internal(T,S) \
   typedef uvm_object_registry#(T,`"S`") type_id; \
   static function type_id get_type(); \
     return type_id::get(); \
   endfunction \
   virtual function uvm_object_wrapper get_object_type(); \
     return type_id::get(); \
   endfunction

 

 继而调用create_object_by_type,此时注意传入的wrapper是指向uvm_object_registry的wrapper句柄,接着调用wrapper的create_object,wrappe的create_object是虚函数,由于类的多态会调用子类的create_object,返回uvm_object类型句柄,但该句柄也是经过隐式转换的,本来是myseq_t类型的,uvm_object类型句柄指向的是myseq_t,接着继续进行显示类型转换,只有指向子类的父类句柄才能进行cast进行类型转换,因为uvm_sequence指向要大于uvm_sequence_base所以能够进行类型转换,关于类型转换有些忘记了,做个实验试试,可知是可以转换成功的。下图中seq_base是指向seq的句柄。

 最后同理,seq指向的是myseq_t,调用strat执行seq,正因为uvm_sequence_base的body函数也是虚函数,所以seq句柄必须是指向的子类对象,否则调用到的只会是uvm_sequence_base的body函数。

下面模拟一下seq启动场景,start的是uvm_sequence_base类型句柄,但指向的是uvm_sequence,uvm_sequence继承于uvm_virtual,uvm_virtual继承于uvm_sequence_base,

module tb;

class uvm_object0;
  virtual function base();
    $display("this is uvm_obj0");
  endfunction
endclass

class uvm_sequence_base0 extends uvm_object0;
  virtual function base();
    $display("this is uvm_sequence_base0");
  endfunction
  virtual function call();
    $display("this is call in seq_base0");
  endfunction
endclass

class uvm_virtual extends uvm_sequence_base0;
  virtual function base();
    $display("this is uvm_virtual_sequence");
  endfunction

  virtual function test();
    $display("test_virtual");
  endfunction
  
  virtual function call();
    $display("this is call in virtual seq0");
    call_by_call();
  endfunction
  
  virtual function call_by_call();
    $display("this is call_by_call in virtual seq0");
  endfunction

endclass

class uvm_sequence0 extends uvm_virtual;
  
  virtual function base();
    $display("this is uvm_sequence0");
  endfunction
  
  virtual function test();
    $display("test_virtual_sequenec");
  endfunction
  
  virtual function call();
    $display("this is call in seq0");
    super.call();
  endfunction
  
  virtual function call_by_call();
    $display("this is call_by_call in seq0");
  endfunction
endclass

uvm_object0 obj;
uvm_sequence_base0 seq_base;
uvm_sequence0 seq;

initial begin
  seq = new();
  seq_base = new();
  obj = seq;

  $display("fail? %d",$cast(seq_base,obj));
  seq_base.base();
  seq_base.call();
end

endmodule

this is uvm_sequence0
this is call in seq0
this is call in virtual seq0
this is call_by_call in seq0

 如果注释掉sequence_base的call,则会报错,因为seq_base是指向子类对象的父类句柄,没法不通过多态访问到子类成员

// start_phase_sequence
// --------------------

function void uvm_sequencer_base::start_phase_sequence(uvm_phase phase);
    uvm_object_wrapper wrapper;
    uvm_sequence_base  seq;
    uvm_factory f = uvm_factory::get();

    // default sequence instance?
    if (!uvm_config_db #(uvm_sequence_base)::get(
          this, {phase.get_name(),"_phase"}, "default_sequence", seq) || seq == null) begin
      // default sequence object wrapper?
      if (uvm_config_db #(uvm_object_wrapper)::get(
               this, {phase.get_name(),"_phase"}, "default_sequence", wrapper) && wrapper != null) begin
        // use wrapper is a sequence type        
        if(!$cast(seq , f.create_object_by_type(
              wrapper, get_full_name(), wrapper.get_type_name()))) begin
          `uvm_warning("PHASESEQ", {"Default sequence for phase '",
                       phase.get_name(),"' %s is not a sequence type"})
          return;
        end
      end
      else begin
        `uvm_info("PHASESEQ", {"No default phase sequence for phase '",
                               phase.get_name(),"'"}, UVM_FULL)
        return;
      end
    end

    `uvm_info("PHASESEQ", {"Starting default sequence '",
       seq.get_type_name(),"' for phase '", phase.get_name(),"'"}, UVM_FULL)

    seq.print_sequence_info = 1;
    seq.set_sequencer(this);
    seq.reseed();
    seq.starting_phase = phase;

    if (!seq.is_randomized && !seq.randomize()) begin
      `uvm_warning("STRDEFSEQ", {"Randomization failed for default sequence '",
       seq.get_type_name(),"' for phase '", phase.get_name(),"'"})
       return;
    end

    fork
      seq.start(this);
    join_none

endfunction

今天想看这个是因为前几天遇到的一个问题,使用default_sequence时会触发多态,今天发现即使是直接start也会触发类的多态(前提是函数都是虚函数),是因为使用type_id例化seq所返回的类型应该也是隐藏了类型转换,seq句柄并不是单纯的指向seq本身。

具体下次再看

type::id::create

  static function T create (string name="", uvm_component parent=null,
                            string contxt="");
    uvm_object obj;
    uvm_factory f = uvm_factory::get();
    if (contxt == "" && parent != null)
      contxt = parent.get_full_name();
    obj = f.create_object_by_type(get(),contxt,name);
    if (!$cast(create, obj)) begin
      string msg;
      msg = {"Factory did not return an object of type '",type_name,
        "'. A component of type '",obj == null ? "null" : obj.get_type_name(),
        "' was returned instead. Name=",name," Parent=",
        parent==null?"null":parent.get_type_name()," contxt=",contxt};
      uvm_report_fatal("FCTTYP", msg, UVM_NONE);
    end
  endfunction

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值