數字硬件建模SystemVerilog(十三)-枚舉數據類型
上一節介紹了已經被淘汰的$unit聲明空間,今天我們來看看一種重要的數據類型-枚舉數據類型。
枚舉數據類型提供了一種聲明變量的方法,該變量可以包含有效值的特定列表。每個值都與一個標簽(確定的用戶自定義名宇)相關聯。枚舉變量用enum關鍵字聲明,后面是用大括號({})括起來的逗號分隔的標簽列表。
在下面的示例中,變量rgb的值可以是RED GREEN BLUE
枚舉列表中的標簽是常量,類似于localparam常量。標簽可以是任何名稱。本系列使用大寫字母作為常量的慣例。
枚舉數據類型聲明語法
枚舉數據類型有一個底層數據類型,稱為基類型,可以是任何SystemVerilog內置數據類型或用戶自定義類型。枚舉列表中的每個標簽都有一個與該標簽關聯的邏輯值。
SystemVerilog提供了兩種用于聲明枚舉數據類型的樣式:隱式樣式和顯式樣式。
隱式樣式枚舉聲明
隱式樣式枚舉聲明使用基類型和標簽值的默認值。默認的基本類型是int。標簽的默認值是列表中的第一個標簽的值為0,并且每個后續標簽的值遞增一。
在以下隱式樣式枚舉聲明中:
enum{WAITE,LOAD,READY}states_e;
states_e是int數據類型的變量,是32位有符號數據類型。這意味著枚舉列表最多可以有2147483648(2^(32-1))個標簽。
列表中的第一個標簽WAITE的值為0,LOAD為l,READY為2。(標簽WAITE故意在末尾拼寫為“E”,以避免與SystemVerilog中保留的關鍵字wait產生混淆或沖突。)
這些默認設置很少適用于硬件建模。基類型int是2-state類型,這意味著在仿真期間導致X的任何設計問題都不能反映在枚舉變量中。基類型int的寬度為32位,通常比所表示的硬件所需的向量大得多。標簽值(如0、1和2)不能代表很多其他類型的硬件設計中使用的編碼,例如獨熱碼值、格雷碼或約翰遜計數。
顯式樣式枚舉聲明
顯式樣式枚舉聲明指定基類型和標簽值。以下聲明表示使用一種獨熱編碼的3位寬狀態變量:
顯式樣式枚舉聲明強制使用了幾個語法規則,可以幫助防止編碼錯誤:
基類型的向量寬度和標簽值的顯式寬度必須相同。允許使用大小不一的文字值(例如WAITE = 1)
每個標簽的值必須是唯一的;兩個標簽不能具有相同的值。
標簽的數量不能超過基本類型的向量寬度所能代表的數量。
無需指定枚舉列表中每個標簽的值。
如果未指定值,則該值將從上一個標簽增加1。在下一個例子中,標簽A顯式地給出了一個值l,B自動給出了遞增為值2,C給出了遞增的值3。D被明確定義為具有13的值,E和F分別被賦予14和15的遞增值。
如果兩個標簽的值相同,則會導致錯誤。以下示例將產生一個錯誤,因為c和D的值相同,都為3:
最佳實踐指南4-3 |
---|
在RTL模型中使用顯式樣式枚舉數據類型聲明,在RTL模型中,基類型和標簽值是指定的,而不是推斷的。 |
指定基本類型和標簽值有幾個優點:它記錄了設計工程師的意圖;它可以更準確地仿真門級行為,并允許更準確的RTL到門級邏輯等價性檢查。
自定義和匿名枚舉數據類型
可以使用typedef將枚舉數據類型聲明為用戶自定義類型,這為使用相同的枚舉值集聲明多個變量或網絡提供了一種便捷的方法。
使用typedef聲明的枚舉數據類型稱為自定義枚舉數據類型。如果未使用typedef,則枚舉數據類型稱為匿名枚舉數據類型。
枚舉數據類型標簽序列
有兩種快捷方式可以指定枚舉數據類型列表中具有相似名稱的多個標簽。
COUNT_[4] 快捷方式將生成四個標簽,分別為COUNT_0、COUNT_1、COUNT_2和COUNT_3。與COUNT_0關聯的值將默認為0,隨后每個標簽的值將增加一。
第二個快捷方式:指定一系列標簽。
COUNT_[8:11]簡寫符號將生成四個標簽,分別為COUNT_8、COUNT_9、COUNT_10和COUNT_11。與COUNT_8關聯的值被明確定義為8,后續標簽的值將增加1。
如果范圍中的第一個值小于第二個值,如在COUNT_[8:11]中,則序列將從第一個數字遞增到最后一個數字。如果范圍內的第一個值大于第二個值,如COUNT_[11: 8]中所示,序列將從第一個數字遞減到最后一個數字。
枚舉數據類型標簽作用域
枚舉數據類型列表中的標簽在聲明和使用標簽的范圍內必須是唯一的。可以包含枚舉數據類型聲明的RTL建模范圍是模塊、接口、包、begin-end塊、任務、函數和$unit聲明空間。
以下代碼片段將導致錯誤,因為枚舉標簽 GO在同一模塊范圍內使用兩次:
可以通過將至少一個枚舉數據類型聲明放在具有自己的名稱范圍的begin-end塊中來糾正上例中的錯誤。
如上圖所示為begin-end塊命名不是必需的,但有助于記錄代碼的可讀性和維護性。
從包中導入枚舉數據類型
自定義枚舉數據類型可以在一個包中定義,它允許多個設計塊和驗證代碼使用相同的定義。
筆記 |
---|
枚舉數據類型定義的顯式導入不會導入該定義中使用的標簽。 |
使用包的通配符導入是解決此限制的最簡單方法 。通配符導入使包中的所有內容都可用。
從包導入自定義枚舉數據類型定義時,只導入自定義名稱。枚舉列表中的值標簽不會自動導入,并在導入枚舉數據類型名稱的名稱空間中顯示。下面的代碼片段將不起作用。
為了同時導入枚舉數據類型標簽,必須顯式導入每個標簽,或者必須通配符導入包-通配符導入將使枚舉數據類型名稱和枚舉標簽在import語句的范圍內可見。下面的部分示例顯示了通配符導入的使用。
從多個包進行通配符導入時必須小心。如果在多個包中定義了標識符(名稱),并且兩個包都使用通配符導入,則會發生編譯或細化錯誤。對于這種情況,要使用的標識符必須顯式導入或直接導入。SV包定義中討論了如何使用多個軟件包。
枚舉數據類型分配規則
大多數SystemVerilog變量類型都是弱類型的,這意味著任何數據類型的值都可以分配給變量,該值將使用SystemVerilog標準中指定的轉換規則轉換為變量類型。
枚舉類型不在 SV的這個一般原則內。枚舉數據類型變量是半強類型的,這意味著只能為該變量指定特定的數據類型。
只能為枚舉數據類型變量賦值:
枚舉數據類型列表中的標簽。
同一類型的另一個枚舉數據類型變量。也就是說,這兩個變量都是使用相同的自定義或匿名枚舉數據類型定義聲明的。
轉換為自定義枚舉數據類型的值,
使用以下定義和枚舉變量舉例說明這些規則:
如下所述,state 和 next_state分配枚舉變量既是合法的也是非法的:
筆記 |
---|
枚舉數據類型的強類型規則僅適用于對枚舉變量的賦值。存儲在枚舉變量中的值只是一個值,在表達式(如比較和數學運算)中不受限制地使用。 |
對枚舉數據類型值的操作。對枚舉數據類型變量執行操作時,枚舉變量的值將轉換為枚舉數據類型定義的基類型。操作的結果不再是枚舉數據類型,結果可以分配給常規的、弱類型的變量,但不能分配回枚舉變量。
logic[2:0]temp;//非枚舉變量 temp = next_state + 1;//合規的:temp是弱類型的 state = next_state + 1;//非法的:next_state + 1不是枚舉表達式 state++;//非法的:++的結果不是枚舉表達式 state += next_state;//非法的:+=的結果不是枚舉表達式
將表達式強制轉換為枚舉數據類型。任何值都可以強制轉換為自定義枚舉數據類型,然后分配給該枚舉數據類型的變量,即使該值與枚舉定義的某個標簽不匹配,
在RTL建模中,有時需要將非枚舉表達式強制轉換為枚舉數據類型。然而,使用cast運算符(后面將詳細討論)時必須小心。將一個值強制放入不在枚舉列表中的枚舉變量可能會導致錯誤行為;無論是在仿真還是在綜合中。使用強制轉換會給設計工程師帶來負擔,因為要確保枚舉變量中只強制輸入有效值。這與弱類型的正則變量沒有什么不同,設計工程師需要確保指定的值是有效的。
SystemVerilog還有一個cast系統功能,可以自動驗證cast操作的結果。不幸的是,對于RTL設計人員來說,cast不受一些主要綜合編譯器的支持,cast在驗證測試臺上很有用,但不被認為是可綜合的結構體。
枚舉類型的專用系統任務和方法
枚舉數據類型有幾個內置函數,稱為方法methods,用于遍歷枚舉數據類型列表中的值。這些方法會自動處理枚舉數據類型的半強類型性質,這樣做很容易,比如遞增到枚舉數據類型列表中的下一個值,以及跳到列表的開頭或結尾。使用這些方法,不需要知道標簽名稱。
筆記 |
---|
在撰寫本文時,一些綜合編譯器支持枚舉數據類型方法,但并非所有綜合編譯器都普遍支持。 |
枚舉數據類型方法對硬件行為建模的用處有限。它們只能通過賦值語句實現的快捷方式。由于枚舉數據類型方法的綜合限制,本文僅簡要介紹了這些方法,并給出了一個簡單的示例。
調用枚舉方法的方法是將方法名附加到枚舉數據類型變量名的末尾,并以句點(.)作為分隔符。這些方法是:
<枚舉變量名>.first-返回指定變量的枚舉列表中第一個成員的值。
<枚舉變量名>.last-返回枚舉列表中最后一個成員的值。
<枚舉變量名>.next(N)-返回枚舉列表中下—個成員的值。可以用一個整數值作為 next 的參數。在這種情況下, 從枚舉變量的當前位置算起, 返回后面第 N 個成員的值。如果到達了枚舉列表的末尾, 則會返回到列表的開頭。如果枚舉變量的當前值不在枚舉列表中, 則返回列表中第一個成員的值。
<枚舉變量名>.prev(N))-返回枚舉列表中前一個成員的值。同 ne*t 的方法一樣.可以給 prev 指定一個整數參數 。在這種情況下, 從枚舉變量的當前位S算起, 返回前面第 N 個成員的值。如果到達枚舉列表的開頭, 則會返冋到列表的末尾。如果枚舉變量 當前值不在枚舉列表中 , 則返回列表中敁后一個成員的值。
<枚舉變量名>.num-返回變量枚舉列表中的標簽個數。
<枚舉變量名>.name-返回枚舉變里中代表這個值的字符串。如果這個值不在枚舉變M列表中, 則返回一個空字符串。
打印枚舉數據類型。枚舉數據類型值可以打印為標簽的實際值,也可以打印為標簽的名稱。直接打印枚舉數據類型變量將打印枚舉數據類型變量的當前實際邏輯值。使用name方法可以打印表示當前值而不是實際值的標簽。
舉一個使用枚舉方法的例子,這個例子演示了如何使用其中一些枚舉數據類型方法來建模狀態機序列器。該模型是一個狀態機,可以設置或清除數據同步標志。如果數據匹配輸入在至少8個連續時鐘周期內為真,則設置數據同步標志;如果數據匹配輸入在多個連續時鐘周期內為假,則清除數據同步標志,清除數據同步標志所需的連續假數據匹配數取決于有多少連續周期數據匹配為真,
圖4-1顯示了該狀態機的狀態流。狀態機可以遞增或遞減的計數器。計數器統計已發生的連續數據匹配數,最多為16。請注意,對于大多數狀態,計數器要么遞增1,要么遞減2。next和prev枚舉數據類型方法可以非常簡潔地仿真這種遞增或遞減行為,但某些綜合編譯器可能不支持這種方法。
圖4-1:置信計數器(confidence counter))狀態機的狀態圖 示例4-5:對置信計數器狀態機使用枚舉數據類型方法
// //Book,"RTLModelingwithSystemVerilogforASICandFPGADesign" //byStuartSutherland // //Statemachinemodelforaconfidencecountermodeledusing //enumeratedtypemethods. // //Copyright2016,StuartSutherland.Allrightsreserved. // //Version1.0 // `begin_keywords"1800-2012"http://useSystemVerilog-2012keywords moduleconfidence_counter (inputlogicdata_matches,compare_en,rstN,clk, outputlogicdata_synched ); timeunit1ns/1ns; typedefenumlogic[3:0]{COUNT[0:15]}states_enum_t; states_enum_tCurState,NextState; //sequentialblock always_ff@(posedgeclk,negedgerstN) if(!rstN)CurState<=?COUNT0; ????else???????CurState?<=?NextState; ??//?next?state?combination?logic?block ??always_comb?begin ????if?(!compare_en) ??????NextState?=?CurState;??//?not?comparing?(no?state?change) ????else?if?(data_matches)???//?compare_en?&&?data_matches ??????case?(CurState) ????????COUNT15?:?;?//?can't?increment?past?15 ????????default:?NextState?=?CurState.next;??//?increment?by?1 ??????endcase ????else?????????????????????//?compare_en?&&?!data_matches ??????case?(CurState) ????????COUNT0?:?;?//?can't?decrement?below?0 ????????COUNT1?:?NextState?=?CurState.prev(1);??//?decrement?by?1 ????????default:?NextState?=?CurState.prev(2);??//?decrement?by?2 ??????endcase ??end ??//?register?output?block ??always_ff?@(posedge?clk,?negedge?rstN) ????if?(!rstN) ??????data_synched?<=?0; ????else ??????begin ????????if?(CurState?==?COUNT8) ??????????data_synched?<=?1; ????????else?if?(CurState?==?COUNT0) ??????????data_synched?<=?0; ??????end endmodule:?confidence_counter `end_keywords
沒有枚舉數據類型的傳統Verilog編碼風格
Verilog語言在成為SystemVerilog之前沒有枚舉數據類型。要為數據值創建標簽,必須定義一個parameter或localparam常量來表示每個值,并為該常量指定一個值。或者,可以使用'define宏定義一組宏名稱,每個名稱都有特定的值。
使用parameter創建標簽的一些示例如下:
請注意,在使用parameters時,state和nex_state變量是reg類型的通用變量,而不是枚舉變量。這些通用變量是弱類型的,這意味著任何值都可以分配給變量。使用弱類型的賦值規則,以下賦值語句是合法賦值,但屬于功能性錯誤:
這種編碼錯誤可能是枚舉數據類型變量的語法錯誤。使用傳統的Verilog風格的參數和通用變量類型并不能防止像這樣的意外編碼錯誤。
SystemVerilog(十二)-$unit聲明空間
SystemVerilog(十一)-SystemVerilog 包
原文標題:SystemVerilog(十三)-枚舉數據類型
文章出處:【微信公眾號:OpenFPGA】歡迎添加關注!文章轉載請注明出處。
-
數據
+關注
關注
8文章
6890瀏覽量
88826 -
硬件
+關注
關注
11文章
3252瀏覽量
66112 -
軟件包
+關注
關注
0文章
101瀏覽量
11583
原文標題:SystemVerilog(十三)-枚舉數據類型
文章出處:【微信號:Open_FPGA,微信公眾號:OpenFPGA】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論