0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

verilog基礎(chǔ)模塊的介紹

電子設(shè)計(jì) ? 來(lái)源:電子設(shè)計(jì) ? 作者:電子設(shè)計(jì) ? 2022-02-08 15:04 ? 次閱讀

作者: ALINX

適用于板卡型號(hào):

AXU2CGA/AXU2CGB/AXU3EG/AXU4EV-E/AXU4EV-P/AXU5EV-E/AXU5EV-P /AXU9EG/AXU15EG

簡(jiǎn)介

本文主要介紹verilog基礎(chǔ)模塊,夯實(shí)基礎(chǔ),對(duì)深入學(xué)習(xí)FPGA會(huì)有很大幫助。

數(shù)據(jù)類(lèi)型

常量

整數(shù):整數(shù)可以用二進(jìn)制b或B,八進(jìn)制o或O,十進(jìn)制d或D,十六進(jìn)制h或H表示,例如, 8’b00001111表示8位位寬的二進(jìn)制整數(shù),4’ha表示4位位寬的十六進(jìn)制整數(shù)。

X和Z:X代表不定值,z代表高阻值,例如,5’b00x11,第三位不定值,3’b00z表示最低位為高阻值。

下劃線:在位數(shù)過(guò)長(zhǎng)時(shí)可以用來(lái)分割位數(shù),提高程序可讀性,如8’b0000_1111

參數(shù)parameter: parameter可以用標(biāo)識(shí)符定義常量,運(yùn)用時(shí)只使用標(biāo)識(shí)符即可,提高可讀性及維護(hù)性,如定義parameter width = 8 ; 定義寄存器reg [width-1:0] a; 即定義了8位寬度的寄存器。

參數(shù)的傳遞:在一個(gè)模塊中如果有定義參數(shù),在其他模塊調(diào)用此模塊時(shí)可以傳遞參數(shù),并可以修改參數(shù),如下所示,在module后用#()表示。

例如定義模塊如下調(diào)用模塊

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可以用于模塊間的參數(shù)傳遞,而localparam僅用于本模塊內(nèi)使用,不能用于參數(shù)傳遞。Localparam多用于狀態(tài)機(jī)狀態(tài)的定義。

變量

變量是指程序運(yùn)行時(shí)可以改變其值的量,下面主要介紹幾個(gè)常用了變量類(lèi)型

1.Wire 型

Wire 類(lèi)型變量,也叫網(wǎng)絡(luò)類(lèi)型變量,用于結(jié)構(gòu)實(shí)體之間的物理連接,如門(mén)與門(mén)之間,不能儲(chǔ)存值,用連續(xù)賦值語(yǔ)句assign賦值,定義為wire [n-1:0] a ; 其中n代表位寬,如定義wire a ; assign a = b ; 是將b的結(jié)點(diǎn)連接到連線a上。如下圖所示,兩個(gè)實(shí)體之間的連線即是wire類(lèi)型變量。

o4YBAGAJvn6AF_u8AAAnf8DJXJY152.jpg

2.Reg 型

Reg 類(lèi)型變量,也稱(chēng)為寄存器變量,可用來(lái)儲(chǔ)存值,必須在always語(yǔ)句里使用。其定義為

reg [n-1:0] a ; 表示n位位寬的寄存器,如reg [7:0] a; 表示定義8位位寬的寄存器a。如下所示定義了寄存器q,生成的電路為時(shí)序邏輯,右圖為其結(jié)構(gòu),為D觸發(fā)器。

module top(d, clk, q);

input d ;

input clk ;

outputreg q ;

always@(posedge clk)

begin

q 《= d ;

end

endmodule

pIYBAGAJvryAB-xfAAAjMVyjjdY255.png

也可以生成組合邏輯,如數(shù)據(jù)選擇器,敏感信號(hào)沒(méi)有時(shí)鐘,定義了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

o4YBAGAJvvyASZs7AAAo7_-c3pY760.png

3.Memory型

可以用memory類(lèi)型來(lái)定義RAM,ROM等存儲(chǔ)器,其結(jié)構(gòu)為reg [n-1:0] 存儲(chǔ)器名[m-1:0],意義為m個(gè)n位寬度的寄存器。例如,reg [7:0] ram [255:0]表示定義了256個(gè)8位寄存器,256也即是存儲(chǔ)器的深度,8為數(shù)據(jù)寬度。

運(yùn)算符

運(yùn)算符可分為以下幾類(lèi):

1. 算術(shù)運(yùn)算符(+,-,*,/,%)

2. 賦值運(yùn)算符(=, 3. 關(guān)系運(yùn)算符(》,=, 4. 邏輯運(yùn)算符(&&,||,!)

5. 條件運(yùn)算符(?:)

6. 位運(yùn)算符(~,|,^,&,^~)

7. 移位運(yùn)算符(》)

8. 拼接運(yùn)算符({ })

算術(shù)運(yùn)算符

“+”(加法運(yùn)算符),”-“(減法運(yùn)算符),”*”(乘法運(yùn)算符),”/”(除法運(yùn)算符,如7/3 =2),“%”(取模運(yùn)算符,也即求余數(shù),如7%3=1,余數(shù)為1)

賦值運(yùn)算符

“=”阻塞賦值,”

代碼如下:激勵(lì)文件如下

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

可以從仿真結(jié)果看到,在clk的上升沿,a的值等于din,并立即賦給b,b的值賦給c。

pIYBAGAJvzmAacggAAAeYd-SmnY027.jpg

如果改為非阻塞賦值,仿真結(jié)果如下,在clk上升沿,a的值沒(méi)有立即賦值給b,b為a原來(lái)的值,同樣,c為b原來(lái)的值

o4YBAGAJv3eAOGIwAAAfHNYhiGw615.jpg

可以從兩者的RTL圖看出明顯不同:

o4YBAGAJv7eAAacmAAAsYEZC3nw667.jpg

o4YBAGAJv_WAJuT9AABCq0Ena6g851.jpg

阻塞賦值RTL圖非阻塞賦值RTL圖

一般情況下,在時(shí)序邏輯電路中使用非阻塞賦值,可避免仿真時(shí)出現(xiàn)競(jìng)爭(zhēng)冒險(xiǎn)現(xiàn)象;在組合邏輯中使用阻塞賦值,執(zhí)行賦值語(yǔ)句后立即改變;在assign語(yǔ)句中必須用阻塞賦值。

關(guān)系運(yùn)算符

用于表示兩個(gè)操作數(shù)之間的關(guān)系,如a》b,a If (a》=b) q else q

邏輯運(yùn)算符

“&&”(兩個(gè)操作數(shù)邏輯與),”||”(兩個(gè)操作數(shù)邏輯或),”!”(單個(gè)操作數(shù)邏輯非)例如:

If (a》b && c b并且c

條件運(yùn)算符

“?:”為條件判斷,類(lèi)似于if else,例如assign a = (i》8)?1’b1:1’b0 ;判斷i的值是否大于8,如果大于8則a的值為1,否則為0。

位運(yùn)算符

“~”按位取反,”|”按位或,”^”按位異或,”&”按位與,”^”按位同或,除了”~”只需要一個(gè)操作數(shù)外,其他幾個(gè)都需要兩個(gè)操作數(shù),如a&b,a|b。具體應(yīng)用在后面的組合邏輯一節(jié)中有講解。

移位運(yùn)算符

“》”右移位運(yùn)算符,如a》2,向右移兩位。

拼接運(yùn)算符

“{ }”拼接運(yùn)算符,將多個(gè)信號(hào)按位拼接,如{a[3:0], b[1:0]},將a的低4位,b的低2位拼接成6位數(shù)據(jù)。另外,{n{a[3:0]}}表示將n個(gè)a[3:0]拼接,{n{1’b0}}表示n位的0拼接。如{8{1’b0}}表示為8’b0000_0000.

優(yōu)先級(jí)別

各種運(yùn)算符的優(yōu)先級(jí)別如下:

pIYBAGAJwDOAe08nAAAwHqCKzW0366.jpg

組合邏輯

本節(jié)主要介紹組合邏輯,組合邏輯電路的特點(diǎn)是任意時(shí)刻的輸出僅僅取決于輸入信號(hào),輸入信號(hào)變化,輸出立即變化,不依賴(lài)于時(shí)鐘。

與門(mén)

在verilog中以“&”表示按位與,如c=a&b,真值表如下,在a和b都等于1時(shí)結(jié)果才為1,RTL表示如右圖

o4YBAGAJwHCAAeqOAAAIrplGvSk164.jpg

o4YBAGAJwLCAKmUQAAAWb0DkhYI721.jpg

代碼實(shí)現(xiàn)如下:激勵(lì)文件如下:

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

仿真結(jié)果如下:

o4YBAGAJwPOAW44gAAAVFuW0Qlw180.jpg

如果a和b的位寬大于1,例如定義input [3:0] a, input [3:0]b,那么a&b則指a與b的對(duì)應(yīng)位相與。如a[0]&b[0],a[1]&b[1]。

或門(mén)

在verilog中以“|”表示按位或,如c = a|b , 真值表如下,在a和b都為0時(shí)結(jié)果才為0。

o4YBAGAJwTGANOl7AAAGcrItYWc718.jpg

o4YBAGAJwXWAanmHAAAyemICokg377.jpg

代碼實(shí)現(xiàn)如下:激勵(lì)文件如下

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

仿真結(jié)果如下:

o4YBAGAJwbKAcYGuAAAVeWsbpwk085.jpg

同理,位寬大于1,則是按位或。

非門(mén)

在verilog中以“~”表示按位取反,如b=~a,真值表如下,b等于a的相反數(shù)。

o4YBAGAJwfCAZNTzAAAEjYkIIN4341.jpg

o4YBAGAJwi6AaStgAAAueLl0tic326.jpg

代碼實(shí)現(xiàn)如下:激勵(lì)文件如下:

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

仿真結(jié)果如如下:

o4YBAGAJwmyAHAcLAAATIwb-S1Q841.jpg

異或

在verilog中以“^”表示異或,如c= a^b ,真值表如下,當(dāng)a和b相同時(shí),輸出為0。

pIYBAGAJwqmAZiP_AAAGNfK8z5o550.jpg

代碼實(shí)現(xiàn)如下:激勵(lì)文件如下:

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

仿真結(jié)果如下:

pIYBAGAJw1KAIl7_AAAYoOA_WBY115.jpg

比較器

在verilog中以大于“》”,等于”==”,小于”=”,小于等于” b ;表示如果a大于b,那么c的值就為1,否則為0。真值表如下:

o4YBAGAJw5CAMcbEAAAGeO6zfro903.jpg

pIYBAGAJw9CABifuAAAxiUrDxHM223.jpg

代碼實(shí)現(xiàn)如下:激勵(lì)文件如下:

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

仿真結(jié)果如下:

半加器

半加器和全加器是算術(shù)運(yùn)算電路中的基本單元,由于半加器不考慮從低位來(lái)的進(jìn)位,所以稱(chēng)之為半加器,sum表示相加結(jié)果,count表示進(jìn)位,真值表可表示如下:

o4YBAGAJxEuAT8TmAAAH3CWA7pc802.jpg

可根據(jù)真值表寫(xiě)出代碼如下:激勵(lì)文件如下:

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

仿真結(jié)果如下:

全加器

而全加器需要加上低位來(lái)的進(jìn)位信號(hào)cin,真值表如下:

pIYBAGAJxVuAI5-EAAAM61JFmSM537.jpg

代碼如下:激勵(lì)文件如下:

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

仿真結(jié)果如下:

o4YBAGAJxdaAde3EAAAgrDqK19c419.jpg

乘法器

乘法的表示也很簡(jiǎn)單,利用”*”即可,如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

仿真結(jié)果如下:

o4YBAGAJxhWAaMAvAAAa-3qzycQ737.jpg

數(shù)據(jù)選擇器

在verilog中經(jīng)常會(huì)用到數(shù)據(jù)選擇器,通過(guò)選擇信號(hào),選擇不同的輸入信號(hào)輸出到輸出端,如下圖真值表,四選一數(shù)據(jù)選擇器,sel[1:0]為選擇信號(hào),a,b,c,d為輸入信號(hào),Mux為輸出信號(hào)。

o4YBAGAJxlKALIDjAAAMr6VgaKs941.jpg

o4YBAGAJxpCAEWDuAABQHByHdCQ287.jpg

代碼如下:激勵(lì)文件如下:

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),

.Mux(Mux));

endmodule

仿真結(jié)果如下

pIYBAGAJxtOAbVp_AAAo-RCA9fg735.jpg

3-8譯碼器

3-8譯碼器是一個(gè)很常用的器件,其真值表如下所示,根據(jù)A2,A1,A0的值,得出不同的結(jié)果。

o4YBAGAJxxCAHbW4AAAZ2SXtVnw466.jpg

o4YBAGAJx06AfQQwAABbQ--mE5k581.jpg

代碼如下:激勵(lì)文件如下:

module top(addr, decoder);

input[2:0] addr ;

outputreg[7:0] decoder ;

always@(addr)

begin

case(addr)

3‘b000: decoder =8’b1111_1110;

3‘b001: decoder =8’b1111_1101;

3‘b010: decoder =8’b1111_1011;

3‘b011: decoder =8’b1111_0111;

3‘b100: decoder =8’b1110_1111;

3‘b101: decoder =8’b1101_1111;

3‘b110: decoder =8’b1011_1111;

3‘b111: decoder =8’b0111_1111;

endcase

end

endmodule

`timescale1 ns/1 ns

module top_tb();

reg[2:0] addr ;

wire[7:0] decoder ;

initial

begin

addr =3‘b000;

#2000 addr =3’b001;

#2000 addr =3‘b010;

#2000 addr =3’b011;

#2000 addr =3‘b100;

#2000 addr =3’b101;

#2000 addr =3‘b110;

#2000 addr =3’b111;

end

top

t0(.addr(addr),.decoder(decoder));

endmodule

仿真結(jié)果如下:

pIYBAGAJx4yAJ4odAAAV8ylH1ls002.jpg

三態(tài)門(mén)

在FPGA使用中,經(jīng)常會(huì)用到雙向IO,需要用到三態(tài)門(mén),如bio = en? din: 1’bz ;其中en為使能信號(hào),用于打開(kāi)關(guān)閉三態(tài)門(mén),下面的RTL圖即是實(shí)現(xiàn)了雙向IO,可參考代碼。激勵(lì)文件實(shí)現(xiàn)兩個(gè)雙向IO的對(duì)接。

o4YBAGAJx8mABRCNAAAq0GGc7ng949.jpg

module top(en, din, dout, bio);

input din ;

input en ;

output dout ;

inout bio ;

assign bio = en? din :1‘bz;

assign dout = bio ;

endmodule

`timescale1 ns/1 ns

module top_tb();

reg en0 ;

reg din0 ;

wire dout0 ;

reg en1 ;

reg din1 ;

wire dout1 ;

wire bio ;

initial

begin

din0 =0;

din1 =0;

forever

begin

#({$random}%100)

din0 =~din0 ;

#({$random}%100)

din1 =~din1 ;

end

end

initial

begin

en0 =0;

en1 =1;

#100000

en0 =1;

en1 =0;

end

top

t0(.en(en0),.din(din0),.dout(dout0),.bi

o(bio));

top

t1(.en(en1),.din(din1),.dout(dout1),.bi

o(bio));

endmodule

激勵(lì)文件結(jié)構(gòu)如下圖

o4YBAGAJyAeAc9d2AABQBR0JKBM990.jpg

仿真結(jié)果如下,en0為0,en1為1時(shí),1通道打開(kāi),雙向IO bio就等于1通道的din1,1通道向外發(fā)送數(shù)據(jù),0通道接收數(shù)據(jù),dout0等于bio;當(dāng)en0為1,en1為0時(shí),0通道打開(kāi),雙向IO bio就等于0通道的din0,0通道向外發(fā)送數(shù)據(jù),1通道接收數(shù)據(jù),dout1等于bio

pIYBAGAJyEWAL9gCAAAuytPhDek686.jpg

時(shí)序邏輯

組合邏輯電路在邏輯功能上特點(diǎn)是任意時(shí)刻的輸出僅僅取決于當(dāng)前時(shí)刻的輸入,與電路原來(lái)的狀態(tài)無(wú)關(guān)。而時(shí)序邏輯在邏輯功能上的特點(diǎn)是任意時(shí)刻的輸出不僅僅取決于當(dāng)前的輸入信號(hào),而且還取決于電路原來(lái)的狀態(tài)。下面以典型的時(shí)序邏輯分析。

D觸發(fā)器

D觸發(fā)器在時(shí)鐘的上升沿或下降沿存儲(chǔ)數(shù)據(jù),輸出與時(shí)鐘跳變之前輸入信號(hào)的狀態(tài)相同。

代碼如下激勵(lì)文件如下

module top(d, clk, q);

input d ;

input clk ;

outputreg q ;

always@(posedge clk)

begin

q 《= d ;

end

endmodule

`timescale1 ns/1 ns

module top_tb();

reg d ;

reg clk ;

wire q ;

initial

begin

d =0;

clk =0;

forever

begin

#({$random}%100)

d =~d ;

end

end

always#10 clk =~clk ;

top t0(.d(d),.clk(clk),.q(q));

endmodule

RTL圖表示如下

o4YBAGAJyIqAV2JMAAAzhP6eS3Y545.jpg

仿真結(jié)果如下,可以看到在t0時(shí)刻時(shí),d的值為0,則q的值也為0;在t1時(shí)刻d發(fā)生了變化,值為1,那么q相應(yīng)也發(fā)生了變化,值變?yōu)???梢钥吹皆趖0-t1之間的一個(gè)時(shí)鐘周期內(nèi),無(wú)論輸入信號(hào)d的值如何變化,q的值是保持不變的,也就是有存儲(chǔ)的功能,保存的值為在時(shí)鐘的跳變沿時(shí)d的值。

pIYBAGAJyMeAWCQRAAAXrdufIXw605.jpg

兩級(jí)D觸發(fā)器

軟件是按照兩級(jí)D觸發(fā)器的模型進(jìn)行時(shí)序分析的,具體可以分析在同一時(shí)刻兩個(gè)D觸發(fā)器輸出的數(shù)據(jù)有何不同,其RTL圖如下:

pIYBAGAJyQiAQbjDAABP8ZpuhBQ567.jpg

代碼如下:激勵(lì)文件如下:

module top(d, clk, q, q1);

input d ;

input clk ;

outputreg q ;

outputreg q1 ;

always@(posedge clk)

begin

q 《= d ;

end

always@(posedge clk)

begin

q1 《= q ;

end

endmodule

`timescale1 ns/1 ns

module top_tb();

reg d ;

reg clk ;

wire q ;

wire q1 ;

initial

begin

d =0;

clk =0;

forever

begin

#({$random}%100)

d =~d ;

end

end

always#10 clk =~clk ;

top

t0(.d(d),.clk(clk),.q(q),.q1(q1));

endmodule

仿真結(jié)果如下,可以看到t0時(shí)刻,d為0,q輸出為0,t1時(shí)刻,q隨著d的數(shù)據(jù)變化而變化,而此時(shí)鐘跳變之前q的值仍為0,那么q1的值仍為0,t2時(shí)刻,時(shí)鐘跳變前q的值為1,則q1的值相應(yīng)為1,q1相對(duì)于q落后一個(gè)周期。

pIYBAGAJyUaABOZwAAAWSvnsdPo959.jpg

帶異步復(fù)位的D觸發(fā)器

異步復(fù)位是指獨(dú)立于時(shí)鐘,一旦異步復(fù)位信號(hào)有效,就觸發(fā)復(fù)位操作。這個(gè)功能在寫(xiě)代碼時(shí)會(huì)經(jīng)常用到,用于給信號(hào)復(fù)位,初始化。其RTL圖如下:

o4YBAGAJyYWAS924AABRu6Nwai4035.jpg

代碼如下,注意要把異步復(fù)位信號(hào)放在敏感列表里,如果是低電平復(fù)位,即為negedge,如果是高電平復(fù)位,則是posedge

module top(d, rst, clk, q);

input d ;

input rst ;

input clk ;

outputreg q ;

always@(posedge clk ornegedge rst)

begin

if(rst ==1’b0)

q 《=0;

else

q 《= d ;

end

endmodule

`timescale1 ns/1 ns

module top_tb();

reg d ;

reg rst ;

reg clk ;

wire q ;

initial

begin

d =0;

clk =0;

forever

begin

#({$random}%100)

d =~d ;

end

end

initial

begin

rst =0;

#200 rst =1;

end

always#10 clk =~clk ;

top

t0(.d(d),.rst(rst),.clk(clk),.q(q));

endmodule

仿真結(jié)果如下,可以看到在復(fù)位信號(hào)之前,雖然輸入信號(hào)d數(shù)據(jù)有變化,但由于正處于復(fù)位狀態(tài),輸入信號(hào)q始終為0,在復(fù)位之后q的值就正常了。

pIYBAGAJyciAALiWAAAXN5tFq_Y217.jpg

帶異步復(fù)位同步清零的D觸發(fā)器

前面講到異步復(fù)位獨(dú)立于時(shí)鐘操作,而同步清零則是同步于時(shí)鐘信號(hào)下操作的,當(dāng)然也不僅限于同步清零,也可以是其他的同步操作,其RTL圖如下:

代碼如下,不同于異步復(fù)位,同步操作不能把信號(hào)放到敏感列表里

module top(d, rst, clr, clk, q);

input d ;

input rst ;

input clr ;

input clk ;

outputreg q ;

always@(posedge clk ornegedge rst)

begin

if(rst ==1‘b0)

q 《=0;

elseif(clr ==1’b1)

q 《=0;

else

q 《= d ;

end

endmodule

`timescale1 ns/1 ns

module top_tb();

reg d ;

reg rst ;

reg clr ;

reg clk ;

wire q ;

initial

begin

d =0;

clk =0;

forever

begin

#({$random}%100)

d =~d ;

end

end

initial

begin

rst =0;

clr =0;

#200 rst =1;

#200 clr =1;

#100 clr =0;

end

always#10 clk =~clk ;

top

t0(.d(d),.rst(rst),.clr(clr),.clk(clk),

.q(q));

endmodule

仿真結(jié)果如下,可以看到clr信號(hào)拉高后,q沒(méi)有立即清零,而是在下個(gè)clk上升沿之后執(zhí)行清零操作,也就是clr同步于clk。

o4YBAGAJykWAUADsAAAhuBYYipI105.jpg

移位寄存器

移位寄存器是指在每個(gè)時(shí)鐘脈沖來(lái)時(shí),向左或向右移動(dòng)一位,由于D觸發(fā)器的特性,數(shù)據(jù)輸出同步于時(shí)鐘邊沿,其結(jié)構(gòu)如下,每個(gè)時(shí)鐘來(lái)臨,每個(gè)D觸發(fā)器的輸出q等于前一個(gè)D觸發(fā)器輸出的值,從而實(shí)現(xiàn)移位的功能。

代碼實(shí)現(xiàn):

module top(d, rst, clk, q);

input d ;

input rst ;

input clk ;

outputreg[7:0] q ;

always@(posedge clk ornegedge rst)

begin

if(rst ==1‘b0)

q 《=0;

else

q 《={q[6:0], d};//向左移位

//q 《= {d, q[7:1]} ; //向右移位

end

endmodule

激勵(lì)文件:

`timescale1 ns/1 ns

module top_tb();

reg d ;

reg rst ;

reg clk ;

wire[7:0] q ;

initial

begin

d =0;

clk =0;

forever

begin

#({$random}%100)

d =~d ;

end

end

initial

begin

rst =0;

#200 rst =1;

end

always#10 clk =~clk ;

top

t0(.d(d),.rst(rst),.clk(clk),.q(q));

endmodule

仿真結(jié)果如下,可以看到復(fù)位之后,每個(gè)clk上升沿左移一位

o4YBAGAJysCAfYW8AAAdXDgrMgQ225.jpg

單口RAM

單口RAM的寫(xiě)地址與讀地址共用一個(gè)地址,代碼如下,其中reg [7:0] ram [63:0]意思是定義了64個(gè)8位寬度的數(shù)據(jù)。其中定義了addr_reg,可以保持住讀地址,延遲一周期之后將數(shù)據(jù)送出。

module top

input[7:0] data,

input[5:0] addr,

input wr,

input clk,

output[7:0] q

);

reg[7:0] ram[63:0];//declare ram

reg[5:0] addr_reg;//addr register

always@(posedge clk)

begin

if(wr)//write

ram[addr]《= data;

addr_reg 《= addr;

end

assign q = ram[addr_reg];//read data

endmodule

`timescale1 ns/1 ns

module top_tb();

reg[7:0] data ;

reg[5:0] addr ;

reg wr ;

reg clk ;

wire[7:0] q ;

initial

begin

data =0;

addr =0;

wr =1;

clk =0;

end

always#10 clk =~clk ;

always@(posedge clk)

begin

data 《= data +1’b1;

addr 《= addr +1‘b1;

end

top t0(.data(data),

.addr(addr),

.clk(clk),

.wr(wr),

.q(q));

endmodule

仿真結(jié)果如下,可以看到q的輸出與寫(xiě)入的數(shù)據(jù)一致

o4YBAGAJyv6APTyjAAA216iTGSk382.jpg

偽雙口RAM

偽雙口RAM的讀寫(xiě)地址是獨(dú)立的,可以隨機(jī)選擇寫(xiě)或讀地址,同時(shí)進(jìn)行讀寫(xiě)操作。代碼如下,在激勵(lì)文件中定義了en信號(hào),在其有效時(shí)發(fā)送讀地址。

module top

input[7:0] data,

input[5:0] write_addr,

input[5:0] read_addr,

input wr,

input rd,

input clk,

outputreg[7:0] q

);

