在SystemVerilog中,經(jīng)常會用到$cast對數(shù)據(jù)類型進行轉(zhuǎn)換,其實在實際使用過程中除了這種明擺著的數(shù)據(jù)類型轉(zhuǎn)換外,SystemVerilog中還有一些“隱性”的數(shù)據(jù)類型轉(zhuǎn)換,本文將通過示例說明SystemVerilog中的數(shù)據(jù)類型轉(zhuǎn)換。
在SystemVerilog中,類型按照的兼容性分為5各層級,分別是匹配(matching)、相同類型(equivalent)、賦值兼容(assignment compatible)、轉(zhuǎn)換兼容(cast compatible)和不相同類型(non-equivalent),其中匹配、相同類型其實也屬于賦值兼容的一部分,所有的賦值兼容和所有的可以使用顯式轉(zhuǎn)換的不相同類型都屬于可轉(zhuǎn)換類型。
因此,可以知道,其實隱式轉(zhuǎn)換主要存在于匹配和相同的數(shù)據(jù)類型之間,而顯式轉(zhuǎn)換存在于其他不同數(shù)據(jù)類型或者賦值兼容的數(shù)據(jù)類型之中。而隱式數(shù)據(jù)類型轉(zhuǎn)換,顯式數(shù)據(jù)類型轉(zhuǎn)換的主要區(qū)別是轉(zhuǎn)換是否“肉眼可見”,隱式轉(zhuǎn)換一般會“靜默”完成,而顯式需要用戶使用特殊的語法結(jié)構(gòu)才能實現(xiàn),下面通過示例具體看看兩種轉(zhuǎn)換的用法。
01? 隱 式 轉(zhuǎn) 換
隱式轉(zhuǎn)換一般情況下下表中的數(shù)據(jù)類型變量相互之間進行賦值時會自動完成類型轉(zhuǎn)換的,例如四值邏輯變量和二值邏輯邏輯變量之間的相互賦值、不同位寬變量之間的相互賦值等等。?
【示例】?
【仿真結(jié)果】?
示例中,將var4賦值為不定態(tài)之后在賦值給var3,雖然var4具有四值數(shù)據(jù)類型,但是因為var3是二值數(shù)據(jù)類型,當var4賦值給var3時,其中的不定態(tài)自動轉(zhuǎn)換為了0,這個轉(zhuǎn)換過程是隱式自動完成的。var2是一個byte類型,為有符號數(shù),示例中其最高位為1,因為var4位寬比var2寬,所以再將其賦值給var4時,需要對高位進行補位操作,這時的補位操作將根據(jù)var2最高位的特點進行補位,并且這個過程是隱式自動完成的。其實在進行具有上表中數(shù)據(jù)類型特點的數(shù)據(jù)進行隱式數(shù)據(jù)類型轉(zhuǎn)換時,為了避免這種“悄無聲息”的轉(zhuǎn)換發(fā)生,需要注意進行操作的數(shù)據(jù)對象的以下幾點: ü操作數(shù)的位寬; ü操作數(shù)的符號特性; ü操作數(shù)的數(shù)據(jù)類型;
02? 顯 式 轉(zhuǎn) 換
顯示的類型轉(zhuǎn)換主要有兩種方式,格式分別如下:
靜態(tài)轉(zhuǎn)換一般發(fā)生于編譯階段,在編譯階段完成類型的檢查,而動態(tài)轉(zhuǎn)換一般位于仿真運行階段。下面將分別對兩種轉(zhuǎn)換進行示例說明。
2.1 static靜態(tài)轉(zhuǎn)換
靜態(tài)轉(zhuǎn)換不會對轉(zhuǎn)換值做檢查,在編譯階如果發(fā)生轉(zhuǎn)換失敗則會報錯,但是對于一般的“integer data types”之間在轉(zhuǎn)換是產(chǎn)生的截位等問題則不會有相應(yīng)的警告信息。
【示例】?
【仿真結(jié)果】?
示例中,企圖將packet通過靜態(tài)轉(zhuǎn)換為int型,此時在代碼編譯階段已經(jīng)報錯,即不支持將class對象轉(zhuǎn)換為int型變量,其實在SystemVerilog中class對象不支持這種轉(zhuǎn)換,基本上所有的不以連續(xù)位方式進行存儲的變量在使用靜態(tài)轉(zhuǎn)換是都會報錯。關(guān)于具體轉(zhuǎn)換可查閱IEEE1800相關(guān)章節(jié)內(nèi)容。下面我們將分別示例常用的靜態(tài)轉(zhuǎn)換都有哪些。
2.1.1 類型轉(zhuǎn)換
在SystemVerilog中,可以通過靜態(tài)轉(zhuǎn)換完成一些賦值兼容的數(shù)據(jù)類型之間轉(zhuǎn)換,如果轉(zhuǎn)換的數(shù)據(jù)類型賦值不兼容,將會產(chǎn)生一些不期望的結(jié)果,特別是在枚舉類型和數(shù)據(jù)流中。數(shù)據(jù)類型轉(zhuǎn)換的語法格式如下:
casting_type’(expression)
【示例】?
【仿真結(jié)果】?
示例中,給int型變量賦值為十進制64,然后通過”string’(vart)”的方式將整數(shù)值64轉(zhuǎn)換成字符,此時的仿真結(jié)果將按照ASCII碼表中整數(shù)64對應(yīng)的字符進行顯示,顯示的結(jié)果字符為”@”,在示例中實現(xiàn)了整數(shù)類型與字符串類型的轉(zhuǎn)換,當然也可以進行其他數(shù)據(jù)類型之間的轉(zhuǎn)換,但是需要注意轉(zhuǎn)換數(shù)據(jù)類型的賦值兼容性以及數(shù)據(jù)位寬和符號特性等問題,否則轉(zhuǎn)換后的結(jié)果可能與期望不一致,所以,從安全性考慮,進行建模時盡量采用統(tǒng)一的數(shù)據(jù)類型之間的相互操作,盡量避免不同數(shù)據(jù)類型之間的相互轉(zhuǎn)換。
2.1.2位寬轉(zhuǎn)換
在SystemVerilog中可以將一個表達式結(jié)果的位寬轉(zhuǎn)換為指定的位寬,這里需要注意不要轉(zhuǎn)換的表達式位于括號中,要轉(zhuǎn)換為的位寬必須為正數(shù),不能為0或者負數(shù)。其語法格式如下:
dst_size’(expression)
【示例】?
【仿真結(jié)果】?
示例中src_vector是8位寬,通過10’(src_vector)將src_vector位寬轉(zhuǎn)換為10位寬。當然示例中的src_vector為無符號數(shù),無符號數(shù)在位寬擴展時高位補0,如果src_vector為有符號數(shù),那么此時將src_vector轉(zhuǎn)換成寬位寬的數(shù)時,此時需要注意該有符號數(shù)的符號位,此時的補位將會按照符號位進行補位,如下例。
【示例】?
【仿真結(jié)果】?
示例中src_vector是8位寬byte有符號數(shù),通過10’(src_vector)將src_vector位寬轉(zhuǎn)換為10位寬,此時因為src_vector為有符號數(shù),所以此時轉(zhuǎn)換時高位補位使用了其符號位進行了補位,結(jié)果為10’b11_1010_1010。
2.1.3符號轉(zhuǎn)換
除了示例中通過靜態(tài)轉(zhuǎn)換可以轉(zhuǎn)換表達式結(jié)果位寬外,在SystemVerilog中還可以通過指定符號特性影響表達式結(jié)果的符號特性,其使用格式如下:
signed’(expression) 和unsigned’(expression)
【示例】?
【仿真結(jié)果】?
示例中,value0為有符號數(shù),并且初值為”-8”,首先將該數(shù)以二進制和十進制方式分別顯示,然后通過unsigned將value0的符號特性轉(zhuǎn)換為無符號數(shù),并且通過二進制和十進制方式分別顯示,顯示結(jié)果中,因為value0為32位數(shù),所以改變后其二進制顯示將會保留未改變符號特性時數(shù)據(jù)在內(nèi)存中的存儲格式,但是此時十進制顯示的結(jié)果就是該數(shù)轉(zhuǎn)換為無符號數(shù)后對應(yīng)的結(jié)果。其實除了上述使用靜態(tài)轉(zhuǎn)換實現(xiàn)符號特性的轉(zhuǎn)換外,在SystemVerilog中還可以通過系統(tǒng)函數(shù)$signed和$unsigned實現(xiàn)一樣的功能,再次就不再贅述了,大家可以將示例中的代碼進行替換仿真。
2.2 dynamic動態(tài)轉(zhuǎn)換
在SystemVerilog中,與靜態(tài)轉(zhuǎn)換對應(yīng)的是動態(tài)轉(zhuǎn)換,動態(tài)轉(zhuǎn)換可以通過使用系統(tǒng)方法$cast實現(xiàn)數(shù)據(jù)類型的轉(zhuǎn)換,這個動態(tài)轉(zhuǎn)換的過程相較于靜態(tài)轉(zhuǎn)換主要區(qū)別在于該轉(zhuǎn)換和檢查發(fā)生在仿真運行階段。同時$cast在SystemVerilog中有兩種存在形式,這兩種形式的格式如下:
function int $cast(singular dest_var,singular src_exp);
和
task $cast(singular dest_var,singular src_exp);
兩種形式實現(xiàn)的功能都是將源表達式src_exp轉(zhuǎn)換給目標變量dest_var,那么既生瑜何生亮,實現(xiàn)的功能都一樣,在具體使用時仿真工具或者用戶如何知道使用的是$cast的那種形式呢?下面我們通過示例說明兩者使用上的差異。
2.2.1 $cast作為任務(wù)task
【示例】?
【仿真結(jié)果】?
示例中,雖然子類scobj是從父類cobj拓展派生而來的,兩個屬于不同的類型,但是父類句柄是可以直接指向子類對象,子類句柄是不能直接指向父類對象的(關(guān)于句柄之間類型轉(zhuǎn)換可參考《硅心思見:【113】SystemVerilog中不同句柄之間的動態(tài)類型轉(zhuǎn)換》)。本示例中企圖通過$cast將子類句柄sp指向父類句柄指向的對象(此時父類句柄指向?qū)ο蟮念愋蜑閏obj),并且代碼的編譯已經(jīng)通過,但是在程序運行時調(diào)用$cast時,檢測類型不匹配,仿真器直接報錯停止,并且給出報錯信息??梢钥吹?,示例中$cast的用法與task相同,都沒有返回值,仿真器會根據(jù)該方法使用的上下文確定該方法按照task進行解析。
2.2.2?$cast作為函數(shù)function
【示例】?
【仿真結(jié)果】
示例中,兩次調(diào)用$cast,都將$cast賦值給了tmp,即此時$cast有返回值,根據(jù)上下文可以此時$cast被作為一個有返回值的方法,此時的$cast被仿真器按照function解析處理。第一次調(diào)用$cast時,因為子類句柄sp指向父類句柄p指向的對象(因為此時父類句柄指向?qū)ο蟮念愋蜑閏obj),當仿真運行調(diào)用$cast時檢測到類型不匹配,函數(shù)返回0給tmp,條件判斷語句根據(jù)tmp值執(zhí)行了對應(yīng)分支的$display語句,同時我們注意到仿真并沒有因為這次不匹配報出任何提示信息和停止仿真;第二次調(diào)用$cast時,因為句柄p指向子類句柄sp指向的對象(父類句柄可以直接指向子類對象),當仿真運行調(diào)用$cast時檢測到類型匹配兼容,函數(shù)返回1給tmp,條件判斷語句根據(jù)tmp值執(zhí)行了對應(yīng)分支的$display語句。
通過上述示例可以匯總?cè)缦聨c:
ü當將$cast作為任務(wù)使用時,如果源對象的數(shù)據(jù)類型與目的對象的數(shù)據(jù)類型不匹配不兼容仿真時會報錯,并且仿真停止;
ü當將$cast作為函數(shù)使用時,如果源對象的數(shù)據(jù)類型與目的對象的數(shù)據(jù)類型不匹配不兼容仿真時,該函數(shù)僅返回值0,并且仿真不會停止也不會給出任何提示,如果類型兼容匹配,轉(zhuǎn)換成功,那么函數(shù)返回非零值;
ü$cast具體作為函數(shù)還是任務(wù),取決于用戶在編碼時按照如何的方式對$cast進行使用,如果期望類型不匹配不兼容時能夠給出信息并且停止仿真,那么用戶應(yīng)該像任務(wù)一樣使用$cast,如果想根據(jù)類型轉(zhuǎn)換的結(jié)果進行特定的操作并不自動停止時,那么用戶應(yīng)該像函數(shù)一樣使用$cast。
編輯:黃飛
評論