數(shù)字硬件建模SystemVerilog(十一)-SystemVerilog 包
最初的Verilog語言沒有一個(gè)可用于多個(gè)模塊的定義。每個(gè)模塊都必須有任務(wù)、函數(shù)、常量和其他共享定義的冗余副本。傳統(tǒng)的Verilog編碼風(fēng)格是將共享定義放在一個(gè)單獨(dú)的文件中,然后可以使用“include”編譯指令將其包含在其他文件中。該指令指示編譯器復(fù)制包含文件的內(nèi)容,并將這些內(nèi)容粘貼到“include”指令的位置。雖然使用文件包含有助于減少代碼冗余,但對于代碼重用和維護(hù)來說,它是一種笨拙的編碼方式。
SystemVerilog將包(packages)添加到最初的Verilog HDL中。包是可以保存共享定義的聲明空間。多個(gè)模塊和接口可以直接引用這些共享定義,或者通過定義導(dǎo)入特定的包項(xiàng),或者通過導(dǎo)入整個(gè)包來引用這些共享定義。包解決了必須在多個(gè)模塊中復(fù)制定義的問題,以及使用xxx將定義復(fù)制到多個(gè)模塊中的尷尬。
包聲明
SystemVerilog包是在關(guān)鍵字package和endpackage之間定義的。包是一個(gè)獨(dú)立的聲明空間。包的概念繼承于VHDL。它不嵌入Verilog模塊中。包中的定義和聲明稱為包項(xiàng)。包可以包含的可綜合定義包括:
- parameter,localparam和const常量聲明
- typedef用戶自定義類型
- task 和 function定義
- 從其他包import聲明
- 包鏈接的export聲明
- 時(shí)間單位定義
包還可以包含不可綜合的驗(yàn)證定義,例如:類(classe)。本文沒有介紹驗(yàn)證結(jié)構(gòu)體。
`begin_keywords"1800-2012"//useSystemVerilog-2012keywords
packagedefinitions_pkg;
timeunit1ns/1ns;
parameterVERSION="1.1";
`ifdef_64bit
typedeflogic[63:0]word_t;
`elsif_32bit
typedeflogic[31:0]word_t;
`else//defaultis16bit
typedeflogic[15:0]word_t;
`endif
typedefenumlogic[1:0]{ADD,SUB,MULT}opcodes_t;
typedefstruct{
word_ta,b;
opcodes_topcode_e;
}instruction_t;
functionautomaticword_tmultiplier(inputword_ta,b);
//codeforacustomn-bitmultiplier
endfunction
endpackage:definitions_pkg
`end_keywords
本文后面將討論示例4-1中所示的枚舉enum和結(jié)構(gòu)體struct構(gòu)造。示例中的word_t用戶自定義類型定義位于’ifdef條件編譯指令中,該指令將word_t定義為16位向量、32位向量或64位向量?!癷fdef構(gòu)造允許工程師選擇調(diào)用編譯器時(shí)要編譯的代碼。所有使用word_t用戶自定義類型的設(shè)計(jì)模塊將使用編譯包時(shí)選擇的word大小。
最佳實(shí)踐指南4-1 |
---|
對包常量僅使用localparam或const定義。不要在包中使用parameter定義 |
包中定義的parameter與模塊中定義的parameter不同??梢詾槟K的每個(gè)實(shí)例重新定義模塊級parameter常量。無法對包中parameter重新定義,因?yàn)樗皇悄K實(shí)例的一部分。在包中,parameter與localparam相同。
使用包項(xiàng)
包中的定義和聲明稱為包項(xiàng)。模塊和接口可以通過四種方式引用包項(xiàng):
- 通配符導(dǎo)入所有包項(xiàng)
- 顯式地導(dǎo)入特定包項(xiàng)
- 明確導(dǎo)入特定包和包項(xiàng)
- 將包項(xiàng)導(dǎo)入$unit聲明空間
本節(jié)將討論引用包項(xiàng)目的前三種方法。后面章節(jié)將討論導(dǎo)入$unit聲明空間中。
包項(xiàng)目的通配符導(dǎo)入(wildcard import)
模塊引用包項(xiàng)的最簡單也是最常見的方法是使用通配符導(dǎo)入語句從包中導(dǎo)入所有項(xiàng)。例如:

包名稱后面的(::)雙冒號是作用域解析運(yùn)算符。它指示編譯器在另一個(gè)位置(范圍)查找信息——本例中是definitions_pkg包。
星號(*)是通配符標(biāo)記。通配符有效地將導(dǎo)入的包添加到SystemVeriog使用的搜索路徑中。
當(dāng)SystemVerilog編譯器遇到標(biāo)識符(名稱)時(shí),它將首先在本地范圍內(nèi)搜索該標(biāo)識符的定義。本地范圍內(nèi)可以是任務(wù)、函數(shù)、begin-end塊、模塊、接口或包。如果在本地范圍中找不到標(biāo)識符定義;接下來,編譯器將搜索下一個(gè)作用域級別,直到到達(dá)模塊、接口或包邊界。如果未找到標(biāo)識符定義,則搜索任何通配符導(dǎo)入的包;最后,工具將在$unit聲明空間中搜索。通配符導(dǎo)入搜索規(guī)則的完整語義規(guī)則比這個(gè)描述更復(fù)雜,并在IEEE 1800 SystemVerilog標(biāo)準(zhǔn)中定義。
示例4-2演示了如何使用通配符導(dǎo)入語句。
`begin_keywords"1800-2012"//useSystemVerilog-2012keywords
modulealu
(inputdefinitions_pkg::instruction_tiw,
inputlogicclk,
outputdefinitions_pkg::word_tresult
);
always_ff@(posedgeclk)begin
case(iw.opcode)
definitions_pkg::ADD:result=iw.a+iw.b;
definitions_pkg::SUB:result=iw.a-iw.b;
definitions_pkg:result=definitions_pkg::
multiplier(iw.a,iw.b);
endcase
end
endmodule:alu
`end_keywords
在本例中,通配符導(dǎo)入的作用是將definitions_pkg包添加到模塊的標(biāo)識符搜索路徑。端口列表可以引用instruction_t用戶自定義類型,編譯器將在包中找到該定義。同樣,case語句可以引用opcode使用的枚舉數(shù)據(jù)類型標(biāo)簽,這些標(biāo)簽的定義也將在包中找到。
但是, 當(dāng)包中的一項(xiàng)或多項(xiàng)需要在模塊中多次引用時(shí),每次顯式地引用包的名稱則太過麻煩了, 我們希望將包中包項(xiàng)導(dǎo)入到設(shè)計(jì)塊中(使用通配符全部導(dǎo)入)。
顯式地導(dǎo)入特定包項(xiàng)
SystemVerilog還允許將特定的包項(xiàng)導(dǎo)入模塊,而無需將整個(gè)包添加到該模塊的標(biāo)識符搜索路徑中。
顯式地導(dǎo)入特定包項(xiàng)的一般語法為:
importpackage_name::item_name;
例4-3,使用顯式地導(dǎo)入將特定的包項(xiàng)帶入模塊。顯式導(dǎo)入比使用通配符導(dǎo)入更簡單,也使模塊更具自文檔性,很容易看出從包中使用了哪些包項(xiàng)。
`begin_keywords"1800-2012"//useSystemVerilog-2012keywords
modulealu
importdefinitions_pkg::instruction_t,
definitions_pkg::word_t;
(inputinstruction_tiw,
inputlogicclk,
outputword_tresult
);
importdefinitions_pkg::ADD;
importdefinitions_pkg::SUB;
importdefinitions_pkg::MULT;
importdefinitions_pkg::multiplier;
always_combbegin
case(iw.opcode)
ADD:result=iw.a+iw.b;
SUB:result=iw.a-iw.b;
MULT:result=multiplier(iw.a,iw.b);
endcase
end
endmodule:alu
`end_keywords
筆記 |
---|
枚舉數(shù)據(jù)類型定義的顯式導(dǎo)入不會導(dǎo)入該定義中使用的標(biāo)簽,所以對于枚舉數(shù)據(jù)類型定義的標(biāo)簽也必須顯式導(dǎo)入。后面會詳細(xì)介紹 |
聲明包導(dǎo)入的位置
聲明包導(dǎo)入的位置語句,無論是通配符導(dǎo)入還是特定包項(xiàng)導(dǎo)入:
- 在模塊端口列表之前——包項(xiàng)可以在端口定義和模塊內(nèi)使用。
- 在模塊端口列表之后-包項(xiàng)可以在模塊內(nèi)使用,但不能在端口定義內(nèi)使用。
- 模塊定義之外——將包項(xiàng)導(dǎo)入偽全局unit聲明空間及其危害。
筆記 |
---|
在SystemVerilog-2009標(biāo)準(zhǔn)中添加了模塊端口列表之前聲明包導(dǎo)入語句。在SystemVerilog-2005中,聲明包導(dǎo)入語句只能出現(xiàn)在端口列表之后,或者出現(xiàn)在unit聲明空間中。 |
使用作用域解析運(yùn)算符直接導(dǎo)入包
作用域解析運(yùn)算符(::)可用于通過指定包名稱和包中的特定項(xiàng)直接引用包項(xiàng)。
示例4-4使用作用域解析運(yùn)算符引用了前面示例4-1中所示的包中定義的幾個(gè)包項(xiàng):
`begin_keywords"1800-2012"//useSystemVerilog-2012keywords
modulealu
importdefinitions_pkg::*;//wildcardimport
(inputinstruction_tiw,
inputlogicclk,
outputword_tresult
);
always_combbegin
case(iw.opcode)
ADD:result=iw.a+iw.b;
SUB:result=iw.a-iw.b;
MULT:result=multiplier(iw.a,iw.b);
endcase
end
endmodule:alu
`end_keywords
顯式引用包項(xiàng)有助于記錄設(shè)計(jì)源代碼。在示例4-4中,包名的使用使得找到instruction_t,word_t ADD, SUB, MULT 和 multiplier定義的地方變得很明顯。但是,對于包項(xiàng)的每次使用,顯式引用包名稱比較冗長。聲明包導(dǎo)入語句的一種更常見的方法是導(dǎo)入整個(gè)包,如前文所述。只有當(dāng)多個(gè)包中有同名的定義,并且需要指明要從哪個(gè)包導(dǎo)入包項(xiàng)時(shí),才需要本節(jié)中顯式引用包。
多個(gè)包導(dǎo)入
較大的設(shè)計(jì)項(xiàng)目通常會使用幾個(gè)包。一個(gè)模塊或接口可以根據(jù)需要從任意多個(gè)包中導(dǎo)入。
導(dǎo)入多個(gè)包時(shí),注意避免名稱沖突。使用通配符導(dǎo)入時(shí)尤其如此。在下面的代碼片段中,包cpu_pkg和gpu_pkg都有一個(gè)名為instruction_t的標(biāo)識符(包項(xiàng))。

在這個(gè)代碼片段中:兩個(gè)包中都定義了一個(gè)instruetion_t標(biāo)識符,并且兩個(gè)包都是通配符(::)導(dǎo)入的,變量instruction被聲明為instruction_t類型。當(dāng)仿真器、綜合編譯器或其他軟件工具搜索instruction_t的定義時(shí),它會在兩個(gè)通配符導(dǎo)入的包中找到一個(gè)定義,并且不知道使用哪個(gè)定義。多個(gè)定義將導(dǎo)致編譯或細(xì)化(Elaboration:是將設(shè)計(jì)組件綁定在一起的過程。Elaboration包括創(chuàng)建實(shí)例化,計(jì)算參數(shù)值,解析分層名稱和連接nets。通常在引用compilation 和 elaboration階段時(shí),它們不會被區(qū)分,但通常直接被稱為compilation。換句話說,“編譯時(shí)錯(cuò)誤”可能指的是run-time階段之前的任何時(shí)間的錯(cuò)誤。)錯(cuò)誤。
當(dāng)存在多個(gè)定義時(shí),源代碼必須顯式引用或顯式導(dǎo)入要在該模型中使用的定義,例如:

顯式包引用優(yōu)先于本地定義或包的顯式導(dǎo)入,后者優(yōu)先于通配符導(dǎo)入。前面代碼段中的顯式導(dǎo)入解決了processor模塊中使用instruction_t定義時(shí)的模糊性。
包鏈
一個(gè)包可以顯式地從另一個(gè)包導(dǎo)入定義,也可以通配符導(dǎo)入另一個(gè)包。但是,導(dǎo)入的項(xiàng)目在該包外不會自動(dòng)可見??紤]下面的例子:

為了讓模塊alu使用來自兩個(gè)包的定義,兩個(gè)包都需要導(dǎo)入到模塊alu。SystemVerilog能夠鏈接包,因此模塊只需導(dǎo)入鏈中的最后一個(gè)包,即前面代碼段中的alu_types_pkg。包鏈?zhǔn)峭ㄟ^包組合導(dǎo)入和導(dǎo)出語句來完成的。

export語句可以顯式導(dǎo)出特定項(xiàng),或使用通配符導(dǎo)出從另一個(gè)包導(dǎo)入所有項(xiàng)。請注意,使用通配符導(dǎo)出時(shí),僅導(dǎo)出包中實(shí)際使用的定義。在前面的片段中;base_types_pkg中word32_t的定義未在alu_types_pkg中使用,因此未鏈接,并且在alu模塊中不可用。下面的顯式導(dǎo)出可以添加到上面的alu_types_pkg示例中,鏈接到word32_t,這樣它就可以在alu模塊中使用。

筆記 |
---|
在寫這本文的時(shí)候,一些仿真器和綜合編譯器還不支持包鏈。包鏈的export聲明是SystemVerilog-2009標(biāo)準(zhǔn)的一部分。SystemVerilog-2005標(biāo)準(zhǔn)沒有定義進(jìn)行包鏈的方法。 |
包的編譯順序
SystemVerilog要求在引用包定義之前對其進(jìn)行編譯。這意味著編譯包和模塊時(shí)存在文件順序依賴關(guān)系——必須先編譯包。這也意味著引用包項(xiàng)的模塊不能獨(dú)立編譯。如果工具支持單獨(dú)的文件編譯,則包必須與模塊一起編譯,或者已經(jīng)預(yù)編譯。
確保在引用包或包項(xiàng)的任何文件之前編譯包的一種方法是控制編譯命令中列出文件的順序。
文件編譯順序通常由Linux“make”文件控制。也可以使用Verilog命令文件(使用-f調(diào)用選項(xiàng)讀取)和腳本或批處理文件。
確保在引用包或包項(xiàng)的任何文件之前編譯包的另一種方法是使用’include 編譯指令指示編譯器讀取包含包的文件,’include指令放在包含對包項(xiàng)引用的每個(gè)設(shè)計(jì)或測試臺文件的開頭。

使用“include指令”時(shí)需要注意一點(diǎn),SystemVerilog不允許在同一編譯中多次包含同一個(gè)包??梢酝ㄟ^放置’ifdef(“if defined-定義”)或’ifndef(“if not defined-未定義”)來實(shí)現(xiàn)圍繞包定義的條件編譯指令,以便編譯器跳過已編譯的包。條件編譯指令允許SystemVerilog源代碼根據(jù)宏名是否已使用’define指令定義進(jìn)行選擇性編譯。
下面的示例使用’ifndef條件編譯指令圍繞包。當(dāng)包含包的文件被編譯器讀入時(shí),“未定義”測試將為真,包將被編譯。編譯的代碼行包含一個(gè)’define指令,該指令設(shè)置了使用的宏名稱。如果在編譯器的同一調(diào)用過程中再次讀取此文件,“未定義”測試將為false,并且將跳過’ifndef和endif之間的代碼。

綜合條件
為了能夠進(jìn)行綜合,包中定義的任務(wù)和函數(shù)必須聲明為自動(dòng)的(automatic),并且不能包含靜態(tài)變量。此規(guī)則的原因是,綜合將在引用包任務(wù)或函數(shù)的每個(gè)模塊或接口中復(fù)制任務(wù)或函數(shù)。如果任務(wù)或函數(shù)在仿真中有靜態(tài)存儲,那么該存儲將由任務(wù)或函數(shù)的所有引用共享,這是一種與復(fù)制不同的行為。通過將任務(wù)或函數(shù)聲明為自動(dòng)的,每次調(diào)用它時(shí)都會分配新的存儲,使其行為與任務(wù)或函數(shù)的唯一副本相同。這確保了對包任務(wù)或函數(shù)的預(yù)綜合引用的仿真行為與后綜合行為相同。
出于仿真的原因,綜合不支持包中的變量聲明。在仿真中,一個(gè)包變量由導(dǎo)入該變量的所有模塊共享。一個(gè)模塊可以寫入變量,另一個(gè)模塊將看到新值。這種不通過模塊端口傳遞值的模塊間通信是不可綜合的。
原文標(biāo)題:SystemVerilog(十一)-SystemVerilog 包
文章出處:【微信公眾號:OpenFPGA】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
-
模塊
+關(guān)注
關(guān)注
7文章
2788瀏覽量
50418 -
Verilog
+關(guān)注
關(guān)注
29文章
1367瀏覽量
112300 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4381瀏覽量
64908
原文標(biāo)題:SystemVerilog(十一)-SystemVerilog 包
文章出處:【微信號:Open_FPGA,微信公眾號:OpenFPGA】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
評論