UVM——sequence機制(數據激勵的產生、配置方式)


一、sequence的執行流程

  • uvm_sequence_item包裝數據):只能對數據進行封裝,不存在自動執行的函數;
  • uvm_sequence生產數據):具有可自動執行的函數,可通過body()函數進行可執行操作,產生數據激勵;
  • uvm_sequencer發送數據):將數據發送給driver

   sequence item是每一次driver與DUT互動的最小粒度內容,在sequence與driver之間起到橋梁作用的是sequencer,sequencer與driver均是component組件,它們之間的通信也是通過TLM端口實現的。UVM序列的連接傳送如下圖所示:

在這里插入圖片描述

  1. sequence對象自身會產生目標數量的sequence item對象。借助於SV的隨機化和sequence item對隨機化的支持,使得產生的每個sequence item對象中的數據內容都不相同。
  2. 產生的sequence item會經過sequencer再流向driver
  3. driver得到了每一個sequence item,經過數據解析,再將數據按照與DUT的物理接口協議寫入到接口上,對DUT形成有效激勵
  4. 必要時,driver在每解析並且消化完一個sequence item,也會將最后的狀態信息同sequence item對象本身再度返回給sequencer,最終抵達sequence對象一側。這么做的目的在於,有的時候sequence需要得知driver與DUT互動的狀態,這就需要driver仍然有一個回路再將處理了的sequence item對象和狀態信息寫回到sequence一側。

二、sequence的啟動方式——start()/default_sequence

  UVM中sequence的啟動分為顯示啟動隱式啟動兩種方式。

  • 顯式啟動(直接啟動)——調用start()方法啟動。
  • 隱式啟動 ——使用uvm_config_db機制配置default_sequence啟動。
//sequence的顯式啟動
//該方法提起和落下objection,通過phase.raise_objection(this)/phase.drop_objection(this)
my_sequence   seq = my_sequence::type_id::create("seq");
phase.raise_objection(this);
seq.start(sequencer);
phase.drop_objection(this)

//sequence的隱式啟動
//該方法可以在sequence中使用starting_phase提起和撤銷objection
uvm_config_db#(uvm_object_wrapper)::set(this,"env.i_agt.sqr.main_phase",
                                        "default_sequence",
                                         case0_sequence::get_type());
//在my_sequence中的body任務中
virtual task body;
  if(starting_phase != null)
    starting_phase.raise_objection(this);
  repeat(10)begin
    `uvm_do(req);
  end
  if(starting_phase != null)
    starting_phase.drop_objection(this);
endtask

二、sequence生產數據——body( )

   當一個sequence啟動后,會自動執行body()函數生產數據,sequencer會將數據發送給driver,完成數據的發送。sequencer與driver的通信也是通過TLM端口實現的,TLM端口在例化中需要對通信參數進行指定,這里的通信參數即sequence item種類

class tr_sequence extends uvm_sequence#(transaction);
   ...
   virtual task body();
      if(starting_phase != null)
         starting_phase.raise_objection(this,"starting");   //1.啟動仿真,生產數據
         `uvm_do(req);                                      //2.通過宏`uvm_do自動隨機化產生數據
      if(starting_phase != null)
         starting_phase.drop_objection(this,"done");        //3.結束仿真
   endtask
endclass  

class driver extends uvm_driver#(transaction);
   ...
   virtual task run_phase(uvm_phase phase);
      forever begin
         seq_item_port.get_next_item(req);                 //4.driver申請數據
         send(req);                                        //5.按照物理時序處理接收到的數據
         seq_item_port.item_done();                        //6.數據傳輸完畢
      end
   endtask
endclass
  • 加粗樣式在sequence中,通過objection機制控制仿真時的數據生產;
  • 在driver的run_phase階段,利用TLM端口seq_item_portget_next_item()和item_done()方法控制數據包的傳輸;

2.1.宏`uvm_do( )的功能

   當一個sequence啟動后,會自動執行sequence中的body任務,在body任務中可以調用`uvm_do系列宏來生產數據
   當同一個sequencer上啟動多個sequence時,由於sequencer會依據何種選擇啟用哪一個sequence的transaction存疑,故引入仲裁機制。使用仲裁機制的相關系列宏如下所指示:(默認仲裁算法是SEQ_ARB_FIFO,遵循先入先出,不考慮優先級)

`uvm_do(SEQ_OR_ITEM)                       //1. 根據sequence_item實例,隨機化產生數據
`uvm_do_with(SEQ_OR_ITEM, CONSTRAINTS)     //2. 在隨機化數據的基礎上,添加約束
`uvm_do_pri(SEQ_OR_ITEM, PRIORITY)
`uvm_do_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS)
`uvm_do_on(SEQ_OR_ITEM, SEQR)               //3. 隨機化同時,顯式的指定使用哪個sequencer來發送此transaction
`uvm_do_on_pri(SEQ_OR_ITEM, SEQR, PRIORITY)
`uvm_do_on_with(SEQ_OR_ITEM, SEQR, CONSTRAINTS)
`uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS)
  • `uvm_do系列宏其實是將下述動作封裝在了一個宏中(start_item與finish_item運用)。在實際的代碼編寫中,工程師可以不使用宏uvm_do()處理數據,而是根據實際情況手動執行這些內嵌程序。
       req = my_sequence::type_id::create("req");  \       1. 創建item對象實例;
       start_item(req);      \                   2.獲取sequencer的授權許可;
       assert(req.randomzie() with {req.data == 100;}); //assert(req.ranomzie()); 3.**對item進行隨機化處理**;
       finish_item(req);     \                   4.將item發送至sequencer,進而完成與driver之間的交互
  • 宏`uvm_do_with (item, { constraint })與 宏 ‘uvm_do( )無本質區別,只是多了約束條件;需要說明的是宏‘uvm_do( )不支持randc類型的隨機變量。

