最近閒來無事,通過公司項目,對數字電路設計比較感興趣,於是接觸了Verilog 硬件描述語言,對FPGA產生了濃厚的興趣。
對Verilog和FPGA不瞭解的朋友們可以自行百度,本文只作為我的筆記。
一、Verilog語法
Verilog的基本設計單元是“模塊”(block)。一個模塊是由兩部分組成的,一部分描述接口,另一部分描述邏輯功能,即定義輸入是如何影響輸出的。如:
module block (a,b,c,d);
input a,b;
output c,d;
assign c= a | b ;
assign d= a & b;
endmodule
從上面的例子可以看出,Verilog結構完全嵌在module和endmodule聲明語句之間,每個Verilog程序包括四個主要部分:端口定義、I/O説明、內部信號聲明、功能定義。
每個語句都必須以;作為結尾,可寫在一行也可換行書寫。
Verilog裏有四種基本的數據類型:reg型、wire型、integer型、parameter型
1、wire型(線變量)數據常用來表示用於以assign關鍵字指定的組合邏輯信號,wire型信號可以用作任何方程式的輸入,也可以用作“assign”語句或實例元件的輸出。且wire型數據只能用於組合邏輯,也是assign語句左側唯一的合法類型。(不能儲存信息)
2、reg型寄存器數據類型常用來儲存數據和傳遞數據,一般用在‘always’語句的指定信號賦值,always語句內每一個被賦值的信號都必須定義為reg型。
reg型信號必須賦予初始值,否則默認初始值為x,x代表數據的不確定值,是Verilog語言裏的一個常用表示不確定值的方法,也可以寫作 ?,除此之外 z代表高阻態。(Verilog區分大小寫)
reg可用於組合邏輯和時序邏輯。
其實常用的就是wire和reg型。
如以下程序:
module led_test
(
input clk, //時鐘輸入,默認wire型
input rst_n, //復位信號輸入,默認wire型,高電平有效
output reg[3:0] led //輸出四位寄存器信號,對應四個led燈的狀態
);
reg [31:0] timer; //32位reg型變量做計數器
always@(posedge clk or negedge rst_n) //時鐘上升沿或復位下降沿觸發
begin
if (rst_n == 1'b0)
timer <= 32'd0; //上電或復位時清零
else if (timer == 32'd199_999_999) //計數值為十進制199999999時(50MHz晶振計數四秒)
timer <= 32'd0; //清零
else
timer <= timer + 32'd1; //計數值加1
end
//Led控制
always@(posedge clk or negedge rst_n)
begin
if (rst_n == 1'b0)
led <= 4'b0000; //復位信號清零led燈狀態
else if (timer == 32'd49_999_999) //第1S,LED1 點亮
led <= 4'b0001;
else if (timer == 32'd99_999_999) //第2S,LED1 點亮
led <= 4'b0010;
else if (timer == 32'd149_999_999) //第3S,LED1 點亮
led <= 4'b0100;
else if (timer == 32'd199_999_999) //第4S,LED1 點亮
led <= 4'b1000;
end
endmodule
上述為Led流水燈程序,上述例子中的變量賦值方式分為阻塞賦值 = 和非阻塞賦值 <=。
1、阻塞賦值
阻塞賦值即a=b,在塊結束之間就進行賦值,也就是我們平時理解的如C語言的a=b相同,是語句執行完就實時發生的。阻塞賦值通常用來構建組合邏輯,可以實現一些功能,但在系統的設計中,使用阻塞賦值可能會引起一些意外的問題。
2、非阻塞賦值
即a<=b,該語句生效與塊結束之後,即在塊中,執行完下一條語句後,a並不等於b,而是要等到整個塊結束a才能等於b。
舉例説明一下,如:
always@(posedge clk)
begin
b<=a;
c<=b;
end
該代碼表示兩個觸發器來實現在時鐘的上升沿將a的值賦給b,將原來的b的值賦給c。
而下面這種:
always @(posedge clk)
behin
b=a;
c=b;
end
則表示在時鐘的上升沿來的時候,將a的值賦予b,再將b的值賦予a,那這樣實際上c等於a的值,實際電路中只用到了一個觸發器,不是設計的初衷。
非阻塞賦值操作只能用於對寄存器類型變量進行賦值,因此只能用在"initial"塊和"always"塊等過程塊中。非阻塞賦值不允許用於連續賦值。
阻塞賦值和非阻塞賦值的原則歸納如下:
1、時序電路建模時,用非阻塞賦值。2、鎖存器電路建模時,用非阻塞賦值。3、用always 塊寫組合邏輯時,採用阻塞賦值。4、在同一個always 塊中同時建立時序和組合邏輯電路時,用非阻塞賦值。5、在同一個always 塊中不要同時使用非阻塞賦值和阻塞賦值。6、不要在多個always 塊中為同一個變量賦值。