Verilog
模塊的基本構成要素有三大部分: 端口信息、輸入/輸出說明、邏輯功能描述。這裏將其看成一種計算機語言就行了,沒有那麼網上說的什麼花裏胡哨的。計算機語言就是用來實現功能的,我們日常接觸最多的就是c++
、python
這種,做的一般是計算仿真,而這個verilog
做的是與硬件相關的,也就是直接控制信號的與或非這種。
而學習一門計算機語言最快的方式就是直接上手幹,話不多說看個例子:
module block1(a, b, c, d, e);
input a, b, c;
output d, e; .
assign d=a|(b&~c);
assign e=(b&~c );
endmodule
可以看到verilog
模塊由兩部分組成:端口信息和內部功能。上述代碼所述功能是輸入三個信號a
,b
,c
(這裏沒有指定位寬,說明這裏都是一位位寬信號); 輸出d
,e
也是沒有指定位寬,表示一根線輸出。中間assign
賦值語句就是內部功能,表示輸入與輸出之間的關係。d
信號的輸出等於a
或上b
與c
的非,e
同理。
Verilog基本模塊
結構
verilog
模塊的結構在module
和enmodule
關鍵詞之間,主要有四個主要部分組成。上述是verilog的一個基本的程序模塊,如果我們想要設計一個verilog模塊的話,其大體組成部分如下圖所示:
- 模塊端口定義用來聲明設計電路模塊的輸入輸出端口。端口定義格式如:
module
模塊名(端口1,端口2,端口3,…);。
任何一個模塊都是以module
開頭的。在端口定義的圓括弧中,是設計電路模塊與外界聯繫的全部輸入輸出端口信號或引腳,它是設計實體對外的一個通信界面,是外界可以看到的部分(不包含電源和接地端),多個端口名之間用“,”分隔," ; "結尾。
- 模塊內容包括
I/O
說明、信號類型聲明和功能描述。模塊的I/O
說明用來聲明模塊端口定義中各端口數據流動方向包括輸入(input
) 、輸出(output
) 和雙向(inout
) 。I/O
說明格式如下:
input ina , inb,cin;
output sum, cont;
這裏寫成一行的話位寬都是一樣的。所以有時候需要指定位寬的時候我們對每個輸入、輸出單獨寫。
-
信號類型聲明用來說明設計電路的功能描述中,所用的信號的數據類型以及函數聲明。信號的數據類型主要有連線(
wire
) 、寄存器(reg
)、整型(integer
) 、實型(real
) 和時間(time
)等類型。在通常設計的時候用的最多的就是連線型(wire
)和整型(reg
),有時候也會用到整型。 -
功能描述是
Verilog HDL
程序設計中最主要的部分,用來描述設計模塊的內部結構和模塊端口間的邏輯關係,在電路上相當於器件的內部電路結構。
功能描述可以用assign
語句、元件例化(instantiate
) 、always
塊語句、initial
塊語句等方法來實現,通常把確定這些設計模塊描述的方法稱爲建模。
語句
(1) 用assign
語句建模的方法很簡單,只需要在“assign”後面再加一個表達式即可。assign
語句一般適合對組合邏輯進行賦值,稱爲連續賦值方式。
module adder1 (sum, cout, ina, inb, cin) ; //模塊端口定義
input ina, inb, cin;
output sum,cout; //I/O聲 明
assign {cout, sum} = ina+inb+cin; //功能描述語句
endmodule //endmodule後不加分號
默認的數據類型爲wire
(連線)型,{ }
爲拼接運算符,是將cout
、sum
這樣兩個1
位操作數拼接爲一個2
位操作數。
(2) 元件例化方式建模是利用Verilog HDL
提供的元件庫實現的。.例如,用與門例化元件定義一個3
輸入端與門可以寫爲and myand3(y,a,b,c)
; and
爲關鍵字,名稱爲myand3
。
(3) always
塊語句可以產生各種邏輯,常用於時序邏輯的功能描述。一個程序設計模塊中,可以包含一個或多個always
語句。程序運行中,在某種條件滿足時,就重複執行一遍always
結構中的語句。
module cnt8(out,cout,data,load,cin,clk,clr);
input [7:0] data; // 輸入數據八個比特
input load, cin, clk, clr; // 一個比特
output| 7:0] out;
output cout;
reg [7:0] out; //寄存器型參量,具有寄存功能
always @(posedge clk) //時鐘 上升沿,每次上升沿,執行always語句
begin
if (clr) out < =8'b0;
else if (load) out <= data;
else out <= out+8'b1;
end
assign cout = &out & cin; //&out”-與縮減運算式
endmodule
輸出out
八位、cout
輸出進位一位、data
八位,load
置數信號一位,cin
輸入進位,clk
時鐘,一位,clr
復位。這裏輸出信號爲out
,之後又將其定義爲寄存器信號。
always@
括號中的是條件,posedge clk
表示的時鐘上升沿。也就是時鐘上升沿一進來進開始執行內部語句。如果clr
復位信號爲高電平,輸出out
就被賦值爲8
比特0
(這裏的<=
就是賦值語句)。當out
全爲1
且進位cin
也爲1
的時候cout
才爲1
。
由於這裏out
信號在always
塊中賦值,所以必須定義爲寄存器型變量。也就是always
塊中的變量必須定義爲寄存器類型。assign
賦值的變量必須是wire
型。
(4) initial
塊語句與always
語句類似,不過在程序中它只執行1
次就結束了。
詞法、語法
Verilog HDL
的常數包括數字、未知X和高阻z三種。數字可以用二進制、十進制、八進制和十六進制等4種不同數制來表示,完整的數字格式爲
<位寬>'<進制符號><數字>
其中,位寬表示數字對應的二進制數的位數寬度; 進制符號包括b
或B
(表示二進制數),d
或D
(表示十進制數),h
或H
(表示十六進制數),o
或O
(表示八進制數)。
-
字符串是用雙引號括起來的可打印字符序列,它必須包含在同一行中。
-
標識符是用戶編程時爲常量、變量、模塊、寄存器、端口、連線、示例和
begin-end
塊等元素定義的名稱。標識符可以是字母、數字和下劃線等符號組成的任意序列。 -
關鍵字是
Verilog HDL
預先定義的單詞,它們在程序中有不同的使用目的。所有關鍵字都用小寫。 -
操作符也稱爲運算符,是
Verilog HDL
預定義的函數名字,這些函數對被操作的對象(即操作數)進行規定的運算,得到一個結果。
操作符通常由1~3個字符組成,例如,“+”表示加操作,“= =” (兩個=字符)表示邏輯等操作,“===”(3個=字符)表示全等操作。
有些操作符的操作數只有1個,稱爲單目操作;有些操作符的操作數有2個,稱爲雙目操作;有些操作符的操作數有3
個,稱爲三目操作。
- 常量是-一個恆定不變的值數,一般在程序前部定義。常量定義格式爲
parameter常量名1 =表達式,常量名2 =表達式,...,
常量名n=表達式;
parameter
是常量定義關鍵字,常量名是用戶定義的標識符,表達式是爲常量賦的值。
- 變量是在程序運行時其值可以改變的量。在
Verilog HDL
中,變量分爲網絡型(nets type
)和寄存器型(register type
)兩種。
nets
型變量是輸出值始終根據輸入變化而更新的變量,它一般用來定義硬件電路中的各種物理連線。常用的是wire
類型。
register
型變量是一種數值容器,不僅可以容納當前值,也可以保持歷史值,這一屬性與觸發器或寄存器的記憶功能有很好的對應關係。
register
型變 量與wire
型變量的根本區別: register
型變量需要被明確地賦值,並且在被重新賦值前–直保持原值。.
register型變量是在always
、initial
等 過程語句中定義,並通過過程語句賦值。
integer
、real
和time
等3種 寄存器型變量都是純數學的抽象描述,不對應任何具體的硬件電路,但它們可以描述與模擬有關的許算。例如,可以利用time型變量控制經過特定的時間後關閉顯示等。
reg
型變量是數字系統中存儲設備的抽象,常用於具體的硬件描述,因此是最常用的寄存器型變量。reg
型變量定義的關鍵字是reg
,定義格式如下:
reg [位寬]變量1, 變量2,...,變量n;
用reg
定義的變量有-一個範圍選項( 即位寬),默認的位寬是1
。位寬爲1
位的變量稱爲標量,位寬超過1
位的變量稱爲向量。
向量定義時需要位寬選項:
reg[7: 0] data; //定義1個8位寄存器型.變量, 最高有效位是7,最低有效位是0
reg[0: 7] data; //I定義1個8位寄存器型變量,最高有效位是0,最低有效位是7
- 數組:若干個相同寬度的向量構成數組。在數字系統中,
reg
型數組變量即爲memory
(存儲器)型變量。
mymemory[1023:0];
上述語句定義了一個1024
個字存儲器變量mymemory
,每個字的字長爲8
位。在表達式中可以用下面的語句來使用存儲器:
mymemory[7]=75; // 存儲器mymemory的第7個字被賦值75。
Verilog語句
基本邏輯門關鍵字是Verilog HDL
預定義的邏輯門,包括and
、or
、not
、xor
、nand
、nor
等。
- 過程賦值語句
過程賦值語句出現在initial和always塊語句中,賦值符號是“=”,格式爲
賦值變量=表達式;
在過程賦值語句中,賦值號“=”左邊的賦值變量必須是reg (寄存器)型變量,其值在該語句結束即可得到。如果一個塊語句中包含若干條過程賦值語句,那麼這些過程賦值語句是按照語句編寫的順序由上至下一條一條地執行,前面的語句沒有完成,後面的語句就不能執行,就象被阻塞了一樣。 因此,過程賦值語句也稱爲阻塞賦值語句。
- 非阻塞賦值語句
非阻塞賦值語句也是出現在initial
和always
塊語句中,賦值符號是“<=
”,格式爲
賦值變量<=表達式;
在非阻塞賦值語句中,賦值號“<=”左邊的賦值變量也必須是reg型變量
,其值不象在過程賦值語句那樣,語句結束時即刻得到,而在該塊語句結束纔可得到。
- 循環語句
循環語句包含for
語句、repeat
語句、while
語句和forever
語句4
種。
模塊實例化
與C
語言相比,verilog
語句是並行的,比如兩個always
塊都是時鐘沿出發的,那麼它們就是並行的。
特殊符號“#”常用來表示延遲。使用'define
編譯引導能提供簡單的文本替代功能。
`define <宏名> <宏文本>
舉例如下:
`define on 1'b1 // 0比特1定義on
`define off 1'b0 // 0比特0定義off
`define and delay #3 // 定義延時
使用'include
編譯引導在編譯的時候能把其指定的整個文件包括進來一起處理。如’include “global.v"
等。
可以將模塊的實例通過端口連接起來構成一個大的系統或元件。每個實例都有自己的名字。實例名是每個對象唯一的標記,通過這個標記可以查看每個實例的內部。實例中端口的次序與模塊的定義的次序相同。模塊實例化與調用程序不同。每個實例都是模塊的一個完全拷貝,相互獨立、並行。
在調用模塊時,可以用順序連接和按名連接把模塊定義的端口與外部信號連接起來。
順序連接:需要連接的信號需要與模塊聲明的端口列表一致;
按名連接:端口和外部信號按名字連接在一起。當設計大規模系統時,端口太多,記住端口順序不大可能,可以採用按名連接方法。
不需要連接的端口直接忽略掉即可: