記錄幾個SystemVerilog的語法——數(shù)據(jù)和類
掃描二維碼
隨時隨地手機看文章
1
基礎知識
1. 使用SystemVerilog語言有什么好處?
SystemVerilog語言提供了統(tǒng)一的硬件設計和硬件驗證語言,有以下幾個主要特點:
支持行為級、寄存器傳輸級和門級的硬件電路建模;
支持覆蓋率、斷言、面向?qū)ο缶幊?/span>和受約束的隨機驗證來搭建驗證環(huán)境;
支持應用程序接口(APIs)與其它編程語言進行交互;
2. 設計元素(Design element)
設計元素在SystemVerilog中指module、program、interface、checker、package、primitive或configuration。這些概念分別用關(guān)鍵字: module, program, interface, checker, package, primitive, and config。設計元素是對設計電路和驗證環(huán)境進行建模的主要模塊,這些模塊提供了一個容器,用于聲明和執(zhí)行特定的任務。
Module:主要用于代表設計模塊,但也可以作為驗證代碼的容器和作為驗證模塊與設計模塊交互的容器。
Program:主要用于對驗證環(huán)境進行建模。Programs塊主要有三個基本用處:1. 提供驗證環(huán)境執(zhí)行的入口點;2. 創(chuàng)建一個封裝數(shù)據(jù)、task和function的作用范圍;3. 用于指定代碼在Reactive區(qū)域調(diào)度。Program把設計模塊和驗證環(huán)境分離開來,讓它們在time slot的不同region里順序執(zhí)行,因此可以避免設計和驗證的時序競爭情況。Program塊可以包含data declarations、class definitions、subroutine definitions、object instances、one or more initial或final procedures。它不能包含always procedure、primitive instance、module instance、interface instance或other program instances。
Interface:Interface用于將設計模塊和設計模塊連接起來,也用于將設計模塊和驗證模塊連接起來。它的功能挺強大的,除了module例化外,其它都可以在它內(nèi)部使用,意味著它可以包含initial和always塊、task、function、SVA、covergroups、classes、parameter、constant和其它interface。
Checker:checker是封裝了斷言和建模代碼的驗證塊。Checker目的是用于驗證庫單元或作為創(chuàng)建形式化驗證中使用的抽象輔助模型的塊。
Package:package提供了一個聲明空間,這個空間可以被其他塊共享。其他塊可以使用import語法來包含package中的聲明。
Primitive:Primitives用于代表低層級的門級電路和開關(guān)。SystemVerilog包含許多內(nèi)建的primitive類型。設計者可以使用user-defined primitives(UDPs)來增補內(nèi)建primitives。
Configuration:SystemVerilog提供了指定設計configurations的能力,通過指定module例化的bingding信息來指定SystemVerilog源代碼。
3. 仿真時間單位和精度
時間單位(time unit)和時間精度(time precision)可以用兩種方式指定:
使用`timescale編譯指導符:給全部設計元素指定默認的時間單位和精度,但如果某些設計元素內(nèi)部包含有timeunit和timeprecision,那么將采用它們內(nèi)部的。如果有多個`timescale,文件排布不同,可能會影響仿真結(jié)果。
使用timeunit和timeprecision關(guān)鍵字:timeunit和timeprecision可以在設計元素內(nèi)直接指定,不管文件如何排布,都不會影響該設計元素內(nèi)的仿真結(jié)果。
4. event simulation (基于事件的仿真)
SystemVerilog語言是根據(jù)離散事件執(zhí)行模型來定義的。SystemVerilog是由執(zhí)行線程或process組成的。Process對象擁有狀態(tài),并可以根據(jù)它們輸入的變化來產(chǎn)生輸出。Process是并發(fā)調(diào)度的,例如initial程序。還有其他process包含但不限制于primitives、intial、always、always_comb、always_latch和always_ff procedure、continuous assignments、asynchronous task、procedural assignment statements(過程賦值語句)。
在SystemVerilog仿真中,net或variable的任何狀態(tài)改變都被認為是一次update event。process對update events很敏感,當有執(zhí)行update event時,所有對該event敏感的processes都將按照任意順序進行evaluation。process的evaluation也被認為是event,稱為evaluation event。
5. Time slot
在特定時間的所有調(diào)度事件定義一個time slot。在仿真時,按照時間順序執(zhí)行并刪除當前仿真time slot中的所有事件后,才能移動到下一個非空的time slot繼續(xù)進行仿真。Time slot按大類分主要有5個:Preponed、Active、Observed、Reactive和Postponed。
我們常用的#1step指的就是在進入當前slot時去采樣,即在當前time slot的preponed region采樣。在preponed region采樣等價于在previous postponed region采樣。
#0會使本應該在active events region執(zhí)行的process(event)被調(diào)度到inactive region去執(zhí)行。
$monitor和$strobe是在Postponed region執(zhí)行的。
2
數(shù)據(jù)類型
1. 區(qū)別data type和data object
data type類似于class type,然后data object類似于class object,相當于一個entity。所以data type可以用于聲明data object。每一個data object是一個命名的entity,它帶有一個data value和data type。比如:
int是一個data?type;int?a=1; ?//a就是一個data?object;
2. 區(qū)別singular和aggregate類型
Data type可以被分類為singular或aggregate。除了unpacked structure、unpacked union、unpacked arrary,其它的data type都是singular type。unpacked structure、unpacked union、unpacked arrary都是aggregate type。一個singular variable或expression代表一個value、symbol或handle。Aggregate expressions和variables代表一組singular value。之所以這樣分類,是因為方便operators和functions可以更方便的引用這些data types。
3. 區(qū)別nets和variables類型
Data objects主要可以分為兩組:variables和nets。這兩組的不同之處在于它們賦值和保持value的方式。
Net可以被一個或多個continuous assignment、primitive output、module port賦值。variable可以被一個或多個procedural statements賦值(包括procedural continuous assignment)。
Net可以在declaration的時候,implicit連續(xù)賦值。但variable如果在declaration的時候也給了assignment,那也只是相當于給該variable初始化,而不是continuous assignment。
有兩個不同類型的net types:built-in和user-defined。Net type主要是模擬物理連線,因此net通常不能store value(除了trireg net)。Net的值取決于它的drivers,例如continuous assignment或gate。如果沒有driver的話,那么它的值將會是高組態(tài)。built-in的net types有:wire、tri、tri0、tri1、trireg、triand、trior、wand、wor、supply0、supply1和uwire。
wire和tri是相同的語法和功能,提供兩個名字主要是用于建模指示不同的目的。wire用于被single gate或continuous assignment驅(qū)動的nets,tri用于被多個drivers驅(qū)動的nets。如果有多個drivers具有相同的logical conflicts,那么結(jié)果就是x態(tài)。
Variable是data storage element的抽象,它可以儲存value。
4. 區(qū)別Scalar和Vector
在reg、logic或bit定義中,scalar是1bit位寬;vector是多bit位寬。
5. packed arrays和unpacked array的區(qū)別
Packed array是聲明在數(shù)據(jù)標識符名字之前的維度,可以是1維或多維的,1維的也稱為向量vector。Unpacked arrary是聲明在數(shù)據(jù)標識符名字之后的維度,可以1維或多維的。
Packed arrays可以將vector分為subfields,這樣可以方便的訪問到array中的元素。因此,packed array需要連續(xù)的bit存儲。
固定size的unpacked arrary用以下兩種方式聲明都可以的:
int?Array[0:7][0:31]; ?//?array?declaration?using?rangesint?Array[8][32]; ? ?//?array?declaration?using?sizes
6. 多維數(shù)組
多維數(shù)組是數(shù)組中包含數(shù)組。多維數(shù)組可以用包括多維來定義的。在標識符名字之前的為packed維度,在標識符名字之后的稱為unpacked維度。
在使用多維數(shù)組時,packed維度在unpacked維度之后,并且最右邊的維度變化最快,如:
bit?[1:10]?v1?[1:5]; ?//?1?to?10?varies most rapidlybit v2?[1:5]?[1:10]; ?//?1?to?10?varies most rapidlybit?[1:5]?[1:10]?v3; ?//?1?to?10?varies most rapidlybit?[1:5]?[1:6]?v4?[1:7]?[1:8]; ?//?1?to?6?varies most rapidly, followed by?1?to?5, then?1?to?8?and then?1?to?7
可以使用typedef分階段定義多個packed維度的數(shù)組,如:
typedef bit?[1:5]?bsix;bsix?[1:10]?v5; //?1?to?5?varies most rapidly
可以使用typedef分階段定義多個unpacked維度的數(shù)組,如:
typedef?bsix?mem_type [0:3]; ?//?array of four?'bsix'?elementsmem_type ba [0:7]; ?//?array of eight?'mem_type'?elements
Part-select指的是選擇一維packed數(shù)組中某1bit或多個連續(xù)bit。
Slice指的是選擇一個數(shù)組中一個或多個連續(xù)的elements。
part-select和slice選擇的size必須是常數(shù),但位置可以是變量,如:
int?i = bitvec[j +: k]; ?// k must be constant.int?a[x:y], b[y:z], e;a = {b[c -: d], e}; ?// d must be constant
7. unpacket和packet數(shù)組訪問方式
數(shù)組的index中如果是超出數(shù)組大小或包含任何的x/z態(tài),那么該index就是無效的。
用invalid index從unpacked數(shù)組讀取內(nèi)容,結(jié)果如下:

