【轉】UVM: Driver和Sequencer之間的握手機制(二)


原文鏈接:https://blog.csdn.net/weixin_43249032/article/details/83994995

seq_item_port的方法

Driver應該使用uvm_seq_item_pull_port內含的多種方法實現sequence->sequencer->driver的數據傳輸以及driver->sequence的反饋機制:

  • task get_next_item(output REQ req_arg):采取blocking的方式等待從sequence獲取下一個item。
  • task try_next_item(output REQ req_arg):采取nonblocking的方式從sequencer獲取item,如果立即返回的結果req_arg為null,則表示sequence還沒有准備好。
  • function void item_done(input RSP rsp_arg=null):用來通知sequence當前的sequence
    item已經消化完畢,可以有選擇性地傳遞RSP參數,返回狀態值。
  • task wait_for_sequences():等待當前的sequence直到產生下一個有效的item。
  • function bit has_do_available():如果當前的sequence准備好而且可以獲取下一個有效的item,則返回1,否則返回0。
  • function void put_response(input RSP rsp_arg):采取nonblocking方式發送response,如果成功返回1,否則返回0。
  • task get(output REQ req_arg):采用get方式獲取item。
  • task peek(output REQ req_arg):采用peek方式獲取item。
  • task put(input RSP rsp_arg):采取blocking方式將response發送回sequence。

driver可以進行哪些操作

uvm_driver實際上是一個具有TLM通信端口的uvm_component的子類,用來與Sequencer進行通信,將Sequence產生transaction通過Interface發送給DUT,需要時也會將transcation反饋給Sequence。

uvm_driver具有兩個參數,一個request另一個是response,默認情況下這兩個參數的類型是一致的,一般會被指定為用戶定義的transaction類型。這兩個參數也是uvm_driver自帶的seq_item_port的參數類型。

在這里插入圖片描述

如上所示,Driver與Sequencer進行通信主要就是依靠uvm_seq_item_pull_port派生的TLM端口seq_item_port的上述多種方法。所以其實也可以不用uvm_driver來派生Driver,只需要在Driver中自行定義seq_item_port並指定好參數類型,並與Sequencer的seq_item_export連接,進而調用seq_item_port的方法即可。