reg[7:0] ram[63:0];//declare ram

reg[5:0] addr_reg;//addr register

always@(posedge clk)

begin

if(wr)//write

ram[write_addr]《= data;

if(rd)//read

q 《= ram[read_addr];

end

endmodule

`timescale1 ns/1 ns

module top_tb();

reg[7:0] data ;

reg[5:0] write_addr ;

reg[5:0] read_addr ;

reg wr ;

reg clk ;

reg rd ;

wire[7:0] q ;

initial

begin

data =0;

write_addr =0;

read_addr =0;

wr =0;

rd =0;

clk =0;

#100 wr =1;

#20 rd =1;

end

always#10 clk =~clk ;

always@(posedge clk)

begin

if(wr)

begin

data 《= data +1’b1;

write_addr 《= write_addr +1‘b1;

if(rd)

read_addr 《= read_addr +1’b1;

end

end

top t0(.data(data),

.write_addr(write_addr),

.read_addr(read_addr),

.clk(clk),

.wr(wr),

.rd(rd),

.q(q));

endmodule

仿真結(jié)果如下,可以看到在rd有效時(shí),對(duì)讀地址進(jìn)行操作,讀出數(shù)據(jù)

真雙口RAM

真雙口RAM有兩套控制線,數(shù)據(jù)線,允許兩個(gè)系統(tǒng)對(duì)其進(jìn)行讀寫(xiě)操作,代碼如下:

module top

input[7:0] data_a, data_b,

input[5:0] addr_a, addr_b,

input wr_a, wr_b,

input rd_a, rd_b,

input clk,

outputreg[7:0] q_a, q_b

);

reg[7:0] ram[63:0];//declare ram

//Port A

always@(posedge clk)

begin

if(wr_a)//write

begin

ram[addr_a]《= data_a;

q_a 《= data_a ;

end

if(rd_a)

//read

q_a 《= ram[addr_a];

end

//Port B

always@(posedge clk)

begin

if(wr_b)//write

begin

ram[addr_b]《= data_b;

q_b 《= data_b ;

end

if(rd_b)

//read

q_b 《= ram[addr_b];

end

endmodule

`timescale1 ns/1 ns

