SystemVerilog:如何處理UVM中的reset(第1部分)

即使聽起來很簡單,但在實際實現中,在UVM agent中處理reset也不是那麼簡單。
在本文中,我將介紹一種處理reset的通用機制,該機制可以在任何UVM agent中重複使用。

讓我們考慮一下,我們有一個具有以下架構的UVM agent:

A Typical UVM Agent Architecture
步驟#1:處理agent組件中的reset


因爲agent是最重要的組件,所以我們可以在其中實現一些邏輯,該邏輯可以檢測到reset何時變爲活動狀態,然後通知其所有子組件,它們應該reset其邏輯(包括driver,monitor,sequencer等)。

class cfs_agent extends uvm_agent;
   ...
   virtual task run_phase(uvm_phase phase);
      forever begin
         wait_reset_start();
         if(agent_config.get_should_handle_reset() == 1) begin
            handle_reset(phase, "HARD");
         end
         wait_reset_end();
      end
   endtask
   ...
endclass


通知所有子組件,它們應該重新reset相應邏輯,其實很簡單:

class cfs_agent extends uvm_agent;
   ...
   virtual function void handle_reset(uvm_phase phase, string kind = "HARD");
      monitor.handle_reset(kind);

      if(driver != null) begin
         driver.handle_reset(kind);
      end

      if(sequencer != null) begin
         sequencer.handle_reset(phase, kind);
      end

      if(coverage != null) begin
         coverage.handle_reset(kind);
      end

      //add here any other component which might need to be reset
   endfunction
   ...
endclass


在agent配置類中,我們聲明用於控制reset處理的開關:

class cfs_agent_config extends uvm_component;
   ...
   protected bit should_handle_reset;

   function new(string name = "");
      super.new(name);
      should_handle_reset = 1;
   endfunction

   virtual function bit get_should_handle_reset();
      return should_handle_reset();
   endfunction

   virtual function void set_should_handle_reset(bit should_handle_reset);
      this.should_handle_reset = should_handle_reset;
   endfunction
endclass

關於此切換背後的原因,請看一下本文的第2部分。

如果您想找到我們如何更好地抽象該agent邏輯,請閱讀SystemVerilog中的“多重繼承”。

步驟#2:處理monitor組件中的復位


從最基本的角度來看,monitor程序邏輯是一個連續的循環,它監視某些物理總線並收集所有傳輸。
基於此,我們可以說復位邏輯應停止該循環(無論復位來時其狀態如何),清除所有臨時信息並在復位完成後重新啓動監視循環。
當然,無論agnet處理的物理協議如何,都必須這樣做。

class cfs_monitor extends uvm_monitor;
   ...
   //process for collect_transactions() task
   protected process process_collect_transactions;

   //task for collecting all transactions
   virtual task collect_transactions();
      fork
         begin
            process_collect_transactions = process::self();

            forever begin
               collect_transaction();
            end
         end
      join
   endtask

   virtual task run_phase(uvm_phase phase);
      forever begin
         fork
            begin
               wait_reset_end();
               collect_transactions();
               disable fork;
            end
         join
      end
    endtask

    //function for handling reset
    virtual function void handle_reset(string kind = "HARD");
       if(process_collect_transactions != null) begin
          process_collect_transactions.kill();
       end
       //clear here any temporary information from the monitor
    endfunction
   ...
endclass

步驟#3:處理driver組件中的復位


我們在monitor中實現的相同邏輯可以適用於driver組件。最後,driver組件的邏輯只是一個循環,等待sequencer的sequence並將它們放在物理總線上。

class cfs_driver extends uvm_driver;
   ...
   //process for drive_transactions() task
   protected process process_drive_transactions;

   //task for driving all transactions
   virtual task drive_transactions();
      fork
         begin
            process_drive_transactions = process::self();

            forever begin
               cfs_item_drv_master transaction;
               seq_item_port.get_next_item(transaction);
               drive_transaction(transaction);
               seq_item_port.item_done();
            end
         end
      join
   endtask

   task run_phase(uvm_phase phase);
      forever begin
         fork
            begin
               wait_reset_end();
               drive_transactions();
               disable fork;
           end
         join
      end
   endtask

   //function for handling reset
   virtual function void handle_reset(string kind = "HARD");
      if(process_drive_transactions != null) begin
         process_drive_transactions.kill();
      end
      //clear here any temporary information, initialize some interface signals etc
   endfunction
   ...
endclass

步驟4:在sequencer組件中處理重置


復位sequencer非常簡單。我們只需要確保丟棄所有待處理的項目,以便sequencer可以在重置後處理新項目:

class cfs_sequencer extends uvm_sequencer;
   ...
   virtual function void handle_reset(uvm_phase phase, string kind = "HARD");
      uvm_objection objection = phase.get_objection();
      int objections_count;

      stop_sequences();

      objections_count = objection.get_objection_count(this);

      if(objections_count > 0) begin
         objection.drop_objection(this, $sformatf("Dropping %0d objections at reset", objections_count), objections_count);
      end

      start_phase_sequence(phase);
   endfunction
   ...
endclass

步驟5:處理Coverage組件中的復位


復位coverage組件更多地取決於物理協議,因爲沒有上述組件必須執行的“標準”邏輯。
因此,您可以使用handle_reset()函數在復位期間進行一些覆蓋率採樣,並清除所有臨時信息:

class cfs_coverage extends uvm_component;
   ...
   virtual function void handle_reset(string kind = "HARD");
      //sample coverage groups related to reset
      //clear some temporary information
   endfunction
   ...
endclass

就是這樣!
該技術非常通用,因此可以用於任何agent。

如果您想了解有關如何將此技術集成到通用agent中的更多信息,漢密爾頓·卡特(Hamilton Carter)曾在2015年寫過兩篇關於此類通用agent的文章:

希望這可以幫助?

在本文的第2部分中,您可以閱讀有關如何在驗證環境中處理重置的信息:SystemVerilog:如何在UVM中處理復位(第2部分)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章