Driver調用get_next_item()時,Sequencer中的FIFO會Pop出一個transaction送給Driver,Driver將這個transaction的數據驅動給DUT后,需要和Sequence達成握手,告訴它這筆transaction已經使用完了,可以發送下一個transaction了(否則sequence會阻塞在`uvm_do或finish_item等指令上),所以它會調用seq_item_port的item_done()函數。

注意到item_done其實是一個參數類的函數,參數類型為RSP,這個是Driver和Sequence之間反饋所需要使用的。如果不加入輸入參數,sequence就不會收到response。

Sequence可以進行哪些操作

Sequence是uvm_sequence的子類,它同樣是參數化的類,一個參數是REQ,對應發送的transaction的類型,一個是RSP,對應Driver反饋的transaction類型,一般來說兩種相同。

Sequence在與Driver的通信中負責發送transaction。很多Sequence使用`uvm_do等系列宏來操作,uvm_do宏實際上是將transaction的實例化、隨機化、start_item、finish_item放在了一個操作里。其中最主要的是start_item,和finish_item任務,它們實際上又是由以下方法組成:
在這里插入圖片描述
所以Sequence操作細分入下:

  • 創建item
  • 通過start_item(),等待獲得sequence的授權許可,其后執行parent sequence的方法pre_do()。
  • 對item進行隨機化處理
  • 通過finish_item(),在對item進行了隨機化處理之后,執行parentsequence的mid_do(),以及調用uvm_sequencer::send_request()和uvm_sequencer::wait_for_item_done()來將item發送至sequencer再完成與driver之間的握手。最后,執行了parent_sequence的post_do()。

從上面可以看出其實也可以不用start_item和finish_item,直接使用send_request(item)等方法來達成通信。

使用get()和put()完成通信

在這里插入圖片描述
上面提到Driver使用get_next_item()獲得item,使用item_done()通知sequence使用完成。此外還有使用get()和put()達成接收transaction和反饋的操作:
在Driver中:

class my_driver extends uvm_driver #(my_data);
   `uvm_component_utils (my_driver)
 
   virtual task run_phase(uvm_phase phase);
      super.run_phase(phase);
 
    // 1. Get an item from the sequencer using "get" method
      seq_item_port.get(req);
 
    // 2. For simplicity, lets assume the driver drives the item and consumes 20ns of simulation time
      #20;
 
    // 3. After the driver is done, assume it gets back a read data called 8'hAA from the DUT
    // Assign the read data into the "request" sequence_item object
      req.data = 8'hAA;
 
    // 4. Call the "put" method to send the request item back to the sequencer
      seq_item_port.put(req);
   endtask
endclass

 

在Sequence中:

class my_sequence extends uvm_sequence #(my_data);
  `uvm_object_utils (my_sequence)
 
  // Create a sequence item object handle to store the sequence_item contents
  my_data tx;
 
  virtual task body();
    // 1. Create the sequence item using standard factory calls
    tx = my_data::type_id::create("tx");
 
    // 2. Start this item on the current sequencer
    start_item(tx);
 
    // 3. Do late randomization since the class handle pointers are the same
    tx.randomize();
 
    // 4. Finish executing the item from the sequence perspective
    // The driver could still be actively driving and waiting for response
    finish_item(tx);
 
    // 5. Because "finish_item" does not indicate that the driver has finished driving the item,
    // the sequence has to wait until the driver explicitly tells the sequencer that the item is over
    // So, wait unitl the sequence gets a response back from the sequencer.
    get_response(tx);
 
    `uvm_info ("SEQ", $sformatf("get_response() fn call done rsp addr=0x%0h data=0x%0h, exit seq", tx.addr, tx.data), UVM_MEDIUM)
  endtask
endclass 
 
          

首先在Driver中使用get()方法從Sequencer中獲得了transaction,並進行了處理(比如驅動DUT)。事實上get()和get_next_item()的區別在於get()中調用了item_done()函數,所以可以發現在上面的代碼中,get到了transaction后並沒有item_done()操作。使用get()后,在Sequence中finish_item也緊接着結束。可以查看https://www.chipverify.com/uvm/driver-using-get-and-put中的舉例的運行結果進行驗證。

之后再使用put()方法將處理完的req返回給Sequence。需要注意兩點:put()與put_response()的區別是,put()是阻塞的,而put_response()是非阻塞的,並且前者是任務,后者是由返回值的函數;此外上面代碼中put()的反饋回去的參數是req,也是接收的transaction,實際上一般使用rsp,這會在下面的內容中討論。

在Sequence中,其它部分和之前一樣,主要差別是使用了get_response方法獲得反饋的transaction,這是一個阻塞的方法,只有成功的獲得返回數據后,它才會結束阻塞。

所以使用get()和put()加上get_response()建立的sequence->sequencer->driver通信主要是為了反饋機制。這種情況下,一個item的周期始於item creat,結束於get_response()。

response機制:Driver->Sequence的反饋

在這里插入圖片描述
uvm_driver有兩個參數,第一個是用戶定義的transaction類型REQ,第二個是RSP,並且uvm_driver中分別定義了REQ和RSP的對象req和rsp。 req通常用作從Sequencer那里接收到的transaction,而rsp則是作為反饋回去的transaction。而且REQ和RSP默認是相同的類型,除非另外聲明。

能夠進行反饋的是seq_item_port的三個方法:item_done(input RSP rsp_arg), put_response(input RSP rsp_arg), put(input RSP rsp_arg)。其實從它們的參數上就可以看出只有這三種方法才能返回item給Sequence。

在Sequence中就只有一種方法獲得返回的item: get_response()。

 seq_item_port.get_next_item(req);

     $cast(rsp,req.clone());

     drive_one_pkt(req); 

     rsp.set_id_info(req);//回response 一定要加上這句!!!

     seq_item_port.put(rsp);

     seq_item_port.item_done();
--------------------- 

 

  • 在多個sequence同時向sequencer發送item時,就需要有ID信息表明該item從哪個sequence來,這個ID信息在sequence創建item時就賦值了,而在到達driver以后,這個ID也能用來跟蹤它的sequence信息

  • 如果使用rsp作為response的話,一定要加上rsp.set_id_info(req)這句,這個方法會將req中的信息復制給rsp,包括id信息。由於可能存在多個Sequence在同一個Sequencer上啟動的情況,只有設置了rsp的id等信息,sequencer才知道將response返回給哪個Sequence。實際上這句話也可以用下面的代碼替代:

    void’($cast (rsp, req.clone( ));
    rsp.set_sequence_id (req.get_sequence_id ( ));

  • response的機制原理是driver將rsp推送給Sequencer,而Sequencer內部維持一個隊列,當有新的response進入時,就推入此隊列,Sequence中的get_response()就是從這個隊列中取出返回數據。這個隊列的大小為8,當只有put的情況而沒有get情況下,隊列中存滿了8個response時,會發出溢出錯誤提示。

  • 有時為了“簡便”,會直接使用req作為反饋給Sequence的response transaction,這樣做的好處是不用做set_id_info操作,也不用聲明rsp。這么做看來,似乎節能環保,但實際上殊不知可能埋下隱患,一方面它延長了本來應該丟進垃圾桶的request item壽命,同時也無法再對request item原始生成數據做出有效記錄。

  • 此外還能使用uvm_dirver中自帶的rsp_port和uvm_sequence中對應的rsp_export來達成反饋機制。

參考文獻:

https://www.chipverify.com/uvm/driver-using-get-and-put
https://blog.csdn.net/qq_41394155/article/details/82112632?utm_source=blogxgwz8
https://blog.csdn.net/qq_41394155/article/details/82112540
http://blog.sina.com.cn/s/blog_13f7886010102x39f.html
https://blog.csdn.net/lbt_dvshare/article/details/80633839

 


免責聲明!

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



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