[UVM] uvm_do系列macro分析

uvm_do_on_pri_with 

`define uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS) \
  begin \
  uvm_sequence_base __seq; \
  `uvm_create_on(SEQ_OR_ITEM, SEQR) \
  if (!$cast(__seq,SEQ_OR_ITEM)) start_item(SEQ_OR_ITEM, PRIORITY);\
  if ((__seq == null || !__seq.do_not_randomize) && !SEQ_OR_ITEM.randomize() with CONSTRAINTS ) begin \
    `uvm_warning("RNDFLD", "Randomization failed in uvm_do_with action") \
  end\
  if (!$cast(__seq,SEQ_OR_ITEM)) finish_item(SEQ_OR_ITEM, PRIORITY); \
  else __seq.start(SEQR, this, PRIORITY, 0); \
  end

uvm_create_on

`define uvm_create_on(SEQ_OR_ITEM, SEQR) \
  begin \
  uvm_object_wrapper w_; \
  w_ = SEQ_OR_ITEM.get_type(); \
  $cast(SEQ_OR_ITEM , create_item(w_, SEQR, `"SEQ_OR_ITEM`"));\
  end

uvm_send_pri

`define uvm_send_pri(SEQ_OR_ITEM, PRIORITY) \
  begin \
  uvm_sequence_base __seq; \
  if (!$cast(__seq,SEQ_OR_ITEM)) begin \
     start_item(SEQ_OR_ITEM, PRIORITY);\
     finish_item(SEQ_OR_ITEM, PRIORITY);\
  end \
  else __seq.start(__seq.get_sequencer(), this, PRIORITY, 0);\
  end

uvm_rand_send_pri_with

`define uvm_rand_send_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS) \
  begin \
  uvm_sequence_base __seq; \
  if (!$cast(__seq,SEQ_OR_ITEM)) start_item(SEQ_OR_ITEM, PRIORITY);\
  else __seq.set_item_context(this); \
  if ((__seq == null || !__seq.do_not_randomize) && !SEQ_OR_ITEM.randomize() with CONSTRAINTS ) begin \
    `uvm_warning("RNDFLD", "Randomization failed in uvm_rand_send_with action") \
  end\
  if (!$cast(__seq,SEQ_OR_ITEM)) finish_item(SEQ_OR_ITEM, PRIORITY);\
  else __seq.start(__seq.get_sequencer(), this, PRIORITY, 0);\
  end

//|   sequencer.wait_for_grant(prior) (task) \ start_item  \
//|   parent_seq.pre_do(1)            (task) /              \
//|                                                      `uvm_do* macros
//|   parent_seq.mid_do(item)         (func) \              /
//|   sequencer.send_request(item)    (func)  \finish_item /
//|   sequencer.wait_for_item_done()  (task)  /
//|   parent_seq.post_do(item)        (func) /

上面的表述中其實沒有包含randomize,uvm_do macro中主要涉及三個task: create_item,start_item,finish_item.

這三個task均來自于uvm_sequence_base

class uvm_sequence_base extends uvm_sequence_item;

 

create_item  就是利用factory create item 或sequence

  protected function uvm_sequence_item create_item(uvm_object_wrapper type_var, 
                                                   uvm_sequencer_base l_sequencer, 
                                                   string name);

    uvm_factory f_ = uvm_factory::get();
    $cast(create_item,  f_.create_object_by_type( type_var, this.get_full_name(), name ));
    create_item.set_item_context(this, l_sequencer);
  endfunction

start_item

virtual task start_item (uvm_sequence_item item,
                           int set_priority = -1,
                           uvm_sequencer_base sequencer=null);
    uvm_sequence_base seq;
     
    if(item == null) begin
      uvm_report_fatal("NULLITM",
         {"attempting to start a null item from sequence '",
          get_full_name(), "'"}, UVM_NONE);
      return;
    end
          
    if($cast(seq, item)) begin //此task只適用于item,不適用于sequence
      uvm_report_fatal("SEQNOTITM",
         {"attempting to start a sequence using start_item() from sequence '",
          get_full_name(), "'. Use seq.start() instead."}, UVM_NONE);
      return;
    end
          
    if (sequencer == null)
        sequencer = item.get_sequencer();//返回item的m_sequencer
        
    if(sequencer == null)
        sequencer = get_sequencer();//返回當前sequence的m_sequencer   
        
    if(sequencer == null) begin
        uvm_report_fatal("SEQ",{"neither the item's sequencer nor dedicated sequencer has been supplied to start item in ",get_full_name()},UVM_NONE);
       return;
    end
      
    if (sequencer == null)
      sequencer = item.get_sequencer();
    
    if (sequencer == null) begin
        uvm_report_fatal("STRITM", "sequence_item has null sequencer", UVM_NONE);
    end

    item.set_item_context(this, sequencer);

    if (set_priority < 0)
      set_priority = get_priority();
    
    sequencer.wait_for_grant(this, set_priority);//向sequencer發起請求,等待ack

    `ifndef UVM_DISABLE_AUTO_ITEM_RECORDING
      void'(sequencer.begin_child_tr(item, m_tr_handle, item.get_root_sequence_name()));
    `endif

    pre_do(1);

  endtask  

finish_item

  virtual task finish_item (uvm_sequence_item item,
                            int set_priority = -1);

    uvm_sequencer_base sequencer;
    
    sequencer = item.get_sequencer();

    if (sequencer == null) begin
        uvm_report_fatal("STRITM", "sequence_item has null sequencer", UVM_NONE);
    end

    mid_do(item);
    sequencer.send_request(this, item);
    sequencer.wait_for_item_done(this, -1);
    `ifndef UVM_DISABLE_AUTO_ITEM_RECORDING
    sequencer.end_tr(item);
    `endif
    post_do(item);

  endtask

start_item 重要的task是wait_for_grant,它做些什麼事情呢?

task uvm_sequencer_base::wait_for_grant(uvm_sequence_base sequence_ptr,
                                        int item_priority = -1,
                                        bit lock_request = 0);
  uvm_sequence_request req_s;
  int my_seq_id;

  if (sequence_ptr == null)
    uvm_report_fatal("uvm_sequencer",
       "wait_for_grant passed null sequence_ptr", UVM_NONE);

  my_seq_id = m_register_sequence(sequence_ptr);//设置当前sequence的sequence_id,下面会讲这个function
  
  // If lock_request is asserted, then issue a lock.  Don't wait for the response, since
  // there is a request immediately following the lock request
  if (lock_request == 1) begin
    req_s = new();
    req_s.grant = 0;
    req_s.sequence_id = my_seq_id;
    req_s.request = SEQ_TYPE_LOCK;
    req_s.sequence_ptr = sequence_ptr;
    req_s.request_id = g_request_id++;
    arb_sequence_q.push_back(req_s);
  end
      
  // Push the request onto the queue
  req_s = new();
  req_s.grant = 0;
  req_s.request = SEQ_TYPE_REQ;
  req_s.sequence_id = my_seq_id;
  req_s.item_priority = item_priority;
  req_s.sequence_ptr = sequence_ptr;
  req_s.request_id = g_request_id++;
  arb_sequence_q.push_back(req_s);
  m_update_lists();

  // Wait until this entry is granted
  // Continue to point to the element, since location in queue will change
  m_wait_for_arbitration_completed(req_s.request_id);

  // The wait_for_grant_semaphore is used only to check that send_request
  // is only called after wait_for_grant.  This is not a complete check, since
  // requests might be done in parallel, but it will catch basic errors
  req_s.sequence_ptr.m_wait_for_grant_semaphore++;

endtask

这个task主要做了两件事情:

1. 为当前sequence 分配一个sequence_id.为当前sequencer分配一个sequencer_id;

2. 把request 放入arb_sequence_q参与仲裁;


那怎么分配id呢?

function int uvm_sequencer_base::m_register_sequence(uvm_sequence_base sequence_ptr);

  if (sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1) > 0)
    return sequence_ptr.get_sequence_id();
  
  sequence_ptr.m_set_sqr_sequence_id(m_sequencer_id, g_sequence_id++);
  reg_sequences[sequence_ptr.get_sequence_id()] = sequence_ptr;
  return sequence_ptr.get_sequence_id();
