很多UVM用戶平時更多的使用get_response()方式去獲得uvm_driver的response,但get_response有些缺點:由于 get_response() 是一種阻塞方法,它會阻塞直到收到來自 UVM 驅(qū)動程序 (put_response()) 的響應。
因此,如果我們使用 get_response() 方法實現(xiàn)并按此順序?qū)?start_item()、finish_item() 和 finally get_response() 放置在序列的 body() 方法中,這將導致非流水線序列實現(xiàn),因為下一個序列項可以只有在 get_response() 方法收到前一個請求序列項的響應項后,才提供給 UVM 驅(qū)動程序。
為了實現(xiàn)背靠背的傳輸,我們可以使用response_handler()機制,它可以將sequence中發(fā)送request和處理response兩個操作分開處理,盡量減少耦合。例子如下流程圖。
1. 如何使用response_handler
如果想要實現(xiàn)response_handler機制的話,第一步需要在要使用這個機制的sequence里使能它,即調(diào)用use_response_handler(1)函數(shù)把m_use_response_handler變量設置為1就行,m_use_response_handler是uvm_sequence_base類里的一個成員變量,默認值為0,也就是不打開。第二步需要override uvm_sequence_base類里的response_handler函數(shù),實現(xiàn)自己對response任意處理的需求。它的原型為:
// Function: response_handler
// When the use_reponse_handler bit is set to 1, this virtual method is called
// by the sequencer for each response that arrives for this sequence.
virtual function void response_handler(uvm_sequence_item response);
return;
endfunction
response_handler對uvm_driver沒有任何影響,也就是不可見,uvm_driver仍然用之前的put_response機制就行。
2. response_handler背后機制
sequence里的response_handler(xxx)函數(shù)在uvm_driver調(diào)用seq_item_export.put_response(rsp)的時會自動被調(diào)用執(zhí)行,故此我們從seq_item_export.put_response(rsp)講起。
uvm_driver調(diào)用put_response(rsp)時,會調(diào)用uvm_sequencer_param_base里的put_response(rsp)函數(shù),這個函數(shù)的定義為:
313行到326行就是對傳參進來的rsp做一些檢查。328行會根據(jù)rsp里攜帶的sequence_id去調(diào)用m_find_sequence函數(shù)在reg_sequences關聯(lián)數(shù)組里找對應sequence的句柄,如果找到了就返回sequence句柄,沒有找到的話,就直接返回null,并報告沒有找到原始sequence的信息。通常我們返回的是非null的,因此會進入330行到337行。
如何避免返回null,在我的另一篇博客中說了,有興趣讀者可以瞄一眼(UVM中使用put_response的一個注意點)。在332行,會判斷m_use_response_handler變量的值,如果為1就執(zhí)行333行sequence里的response_handler函數(shù),如果為0就執(zhí)行337行response_handler的put_response??上攵@是1個關鍵分叉點。我們分別介紹這兩個方法。
2.1 sequence_ptr.response_handler(t)
sequence里的response_handler()函數(shù)我們在第一小節(jié)里也提到了,原型是個空函數(shù),需要用到這個機制的用戶自己去override它來實現(xiàn)需要的功能。
2.2 sequence_ptr.put_response(t)
在uvm_sequence_base類的put_response函數(shù)又會繼續(xù)調(diào)用put_base_response函數(shù),它們倆的代碼為:
virtual function void put_response (uvm_sequence_item response_item);
put_base_response(response_item); // no error-checking
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
可以看出,在put_base_response函數(shù)里會將uvm_driver送過的rsp放到response_queue隊列了,response_queue隊列定義為:protected uvm_sequence_item response_queue[$]。另外說下response_queue_depth這個int類型變量,它的默認值為8,也就是response_queue隊列默認只能放8個rsp,如果超過的話,會被直接忽視掉(用戶可以打開response_queue_error_report_disabled來報錯)。
但如果用戶想要讓response_queue隊列可以放更多的rsp呢?需要調(diào)用uvm_sequence_base里的set_response_queue_depth(xx)來設置新值,xx就是傳進去的int類型數(shù)值。也可以調(diào)用get_response_queue_depth()來返回當前設置的值。
response_queue隊列里的值會給get_reponse(xxx)使用。
3. get_response背后機制
在sequence中調(diào)用get_response(xxx)的時候,對調(diào)用uvm_sequence_base類里的get_base_response(xxx)方法。
virtual task get_response(output RSP response, input int transaction_id = -1);
uvm_sequence_item rsp;
get_base_response( rsp, transaction_id);
$cast(response,rsp);
endtask
get_base_response(xxx)方法的代碼如下:
從以上代碼可以看出,get_reponse(xxx)就是從response_queue隊列里拿數(shù)據(jù),response_queue里的數(shù)據(jù)是put_response在沒有使能response_handler機制情況下放進去的。因此用戶要注意一旦采用response_handler機制后,在當前sequence里一定不能用get_response,反則它會get不到response,一直block在get_base_response方法的991行。
如果transaction_id為-1,也就是用戶沒有指定要得到特定transaction_id的response時,get_base_response會默認返回response_queue里的第一個response,類似于FIFO。如果transaction_id不為-1,那么get_base_response會在response_queue里檢索,直到找到1個匹配對應transaction_id的response為止。
-
UVM
+關注
關注
0文章
182瀏覽量
19171 -
FIFO存儲
+關注
關注
0文章
103瀏覽量
5982
發(fā)布評論請先 登錄
相關推薦
評論