用invalid index寫到數(shù)組中,應該是不執(zhí)行任何操作,除了queue中[$+1]的元素操作或者associative array創(chuàng)建新元素。
用invalid index從packed 數(shù)組讀取內(nèi)容,也就是從vector、packed array、packed structure、parameter或concatenation變量中選取某1-bit。用于尋址bit的index如果超出變量范圍或有x態(tài)或有z態(tài),那么對于4-state bit則返回x,對于2-state bit則返回0。對于scalar、real變量和real參數(shù)進行part-select是無效的。
8. 數(shù)組類型
動態(tài)數(shù)組(Dynamic arrary)是unpacked數(shù)組,它的大小在放著運行時是可以改變的。動態(tài)數(shù)組的大小是通過new[]或者賦值來獲得的。
動態(tài)數(shù)組適用于連續(xù)且數(shù)組大小動態(tài)變化的情況。而關(guān)聯(lián)數(shù)組(associative arrarys)可以用于需要存儲的數(shù)據(jù)是分散的。
隊列(queue)是大小可變,并且有順序的數(shù)組。Index=0表示第一個元素,index=$表示最后一個元素。在定義時,可以選擇隊列的最大個數(shù),如果在使用時超過這個最大個數(shù),會有信息提示。對queue[$+1]進行讀寫是可以的,也就queue有這個例外,其它數(shù)組的話,如果沒有提前搞好size,直接這樣搞會報錯的。queue的內(nèi)置方法:
size()、insert()、delete()、pop_front()、pop_back()、push_front()、push_back()
SystemVerilog給數(shù)組也提供了一些新的系統(tǒng)函數(shù)用于返回數(shù)組的一些信息,有$left, $right, $low, $high, $increment, $size, $dimensions和$unpacked_dimensions。
SystemVerilog給數(shù)組提供了幾個內(nèi)建操控方法,用于對數(shù)組進行searching、ordering和reduction。
array locator methods:用于對unpacked 數(shù)組操作,包含find()、find_index()、find_first()、find_first_index()、find_last()、find_last_index()。這幾個方法后面必須帶有with (xxx)。min()、max()、unique()、unique()后面的with關(guān)鍵字可以被省略。
arrary ordering methods:用于對unpacked 數(shù)組的reorder操作,有reverse()、sort()、rsort()、shuffle()。
array reduction methods:用于對unpacked 數(shù)組的操作,有sum()、product()、and()、or()、xor()。
3
類(class)
1. class內(nèi)容
class里面包含data和對data進行操作的subroutines(functions and tasks)。class的data稱為class properties(類屬性),subroutines稱為methods(方法)。兩者都是class的members。
class相當于是定義了一個data type。object是該class的instance。Object handle是持有該class instance的變量。
class里method的生命周期必須為automatic,如果定義成static是非法的(這里不是指static task,而是task內(nèi)static的variables或arguments)
2. class構(gòu)造函數(shù)
SystemVerilog提供了class的構(gòu)造函數(shù),支持在創(chuàng)建object的時候?qū)nstance進行初始化。
如果用戶沒有顯示指定new方法,那么隱藏的new方法將會被自動加上。在子類的new方法里應該首先call父類的new構(gòu)造函數(shù)。
super.new需要在子類構(gòu)造函數(shù)中第一條語句就執(zhí)行,這是因為superclass需要在子class之前被初始化,如果用戶沒有提供superclass的初始化,那么compiler會自動插入super.new。
3. class的static屬性
class中的static屬性可以直接引用,不需要該通過class的instance。
class中的methods也可以是static,static method不能訪問non-static 成員變量(properties或methods),但它可以訪問同個class內(nèi)的static 成員變量。如果它訪問了non-static 成員變量或this關(guān)鍵字句柄,那么會報編譯錯誤。static methods也不能是virtual。
4. shallow copy和deep copy
shallow copy只是復制原有object的properties,但如果原有object里含有object handler,也只是復制handler的值,不會把handler object里的properties也進行復制。Shallow copy也不會創(chuàng)建新的coverage objects(covergroup instances)。
如果要做到連handler里的properties都復制,那么需要deep_copy,deep copy需要user自己實現(xiàn)的。
5. 多級構(gòu)造函數(shù)
如果多層class繼承的話,那么在構(gòu)造函數(shù)里需要調(diào)用父類的構(gòu)造函數(shù)。
如果父類的構(gòu)造函數(shù)需要參數(shù),那么有兩種方法:1. 用super.new(xx)傳進去;2. 在繼承父類class時就傳進去的,用這種方式,在constructor里就別加super.new(xx)了。
父類的new函數(shù)如果不需要參數(shù)(沒有參數(shù)或參數(shù)帶默認值),那么在子類構(gòu)造函數(shù)里對super.new()可寫可不寫,不寫的話,compiler會自動插入。如果父類的構(gòu)造函數(shù)需要傳參數(shù),那么compiler自動插入也只是為super.new(),也不會給你傳參數(shù)值進去的(除非在繼承時指定),這樣simulator會報錯。
記住:如果將new定義為local,那么該類將不可以被繼承的。
在子類構(gòu)造函數(shù)中需要第一條調(diào)用父類構(gòu)造函數(shù)super.new()中,要等super.new()執(zhí)行完之后,才會做子類的property初始化,如果property有指定初始值,那么就賦值,如果沒有指定,那就是undefined的。最后才會繼續(xù)執(zhí)行子類構(gòu)造函數(shù)中super.new()以下的語句。因此在給父類構(gòu)造函數(shù)傳輸參數(shù),如果用子類定義的變量,那么結(jié)果會是undefined的,因此,來不及初始化啊。例子如下:
class?C;? ??int?c1 =?1;? ??int?c2 =?1;? ??int?c3 =?1;? ??function?new(int?a);? ? ? ? c2 =?2;? ? ? ? c3 = a;? ? ?endfunctionendclassclass?D?extends?C;? ??int?d1 =?4;? ??int?d2 = c2;? ??int?d3 =?6;? ? function?new;? ? ? ? super.new(d3);? ? endfunctionendclass
D類對象創(chuàng)建完成后,這些屬性的值如下:
c1的值是1;
c2的值是2,這是因為構(gòu)造函數(shù)賦值發(fā)生在屬性初始化之后;
c3的值是不確定的,這是因為D的構(gòu)造函數(shù)調(diào)用傳遞了d3的值,這個值在super.new(d3)調(diào)用時是未定義的;
d1的值是4;
d2的值是2,這是因為super.new調(diào)用先于d2初始化;
d3的值是6;