endfunction

  每new一个sequencer ,其sequencer_id 就会从1开始自增(m_sequencer_id)

  每do一个sequence通过start_item sequence_id就会从1开始自增(g_sequence_id)

  function int m_get_sqr_sequence_id(int sequencer_id, bit update_sequence_id);
    if (m_sqr_seq_ids.exists(sequencer_id)) begin
      if (update_sequence_id == 1) begin
        set_sequence_id(m_sqr_seq_ids[sequencer_id]);
      end
      return m_sqr_seq_ids[sequencer_id];
    end

    if (update_sequence_id == 1)
      set_sequence_id(-1);

    return -1;
  endfunction
  

  // m_set_sqr_sequence_id
  // ---------------------

  function void m_set_sqr_sequence_id(int sequencer_id, int sequence_id);
    m_sqr_seq_ids[sequencer_id] = sequence_id;
    set_sequence_id(sequence_id);
  endfunction

     所有sequence共同维护两个哈希 :

           m_sqr_seq_ids[sequencer_id] = sequence_id;

           reg_sequences[sequence_id] = sequence_ptr;

   其作用:

        1. 便于知道一个sequencer上do sequence的数目;

        2. driver回response时知道回给哪个sequence;


  一笔transaction所包含的信息包括:

  •  transaction_id(在send_request 中设定)
  •  sequence_id(在m_register_sequence中设定)
  •  sequencer info

 这些信息在start_item和finish_item已完成设定

