Verilog教程
這個教程寫的很好,可以多看看。本篇還沒整理完。
一、Verilog簡介
什么是FPGA?一種可通過編程來修改其邏輯功能的數字集成電路(芯片)
與單片機的區別?對單片機編程并不改變其地電路的內部結構,只是根據要求實現的功能來編寫運行的程序(指令)。舉例:單片機就兩個uart,但是我想用4個uart,單片機就沒辦法了。
什么是HDL?(hardware description language)硬件描述語言,用于描述數字電路結構和功能的語言。
Verilog和C的區別?Verilog是硬件描述語言,在編譯下載到FPGA之后,會生成電路,所以Verilog是并行運行的。C語言是軟件編程語言,編譯下載到單片機之后,是存儲器中的一組指令。而單片機處理軟件指令需要取指、譯碼、執行,這個過程是串行執行的。
二、Verilog基礎語法
2.1基礎知識
2.1.1邏輯值
0:低電平,GND。
1:高電平,VCC。
X:未知,高或低。
Z:高阻態,外部沒有激勵信號,是一個懸空狀態。
2.1.2數字進制格式
二進制(b)、八進制(o)、十進制(d)、十六進制(h)
2.1.3標識符
用于定義模塊名、端口名、信號名。
字母、數字、$符號、_下劃線。第一個字符必須是字母或者下劃線。
嚴格區分大小寫。
不建議大小寫混合使用。
普通內部信號建議全部小寫。
2.2數據類型
2.2.1寄存器類型reg
數據存儲單元,默認初始值是不定值x。未寫位寬的時候默認32位。
reg類型數據只能在always和initial中賦值。
如果該過程語句描述的是時序邏輯,即always語句帶有時鐘信號,則該寄存器變量對應為觸發器。
如果該過程語句描述的是組合邏輯,即always語句不帶有時鐘信號,則該寄存器變量對應為硬件連線。
2.2.2線網類型wire、tri
線網類型便是結構實體之間的物理連線。不能存儲值,它的值由驅動的元件所決定。
驅動線網類型變量的元件有門、連續賦值語句、assign等。
如果沒有驅動元件連接到線網類型的變量上,則該變量就是高阻態。
2.2.3參數類型parameter
常量,類似#define。可以一次定義多個參數,參數與參數之間需要用逗號隔開。每個參數定義的右邊必須是一個常數表達式。
#
1.參數的傳遞
模塊定義的時候傳入參數,模塊實例化的時候傳入參數。
2.時序仿真中的延時
//延時2.5個時間單位后執行sys_clk_i信號的翻轉
always #2.5 sys_clk_i = ~sys_clk_i;
2.3運算符
算數運算符:+、-、*、/、%
關系運算符:>、<、<=、>=、==、!=
邏輯運算符:!、&&、||
條件操作符:?:
位運算符:~、&、|、^
移位運算符:<<、>>;注意:左移位寬要增加、右移位寬不變。
拼接運算符:{}。{a,b[3:0]}
2.3.1優先級
2.4編譯指令
1.`define, `undef
2.`include
3.`timescale
用于定義時延、仿真的單位和精度
`timescale time_unit / time_precision
- time_unit 表示時間單位,time_precision 表示時間精度,
- 單位 s(秒),ms(毫秒),us(微妙),ns(納秒),ps(皮秒)和 fs(飛秒)。
- 時間單位≥時間精度。
- 編譯過程中,`timescale會影響后面的模塊中的時延值。直到遇到另一個`timescale或者`resetall。
- 沒有默認的`timescale,沒有指定的情況下,會繼承前面編譯模塊的`timescale參數,可能導致設計出錯。
- 一個設計多個模塊都有`timescale時,時延單位不受影響,但是時延精度會換算成最小時延精度。
- 如果有并行子模塊,子模塊間的 `timescale 并不會相互影響。
- 時間精度設置是會影響仿真時間的。時間精度越小,仿真時占用內存越多,實際使用的仿真時間就越長。所以如果沒有必要,應盡量將時間精度設置的大一些。
- 如果延時時間的最小位數小于時間精度,將會四舍五入。例如時間單位為10ns,精度為1ns,#1.04表示延時1.04個時間單位=1.04x10ns=10.4ns,但精度無法表示0.1ns,#1.04≈10ns
4.`default_nettype
5.`resetall
6.`celldefine, `endcelldefine
7.`unconnected_drive, `nounconnected_drive
三、程序框架
3.1Verilog注釋
//、/**/、
3.2Verilog關鍵字
3.3Verilog程序框架
模塊的結構
一個模塊由兩部分組成:一部分描述接口,一部分描述邏輯功能。
端口定義、IO說明、內部信號聲明、功能定義。
模塊的調用
四、高級知識點
4.1結構語句
1.?initial
只執行一次。
常用于測試文件的編寫,用來產生仿真測試信號(激勵信號),或者用于對存儲器變量賦初值。
2. always
一直不斷地重復活動。
但是只有和一定的時間控制結合在一起才有作用。
always時間控制可以是沿觸發或者電平觸發。敏感列表。
沿觸發:
多個信號中間要用or連接。(posedge,negedge)
電平觸發:(*)
4.2賦值語句
1.阻塞賦值(與C語言一樣)
b = a;
描述組合邏輯時,用阻塞賦值。
2.非阻塞賦值(并行同時賦值)
b <= a;
只能用于對寄存器類型的變量進行賦值,只能用于initial和always中。
描述時序邏輯時,用非阻塞賦值。
注意:在同一個always塊中不要既用非阻塞賦值又要阻塞賦值,不允許在多個always塊中對同一個變量進行賦值。
組合邏輯
任意時刻輸出僅僅取決于該時刻的輸入,與電路原來的狀態無關。
時序邏輯
任意時刻的輸出不僅取決于當時的輸入信號,而且還取決于電路原來的狀態。或者說還與之前的輸入有關,因此時序邏輯必須具備記憶功能。
4.3條件語句
條件語句必須在過程塊(initial、always)中使用。
if-else
0,x,z按假處理。
if和else后面可以用begin end包含多個語句。
case
位寬必須相等。
casez,不用考慮表達式中的高阻值。
casex,不用考慮高阻值z和不定值x。
4.4函數
4.5任務
- 任務的輸入輸出可以沒有或者多個,且端口聲明可以為 inout 型。
- 不能出現initial和always過程塊。但可以包含其他時序控制,如延時語句。
- 任務可以調用函數和任務。
- 任務可以作為一條單獨的語句出現語句塊中。
4.5.1 任務聲明
任務在模塊中任意位置定義,并在模塊內任意位置引用,作用范圍也局限于此模塊。
模塊內子程序出現下面任意一個條件時,則必須使用任務而不能使用函數。
- 1)子程序中包含時序控制邏輯,例如延遲,事件控制等
- 2)沒有輸入變量
- 3)沒有輸出或輸出端的數量大于 1
對 output 信號賦值時也不要用關鍵字 assign。為避免時序錯亂,建議 output 信號采用阻塞賦值。
task task_id ;port_declaration ;procedural_statement ;
endtask
task xor_oper_iner(input [N-1:0] ? numa,input [N-1:0] ? numb,output [N-1:0] ?numco ?) ; #3 ?numco ? ? ? = numa ^ numb ;
endtask
4.5.2 任務調用
task_id(input1, input2, …,outpu1, output2, …);
輸入端連接的模塊內信號可以是 wire 型,也可以是 reg 型。輸出端連接的模塊內信號要求一定是 reg 型。
4.6狀態機
4.6.1狀態機概念FSM
在有限個狀態之間按一定規律轉換的時序電路
4.6.2狀態機模型
狀態寄存器由一組觸發器組成,用來記憶狀態機當前所處的狀態,狀態的改變只發生在時鐘的跳變沿。
4.6.3狀態機設計
狀態空間定義
狀態跳轉(時序邏輯)
下個狀態判斷(組合邏輯)
各個狀態下的動作