uvm_objection机制

本文详细介绍了UVM1.1之后仿真结束的机制,主要依赖objection挂起,包括在scoreboard和sequence中控制objection的策略。特别强调了UVM提倡的由sequence控制激励生成的设计哲学。同时,文章展示了如何在不同的UVM版本中管理objection以及sequence在验证平台中的作用。

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

uvm1.1之后,结束仿真的机制有且只有一种,那就是利用objection挂起机制来控制仿真结束

在进入某一phase时,UVM会收集此phase提出的所有objection,并且实时监测所有的objection是否已经被撤销,当发现所有objection都已经撤销后,关闭此phase,进入下一phase,当所有phase执行完毕后,就会调用$finish关掉整个验证平台

一般来说,在一个实际的验证平台中,通常会在以下两种objection的控制策略中选择一种:

第一种是在scoreboard中进行控制。scoreboard的main_phase一般会被做成一个无限循环,如果要在scoreboard中控制objection,则需要去除这个无限循环,通过config_db::set的方式设置收集到的transaction的数量pkt_num(可以在sequence层级设置,sequence层级设置时,scb中get要有一定延迟;或者是在test层级直接set),当收集到指定数量pkt_num的transaction后跳出循环。

第二种则是在sequence中raise sequencer的objection,当sequence完成后,再drop此objection ,以上两种方式在验证平台中都有应用。

其中用得最多的是第二种,这种方式是UVM提倡的方式。UVM的设计哲学就是全部由sequence来控制激励的生成,因此一般情况下只在sequence中控制objection。

如果用的是UVM-1.2,则可以在new函数中打开自动控制objection的开关,UVM将会自动控制objection的raise和drop;

如果用的是UVM-1.1,则分别在pre_start和post_start任务中去raise/drop objection,当然在pre body和post body 或者 body中都是可以的

class base_sequence extends uvm_sequence; // other code not shown
  function new(string name = "base_sequence");
    super.new(name);
    `ifdef UVM_VERSION_1_2
      set_automatic_phase_objection(1); // UVM-1.2 & IEEE UVM Only!
    `endif
  endfunction : new
  
  virtual task pre_start();
    `ifdef UVM_VERSION_1_1
      if (get_parent_sequence() == null && starting_phase != null)
          starting_phase.raise_objection(this); // UVM-1.1 ONLY!
    `endif
  endtask : pre_start
  
  virtual task post_start();
    `ifdef UVM_VERSION_1_1
      if (get_parent_sequence() == null && starting_phase != null)
        starting_phase.drop_objection(this); // UVM-1.1 ONLY!
    `endif
  endtask : post_start
  
  virtual task body();

  endtask : body
endclass : base_sequence

自己编写执行的sequence只需要从这个基类中继承过来,在body的task中写测试激励就可以了

class test_sequence extends base_sequence;
  function new(string name = "test_sequence");
    super.new(name);
  endfunction : new

  virtual task body();
    //TODO: 
  endtask : body
endclass : test_sequence

为什么可以在类型为object的seq中控制整个验证平台component的phase运行?

因为在seq中raise和drop objection本质是在sqr中main_phase中raise和drop,sqr为componet类型,自然也就可以控制整个环境生命周期

验证平台一般会在test层通过config_db的方式指定要执行的default_seq,在启动seq的时候,会执行start函数,uvm_sequence_base中的虚函数start()调用了pre_start()→pre_body()→body()→post_body()→post_start() 函数

根据上文得知,在pre_start中会raise_objection,post_start中drop_objection,因此sqr的main_phase的生命周期相当于seq的生命周期,从而控制整个验证平台component的phase执行

class my_test extends base_test;
  function new(string name = "my_test");
    super.new(name);
  endfunction : new
  virtual function void build_phase(uvm_phase phase);
	  super.build_phase(phase);
      uvm_config_db#(uvm_object_wrapper)::set(this,
                     "vsqr.main_phase","default_sequence",
                     my_seq::type_id::get());
  endfunction
endclass : my_test 

 UVM源码:

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

    if (!(m_sequence_state inside {UVM_CREATED,UVM_STOPPED,UVM_FINISHED})) begin
      uvm_report_fatal("SEQ_NOT_DONE", 
         {"Sequence ", get_full_name(), " already started"},UVM_NONE);
    end

    if (m_parent_sequence != null) begin
       m_parent_sequence.children_array[this] = 1;
    end

    if (this_priority < -1) begin
      uvm_report_fatal("SEQPRI", $sformatf("Sequence %s start has illegal priority: %0d",
                                           get_full_name(),
                                           this_priority), UVM_NONE);
    end
    if (this_priority < 0) begin
       if (parent_sequence == null) this_priority = 100;
       else this_priority = parent_sequence.get_priority();
    end

    // Check that the response queue is empty from earlier runs
    clear_response_queue();

    m_priority           = this_priority;

    if (m_sequencer != null) begin
       integer handle;
       uvm_tr_stream stream;
       if (m_parent_sequence == null) begin
          stream = m_sequencer.get_tr_stream(get_name(), "Transactions");
          handle = m_sequencer.begin_tr(this, get_name());
          m_tr_recorder = uvm_recorder::get_recorder_from_handle(handle);
       end else begin
          stream = m_sequencer.get_tr_stream(get_root_sequence_name(), "Transactions");
          handle = m_sequencer.begin_child_tr(this, 
                                              (m_parent_sequence.m_tr_recorder == null) ? 0 : m_parent_sequence.m_tr_recorder.get_handle(), 
                                              get_root_sequence_name());
          m_tr_recorder = uvm_recorder::get_recorder_from_handle(handle);
       end
    end

    // Ensure that the sequence_id is intialized in case this sequence has been stopped previously
    set_sequence_id(-1);
    // Remove all sqr_seq_ids
    m_sqr_seq_ids.delete();

    // Register the sequence with the sequencer if defined.
    if (m_sequencer != null) begin
      void'(m_sequencer.m_register_sequence(this));
    end

    // Change the state to PRE_START, do this before the fork so that
    // the "if (!(m_sequence_state inside {...}" works
    m_sequence_state = UVM_PRE_START;
    fork
      begin
        m_sequence_process = process::self();

        // absorb delta to ensure PRE_START was seen
        #0;

        // Raise the objection if enabled
        // (This will lock the uvm_get_to_lock_dap)
        if (get_automatic_phase_objection()) begin
           m_safe_raise_starting_phase("automatic phase objection");
        end
         
        pre_start();

        if (call_pre_post == 1) begin
          m_sequence_state = UVM_PRE_BODY;
          #0;
          pre_body();
        end

        if (parent_sequence != null) begin
          parent_sequence.pre_do(0);    // task
          parent_sequence.mid_do(this); // function
        end

        m_sequence_state = UVM_BODY;
        #0;
        body();

        m_sequence_state = UVM_ENDED;
        #0;

        if (parent_sequence != null) begin
          parent_sequence.post_do(this);
        end

        if (call_pre_post == 1) begin
          m_sequence_state = UVM_POST_BODY;
          #0;
          post_body();
        end

        m_sequence_state = UVM_POST_START;
        #0;
        post_start();

其他

  • 关于本文,您有什么想法均可在评论区留言交流。
  • 自身能力不足,如有错误还请多多指出!

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

uvm_1.2

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

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

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

打赏作者

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

抵扣说明:

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

余额充值