Verilog常用語法之一
1.一個完整版實例
上一次Verilog學習筆記中,我通過幾個小例子,較為直觀的對Verilog程式設計有了一些瞭解。這次筆記,我開始著重的系統學習Verilog程式設計語法基礎。在我系統學習語法之前,我先用一個實例,引入這次筆記。
上圖被測試器件被測試器件DUT 是一個二選一多路器。測試裝置(test testbench or
fixture)提供測試激勵及驗證機制。TestBench 使用行為級描述,DUT採用門級描述。下面將給出
採用gate level門級描述。下面將給出TestBench的描述、DUT的描述及如何進行混合模擬。
1)書寫Verilog程式
上圖依舊是我們曾經提到的經典二選一電路,現在我對其進行Verilog程式設計(以後文章中程式均為筆者在Sublime Text3中書寫):
2)書寫該程式的TestBench
書寫TestBench時候應注意,此驗證性程式是沒有埠的,這是因為TestBench是最頂層模組,不會被其他模組產生實體,所以不需要埠。同時硬體描述程式中,即MUX2_1.V程式在TestBench中需要進行產生實體,應注意模組名字要與引用模組(即MUX2_1)相同;實例的名字可以任意,但是要符合標記命名規則;埠清單與引用模組次序相同(即out ,a,b,sel)。
在書寫TestBench時候常用initial和always這兩個過程語句,二者區別為:initial:只能執行一次;always:迴圈執行。值得注意的是所有過程在時間0執行一次,過程之間是並存執行的(FPGA的特點)。
激勵描述:
(本圖同數位電路中真值表)
• 例子中,a,
b, sel說明為reg類資料。reg類資料是寄存器類資料信號,在重新賦值前一直保持當前資料。例子中,a, b, sel說明為reg類資料。reg類資料是寄存器類資料信號,在重新賦值前一直保持當前資料。
• #5 用於指示等待5個時間單位。
• $ stop是結束模擬的系統任務,也可以寫成$finish。
3)TestBench
響應的產生
Verilog 提供了一些系統任務和系統函數,包括:
• $time 系統函數,給出當前模擬時間;
• $monitor 系統任務,若參數清單中的參數值發生變化,則在時間單位末顯示參數值。
格式:$monitor
([“format_specifiers”,]
<arguments>);
例如:$monitor($time,
o, in1, in2);
$monitor($time,
“%b %h%d %o”, sig1, sig2, sig3,sig4);
說明:
a)$time 是一個系統函數,返回當前返回模擬時間。時間用64位元整數表示。
b)$monitor 在時間單位末,若參數清單中的參數值發生變化則顯示所列參數的值。由$time引起的變化不會顯示。
c)$monitor系統任務支援不同的數基。缺省數基是十進位。支援的數基還有二進位、八進制、十進位。
4)完整的TestBench
4)完整的TestBench
2.模組的結構
Verilog的基本設計單元是“模組”(block) 。一個模組是由兩部分組成的,一部分描述介面,另一部分描述邏輯功能,即定義輸入是如何影響輸出的。
Verilog 模組的結構由在module和endmodule 關鍵字之間的四個主要部分組成:
1)模組埠的定義
模組的埠聲明了模組的輸入輸出口。其格式如下:
module 模組名(口1,口2,口3,口4, ………);
模組名(識別字)的命名規則:
• 識別字是用戶在描述時給 識別字是用戶在描述時給Verilog物件起的名字;
• 識別字必須以字母 識別字必須以字母(a-z, A-Z) 或( _ ) 開頭,後面可以是字母、數位、( $ )或( _ )。
• 最長可以是1023個字元個字元。
• 識別字區分大小寫,識別字區分大小寫,sel 和SEL是不同的識別字。
• 模組、埠和實例的名字都是識別字。
• 識別字要區別與關鍵字,這個命名規則和C語言大同小異。
2)程式設計命名規範
a)匈牙利命名:
開頭字母用變數類型的縮寫,其餘部分用變數的英文或英文的縮寫,要求單詞第一個字母大寫。
int iMyAge; “i”是int類型的縮寫; char cMyName[10]; “c”是char類型的縮寫; float fManHeight; “f”是float類型的縮寫;
b)駝峰式命名法:
又叫小駝峰式命名法。第一個單詞首字母小寫,後面其他單詞首字母大寫。
int myAge;
char myName[10];
float manHeight;
char myName[10];
float manHeight;
c)帕斯卡命名法:
又叫大駝峰式命名法。每個單詞的第一個字母都大寫。
int MyAge;
char MyName[10];
float ManHeight;
char MyName[10];
float ManHeight;
個人比較喜歡駝峰命名法和底線結合來用。
3)模組內容
模組的內容包括I/O說明、內部信號聲明、功能定義。
I/O說明的格式:
輸入口:input[信號位元寬-1:0] 埠名1;
input[信號位元寬-1:0] 埠名2;
…
input[信號位元寬-1:0] 埠名i; //(共有i個輸入口)
輸出口:output[信號位元寬-1:0] 埠名1;
output[信號位元寬-1:0] 埠名2;
…
output[信號位元寬-1:0] 埠名j; //(共有j個輸出口)
輸入/輸出口:inout[信號位元寬-1:0] 埠名1;
inout[信號位元寬-1:0] 埠名2;
…
inout[信號位元寬-1:0] 埠名k; //(共有k個雙向匯流排埠)
注:I/O說明也可以寫在埠聲明語句裡。其格式如下:
module
module_name(input port1,input port2,… output port1,output port2… );
4)內部信號說明
在模組內用到的和與埠有關的wire 和 reg 變數的聲明。
如: reg
[width-1 :0] R變數1,R變數2 …;
wire [width-1 :
0] W變數1,W變數2 …;
5)功能定義
模組中最重要的部分是邏輯功能定義部分。有三種方法可在模組中產生邏輯。
a)用 assign 語句(資料流程描述):assign a = b & c ;
b)用實例元件(結構化描述):and2 and_inst ( q, a, b);
c)用 “always”
塊(行為描述):
always @
(posedge clk or
posedge clr)//敏感性列表
posedge clr)//敏感性列表
begin
if (clr) q<=
0;
else if (en) q<= d;
else if (en) q<= d;
end //begin……end相當於C語言中的()
說明:上述三條語句是並行的,他們產生獨立的邏輯電路;而在always塊中:begin和end之間是循序執行的。
3.資料類型及常量和變數
1)常量
在程式運行過程中,其值不能被改變的量稱為常量。
I.數字:
(1)整數
在Verilog
HDL中,整型常量即整常數有以下四種進制表示形式:
a)二進位整數(b或B)
b) 十進位整數(d或D)
c) 十六進位整數(h或H)
d) 八進制整數(o或O)
數位表達方式有以下三種:
a) <位元寬><進制><數字>這是一種全面的描述方式。
b) <進制><數位>在這種描述方式中,數位的位元寬採用缺省位寬(這由具體的機器系統決定,但至少32位)。
c) <數位>在這種描述方式中,採用缺省進制十進位。
(2)X,Z,0,1的含義
在數位電路中,x代表不定值,z代表高阻值。一個x可以用來定義十六進位數的4位元二進位數字的狀態,八進位數的3位元,二進位數字的1位。z的表示方式同x類似。z還有一種表達方式是可以寫作“?”。
(3)負數
一個數字可以被定義為負數,只需在位寬運算式前加一個減號,減號必須寫在數字定義運算式的最前面。注意減號不可以放在位寬和進制之間也不可以放在進制和具體的數之間。
-8'd5 //這個運算式代表5的補數(用八位二進位數字表示)
8‘d-5 //非法格式
(4)下畫線(underscore_)
底線可以用來分隔開數的表達以提高程式可讀性。但不可以用在位寬和進制處,只能用在具體的數字之間。
16'b1010_1011_1111_1010 //合法格式
8'b_0011_1010 //非法格式
當常量不說明位數時,預設值是32位元,每個字母用8位元的ASCII值表示。
(5)基數符號及其合法的表示值
舉例:
(6)實型數及其表示
Verilog中的實數可以用十進位與科學計數法兩種格式來表示,如果採用十進位格式,小數點兩邊必須都有數位,否則為非法的表示形式。
實例:
II. 參數型(parameter)
a)用參數聲明一個可變常量,常用于定義延時及寬度變數。
b)參數定義的語法:parameter
<list_of_assignment>;
c)可一次定義多個參數,用逗號隔開。
d)在使用文字(literal)的地方都可以使用參數。
e)參數的定義是局部的,只在當前模組中有效。
f)參數定義可使用以前定義的整數和實數參數。
2)變數
變數即在程式運行過程中其值可以改變的量。常用的網路資料類型包括wire型和tri型。wire型變數通常是用來表示單個門驅動或連續設定陳述式驅動的網路型資料,tri型變數則用來表示多驅動器驅動的網路型資料。
a)wire型
wire型資料常用來表示用於以assign關鍵字指定的組合邏輯信號。Verilog程式模組中輸入輸出信號類型缺省時自動定義為wire型。其格式如下:
wire [n-1:0] 資料名1,資料名2,……資料名i; //共有i條匯流排,每條匯流排內有n條線路,或
wire [n:1] 資料名1,資料名2,……資料名i;
b)reg型
寄存器是資料儲存單元的抽象。寄存器資料類型的關鍵字是
reg。 reg類型資料的預設初始值為不定值x。reg型資料常用來表示用於“always”模組內的指定信號,常代表觸發器。在“always”塊內被賦值的每一個信號都必須定義成reg型。
reg型資料的格式如下:
reg [n-1:0] 資料名1,資料名2,… 資料名i;
或
reg [n:1] 資料名1,資料名2,… 資料名i;
c)memory型
Verilog HDL通過對reg型變數建立陣列來對記憶體建模,可以描述RAM型記憶體,ROM記憶體和reg檔。陣列中的每一個單元通過一個陣列索引進行定址。在Verilog語言中沒有多維陣列存在。 memory型資料是通過擴展reg型資料的位址範圍來生成的。其格式如下:
reg [n-1:0] 記憶體名[m-1:0];
或
reg [n-1:0] 記憶體名[m:1];
3)如何選擇正確的資料類型
a)輸入口(input)可以由寄存器或網路連接驅動,但它本身只能驅動網路連接。
b)輸出口
(output)可以由寄存器或網路連接驅動,但它本身只能驅動網路連接。
c)輸入/輸出口(inout)只可以由網路連接驅動,它本身也只能驅動網路連接。
d)如果信號變數是在過程塊 (initial塊或always塊)中被賦值的,必須把它聲明為寄存器類型變數。
沒有留言:
張貼留言