原文鏈接: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