module top_tb();

reg[7:0] data_a, data_b ;

reg[5:0] addr_a, addr_b ;

reg wr_a, wr_b ;

reg rd_a, rd_b ;

reg clk ;

wire[7:0] q_a, q_b ;

initial

begin

data_a =0;

data_b =0;

addr_a =0;

addr_b =0;

wr_a =0;

wr_b =0;

rd_a =0;

rd_b =0;

clk =0;

#100 wr_a =1;

#100 rd_b =1;

end

always#10 clk =~clk ;

always@(posedge clk)

begin

if(wr_a)

begin

data_a 《= data_a +1‘b1;

addr_a 《= addr_a +1’b1;

end

else

begin

data_a 《=0;

addr_a 《=0;

end

end

always@(posedge clk)

begin

if(rd_b)

begin

addr_b 《= addr_b +1‘b1;

end

else addr_b 《=0;

end

top

t0(.data_a(data_a),.data_b(data_b),

.addr_a(addr_a),.addr_b(addr_b

),

.wr_a(wr_a),.wr_b(wr_b),

.rd_a(rd_a),.rd_b(rd_b),

.clk(clk),

.q_a(q_a),.q_b(q_b));

endmodule

仿真結(jié)果如下

單口ROM

ROM是用來(lái)存儲(chǔ)數(shù)據(jù)的,可以按照下列代碼形式初始化ROM,但這種方法處理大容量的ROM就比較麻煩,建議用FPGA自帶的ROM IP核實(shí)現(xiàn),并添加初始化文件。

代碼實(shí)現(xiàn)

moduletop

input[3:0] addr,

input clk,

outputreg[7:0] q

);

always@(posedge clk)

begin

case(addr)

4’d0: q 《=8‘d15;

4’d1: q 《=8‘d24;

4’d2: q 《=8‘d100;

4’d3: q 《=8‘d78;

4’d4: q 《=8‘d98;

4’d5: q 《=8‘d105;

4’d6: q 《=8‘d86;

4’d7: q 《=8‘d254;

4’d8: q 《=8‘d76;

4’d9: q 《=8‘d35;

4’d10: q 《=8‘d120;

4’d11: q 《=8‘d85;

4’d12: q 《=8‘d37;

4’d13: q 《=8‘d19;

4’d14: q 《=8‘d22;

4’d15: q 《=8‘d67;

default: q 《=8’d0;

endcase

end

endmodule

`timescale1 ns/1 ns

module top_tb();

reg[3:0] addr ;

reg clk ;

wire[7:0] q ;

initial

begin

addr =0;

clk =0;

end

always#10 clk =~clk ;

always@(posedge clk)

begin

addr 《= addr +1‘b1;

end

top t0(.addr(addr),

.clk(clk),

.q(q));

endmodule

仿真結(jié)果如下

有限狀態(tài)機(jī)

在verilog里經(jīng)常會(huì)用到有限狀態(tài)機(jī),處理相對(duì)復(fù)雜的邏輯,設(shè)定好不同的狀態(tài),根據(jù)觸發(fā)條件跳轉(zhuǎn)到對(duì)應(yīng)的狀態(tài),在不同的狀態(tài)下做相應(yīng)的處理。有限狀態(tài)機(jī)主要用到always及case語(yǔ)句。下面以一個(gè)四狀態(tài)的有限狀態(tài)機(jī)舉例說(shuō)明。

在程序中設(shè)計(jì)了8位的移位寄存器,在Idle狀態(tài)下,判斷shift_start信號(hào)是否為高,如果為高,進(jìn)入Start狀態(tài),在Start狀態(tài)延遲100個(gè)周期,進(jìn)入Run狀態(tài),進(jìn)行移位處理,如果shift_stop信號(hào)有效了,進(jìn)入Stop狀態(tài),在Stop狀態(tài),清零q的值,再跳轉(zhuǎn)到Idle狀態(tài)。

Mealy有限狀態(tài)機(jī),輸出不僅與當(dāng)前狀態(tài)有關(guān),也與輸入信號(hào)有關(guān),在RTL中會(huì)與輸入信號(hào)有連接。

module top

input shift_start,

input shift_stop,

input rst,

input clk,

input d,

outputreg[7:0] q

);

parameter Idle =2’d0;//Idle state

parameter Start =2‘d1;//Start state

parameter Run =2’d2;//Run state

parameter Stop =2‘d3;//Stop state

reg[1:0] state ;//statement

reg[4:0] delay_cnt ;//delay counter

always@(posedge clk ornegedge rst)

begin

if(!rst)

begin

state 《= Idle ;

delay_cnt 《=0;

q 《=0;

end

else

case(state)

Idle :begin

if(shift_start)

state 《= Start ;

end

Start :begin

if(delay_cnt ==5’d99)

begin

delay_cnt 《=0;

state 《= Run ;

end

else

delay_cnt 《= delay_cnt +1‘b1;

end

Run :begin

if(shift_stop)

state 《= Stop ;

else

q 《={q[6:0], d};

end

Stop :begin

q 《=0;

state 《= Idle ;

end

default: state 《= Idle ;

endcase

end

endmodule

Moore有限狀態(tài)機(jī),輸出只與當(dāng)前狀態(tài)有關(guān),與輸入信號(hào)無(wú)關(guān),輸入信號(hào)只影響狀態(tài)的改變,不影響輸出,比如對(duì)delay_cnt和q的處理,只與state狀態(tài)有關(guān)。

module top

input shift_start,

input shift_stop,

input rst,

input clk,

input d,

outputreg[7:0] q

);

parameter Idle =2’d0;//Idle state

parameter Start =2‘d1;//Start state

parameter Run =2’d2;//Run state

parameter Stop =2‘d3;//Stop state

reg[1:0] current_state ;//statement

reg[1:0] next_state ;

reg[4:0] delay_cnt ;//delay counter

//First part: statement transition

always@(posedge clk ornegedge rst)

begin

if(!rst)

current_state 《= Idle ;

else

current_state 《= next_state ;

end

//Second part: combination logic, judge statement transition condition

always@(*)

begin

case(current_state)

Idle :begin

if(shift_start)

next_state 《= Start ;

else

next_state 《= Idle ;

end

Start :begin

if(delay_cnt ==5’d99)

next_state 《= Run ;

else

next_state 《= Start ;

end

Run :begin

if(shift_stop)

next_state 《= Stop ;

else

next_state 《= Run ;

end

Stop : next_state 《= Idle ;

default:next_state 《= Idle ;

endcase

end

//Last part: output data

always@(posedge clk ornegedge rst)

begin

if(!rst)

delay_cnt 《=0;

elseif(current_state == Start)

delay_cnt 《= delay_cnt +1‘b1;

else

delay_cnt 《=0;

end

always@(posedge clk ornegedge rst)

begin

if(!rst)

q 《=0;

elseif(current_state == Run)

q 《={q[6:0], d};

else

q 《=0;

end

endmodule

在上面兩個(gè)程序中用到了兩種方式的寫(xiě)法,第一種的Mealy狀態(tài)機(jī),采用了一段式的寫(xiě)法,只用了一個(gè)always語(yǔ)句,所有的狀態(tài)轉(zhuǎn)移,判斷狀態(tài)轉(zhuǎn)移條件,數(shù)據(jù)輸出都在一個(gè)always語(yǔ)句里,缺點(diǎn)是如果狀態(tài)太多,會(huì)使整段程序顯的冗長(zhǎng)。第二個(gè)Moore狀態(tài)機(jī),采用了三段式的寫(xiě)法,狀態(tài)轉(zhuǎn)移用了一個(gè)always語(yǔ)句,判斷狀態(tài)轉(zhuǎn)移條件是組合邏輯,采用了一個(gè)always語(yǔ)句,數(shù)據(jù)輸出也是單獨(dú)的 always語(yǔ)句,這樣寫(xiě)起來(lái)比較直觀清晰,狀態(tài)很多時(shí)也不會(huì)顯得繁瑣。

pIYBAGAJzDiAfbFvAABydpt4ScI860.jpg

Mealy有限狀態(tài)機(jī)RTL圖

Moore有限狀態(tài)機(jī)RTL圖

激勵(lì)文件如下:

`timescale1 ns/1 ns

