FPGA需要良好的數電模電基礎,verilog需要良好C語言基礎。
FPGA的準備工作:下載Quartus II,Modelsim和notepad++(notepad++是文本編輯器,quartus有自帶的,可以不裝,也可以用其他的)。安裝完成后,實現Quartus II與Modelsim和notepad++的關聯(不關聯notepad++的話默認用quartus自帶的)。方法是:tools欄的option,如下圖選中Win64。
關聯notepad++如圖,在文件夾中選擇安裝好的exe應用程序。
Verilog可能是FPGA路上的第一個絆腳石,但是代碼類的學習都是熟能生巧,掌握規律只需3天即可上手。
基礎語法 :
1、區分大小寫,分號結尾(空格、換行無意義),單行注釋用//,多行注釋用/* 代碼 */,標識符區分大小寫,關鍵字小寫。
2、0表示假,1表示真,X/x表示未知,Z/z表示高阻。
3、十進制('d 或 'D),十六進制('h 或 'H),二進制('b 或 'B),八進制('o 或 'O),4'b1011中4表示位數,b表示進制,1011是數值。 字符串用雙引號且不能換行。
4、最常用的數據類型:wire和reg,wire 表示物理連線,reg表示存儲單元。
5、表達式由操作符和操作數構成,其中操作符有算術、關系、等價、邏輯、按位、歸約、移位、拼接、條件共9種,操作數可以是任意的數據類型。注意邏輯與(&&)、按位與(&)。
數電中有組合邏輯電路和時序邏輯電路。組合邏輯電路模塊:
6、連續賦值語句以assign開頭用于對 wire 型變量進行賦值
7、普通時延:assign #10 Z = A & B ;把A與B的結果延時10個單位再賦值給Z。隱式時延:wire #10 Z = A & B;聲明wire型變量時對其進行包含一定時延的連續賦值。A 或 B 任意一個變量發生變化,那么 Z會有 10 個時間單位的時延。如果在這 10 個時間單位內,A 或 B 任意一個值又發生了變化,那么計算 Z 的新值時會取 A 或 B 當前的新值。所以稱之為慣性時延,即信號脈沖寬度小于時延時,對輸出沒有影響。因此仿真時,時延一定要合理設置,防止某些信號不能進行有效的延遲。
時序邏輯電路模塊:
8、一個模塊中可以包含多個 initial 和 always 語句,但 2 種語句不能嵌套使用。語句在模塊間并行執行,與前后順序無關。語句內部是順序執行的(非阻塞賦值除外)。**initial **語句從 0 時刻開始執行,只執行一次,多個 initial 塊之間是相互獨立的。如果 initial 塊內包含多個語句,需要使用關鍵字 begin 和 end 組成一個塊語句。只包含一條語句可以不用。**always **語句是重復執行的。always 語句塊從 0 時刻開始執行其中的行為語句;當執行完最后一條語句后,便再次執行語句塊中的第一條語句,如此循環反復。always 語句多用于仿真時鐘的產生,信號行為的檢測等。
后面會結合數電詳細講解。
1、熟悉wire
module top_module(
input a,
input b,
input c,
input d,
output out,
output out_n );
assign out=(a&b)|(c&d);
assign out_n=~((a&b)|(c&d));
endmodule
verilog采用自頂向下的設計方法,分模塊設計,這樣做的好處是,不同的人可以負責不同的模塊,最后組裝起來。每個模塊都以Module 模塊名開始,以endmodule結尾,且需要定義輸入輸出,以及輸出與輸入的關系。在這個實例中,需要填入的就是兩個assign語句,得到out和out_n。
2、熟悉向量
當位寬大于 1 時,wire 或 reg 即可聲明為向量的形式。
module top_module(
input [2:0] a,
input [2:0] b,
output [2:0] out_or_bitwise,
output out_or_logical,
output [5:0] out_not
);
assign out_or_bitwise=a|b;
assign out_or_logical=a||b;
assign out_not={~b,~a};
endmodule
邏輯或||和位或|的區別:位或是兩個 N 位向量之間的每一位都進行或運算形成N位新向量,而邏輯運算將整個向量視為布爾值(true = 非零,false = 零)并生成 1 位輸出。{向量1,向量2,...}可以用于合并向量。位數少時可以用于向量反轉,例如in[3:0]反轉可以使out={in[0],in[1],in[2],in[3]}。
module top_module (
input a, b, c, d, e,
output [24:0] out );//
assign out=~{{5{a}},{5{b}},{5{c}},{53z7dhrbd},{5{e}}}^{5{a,b,c,d,e}};
endmodule
向量復制的格式是{復制次數{向量}},注意復制后的向量需要用{}。異或是a^b,同或是~a^b。
3、熟悉模塊
和之前在python中一樣,模塊實例化有非常重要的作用。如果事先定義一個模塊的功能,后面每一次使用時,都只需要讓自己定義的端口對應上原模塊的端口,就可以調用。如果不這樣做,每一次使用都需要寫一次這個模塊的代碼。
實例化有兩種方式,按位置:mod_a instance1 ( wa, wb, wc );按名稱:mod_a instance2 ( .out(wc), .in1(wa), .in2(wb) );前一種不建議使用,因為如果模塊的端口列表發生更改,則還需要查找并更改模塊的所有實例化以匹配新模塊。后一種雖然寫起來比較復雜,但是將每一個端口都對應上,與位置無關。
按名稱:
module top_module ( input a, input b, output out );
mod_a instance1 (
.out(out),
.in1(a),
.in2(b)
);
endmodule
按位置:
module top_module ( input a, input b, output out );
mod_a instance1 (a,b,out);
endmodule
top_module是模塊名,這個模塊有兩個輸入端口和一個輸出端口。這個模塊里用到了一個事先定義好的函數mod_a,也有兩個輸入端口和輸出端口。將端口對應起來,這個模塊就可以實現mod_a的功能。
下面看幾個復雜的例子:
移位寄存器
module top_module ( input clk, input d, output q );
wire q1,q2;
my_dff d0(.clk(clk),.d(d),.q(q1));
my_dff d1(.clk(clk),.d(q1),.q(q2));
my_dff d2(.clk(clk),.d(q2),.q(q));
endmodule
這個模塊名是top_module,有時鐘,輸入和輸出。實現定義了一個函數my_dff,整個模塊使用了三次D觸發器,因此需要實例化三次。對于函數d0,d1,d2都需要把端口對應上,由于q1,q2是引入的變量,用來將前一級觸發器輸出和后一級觸發器輸入連接上,所以需要先聲明q1,q2是wire型變量。
評論
查看更多