Verilog HDL 快速入門
Verilog HDL是一種硬件描述語言(HDL:Hardware Description Language),它是以文本形式來描述數字系統硬件的結構和行為的語言。 世界上最流行的兩種硬件描述語言是Verilog HDL和VHDL。
注意,VerilogHDL是一種描述語言,它和常見的編程語言C有根本的不同。C語言,讓計算機的CPU從上往下按順序執行每一條指令,執行完程序就結束了。而VerilogHDL主要是描述了一個數字模塊的結構,或者行為。有點像商業合同,合同里面也會描述產品的結構,產品的功能等等。合同的每一個條款,并不需要嚴格的先后順序,只要把項目的方方面面都考慮全面,寫下來就OK了。VerilogHDL就是這樣。
我們用VerilogHDL描述數字模塊的功能,剩下的交給編譯器(如,Quartus),編譯器會根據我們的要求設計重構FPGA內部硬件。對于大批懶人來說,這技術簡直碉堡了。這就是EDA(Electronic Design Automation,電子設計自動化)。
好,下面就來認識一下VerilogHDL 我們先設計一個“數據選擇器”: s是數據選擇控制端, a,b是輸入信號,y是輸出信號
代碼如下:
//模塊名、模塊接口列表
module mux2_1(a, b, s, y);
input a, b, s;// 定義輸入端口
output y; // 定義輸出端口
/* s為0時,選擇a輸出;
s為1時,選擇b輸出。*/
assign y = (s == 0) ? a : b;
endmodule
每個Verilog文件都至少包含一個module 開始,endmodule 結束的代碼塊。 這個代碼塊定義了一個叫 mux2_1 的模塊,模塊名后的括號內列出了該模塊的接口信號,相當于數字器件的引腳。 但是括號內沒有說明接口的信號方向,所以緊跟著另起一行用input 和output 再說明一下。注釋和C語言一樣,用// 或 /**/ 。
assign 是Verilog的關鍵詞,書上稱為連續賦值。我一般把它視為“連線”操作,assign后面的緊跟的 y 在硬件上被設計成導線wire(或輸出引腳output)。
assign y = (s == 0) ? a : b; 這句表示:s如果為0,那么等號左邊就是a,否則就是b。將這個表達式的輸出結果接在輸出引腳 y 上。 這就是一個簡單的Verilog程序,不需要我們去設計與非門,直接表達你的你想要的功能就好了。編譯下載到FPGA硬件,功能就實現了。
assign “導線” = “表達式”(也可以是數值、寄存器等能代表高低電平的量);
上面的2選1數據選擇器,內部實現結構如下:
上面的assign語句還可以直接使用邏輯表達式: assign y = (a & (~ s)) | (b & s); 這個表明了門級結構連接關系(數據流描述方式),近乎結構描述。
很明顯,這種結構描述比行為描述要費力得多,而且不太容易讀懂程序功能。
來看看行為描述方法:
module mux2_1(a, b, s, y);
input a, b, s;
output y;
reg y; //reg 表示寄存器
always @(a, b, s)
begin
if(!s) y = a;
else y = b;
end
endmodule
這里reg表示寄存器(存儲單元),需要提醒一下的是,assign后面不能接reg型,只能接wire型前面已經說過了。 為什么不能?因為寄存器的賦值除了需要輸入信號,還需要一個觸發信號(例如:D觸發器),assign?sorry,he can’t。
always @(a, b, s)中,括號里面的輸入信號a,b,s表示敏感信號;這句表示,敏感信號列表中的任何一個信號發生變化,將會引發 begin …… end 之間的行為。 Verilog用begin和end包圍代碼段,相當于c語言中大括號{ }的功能。
always @( ) 是一種固定用法,括號內填寫行為觸發條件。
if(!s) y = a; 這里的“=”,書上叫做“阻塞賦值”,和C語言里的賦值語句意思差不多,使用也差不多。 比如,有這么一段代碼:
input clk;//時鐘信號
reg a,b,c;
//觸發動作:時鐘上升沿
always@(posedge clk)
begin
b = a;
c = b;
end
那么時鐘上升沿出現后,c的值就等于a,b的值也是a,這個行為在描述的時候,語句先后順序,決定了賦值的先后,值是立即更新的。
Verilog還有一個“非阻塞賦值”,表示方法是 <=,我把這種賦值稱為“并行賦值”,在always@ 代碼塊內書寫時,沒有先后順序。一般用于設計時序邏輯電路,舉個例子:
always@(posedge clk)
begin
b <= a;
c <= b;
end
含義:時鐘上升沿出現前a,b的值,在上升沿結束后分別賦給b,c.
非阻塞賦值“<=”符號,
右側所有變量,代表的是這些變量上升沿前的值,
左側變量表示,上升沿后該變量將要更新為右側表達式的值。
所以,這兩句書寫沒有先后順序,調換次序后表達的含義是一樣的,新寄存器的值是在always塊結束后同時更新的。調換次序后如下,仍然表示同樣的含義:
always@(posedge clk)
begin
c <= b;
b <= a;
end
最后提一句:
阻塞和非阻塞賦值,都只能寫在always@()代碼塊內。
assign后面的=是和assign一起連用的,并不是阻塞賦值。
更詳細的分析,請參考另一篇文章:阻塞賦值和非阻塞賦值。
結語
本文使用多種方式描述了一個數據選擇器,來介紹Verilog的基本書寫結構。其間,涉及了一部分語法和關鍵詞:
1、module …… endmodule
2、assign
3、always @( )
4、阻塞賦值 = 非阻塞賦值<=