finish_item中重要的两个task:send_request, wait_for_item_done()。

function void uvm_sequencer_param_base :: send_request(uvm_sequence_base sequence_ptr,
                                                     uvm_sequence_item t,
                                                     bit rerandomize = 0);
  REQ param_t;


  if (sequence_ptr == null) begin
    uvm_report_fatal("SNDREQ", "Send request sequence_ptr is null", UVM_NONE);
  end


  if (sequence_ptr.m_wait_for_grant_semaphore < 1) begin
    uvm_report_fatal("SNDREQ", "Send request called without wait_for_grant", UVM_NONE);
  end
  sequence_ptr.m_wait_for_grant_semaphore--;
  
  if ($cast(param_t, t)) begin
    if (rerandomize == 1) begin
      if (!param_t.randomize()) begin
        uvm_report_warning("SQRSNDREQ", "Failed to rerandomize sequence item in send_request");
      end
    end
    if (param_t.get_transaction_id() == -1) begin
      param_t.set_transaction_id(sequence_ptr.m_next_transaction_id++);//每do一个item,transaction_id即自增1
    end
    m_last_req_push_front(param_t);
  end else begin
    uvm_report_fatal(get_name(),$sformatf("send_request failed to cast sequence item"), UVM_NONE);
  end

  param_t.set_sequence_id(sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1));//设定sequence_id
  t.set_sequencer(this);//设置sequencer
  if (m_req_fifo.try_put(param_t) != 1) begin
    uvm_report_fatal(get_full_name(), 
                     $sformatf("Sequencer send_request not able to put to fifo, depth; %0d", m_req_fifo.size()), UVM_NONE);
  end


  m_num_reqs_sent++;
  // Grant any locks as soon as possible
  grant_queued_locks();

endfunction
--------------------- 

task uvm_sequencer_base::wait_for_item_done(uvm_sequence_base sequence_ptr,
                                            int transaction_id);
  int sequence_id;

  sequence_id = sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1);
  m_wait_for_item_sequence_id = -1;
  m_wait_for_item_transaction_id = -1;

  if (transaction_id == -1)//default 走这个分支
    wait (m_wait_for_item_sequence_id == sequence_id);//等到对应sequence_id的item完成
  else
    wait ((m_wait_for_item_sequence_id == sequence_id &&
           m_wait_for_item_transaction_id == transaction_id));
endtask

function void uvm_sequencer::item_done(RSP item = null); //在driver中调用此函数
  REQ t;

  // Set flag to allow next get_next_item or peek to get a new sequence_item
  sequence_item_requested = 0;
  get_next_item_called = 0;
  
  if (m_req_fifo.try_get(t) == 0) begin
    uvm_report_fatal(get_full_name(), {"Item_done() called with no outstanding requests.",
      " Each call to item_done() must be paired with a previous call to get_next_item()."});
  end else begin
    m_wait_for_item_sequence_id = t.get_sequence_id();//返回当前item的sequence_id和transaction_id
    m_wait_for_item_transaction_id = t.get_transaction_id();
  end
  
  if (item != null) begin
    seq_item_export.put_response(item);
  end

  // Grant any locks as soon as possible
  grant_queued_locks();
endfunction

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值