2.2.sequence的嵌套啟動

   嵌套sequence的啟動可以通過start(m_sequencer)來完成,也可以通過uvm_do()系列宏來完成;

  • m_sequencer是base_sequencer啟動時所使用的sequencer的指針,也就是說,嵌套的seq啟動時所使用的sequencer同所在的sequence所使用的sequencer一致
class base_sequence extends uvm_sequence#(transaction);
  ...
  virtual task body();
    crc_seq    cseq=crc_seq::type_id::create("cseq");
    long_seq       lseq=long_seq:;type_id::create("lseq");
    
    repeat(10)begin
        cseq.start(m_sequencer);             //啟動嵌套的seq
        lseq.start(m_sequencer);
    end

  endtask
endclass
  • 采用uvm_do宏啟動嵌套的seq,更加簡單;
class base_sequence extends uvm_sequence#(transaction);
  ...
  virtual task body();
    crc_seq    cseq;
    long_seq       lseq;
    
    repeat(10)begin
        `uvm_do(cseq);             //啟動嵌套seq
        `uvm_do(lseq);
    end

  endtask
endclass

2.3.sequence接收響應rsp

class tr_sequence extends uvm_sequence#(transaction);
   ...
   virtual task body();
      ...
        `uvm_do(req);                                      
         get_response(rsp);                               //3.接收響應信息rsp
   endtask
endclass  

class driver extends uvm_driver#(transaction);
   ...
   virtual task run_phase(uvm_phase phase);
      forever begin
         seq_item_port.get_next_item(req);              
         send(req);      
         rsp = transaction::type_id::create("rsp");       
         rsp.set_id_info(req);                            //1. 創建並配置響應ID
         seq.item.port.item_done(rsp);                    //2. driver返回響應rsp
      end
   endtask
endclass

三、config_db配置sequence

3.1.默認執行的sequence

  默認的測試用例(test_base)執行默認的default sequence,該sequence在驗證環境中配置的;

class environment extends uvm_env;       //在初始環境中配置默認的sequence
   ...
   function void build_phase(uvm_phase phase);
      ...
      uvm_config_db #(uvm_object_wrapper)::set(this,"*.seqr.main_phase","default_sequence",transaction_sequence::get_type());
      ...
   endfunciton
endclass   

  默認sequence在main_phase階段執行,此時也可將null賦給default sequence,不產生數據

3.2.配置sequence——get_full_name() / m_sequencer

  • 通過get_full_name( )獲取配置的路徑名稱,可以有效防止不同的sequence中有相同變量進行配置時產生的沖突
  • get_full_name()在sequence中被調用時,打印的路徑為:uvm_test_top.env.agt.seqr.seq
  • 需要說明的是,當sequence在virtual sequence中被啟動,調用的get_full_name()方法打印的路徑結果:uvm_test_top.v_seqr.*,這是由於virtual sequence不遵循UVM樹的路徑層次;
class tr_sequence extends base_sequence;        //2.在底層組件捕獲sequence配置
   int item_count = 10;
      ...
   virtual task pre_start();
      ...
      uvm_config_db #(int)::get(null, "this.get_full_name()", "item_count", item_count);   //本地變量item_count = 20,配置成功
     
     //uvm_config_db #(int)::get(null, this.get_full_name(), "item_count", item_count);   get_full_name() 不添加引號

    //uvm_config_db #(int)::get(m_sequencer, “”, "item_count", item_count);   m_sequencer 指定路徑
   endfunciton
endclass      

class test_20_items extends test_base;        //1.在測試用例中啟動sequence配置
   ...
   function void build_phase(uvm_phase phase);
      ...
      uvm_config_db #(int)::set(this,"env.agt.seqr.*","item_count",20);     //item_count = 20 ,啟動配置賦值
   endfunciton
endclass      

3.3.配置sequence——get_sequncer()

  • 通過get_sequencer( )獲取配置字段的sequencer,可以為sequencer下的所有sequence中的相同變量同時提供配置。
class tr_sequence extends base_sequence;        //2.在底層組件捕獲sequence配置
   int item_count = 10;
      ...
   virtual task pre_start();
      ...
      uvm_config_db #(int)::get(this.get_sequencer(),"","item_count",item_count);   //本地變量item_count = 20,配置成功
   endfunciton
endclass      

class test_20_items extends test_base;        //1.在測試用例中啟動sequence配置
   ...
   function void build_phase(uvm_phase phase);
      ...
      uvm_config_db #(int)::set(this,"env.agt.seqr.*","item_count",20);     //item_count = 20 ,啟動配置賦值
   endfunciton
endclass      


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM