一個復雜電路的完整Verilog HDL模型是由若個Verilog HDL 模塊構成的,每一個模塊又可以由若干個子模塊構成。利用Verilog HDL語言結構所提供的這種功能就可以構造一個模塊間的清晰層次結構來描述極其復雜的大型設計。
- 每個模塊的內容都是嵌在module和endmodule兩個語句之間,每個模塊實現特定的功能,模塊是可以進行層次嵌套的。
- 每個模塊首先要進行端口定義.並說明輸入(input)和輸出(output),然后對模塊的功能進行邏輯描述。
- Verilog HDL程序的書寫格式自由,一行可以寫幾個語句,一個語句也可以分多行寫。
- 除了endmodule語句外,每個語句的最后必須有分號。
- 一個模塊是由兩部分組成的,一部分描述接口;另一部分描述邏輯功能,即定義輸入是如何影響輸出的。
模塊(block)的組成
Verilog HDL結構完全嵌在module和endmodule聲明語句之間,每個Verilog程序包括4個主要部分:端口定義,I/O說明,信號類型聲明和功能描述。
module<模塊名>(<端口列表>);
端口說明(input,output,inout)
參數定義(可選)
數據類型定義
連續賦值語句(assign)
過程塊(initial 和 always)
行為描述語句
低層模塊實例
任務和函數
延時說明塊
endmodule
- 模塊聲明
模塊聲明包括模塊名和端口列表。其格式如下:
module 模塊名(端口1,端口2,端口3,…);
模塊結束的標志為關鍵字:
endmodule
。 - 端口定義
input(輸入端口),output(輸出端口)和inout(雙向端口)。
格式如下:
input 端口名1,端口名2,………,端口名N; //輸入端口 output 端口名1,端口名2,………,端口名N; //輸出端口 inout 端口名1,端口名2,………,端口名N; //輸入輸出端口
也可以寫在端口聲明語句里,其格式如下(為了代碼的可讀性,一般不這么寫):
module module_name(input port1,input port2,…output port1,output port2… );
- 信號類型說明
信號可以分為端口信號和內部信號;
- 所有信號都必須進行數據類型的定義,如寄存器類型(reg等),連線類型(wire等);
- 如果信號沒有定義數據類型,則綜合器將其默認為wire型;
- 端口的位寬最好定義在端口定義中,不要放在數據類型定義中;
- 不能將input和inout類型聲明為reg型;
- 模塊的端口表示的是模塊的輸入和輸出口名,也就是說,它與別的模塊聯系端口的標識。
在模塊被引用時,在引用的模塊中,有些信號要輸入到被引用的模塊中,有的信號需要從被引用的模塊中取出來口。在引用模塊時其端口可以用兩種方法連接:
(1)在引用時,嚴格按照模塊定義的端口順序來連接,不用標明原模塊定義時規定的端口名,例如:
模塊名(連接端口1信號名,連接端口2 信號名,連接端口3信號名,……);
(2)在引用時用“.”符號,標明原模塊是定義時規定的端口名,例如:
模塊名( . 端口1名(連接信號1名),. 端口2名(連接信號2名),...);
優點:在於可以用端口名與被引用模塊的端口相對應,而不必嚴格按端口順序對應,提高了程序的可讀性和可移植性。
常量
關鍵字
關鍵字(又稱保留字), 小寫的英文字符串。如: module、endmodule、input、output、wire、reg、and、assign、always等。
標識符
標識符(identifier)是程序代碼中給對象(如模塊、端口、變量等)取名所用的字符串。
標識符的組成:由字母、數字字符、下划線_和美元符號$組 成 ,區 分大小寫 , 其 第 一 個 字 符必須是英文字母或下划線。
注意:
1.關鍵字不能作為標識符使用。
2.用有意義的有效的名字如Sum 、CPU_addr等。
3.用下划線區分詞。
4.采用一些前綴或后綴,如 時鍾采用Clk 前綴:Clk_50,Clk_CPU; 低電平采用_n 后綴:Enable_n;
5.統一定的縮寫如全局復位信號Rst。
6.同一信號在不同層次保持一致性,如同一時鍾信號必須在各模塊保持一致。
7.參數(parameter)采用大寫,如SIZE 。
用下列四種基本的值表示電路的邏輯狀態:
0:邏輯0或“假”;
1:邏輯1或“真”;
x:未知狀態,通常在信號未被賦值前;
z:高阻;
在輸入或表達式中,“z”的值通常被解釋成“x”,z和x是不分大小寫的,如01xz 與01XZ相同;
Verilog HDL中,有3種類型的常量:整數型常量(整數)、實數型常量(實數)和參數型常量。
整數
整數的一般表達式為:
<+/-><size> ’ <base format><number>
其中 size : 大小,表示二進制位數(bit)。缺省為32位。(可有可無);
base format:數基,可為2(b)、8(o)、10(d)、16(h)進制。缺省為10進制;
number:是所選數基內任意有效數字,包括X、Z。
默認數基為10進制
當數值number大於指定的大小時,截去高位。2’b1101表示的是2’b01
一個數字可以被定義為負數,只需在位寬表達式前加一個負號,注意必須在數字定義表達式的最前面。
下划線符號_可以自由的在整數或實數中使用;就數值本身而言,它們沒有任何意義。它們能夠用來提高可讀性;唯一的限制是下划線符號不能用來作為常數的首字符。例:a=8’b0001_0000;
-14 //十進制數-14
16’d255 //位寬為16的十進制數255
8’h9a //位寬為8的十六進制數9a
’o21 //位寬為32的八進制數21
’hAF //位寬為32的十六進制數AF
-4’d10 //位寬為4的十進制數-10
(3+2)’b11001 //非法表示,位寬不能為表達式
實數
(1)十進制格式,由數字和小數點組成(必須有小數點),例如:
0.1, 3.1415, 2.0 √ 3. x
(2) 指數格式:由數字和字符e(E)組成,e(E)的前面必須要有數字而且后面必須為整數,例如:
13_5.1e2 //其值為13510.0
8.5E2 //850.0 (e與E相同)
4E-4 //0.0004
parameter(參數型)
在Verilog HDL中為了提高程序的可讀性和可維護性,用parameter來定義一個標識符代表一個常量,稱為符號常量。
其說明格式如下:
parameter 參數名1 = 表達式,參數名2 = 表達式, …,參數名n = 表達式;
parameter是參數型數據的確認符。確認符后跟着一個用逗號分隔開的賦值語句表。常用參數來聲明運行時的常數。可用字符串表示的任何地方,都可以用定義的參數來代替。參數是本地的,其定義只在本模塊內有效。
在一個模塊中改變另一個模塊的參數時,需要使用defparam命令。
變量的數據類型
線狀網型變量(net)wire(需要被持續的驅動,驅動它的可以是門和模塊)
wire型信號定義格式如下:
wire [n-1:0] 變量名1,變量名2,…變量名n;
wire [n:1] 變量名1,變量名2,…變量名n;
wire a; //定義了一個1位的wire型數據
wire [7:0] b; //定義了一個8位的wire型向量
wire [4:1] c, d; //定義了二個4位的wire型向量
寄存器型變量 (reg)
reg [msb:lsb] 變量名1, 變量名2,…變量名n;
例如:
reg clock;
reg [3:0] regb;
reg [4:1] regc, regd;
可以理解為實際電路中的寄存器,具有記憶性,是數據儲存單元的抽象,在輸入信號消失后它可以保持原有的數值不變。常代表觸發器
與線網型變量的根本區別在於:register型變量需要被明確地賦值,並且在被重新賦值前一直保持原值。
只能在initial或always賦值,默認值是x。
注意在always和initial塊內被賦值的每一個信號都必須定義成reg型。
Verilog程序模塊中,被聲明為input或者inout型的端口,只能被定義為線網型變量,被聲明為output型的端口可以被定義為線網型或者寄存器型變量,輸入輸出信號類型缺省時自動定義為wire型。
wire型信號可以用作任何方程式的輸入,也可以用作“assign”語句或實例元件的輸出,不可以在initial和always模塊中被賦值。
字符串的表示:
是由一對雙引號括起來的字符序列。必須在一行內寫完。如”hello world!”是一個合法字符串。
每個字符串(包括空格)被看作是8位的ASCII值序列。存儲字符串“hello world!”,就需要定義一個8*12位的變量:
reg[8*12:1] stringvar;
initial
begin
stringvar = “ hello world”;
end
端口數據類型
一個端口看成是由相互連接的兩個部分組成,一部分位於模塊的內部,另一部分位於模塊的外部。當在一個模塊中調用(引用)另一個模塊時,端口之間的連接必須遵守一些規則。
- 輸入端口:從模塊內部來講,輸入端口必須為線網數據類型,從模塊外部來看,輸入端口可以連接到線網或者reg數據類型的變量。
輸出端口:從模塊內部來講,輸出端口可以是線網或者reg數據類型,從模塊外部來看,輸出必須連接到線網類型的變量,而不能連接到reg類型的變量。
輸入/輸出端口
從模塊內部來講,輸入/輸出端口必須為線網數據類型;從模塊外部來看,輸入/輸出端口也必須連接到線網類型的變量。
位寬匹配
在對模塊進行調用的時候,verilog允許端口的內、外兩個部分具有不同的位寬。一般情況下,verilog仿真器會對此警告。
- 未連接端口
Verilog允許模塊實例的端口保持未連接的狀態。例如,如果模塊的某些輸出端口只用於調試,那么這些端
口可以不與外部信號連接。端口與外部信號的連接在對模塊調用的時候,可以使用兩種方法將模塊定義的端口與外部環境中的信號連接起來:按順序連接以及按名字連接。但兩種方法不能混合在一起使用。
- 順序端口連接:需要連接到模塊實例的信號必須與模塊聲明時目標端口在端口列表中的位置保持一致。
運算符與表達式
1.算數運算符
在進行算術運算時,如果操作數的某一位為x或z,則整個表達式運算結果為不確定。 例1 + z = unknown。
兩個整數進行除法運算時,結果為整數,小數部分被截去。如,6/4=1。
在進行加法運算時,如果結果和操作數的位寬相同,則進位被截去。
2.位運算符(除了~,其余都是雙目運算符)
縮位運算符(單目運算符)
縮位運算符(Reduction Operators):又稱縮減運算符,僅對一個操作數進行運算,按照從右到左的順序依次對所有位進行運算,並產生一位的邏輯值
4.關系運算符
在進行關系運算時,如果聲明的關系是假,則返回值是0;如果聲明的關系是真,則返回值是1;如果操作數的某一位為x或z,則結果為不確定值。
5.等式運算符
邏輯相等:==
邏輯不等:!=
全等:===
z, x等位嚴格相等
非全等:!==
相等運算符(==)和全等運算符(===)的區別:
對於相等運算符,當參與比較的兩個操作數逐位相等,其結果才為1,如果某些位是不定態或高阻值,其相等比較得到的結果就會是不定值。
對於全等比較(===)是對這些不定態或高阻值的位也進行比較,兩個操作數必須完全一致,其結果才為1,否則結果是0。
6.邏輯運算符
邏輯運算符中,“&&”和“||”是雙目運算符,它要求有兩個操作數。
“!”是單目運算符,只要求一個操作數。
7.移位運算符
Verilog HDL的移位運算符只有左移和右移兩個。其用法為:A>>n或 A<<n; 表示把操作數A右移或左移n位,同時用0填補移出的位。
8.位拼接運算符
在Verilog語言中有一個特殊的運算符:位拼接運算符{ }。
位拼接運算符{}可以把兩個或多個信號的某些位拼接起來,表示一個整體信號進行運算操作。其使用方法如下:
{信號1的某幾位,信號2的某幾位,..,..,信號n的某幾位}
對於一些信號的重復連接,可以使用簡化的表示方式{n{A}}。這里A是被連接的對象,n是重復的次數。
9.條件運算符
三目運算符,對3個操作數進行運算,方式如下:
信號 = 條件?表達式1:表達式2
說明:當條件成立時,信號取表達式1的值,反之取表達式2的值。
例如:
assign out= (sel == 0) ? a : b;