uvm_declare_p_sequencer获取sequencer原理

在看张强白皮书P189中对uvm_declare_p_sequencer的描述时有一个疑问,就是为什么通过sequencer的类名就能获取到sequencer,然后自己下来查了一下,理了一下关系才明白。

首先就是uvm_declare_p_sequencer这个宏,看了一下定义的地方,在uvm_sequence_defines.svh中:

`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  

书上一样,就是把m_sequencer转成了p_sequencer,这个m_set_p_sequencer函数是在uvm_sequence_item里面,最开始是空的,宏定义进行了扩展,具体细节往下。

//原始m_set_p_sequencer函数
virtual function void m_set_p_sequencer();
    return;
 endfunction  


class uvm_sequence_item extends uvm_transaction;

  local      int                m_sequence_id = -1;
  protected  bit                m_use_sequence_info;
  protected  int                m_depth = -1;
  protected  uvm_sequencer_base m_sequencer;
  protected  uvm_sequence_base  m_parent_sequence;
  static     bit issued1,issued2;
  bit        print_sequence_info;

m_sequencer是在uvm_sequence_item里定义的,类型是uvm_sequencer_base,和书上一样。

  virtual function void set_sequencer(uvm_sequencer_base sequencer);
    m_sequencer = sequencer;
    m_set_p_sequencer();
  endfunction

m_sequencer是在uvm_sequence_item的set_sequencer里赋值的,然后我们继续找这个函数。

  function void set_item_context(uvm_sequence_base  parent_seq,
                                 uvm_sequencer_base sequencer = null);
     set_use_sequence_info(1);
     if (parent_seq != null) set_parent_sequence(parent_seq);
     if (sequencer == null && m_parent_sequence != null) sequencer = m_parent_sequence.get_sequencer();
     set_sequencer(sequencer); 
     if (m_parent_sequence != null) set_depth(m_parent_sequence.get_depth() + 1); 
     reseed();      
  endfunction

set_sequencer是在uvm_sequence_item的set_item_context里调用,可以看见前面两个函数的参数都有一个sequencer,我们继续找这个是从哪来的。

virtual task start (uvm_sequencer_base sequencer,
                      uvm_sequence_base parent_sequence = null,
                      int this_priority = -1,
                      bit call_pre_post = 1);

    set_item_context(parent_sequence, sequencer);

    if (!(m_sequence_state inside {CREATED,STOPPED,FINISHED})) begin
      uvm_report_fatal("SEQ_NOT_DONE", 
         {"Sequence ", get_full_name(), " already started"},UVM_NONE);
    end
.....

可以看到,在uvm_sequence_base里面,start启动了这个函数,并且传了一个sequencer进去,这个sequencer是在sequence启动的时候指定的那个sequencer,这下就明白了,实际上被cast的m_sequencer传入的参数就是我们启动时候指定的sequencer。

总结一下,sequence不管是显式还是隐式启动,都会调用start函数指定需要在哪个sequencer上启动,指定的是实例化后的sequencer的对象,然后将sequencer传给set_item_context,set_item_context再传给set_sequencer,最后赋给m_sequencer,然后通过cast将m_sequencer转换到p_sequencer。

你可能感兴趣的:(UVM)