1. 程式人生 > >基於systemVerilog的UVM 除錯問題及解決辦法集錦

基於systemVerilog的UVM 除錯問題及解決辦法集錦

說在前頭

目前接觸的UVM內容都是基於systemVerilog的。所以,碰到的問題主要基於sv。

一、低階語法錯誤

此類錯誤是由於一些低階操作或常識不清導致的,並很容易解決。
多為語法錯誤。

1、訊號賦值

訊號主要分為wire型和reg型。
在進行訊號賦值時,wire型訊號不能出現在等號左邊只能在右邊,reg型訊號可以出現在等號左邊和右邊。故,當不小心把wire型訊號放在等號左邊,就會報錯。
訊號賦值,左右兩邊的訊號必須是相同型別,否則無法賦值。

當然,現在systemVerilog中引入了logic型別的變數,可看作是wire型和reg型的綜合。使用logic型別的訊號,就能避免上面的問題。

2、拼寫錯誤

因為每天敲很多程式碼,經常由於錯敲、多敲、漏敲字母導致訊號名錯誤,使得編譯報錯:該訊號未定義。
另外,由於螢幕解析度及字型原因,導致小寫的“i”與數字”1”不易區分,數字“0”和字母“O”不易區分,稍不留意就會認錯。

3、語法錯誤

有時編譯報錯為語法錯誤,但是仔細反覆檢查那一行,卻找不出問題。這時候,不妨往上一行看看。
原因是,經常由於上一行末尾少敲結尾的分號“;”,導致下一行編譯報語法錯誤。

4、invalid錯誤

實際工程中,自己動手敲程式碼,編譯發現invalid型別錯誤。
比如,某個型別的物件,編譯提示該型別未定義,invalid。但是,去檢查程式碼,自己明明定義了的。
原因是什麼?
哈哈,其實很簡單,不是你定義出問題了(若是,那也不會是invalid的了!)。
解決問題分兩步:

第一,檢查自己的型別名稱拼寫是否有錯誤。

對的,很有可能是敲錯了!
名稱對不上,自然是invalid。

第二,檢查程式碼編譯順序。

已經排除拼寫錯誤,那麼自然型別定義是沒有問題的。
那是什麼原因?
因為編譯時會將include的檔案按照程式碼順序編譯,於是,很有可能因為順序問題,導致應用型別的程式碼比定義型別的程式碼先編譯,那麼,基於先定義再使用的原則,顯然該型別在編譯到應用該型別時,自然是未定義的,也就是invalid。
解決辦法:只需要將定義的程式碼說在檔案的include順序提前到應用型別的檔案前面。
對,就是這麼簡單!
你以為多深奧?
再說一遍,核心辦法是:檢視在頂層中一大堆include“xxxx”的順序,確定型別的先定義再應用的順序。
經驗之談:一般,將最底層的檔案放在開頭,也就是自己純定義型別,不應用別的型別;應用型別的檔案,一定放在該型別的定義檔案之後。

5、使用UVM機制

UVM中提供了各種功能強大的機制,提高工作效率。比如factory機制。
但是,要使用這些機制,定義的object、component都必須用特定的巨集註冊。
否則,無法使用對應機制。
並造成對應定義的object或component存在invalid問題。

6、類變數的invalid

UVM使用systemVerilog,與C++、Java等面嚮物件語言有很多相同點。比如,類的物件,聲明後,在使用前,需要例項化。在SystemVerilog中使用new()函式實現.
有時候,程式碼通過編譯,但是在模擬時因出錯而停止,會出現“NULL pointer dereference”的錯誤提示.
這種錯誤是說:出現空指標的引用。
就說明,當前錯誤的地方是因為宣告的該例項沒有例項化。
當正確宣告一個變數,使用時,需要先進行new操作,即例項化。例項化,會申請對應空間供變數使用。否則,宣告的變數就只是一個單純的該型別指標,沒有實際空間,無法直接使用。
比如:
A a;// class A
a.copy(); // 報錯:NULL pointer dereference

修改為:
A a;// class A;
a = new(“a”);
a.copy() // 正確

7、虛擬介面

UVM中提供了虛擬介面,用於避免使用絕對路徑。
每一組虛擬介面,在定義後,都必須完善連線。否則,由於介面沒有連線上,使用會報錯。

8、函式呼叫錯誤

呼叫函式,不管是系統函式還是自定義函式,函式中的引數個數要匹配,否則,會報錯。
錯誤資訊大概如下:
The above function/task call is done with more arguments than needed.
這類錯誤比較容易解決,直接去參看原函式定義,檢查引數型別及數量,一一對應修改即可。

9、uvm_info引起的錯誤

通常,為了方便除錯,會新增uvm_info列印資訊,功能等同與C語言中的printf函式。
這個當然很好。
但是,一不小心,就會引起錯誤。還很莫名其妙。
比如,在某個UVM component的某個phase中,需要在執行進入該phase中,就列印相關資訊,提醒當前已經執行到這裡。
想法很好,uvm_info的語法也簡單。
一般不會有錯。
但是,假如uvm_info後面有變數宣告,那麼,不好意思,編譯時會報錯,提示新增“=”or“<=”。
WTF?
莫名其妙嘛!
解決辦法,將uvm_info語句移到變數宣告的後面即可。

二、高階邏輯錯誤

所謂高階錯誤,是為了和前方的低階錯誤相區別。
化用偉人的話說,此類錯誤,已經脫離了低階趣味。
不再是簡單的語法、常識錯誤,而是更深層次的邏輯錯誤。
表現為:能正常通過編譯環節,但是在模擬階段會出錯。
這類錯誤往往更難處理,需要對UVM各部件本身及部件之間的連線關係有深刻理解。

UVM有許多component和object。這些部件之間的相互協作有一定的工作順序,當前後順序錯誤時,同樣導致模擬階段無法正常工作。

1、sequence

最近(2016-10-10)碰到的一個問題。
模擬給出的錯誤資訊如下:
reg_seq [SEQ] neither the item’s sequencer nor dedicated sequencer has been supplied to start item in reg_seq
從字面意思看,就是說在處理reg_seq的時候,對應的sequencer並未預先設定完成。
都說sequence就是子彈夾,sequencer就是槍。
子彈夾已經就緒,槍還沒有,所以無法開槍。
那該怎麼辦?
經過兩天的檢視,發現問題是由於需要用到的sequencer等尚未定義,因此,此處使用sequencer當然就還沒有準備好。

2、null object access(NOA)

昨天晚上除錯驗證平臺程式碼,模擬階段出現了NOA錯誤,錯誤資訊顯示,需要使用的object並沒有預先完成例項化。
這類錯誤主要由於在宣告object之後,忘記例項化造成的。
有人會問,怎麼這麼粗心大意?
這都能忘?
我:……
這麼低階的錯誤,本小白肯定還不至於這麼不小心。
經過自己梳理平臺中object、component之間的呼叫關係,以及驗證平臺的執行順序後,發現是昨晚剛對底層的component的定義做了修改,由於功能需要,添加了新的object,及操作。
經過反覆檢查確認,新新增的程式碼,本身沒有問題,需要呼叫的地方也沒問題。
問題出在其他位置呼叫此component的情況。
需要呼叫新object的地方,對新object做了相應處理。
而舊的呼叫的地方,則並沒有做處理,於是問題就出來了。
在並不需要新object的地方,並沒有進行例項化。而該object依然進行了相應的操作,比如賦值,於是,出現了NOA錯誤。

總結教訓:以後修改底層檔案,一定要小心,修改底層檔案,那麼凡是呼叫這個檔案的地方,都要做檢查,按照需要進行相應修改,否則,各種NOA,讓人莫名其妙,煩不勝煩。最好的辦法,不到萬不得已,千萬不要修改底層檔案!