本原創教程由芯驛電子科技(上海)有限公司(ALINX)創做,版權歸本公司全部,如需轉載,需受權並註明出處。node
AXU2CGA/AXU2CGB/AXU3EG/AXU4EV-E/AXU4EV-P/AXU5EV-E/AXU5EV-P /AXU9EG/AXU15EG網絡
本文主要介紹verilog基礎模塊,夯實基礎,對深刻學習FPGA會有很大幫助。dom
常量異步
整數:整數能夠用二進制b或B,八進制o或O,十進制d或D,十六進制h或H表示,例如, 8’b00001111表示8位位寬的二進制整數,4’ha表示4位位寬的十六進制整數。學習
X和Z:X表明不定值,z表明高阻值,例如,5’b00x11,第三位不定值,3’b00z表示最低位爲高阻值。spa
下劃線:在位數過長時能夠用來分割位數,提升程序可讀性,如8’b0000_1111設計
參數parameter: parameter能夠用標識符定義常量,運用時只使用標識符便可,提升可讀性及維護性,如定義parameter width = 8 ; 定義寄存器reg [width-1:0] a; 即定義了8位寬度的寄存器。3d
參數的傳遞:在一個模塊中若是有定義參數,在其餘模塊調用此模塊時能夠傳遞參數,並能夠修改參數,以下所示,在module後用#()表示。code
例如定義模塊以下調用模塊orm
module rom #( parameter depth =15, parameter width =8 ) ( input[depth-1:0] addr , input[width-1:0] data , output result ); endmodule module top(); wire[31:0] addr ; wire[15:0] data ; wire result ; rom #( .depth(32), .width(16) ) r1 ( .addr(addr), .data(data), .result(result) ); endmodule
Parameter能夠用於模塊間的參數傳遞,而localparam僅用於本模塊內使用,不能用於參數傳遞。Localparam多用於狀態機狀態的定義。
變量
變量是指程序運行時能夠改變其值的量,下面主要介紹幾個經常使用了變量類型
1.Wire 型
Wire 類型變量,也叫網絡類型變量,用於結構實體之間的物理鏈接,如門與門之間,不能儲存值,用連續賦值語句assign賦值,定義爲wire [n-1:0] a ; 其中n表明位寬,如定義wire a ; assign a = b ; 是將b的結點鏈接到連線a上。以下圖所示,兩個實體之間的連線便是wire類型變量。
2.Reg 型
Reg 類型變量,也稱爲寄存器變量,可用來儲存值,必須在always語句裏使用。其定義爲
reg [n-1:0] a ; 表示n位位寬的寄存器,如reg [7:0] a; 表示定義8位位寬的寄存器a。以下所示定義了寄存器q,生成的電路爲時序邏輯,右圖爲其結構,爲D觸發器。
module top(d, clk, q); input d ; input clk ; outputreg q ; always@(posedge clk) begin q <= d ; end endmodule
也能夠生成組合邏輯,如數據選擇器,敏感信號沒有時鐘,定義了reg Mux,最終生成電路爲組合邏輯。
module top(a, b, c, d, sel, Mux); input a ; input b ; input c ; input d ; input[1:0] sel ; outputreg Mux ; always@(sel or a or b or c or d) begin case(sel) 2'b00: Mux = a ; 2'b01: Mux = b ; 2'b10: Mux = c ; 2'b11: Mux = d ; endcase end endmodule
3.Memory型
能夠用memory類型來定義RAM,ROM等存儲器,其結構爲reg [n-1:0] 存儲器名[m-1:0],意義爲m個n位寬度的寄存器。例如,reg [7:0] ram [255:0]表示定義了256個8位寄存器,256也便是存儲器的深度,8爲數據寬度。
運算符可分爲如下幾類:
算術運算符
「+」(加法運算符),」-「(減法運算符),」*」(乘法運算符),」/」(除法運算符,如7/3 =2),「%」(取模運算符,也即求餘數,如7%3=1,餘數爲1)
賦值運算符
「=」阻塞賦值,」<=」非阻塞賦值。阻塞賦值爲執行完一條賦值語句,再執行下一條,可理解爲順序執行,並且賦值是當即執行;非阻塞賦值可理解爲並行執行,不考慮順序,在always塊語句執行完成後,才進行賦值。以下面的阻塞賦值:
代碼以下:激勵文件以下
module top(din,a,b,c,clk); input din; input clk; outputreg a,b,c; always@(posedge clk) begin a = din; b = a; c = b; end endmodule `timescale1 ns/1 ns module top_tb(); reg din ; reg clk ; wire a,b,c ; initial begin din =0; clk =0; forever begin #({$random}%100) din =~din ; end end always#10 clk =~clk ; top t0(.din(din),.a(a),.b(b),.c(c),.clk(clk)); endmodule
能夠從仿真結果看到,在clk的上升沿,a的值等於din,並當即賦給b,b的值賦給c。
若是改成非阻塞賦值,仿真結果以下,在clk上升沿,a的值沒有當即賦值給b,b爲a原來的值,一樣,c爲b原來的值
能夠從二者的RTL圖看出明顯不一樣:
阻塞賦值RTL圖非阻塞賦值RTL圖
通常狀況下,在時序邏輯電路中使用非阻塞賦值,可避免仿真時出現競爭冒險現象;在組合邏輯中使用阻塞賦值,執行賦值語句後當即改變;在assign語句中必須用阻塞賦值。
用於表示兩個操做數之間的關係,如a>b,a<b,多用於判斷條件,例如:
If (a>=b) q <=1’b1 ; else q <= 1’b0 ;表示若是a的值大於等於b的值,則q的值爲1,不然q的值爲0 |
「&&」(兩個操做數邏輯與),」||」(兩個操做數邏輯或),」!」(單個操做數邏輯非)例如:
If (a>b && c <d) 表示條件爲a>b而且c<d; if (!a)表示條件爲a的值不爲1,也就是0。
「?:」爲條件判斷,相似於if else,例如assign a = (i>8)?1’b1:1’b0 ;判斷i的值是否大於8,若是大於8則a的值爲1,不然爲0。
「~」按位取反,」|」按位或,」^」按位異或,」&」按位與,」^」按位同或,除了」~」只須要一個操做數外,其餘幾個都須要兩個操做數,如a&b,a|b。具體應用在後面的組合邏輯一節中有講解。
「<<」左移位運算符,」>>」右移位運算符,如a<<1表示,向左移1位,a>>2,向右移兩位。
「{ }」拼接運算符,將多個信號按位拼接,如{a[3:0], b[1:0]},將a的低4位,b的低2位拼接成6位數據。另外,{n{a[3:0]}}表示將n個a[3:0]拼接,{n{1’b0}}表示n位的0拼接。如{8{1’b0}}表示爲8’b0000_0000.
各類運算符的優先級別以下:
本節主要介紹組合邏輯,組合邏輯電路的特色是任意時刻的輸出僅僅取決於輸入信號,輸入信號變化,輸出當即變化,不依賴於時鐘。
在verilog中以「&」表示按位與,如c=a&b,真值表以下,在a和b都等於1時結果才爲1,RTL表示如右圖
代碼實現以下:激勵文件以下:
module top(a, b, c); input a ; input b ; output c ; assign c = a & b ; endmodule `timescale1 ns/1 ns module top_tb(); reg a ; reg b ; wire c ; initial begin a =0; b =0; forever begin #({$random}%100) a =~a ; #({$random}%100) b =~b ; end end top t0(.a(a),.b(b),.c(c)); endmodule
仿真結果以下:
若是a和b的位寬大於1,例如定義input [3:0] a, input [3:0]b,那麼a&b則指a與b的對應位相與。如a[0]&b[0],a[1]&b[1]。
在verilog中以「|」表示按位或,如c = a|b , 真值表以下,在a和b都爲0時結果才爲0。
代碼實現以下:激勵文件以下
module top(a, b, c); input a ; input b ; output c ; assign c = a | b ; endmodule `timescale1 ns/1 ns module top_tb(); reg a ; reg b ; wire c ; initial begin a =0; b =0; forever begin #({$random}%100) a =~a ; #({$random}%100) b =~b ; end end top t0(.a(a),.b(b),.c(c)); endmodule
仿真結果以下:
同理,位寬大於1,則是按位或。
在verilog中以「~」表示按位取反,如b=~a,真值表以下,b等於a的相反數。
代碼實現以下:激勵文件以下:
module top(a, b); input a ; output b ; assign b =~a ; endmodule `timescale1 ns/1 ns module top_tb(); reg a ; wire b ; initial begin a =0; forever begin #({$random}%100) a =~a ; end end top t0(.a(a),.b(b)); endmodule
仿真結果如以下:
在verilog中以「^」表示異或,如c= a^b ,真值表以下,當a和b相同時,輸出爲0。
代碼實現以下:激勵文件以下:
module top(a, b, c); input a ; input b ; output c ; assign c = a ^ b ; endmodule `timescale1 ns/1 ns module top_tb(); reg a ; reg b ; wire c ; initial begin a =0; b =0; forever begin #({$random}%100) a =~a ; #({$random}%100) b =~b ; end end top t0(.a(a),.b(b),.c(c)); endmodule
仿真結果以下:
在verilog中以大於「>」,等於」==」,小於」<」,大於等於」>=」,小於等於」<=」,不等於」!=」表示,以大於舉例,如c= a > b ;表示若是a大於b,那麼c的值就爲1,不然爲0。真值表以下:
代碼實現以下:激勵文件以下:
module top(a, b, c); input a ; input b ; output c ; assign c = a > b ; endmodule `timescale1 ns/1 ns module top_tb(); reg a ; reg b ; wire c ; initial begin a =0; b =0; forever begin #({$random}%100) a =~a ; #({$random}%100) b =~b ; end end top t0(.a(a),.b(b),.c(c)); endmodule
仿真結果以下:
半加器和全加器是算術運算電路中的基本單元,因爲半加器不考慮從低位來的進位,因此稱之爲半加器,sum表示相加結果,count表示進位,真值表可表示以下:
可根據真值表寫出代碼以下:激勵文件以下:
module top(a, b, sum, count); input a ; input b ; output sum ; output count ; assign sum = a ^ b ; assign count = a & b ; endmodule `timescale1 ns/1 ns module top_tb(); reg a ; reg b ; wire sum ; wire count ; initial begin a =0; b =0; forever begin #({$random}%100) a =~a ; #({$random}%100) b =~b ; end end top t0(.a(a),.b(b), .sum(sum),.count(count)); endmodule
仿真結果以下:
而全加器須要加上低位來的進位信號cin,真值表以下:
代碼以下:激勵文件以下:
module top(cin, a, b, sum, count); input cin ; input a ; input b ; output sum ; output count ; assign{count,sum}= a + b + cin ; endmodule `timescale1 ns/1 ns module top_tb(); reg a ; reg b ; reg cin ; wire sum ; wire count ; initial begin a =0; b =0; cin =0; forever begin #({$random}%100) a =~a ; #({$random}%100) b =~b ; #({$random}%100) cin =~cin ; end end top t0(.cin(cin),.a(a),.b(b), .sum(sum),.count(count)); endmodule
仿真結果以下:
乘法的表示也很簡單,利用」*」便可,如a*b,舉例代碼以下:
module top(a, b, c); input[1:0] a ; input[1:0] b ; output[3:0] c ; assign c = a * b ; endmodule `timescale1 ns/1 ns module top_tb(); reg[1:0]a ; reg[1:0]b ; wire[3:0]c ; initial begin a =0; b =0; forever begin #({$random}%100) a =~a ; #({$random}%100) b =~b ; end end top t0(.a(a),.b(b),.c(c)); endmodule
仿真結果以下:
在verilog中常常會用到數據選擇器,經過選擇信號,選擇不一樣的輸入信號輸出到輸出端,以下圖真值表,四選一數據選擇器,sel[1:0]爲選擇信號,a,b,c,d爲輸入信號,Mux爲輸出信號。
代碼以下:激勵文件以下:
module top(a, b, c, d, sel, Mux); input a ; input b ; input c ; input d ; input[1:0] sel ; outputreg Mux ; always@(sel or a or b or c or d) begin case(sel) 2'b00: Mux = a ; 2'b01: Mux = b ; 2'b10: Mux = c ; 2'b11: Mux = d ; endcase end endmodule `timescale1 ns/1 ns module top_tb(); reg a ; reg b ; reg c ; reg d ; reg[1:0] sel ; wire Mux ; initial begin a =0; b =0; c =0; d =0; forever begin #({$random}%100) a ={$random}%3; #({$random}%100) b ={$random}%3; #({$random}%100) c ={$random}%3; #({$random}%100) d ={$random}%3; end end initial begin sel =2'b00; #2000 sel =2'b01; #2000 sel =2'b10; #2000 sel =2'b11; end top t0(.a(a),.b(b),.c(c),.d(d),.sel(sel), .