數字硬件建模SystemVerilog(十一)-SystemVerilog 包
最初的Verilog語言沒有一個可用于多個模塊的定義。每個模塊都必須有任務、函數、常量和其他共享定義的冗余副本。傳統的Verilog編碼風格是將共享定義放在一個單獨的文件中,然后可以使用“include”編譯指令將其包含在其他文件中。該指令指示編譯器復制包含文件的內容,并將這些內容粘貼到“include”指令的位置。雖然使用文件包含有助于減少代碼冗余,但對于代碼重用和維護來說,它是一種笨拙的編碼方式。
SystemVerilog將包(packages)添加到最初的Verilog HDL中。包是可以保存共享定義的聲明空間。多個模塊和接口可以直接引用這些共享定義,或者通過定義導入特定的包項,或者通過導入整個包來引用這些共享定義。包解決了必須在多個模塊中復制定義的問題,以及使用xxx將定義復制到多個模塊中的尷尬。
包聲明
SystemVerilog包是在關鍵字package和endpackage之間定義的。包是一個獨立的聲明空間。包的概念繼承于VHDL。它不嵌入Verilog模塊中。包中的定義和聲明稱為包項。包可以包含的可綜合定義包括:
包還可以包含不可綜合的驗證定義,例如:類(classe)。本文沒有介紹驗證結構體。
`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和結構體struct構造。示例中的word_t用戶自定義類型定義位于’ifdef條件編譯指令中,該指令將word_t定義為16位向量、32位向量或64位向量。“ifdef構造允許工程師選擇調用編譯器時要編譯的代碼。所有使用word_t用戶自定義類型的設計模塊將使用編譯包時選擇的word大小。
最佳實踐指南4-1 |
---|
對包常量僅使用localparam或const定義。不要在包中使用parameter定義 |
包中定義的parameter與模塊中定義的parameter不同。可以為模塊的每個實例重新定義模塊級parameter常量。無法對包中parameter重新定義,因為它不是模塊實例的一部分。在包中,parameter與localparam相同。
使用包項
包中的定義和聲明稱為包項。模塊和接口可以通過四種方式引用包項:
- 通配符導入所有包項
- 顯式地導入特定包項
- 明確導入特定包和包項
- 將包項導入$unit聲明空間
本節將討論引用包項目的前三種方法。后面章節將討論導入$unit聲明空間中。
包項目的通配符導入(wildcard import)
模塊引用包項的最簡單也是最常見的方法是使用通配符導入語句從包中導入所有項。例如:
包名稱后面的(::)雙冒號是作用域解析運算符。它指示編譯器在另一個位置(范圍)查找信息——本例中是definitions_pkg包。
星號(*)是通配符標記。通配符有效地將導入的包添加到SystemVeriog使用的搜索路徑中。
當SystemVerilog編譯器遇到標識符(名稱)時,它將首先在本地范圍內搜索該標識符的定義。本地范圍內可以是任務、函數、begin-end塊、模塊、接口或包。如果在本地范圍中找不到標識符定義;接下來,編譯器將搜索下一個作用域級別,直到到達模塊、接口或包邊界。如果未找到標識符定義,則搜索任何通配符導入的包;最后,工具將在$unit聲明空間中搜索。通配符導入搜索規則的完整語義規則比這個描述更復雜,并在IEEE 1800 SystemVerilog標準中定義。
示例4-2演示了如何使用通配符導入語句。
`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
在本例中,通配符導入的作用是將definitions_pkg包添加到模塊的標識符搜索路徑。端口列表可以引用instruction_t用戶自定義類型,編譯器將在包中找到該定義。同樣,case語句可以引用opcode使用的枚舉數據類型標簽,這些標簽的定義也將在包中找到。
但是, 當包中的一項或多項需要在模塊中多次引用時,每次顯式地引用包的名稱則太過麻煩了, 我們希望將包中包項導入到設計塊中(使用通配符全部導入)。
顯式地導入特定包項
SystemVerilog還允許將特定的包項導入模塊,而無需將整個包添加到該模塊的標識符搜索路徑中。
顯式地導入特定包項的一般語法為:
importpackage_name::item_name;
例4-3,使用顯式地導入將特定的包項帶入模塊。顯式導入比使用通配符導入更簡單,也使模塊更具自文檔性,很容易看出從包中使用了哪些包項。
`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
筆記 |
---|
枚舉數據類型定義的顯式導入不會導入該定義中使用的標簽,所以對于枚舉數據類型定義的標簽也必須顯式導入。后面會詳細介紹 |
聲明包導入的位置
聲明包導入的位置語句,無論是通配符導入還是特定包項導入:
- 在模塊端口列表之前——包項可以在端口定義和模塊內使用。
- 在模塊端口列表之后-包項可以在模塊內使用,但不能在端口定義內使用。
- 模塊定義之外——將包項導入偽全局unit聲明空間及其危害。
筆記 |
---|
在SystemVerilog-2009標準中添加了模塊端口列表之前聲明包導入語句。在SystemVerilog-2005中,聲明包導入語句只能出現在端口列表之后,或者出現在unit聲明空間中。 |
使用作用域解析運算符直接導入包
作用域解析運算符(::)可用于通過指定包名稱和包中的特定項直接引用包項。
示例4-4使用作用域解析運算符引用了前面示例4-1中所示的包中定義的幾個包項:
`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
顯式引用包項有助于記錄設計源代碼。在示例4-4中,包名的使用使得找到instruction_t,word_t ADD, SUB, MULT 和 multiplier定義的地方變得很明顯。但是,對于包項的每次使用,顯式引用包名稱比較冗長。聲明包導入語句的一種更常見的方法是導入整個包,如前文所述。只有當多個包中有同名的定義,并且需要指明要從哪個包導入包項時,才需要本節中顯式引用包。
多個包導入
較大的設計項目通常會使用幾個包。一個模塊或接口可以根據需要從任意多個包中導入。
導入多個包時,注意避免名稱沖突。使用通配符導入時尤其如此。在下面的代碼片段中,包cpu_pkg和gpu_pkg都有一個名為instruction_t的標識符(包項)。
在這個代碼片段中:兩個包中都定義了一個instruetion_t標識符,并且兩個包都是通配符(::)導入的,變量instruction被聲明為instruction_t類型。當仿真器、綜合編譯器或其他軟件工具搜索instruction_t的定義時,它會在兩個通配符導入的包中找到一個定義,并且不知道使用哪個定義。多個定義將導致編譯或細化(Elaboration:是將設計組件綁定在一起的過程。Elaboration包括創建實例化,計算參數值,解析分層名稱和連接nets。通常在引用compilation 和 elaboration階段時,它們不會被區分,但通常直接被稱為compilation。換句話說,“編譯時錯誤”可能指的是run-time階段之前的任何時間的錯誤。)錯誤。
當存在多個定義時,源代碼必須顯式引用或顯式導入要在該模型中使用的定義,例如:
顯式包引用優先于本地定義或包的顯式導入,后者優先于通配符導入。前面代碼段中的顯式導入解決了processor模塊中使用instruction_t定義時的模糊性。
包鏈
一個包可以顯式地從另一個包導入定義,也可以通配符導入另一個包。但是,導入的項目在該包外不會自動可見。考慮下面的例子:
為了讓模塊alu使用來自兩個包的定義,兩個包都需要導入到模塊alu。SystemVerilog能夠鏈接包,因此模塊只需導入鏈中的最后一個包,即前面代碼段中的alu_types_pkg。包鏈是通過包組合導入和導出語句來完成的。
export語句可以顯式導出特定項,或使用通配符導出從另一個包導入所有項。請注意,使用通配符導出時,僅導出包中實際使用的定義。在前面的片段中;base_types_pkg中word32_t的定義未在alu_types_pkg中使用,因此未鏈接,并且在alu模塊中不可用。下面的顯式導出可以添加到上面的alu_types_pkg示例中,鏈接到word32_t,這樣它就可以在alu模塊中使用。
筆記 |
---|
在寫這本文的時候,一些仿真器和綜合編譯器還不支持包鏈。包鏈的export聲明是SystemVerilog-2009標準的一部分。SystemVerilog-2005標準沒有定義進行包鏈的方法。 |
包的編譯順序
SystemVerilog要求在引用包定義之前對其進行編譯。這意味著編譯包和模塊時存在文件順序依賴關系——必須先編譯包。這也意味著引用包項的模塊不能獨立編譯。如果工具支持單獨的文件編譯,則包必須與模塊一起編譯,或者已經預編譯。
確保在引用包或包項的任何文件之前編譯包的一種方法是控制編譯命令中列出文件的順序。
文件編譯順序通常由Linux“make”文件控制。也可以使用Verilog命令文件(使用-f調用選項讀取)和腳本或批處理文件。
確保在引用包或包項的任何文件之前編譯包的另一種方法是使用’include 編譯指令指示編譯器讀取包含包的文件,’include指令放在包含對包項引用的每個設計或測試臺文件的開頭。
使用“include指令”時需要注意一點,SystemVerilog不允許在同一編譯中多次包含同一個包。可以通過放置’ifdef(“if defined-定義”)或’ifndef(“if not defined-未定義”)來實現圍繞包定義的條件編譯指令,以便編譯器跳過已編譯的包。條件編譯指令允許SystemVerilog源代碼根據宏名是否已使用’define指令定義進行選擇性編譯。
下面的示例使用’ifndef條件編譯指令圍繞包。當包含包的文件被編譯器讀入時,“未定義”測試將為真,包將被編譯。編譯的代碼行包含一個’define指令,該指令設置了使用的宏名稱。如果在編譯器的同一調用過程中再次讀取此文件,“未定義”測試將為false,并且將跳過’ifndef和endif之間的代碼。
綜合條件
為了能夠進行綜合,包中定義的任務和函數必須聲明為自動的(automatic),并且不能包含靜態變量。此規則的原因是,綜合將在引用包任務或函數的每個模塊或接口中復制任務或函數。如果任務或函數在仿真中有靜態存儲,那么該存儲將由任務或函數的所有引用共享,這是一種與復制不同的行為。通過將任務或函數聲明為自動的,每次調用它時都會分配新的存儲,使其行為與任務或函數的唯一副本相同。這確保了對包任務或函數的預綜合引用的仿真行為與后綜合行為相同。
出于仿真的原因,綜合不支持包中的變量聲明。在仿真中,一個包變量由導入該變量的所有模塊共享。一個模塊可以寫入變量,另一個模塊將看到新值。這種不通過模塊端口傳遞值的模塊間通信是不可綜合的。
原文標題:SystemVerilog(十一)-SystemVerilog 包
文章出處:【微信公眾號:OpenFPGA】歡迎添加關注!文章轉載請注明出處。
-
模塊
+關注
關注
7文章
2731瀏覽量
47686 -
Verilog
+關注
關注
28文章
1351瀏覽量
110310 -
函數
+關注
關注
3文章
4345瀏覽量
62911
原文標題:SystemVerilog(十一)-SystemVerilog 包
文章出處:【微信號:Open_FPGA,微信公眾號:OpenFPGA】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論