module top_tb();

reg shift_start ;

reg shift_stop ;

reg rst ;

reg clk ;

reg d ;

wire[7:0] q ;

initial

begin

rst =0;

clk =0;

d =0;

#200 rst =1;

forever

begin

#({$random}%100)

d =~d ;

end

end

initial

begin

shift_start =0;

shift_stop =0;

#300 shift_start =1;

#1000 shift_start =0;

shift_stop =1;

#50 shift_stop =0;

end

always#10 clk =~clk ;

top t0

.shift_start(shift_start),

.shift_stop(shift_stop),

.rst(rst),

.clk(clk),

.d(d),

.q(q)

);

endmodule

仿真結(jié)果如下:

總結(jié)

本文檔介紹了組合邏輯以及時(shí)序邏輯中常用的模塊,其中有限狀態(tài)機(jī)較為復(fù)雜,但經(jīng)常用到,希望大家能夠深入理解,在代碼中多運(yùn)用,多思考,有利于快速提升水平。

審核編輯:何安

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • FPGA
    +關(guān)注

    關(guān)注

    1620

    文章

    21510

    瀏覽量

    598981
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Verilog的版本有哪些

    電子發(fā)燒友網(wǎng)站提供《Verilog的版本有哪些.docx》資料免費(fèi)下載
    發(fā)表于 05-31 11:29 ?0次下載

    verilog中input和output作用

    以完成各種計(jì)算和控制任務(wù)。本文將詳細(xì)介紹input和output在Verilog中的作用及其使用方式。 一、input的作用及使用方式 作用 在Verilog中,input用于定義模塊
    的頭像 發(fā)表于 02-23 10:29 ?2224次閱讀

    verilog與其他編程語(yǔ)言的接口機(jī)制

    Verilog是一種硬件描述語(yǔ)言,用于描述數(shù)字電路的行為和結(jié)構(gòu)。與其他編程語(yǔ)言相比,Verilog具有與硬件緊密結(jié)合的特點(diǎn),因此其接口機(jī)制也有一些與眾不同之處。本文將詳細(xì)介紹Verilog
    的頭像 發(fā)表于 02-23 10:22 ?471次閱讀

    verilog調(diào)用模塊端口對(duì)應(yīng)方式

    Verilog是一種硬件描述語(yǔ)言(HDL),廣泛應(yīng)用于數(shù)字電路設(shè)計(jì)和硬件驗(yàn)證。在Verilog中,模塊是構(gòu)建電路的基本單元,而模塊端口對(duì)應(yīng)方式則用于描述
    的頭像 發(fā)表于 02-23 10:20 ?1089次閱讀

    verilog雙向端口的使用

    Verilog硬件描述語(yǔ)言中,端口是指連接模塊(Module)與其他模塊、寄存器或是物理設(shè)備的輸入或輸出接口。單向端口可以作為輸入或輸出使用,而雙向端口具有雙重作用,既可以接收輸入信號(hào),又可以輸出
    的頭像 發(fā)表于 02-23 10:18 ?978次閱讀

    verilog中for循環(huán)是串行執(zhí)行還是并行執(zhí)行

    Verilog中,for循環(huán)是并行執(zhí)行的。Verilog是一種硬件描述語(yǔ)言,用于描述和設(shè)計(jì)數(shù)字電路和系統(tǒng)。在硬件系統(tǒng)中,各個(gè)電路模塊是同時(shí)運(yùn)行的,并且可以并行執(zhí)行多個(gè)操作。因此,在Veril
    的頭像 發(fā)表于 02-22 16:06 ?2098次閱讀

    verilog如何調(diào)用其他module

    第一部分:簡(jiǎn)介 1.1 什么是Verilog模塊? 在Verilog中,模塊是其設(shè)計(jì)層次結(jié)構(gòu)的基本單元。模塊是一個(gè)用于實(shí)現(xiàn)特定功能的單獨(dú)的硬
    的頭像 發(fā)表于 02-22 15:56 ?4166次閱讀

    verilog task和function區(qū)別

    verilog中的task和function都是用于實(shí)現(xiàn)模塊中的可重復(fù)的功能,并且可以接收參數(shù)和返回結(jié)果。但是它們?cè)诰帉?xiě)和使用上有一些區(qū)別。下面將詳細(xì)介紹task和function的區(qū)別。 語(yǔ)法結(jié)構(gòu)
    的頭像 發(fā)表于 02-22 15:53 ?729次閱讀

    verilog function函數(shù)的用法

    Verilog 中被廣泛用于對(duì)電路進(jìn)行模塊化設(shè)計(jì),以簡(jiǎn)化和組織代碼。 本文將詳細(xì)介紹 Verilog 函數(shù)的用法,并探討函數(shù)在硬件設(shè)計(jì)中的重要性和實(shí)際應(yīng)用場(chǎng)景。 一.
    的頭像 發(fā)表于 02-22 15:49 ?3942次閱讀

    verilog的135個(gè)經(jīng)典實(shí)例

    verilog的135個(gè)經(jīng)典實(shí)例
    發(fā)表于 02-02 10:17 ?14次下載

    怎么用emac實(shí)現(xiàn)Verilog自動(dòng)連線呢?

    我們?cè)诰帉?xiě)一些比較復(fù)雜的Verilog代碼時(shí),通常需要進(jìn)行大量的手動(dòng)連線工作,這種工作十分容易出錯(cuò),并且在代碼模塊的嵌套層級(jí)較多時(shí),更改里層的一個(gè)代碼
    的頭像 發(fā)表于 01-24 10:03 ?1062次閱讀

    verilog bug的利器—notepad++介紹

    相信大家寫(xiě)verilog代碼的時(shí)候,都會(huì)用到notepad++,大家也知道notepad++可以和vivado關(guān)聯(lián)使用,這樣寫(xiě)起工程代碼的時(shí)候,調(diào)試很方便。
    的頭像 發(fā)表于 12-21 09:41 ?1604次閱讀
    找<b class='flag-5'>verilog</b> bug的利器—notepad++<b class='flag-5'>介紹</b>

    例說(shuō)Verilog HDL和VHDL區(qū)別

    Verilog和VHDL之間的區(qū)別將在本文中通過(guò)示例進(jìn)行詳細(xì)說(shuō)明。對(duì)優(yōu)點(diǎn)和缺點(diǎn)的Verilog和VHDL進(jìn)行了討論。
    的頭像 發(fā)表于 12-20 09:03 ?2258次閱讀
    例說(shuō)<b class='flag-5'>Verilog</b> HDL和VHDL區(qū)別

    Verilog 模塊基本結(jié)構(gòu)

    verilog極簡(jiǎn)語(yǔ)法手冊(cè)
    發(fā)表于 10-23 09:28 ?0次下載

    FPGA設(shè)計(jì)之Verilog中clk為什么要用posedge而不用negedge?

    Verilog是一種硬件描述語(yǔ)言,用于描述數(shù)字電路的行為和特性。在Verilog中,時(shí)鐘信號(hào)(clk)和線路是非常重要的,它用于同步電路中的各個(gè)模塊,確保它們?cè)谕粫r(shí)刻執(zhí)行。
    發(fā)表于 10-10 15:41 ?2526次閱讀
    FPGA設(shè)計(jì)之<b class='flag-5'>Verilog</b>中clk為什么要用posedge而不用negedge?