跳转至

输入查询内容

    本页内容

    sequence.kill() 清理仲裁请求、锁与路由,保留已排队响应

    影响范围

    运行中 kill sequence,特别是跨 sequencer 路由,或需要清理已排队响应。

    具体差异

    1.2 的 kill 会清理默认 sequencer,非默认 sequencer 上的仲裁请求或锁可能残留;2.0 增加遍历所有已路由 sequencer 的清理,删除关联仲裁请求、锁和路由注册。注销路由使晚到响应无法再经该路由送达,但不会清空 sequence 已有的 response_queue,也不能据此认定 driver 在途事务已取消。目标 sequence/sequencer 文件与 Accellera 2.0 相同。两版重新 start 都会清空 response_queue,因此重启后为空不能证明 kill 时已清空。

    修改方案

    保留 sequence.kill();确认跨 sequencer 仲裁请求和锁已清理后,才移除针对这些残留的旧补偿。若业务要求即时丢弃已排队响应,继续显式调用 clear_response_queue;需要检查或消费响应的流程先完成对应处理。driver/scoreboard 在途事务仍按业务协议收尾,再验证后续请求与响应链路。

    对需要丢弃已排队响应的退出流程,两版均保留以下操作;迁移时不能简化成仅调用 kill:

    seq.kill();
    seq.clear_response_queue();
    

    doc_fact_probe 在活动 sequence 中预先放入一个响应。两版 kill 后均为 UVM_STOPPED,响应数仍为 1;显式 clear_response_queue 后均为 0,观察发生在再次 start 之前。该实验只核对已排队响应,跨 sequencer 锁修复另见 lifecycle 实验,不覆盖全部并发和晚到响应协议。

    兼容措施与范围:现有入口无需兼容开关;这不表示两版行为相同,仍按本条条件和验证方法核对。

    迁移后验证

    分别在持锁、有仲裁请求和有 response 时 kill;重新 start 之前检查响应队列,再验证其他 sequence 可继续服务。需要清空响应时,显式 clear_response_queue 后检查队列为空。

    记录本条结果M06-013 · 状态与证据

    已有实测与复现

    补充查阅

    扫描定位与记录结果

    有扫描规则,覆盖部分可识别写法。脚本检查名称、参数和部分 FLAG 表达式,并对少数直接声明关联使用点;未做完整类型解析或预处理,行为结果仍需验证。

    • S34 · 启发式:sequence lock/kill 与等待请求流程。 排除已识别的 process/component 接收者;未知类型仍保留启发式提示。扫描不能证明并发竞争与 kill 时序。
    uv run tools/uvm_migration_scan.py <SoC代码目录> --rules S34
    

    核对命中对象及生效分支后,在条目清单记录修改与验证证据;扫描规则记录用于整理命中位置。

    扫描器下载、输入范围与报告说明

    源码与标准依据

    核查方式:源码与实测核对。实测仅覆盖本条所列场景。

    VCS 内置 UVM-1.2uvm_sequence_base.svh:880(kill 经默认 sequencer 清理)、uvm_sequence_base.svh:914(m_kill 不遍历其他 sequencer)、uvm_sequence_base.svh:286(start 清响应队列)、uvm_sequence_base.svh:1184(显式 clear_response_queue)

    VCS 内置 uvm-ieee-2020-2.0uvm_sequence_base.svh:884(m_kill 内 uvm_sequence_base.svh:896 调用 clean_exit_sequence)、uvm_sequence_base.svh:420(遍历所有路由过的 sequencer)、uvm_sequence_base.svh:310(start 清响应队列)、uvm_sequence_base.svh:1176(显式 clear_response_queue);uvm_sequencer_base.svh:1159(移除仲裁请求)、uvm_sequencer_base.svh:1185(移除锁)、uvm_sequencer_base.svh:1204(注销响应路由)

    引用代码(高亮为引用行);上方行号链接可直接定位。

    src/vcs-uvm-1.2/seq/uvm_sequence_base.svh
        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());
    

    src/vcs-uvm-1.2/seq/uvm_sequence_base.svh
      // with the other sequencer(s) using the sequencer unregister_sequence() 
      // method.
    
      function void kill();
        if (m_sequence_process != null) begin
          // If we are not connected to a sequencer, then issue
          // kill locally.
          if (m_sequencer == null) begin
            m_kill();
            // We need to drop the objection if we raised it...
            if (get_automatic_phase_objection()) begin
               m_safe_drop_starting_phase("automatic phase objection");
            end
            return;
          end
          // If we are attached to a sequencer, then the sequencer
          // will clear out queues, and then kill this sequence
          m_sequencer.kill_sequence(this);
          // We need to drop the objection if we raised it...
    

    src/vcs-uvm-1.2/seq/uvm_sequence_base.svh
        return;
      endfunction
    
      function void m_kill();
        do_kill();
        foreach(children_array[i]) begin
           i.kill();
        end
        if (m_sequence_process != null) begin
          m_sequence_process.kill;
          m_sequence_process = null;
        end
        m_sequence_state = UVM_STOPPED;
        if ((m_parent_sequence != null) && (m_parent_sequence.children_array.exists(this)))
          m_parent_sequence.children_array.delete(this);
      endfunction
    
    
      //-------------------------------
    

    src/vcs-uvm-1.2/seq/uvm_sequence_base.svh
      //
      // Empties the response queue for this sequence.
    
      virtual function void clear_response_queue();
        response_queue.delete();
      endfunction
    
    
      virtual function void put_base_response(input uvm_sequence_item response);
        if ((response_queue_depth == -1) ||
            (response_queue.size() < response_queue_depth)) begin
          response_queue.push_back(response);
          return;
        end
        if (response_queue_error_report_disabled == 0) begin
          uvm_report_error(get_full_name(), "Response queue overflow, response was dropped", UVM_NONE);
        end
      endfunction
    

    完整源码 · SHA256:1594d38afd79cb400a689fdbe6c8e33ff60714bb7527cd8d79739d9357b31682

    src/vcs-uvm-ieee-2020-2.0/seq/uvm_sequence_base.svh
        end
    
        // Check that the response queue is empty from earlier runs
        clear_response_queue();
    
        m_priority           = this_priority;
    
        if (m_sequencer != null) begin
           int handle;
           if (m_parent_sequence == null) begin
              handle = m_sequencer.begin_tr(this, get_name());
              m_tr_recorder = uvm_recorder::get_recorder_from_handle(handle);
           end else begin
              handle = m_sequencer.begin_tr(.tr(this), .stream_name(get_root_sequence_name()),
                                            .parent_handle((m_parent_sequence.m_tr_recorder == null) ? 0 : m_parent_sequence.m_tr_recorder.get_handle()));                                          
              m_tr_recorder = uvm_recorder::get_recorder_from_handle(handle);
           end
        end
    

    src/vcs-uvm-ieee-2020-2.0/seq/uvm_sequence_base.svh
      // This function is for Clean up any sequencer queues after exiting; if we
      // were forcibly stopped, this step has already taken place
    
       function void clean_exit_sequence();
         if (m_sequencer != null) begin
           m_sequencer.m_sequence_exiting(this);     
         end
         // remove any routing for this sequence even when virtual sequencers (or a null sequencer is involved)
         // once we pass this point nothing can be routed to this sequence(id)
         foreach(m_sqr_seq_ids[seqrID]) begin
           uvm_sequencer_base s = uvm_sequencer_base::all_sequencer_insts[seqrID];
           s.m_sequence_exiting(this);
         end    
         m_sqr_seq_ids.delete();
        // Release the state mutex to allow for re-use (not recommended)
        m_sequence_state_mutex.put(1);
     endfunction
    

    src/vcs-uvm-ieee-2020-2.0/seq/uvm_sequence_base.svh
        return;
      endfunction
    
      function void m_kill();
        do_kill();
        foreach(children_array[i]) begin
           i.kill();
        end
        if (m_sequence_process != null) begin
          m_sequence_process.kill;
          m_sequence_process = null;
        end
        m_sequence_state = UVM_STOPPED;
        if ((m_parent_sequence != null) && (m_parent_sequence.children_array.exists(this)))
          m_parent_sequence.children_array.delete(this);
        clean_exit_sequence();
      endfunction
    
    
      //-------------------------------
      // Group -- NODOCS -- Sequence Item Execution
      //-------------------------------
    
      // Function -- NODOCS -- create_item
      //
      // Create_item will create and initialize a sequence_item or sequence
      // using the factory.  The sequence_item or sequence will be initialized
      // to communicate with the specified sequencer.
    
      // @uvm-ieee 1800.2-2020 auto 14.2.6.1
      protected function uvm_sequence_item create_item(uvm_object_wrapper type_var,
    

    src/vcs-uvm-ieee-2020-2.0/seq/uvm_sequence_base.svh
      // Empties the response queue for this sequence.
    
      // @uvm-ieee 1800.2-2020 auto 14.2.7.8
      virtual function void clear_response_queue();
        response_queue.delete();
      endfunction
    
    
      virtual function void put_base_response(input uvm_sequence_item response);
        if ((response_queue_depth == -1) ||
            (response_queue.size() < response_queue_depth)) begin
          response_queue.push_back(response);
          return;
        end
        if (response_queue_error_report_enabled) begin
          uvm_report_error(get_full_name(), "Response queue overflow, response was dropped", UVM_NONE);
        end
      endfunction
    

    完整源码 · SHA256:aedbad6d9991d5712dd8e5e676a9fb5487ab33af52219ae4786e6adaa7001375

    src/vcs-uvm-ieee-2020-2.0/seq/uvm_sequencer_base.svh
    // remove_sequence_from_queues
    // ---------------------------
    
    function void uvm_sequencer_base::remove_sequence_from_queues(
                                           uvm_sequence_base sequence_ptr);
      int i;
      int seq_id;
    
      seq_id = sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 0);
    
      // Remove all queued items for this sequence and any child sequences
      i = 0;
      do
        begin
          if (arb_sequence_q.size() > i) begin
            if ((arb_sequence_q[i].sequence_id == seq_id) ||
                (is_child(sequence_ptr, arb_sequence_q[i].sequence_ptr))) begin
              if (sequence_ptr.get_sequence_state() == UVM_FINISHED)
                `uvm_error("SEQFINERR", $sformatf("Parent sequence '%s' should not finish before all items from itself and items from descendent sequences are processed.  The item request from the sequence '%s' is being removed.", sequence_ptr.get_full_name(), arb_sequence_q[i].sequence_ptr.get_full_name()))
    

    src/vcs-uvm-ieee-2020-2.0/seq/uvm_sequencer_base.svh
        end
      while (i < arb_sequence_q.size());
    
      // remove locks for this sequence, and any child sequences
      i = 0;
      do
        begin
          if (lock_list.size() > i) begin
            if ((lock_list[i].get_inst_id() == sequence_ptr.get_inst_id()) ||
                (is_child(sequence_ptr, lock_list[i]))) begin
              if (sequence_ptr.get_sequence_state() == UVM_FINISHED)
                `uvm_error("SEQFINERR", $sformatf("Parent sequence '%s' should not finish before locks from itself and descedent sequences are removed.  The lock held by the child sequence '%s' is being removed.",sequence_ptr.get_full_name(), lock_list[i].get_full_name()))
              lock_list.delete(i);
              m_update_lists();
            end
            else begin
              i++;
            end
          end
        end
      while (i < lock_list.size());
    
      // Unregister the sequence_id, so that any returning data is dropped
      m_unregister_sequence(sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1));
    endfunction
    
    
    // stop_sequences
    // --------------
    
    function void uvm_sequencer_base::stop_sequences();
      uvm_sequence_base seq_ptr;
    
      seq_ptr = m_find_sequence(-1);
      while (seq_ptr != null)
        begin
          kill_sequence(seq_ptr);
          seq_ptr = m_find_sequence(-1);
    

    完整源码 · SHA256:6d2477484529dad661a38b31619edf9898bfa3375f217f06a27b3a69af32ccf7

    术语解释 · 兼容配置

    返回Sequence / Sequencer · 迁移清单

    版本适用范围