《Xilinx FPGA設(shè)計與實踐教程》課件-第6章_第1頁
《Xilinx FPGA設(shè)計與實踐教程》課件-第6章_第2頁
《Xilinx FPGA設(shè)計與實踐教程》課件-第6章_第3頁
《Xilinx FPGA設(shè)計與實踐教程》課件-第6章_第4頁
《Xilinx FPGA設(shè)計與實踐教程》課件-第6章_第5頁
已閱讀5頁,還剩119頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第六章時序狀態(tài)機設(shè)計6.1有限狀態(tài)機6.2狀態(tài)機設(shè)計實例6.3帶數(shù)據(jù)路徑的狀態(tài)機(FSMD)6.4FSMD的HDL代碼開發(fā)6.5設(shè)計舉例本章小結(jié)

6.1有?限?狀?態(tài)?機6.1.1Moore和Mealy狀態(tài)機有限狀態(tài)機的基本組成和規(guī)則時序電路是一樣的,由狀態(tài)寄存器、下一狀態(tài)邏輯模塊和輸出邏輯模塊組成,如圖6-1所示。如果輸出邏輯僅僅是狀態(tài)寄存器的函數(shù),也就是僅與狀態(tài)寄存器有關(guān),則為摩爾狀態(tài)機;如果輸出邏輯是當(dāng)前狀態(tài)和外部輸入的函數(shù),則為米利狀態(tài)機。圖6-1同步狀態(tài)機框圖6.1.2有限狀態(tài)機的描述方式

常用的描述有限狀態(tài)機的方法是狀態(tài)轉(zhuǎn)移圖(StateTransitionGraph,STG)和算法狀態(tài)機表(ASMchart)。這兩種方法都是用來描述系統(tǒng)內(nèi)部以及系統(tǒng)與周圍接口信號的有效輸入與狀態(tài)轉(zhuǎn)移關(guān)系的,其中狀態(tài)轉(zhuǎn)移圖描述比較緊湊簡潔,非常適合簡單的應(yīng)用,而算法狀態(tài)圖類似于軟件流程圖,適合描述復(fù)雜的狀態(tài)轉(zhuǎn)換和數(shù)據(jù)傳輸。

1.狀態(tài)轉(zhuǎn)移圖

狀態(tài)轉(zhuǎn)移圖是一種有向圖,由節(jié)點和弧線組成。節(jié)點與時序狀態(tài)機的狀態(tài)一一對應(yīng),弧線為有向線,表示起點狀態(tài)在輸入信號的作用下可能發(fā)生的狀態(tài)轉(zhuǎn)移的條件,當(dāng)條件滿足時,觸發(fā)起點狀態(tài)跳轉(zhuǎn)到新的狀態(tài)。如圖6-2(a)所示為一個簡單的狀態(tài)轉(zhuǎn)移圖節(jié)點,標注在弧線上的外部輸入信號的邏輯表達式為狀態(tài)跳轉(zhuǎn)的條件。

摩爾狀態(tài)機的輸出值僅與當(dāng)前狀態(tài)有關(guān),所以其值在節(jié)點圓中表示。而米利狀態(tài)機的輸出值與當(dāng)前狀態(tài)和外部輸入都有關(guān),為了簡化狀態(tài)圖的分支,輸出值隨跳轉(zhuǎn)條件一起在弧線上列舉出來,如果沒有列舉,則輸出值保持默認值。圖6-2狀態(tài)機符號描述圖6-3(a)所示為一個復(fù)雜的狀態(tài)圖,包含有三個狀態(tài)、兩個外部輸入信號(a和b)、一個摩爾輸出(y1)和一個米利輸出(y0)。y1在狀態(tài)機狀態(tài)為s0和s1時邏輯輸出;y0在狀態(tài)為s0并且a和b信號為“11”時邏輯輸出。圖6-3狀態(tài)機STG和ASM圖描述

2.算法狀態(tài)機圖

算法狀態(tài)機(AlgorithmicStateMachine,ASM)圖是時序狀態(tài)機功能的抽象表達方式,類似于軟件流程圖。該圖在描述時序狀態(tài)機的行為方面以及設(shè)計狀態(tài)機來控制數(shù)據(jù)通道方面都是非常有用的。其描述主要由四部分組成:狀態(tài)轉(zhuǎn)移框、條件輸出、寄存器操作框和判決框。狀態(tài)轉(zhuǎn)移框為狀態(tài)機主體,對于摩爾狀態(tài)機,其輸出邏輯值在狀態(tài)轉(zhuǎn)移框中表示,并且僅有一條輸出路徑。對于米利狀態(tài)機,條件判決框通過判斷外部輸入決定狀態(tài)輸出路徑,它有兩條輸出路徑,標記為T和F,分別對應(yīng)外部輸入條件為真和假兩種情況下的輸出路徑。米利狀態(tài)機的輸出邏輯在條件判斷框之后,表示在對應(yīng)狀態(tài)條件和外部條件同時滿足的情況下,米利狀態(tài)機才可輸出。

狀態(tài)轉(zhuǎn)移圖和ASM圖之間可以靈活轉(zhuǎn)換,如圖6-2(a)和(b)及圖6-3(a)和(b)所示,采用兩種不同的描述方式描述同一個狀態(tài)機。6.1.3有限狀態(tài)機的HDL開發(fā)

1.狀態(tài)機描述的編碼方式

在狀態(tài)機的描述中,為了更清楚地表示狀態(tài),一般采用帶有意義的常數(shù)符號來定義狀態(tài)參數(shù)。如圖6-3所示的三個狀態(tài)可以定義為

localparam[1:0] s0=2'b00,

s1=2'b01,

s2=2'b10;需要注意的是,狀態(tài)機的定義用localparam或者parameter,不推薦使用'define宏定義的方式。這是因為采用'define宏定義在編譯時會自動替換整個設(shè)計中所有的宏,而parameter僅僅定義模塊內(nèi)部的參數(shù),定義的參數(shù)不會與模塊外的其他狀態(tài)機混淆。

狀態(tài)機的編碼方式很多,包括順序編碼、格雷瑪(GrayEncoding)、一位熱碼(One-HotEncoding)、BCD碼等。雖然在綜合過程中,綜合工具可以辨別出狀態(tài)機結(jié)構(gòu),并可以根據(jù)需求將這些狀態(tài)機符號常數(shù)映射為各種二進制形式,但是在FPGA設(shè)計中,編碼方式可影響狀態(tài)機的執(zhí)行效率和功能,所以建議讀者在設(shè)計中根據(jù)不同的需求,選擇不同的編碼方式,具體請參考表6-1。

2.狀態(tài)機HDL描述

狀態(tài)機HDL描述包含三部分:同步時序描述狀態(tài)轉(zhuǎn)移、下一狀態(tài)邏輯跳轉(zhuǎn)產(chǎn)生、摩爾和米利邏輯輸出。

【程序6-1】三段式狀態(tài)機描述。

modulethree_seg_fsm

(

input

wireclk,reset,

input

wirea,b,

output

wirey0,y1

);

//定義狀態(tài)常數(shù)

localparam[1:0]s0=2'b00,

s1=2'b01,

s2=2'b10;

//信號聲明

reg[1:0]state_reg,state_next;

//狀態(tài)機寄存器描述

always@(posedgeclk,posedgereset)

if(reset)

state_reg<=s0;

else

state_reg<=state_next;

//下一狀態(tài)邏輯

always@*

case(state_reg)

s0:if(a)

if(b)

state_next=s2;

else

state_next=s1;

else

state_next=s0;

s1:if(a)

state_next=s0;

else

state_next=s1;

s2:state_next=s0;

default:state_next=s0;

endcase

//摩爾輸出邏輯

assigny1=(state_reg==s0)||(state_reg==s1);

//米利輸出邏輯

assigny0=(state_reg==s0)&a&b;

endmodule

產(chǎn)生下一狀態(tài)邏輯為邏輯狀態(tài)轉(zhuǎn)換的關(guān)鍵,其中always的敏感列表為當(dāng)前狀態(tài)state_reg,下一狀態(tài)邏輯由當(dāng)前狀態(tài)(state_reg)和外部輸入共同決定。為了避免不確定的狀態(tài)的產(chǎn)生,case語句中如果還有未列舉的狀態(tài),則需要采用others語句對未列舉的狀態(tài)進行賦值。

還有一種更為簡潔的描述方式,將摩爾輸出和米利輸出融合在下一狀態(tài)邏輯代碼段當(dāng)中,如程序6-2所示。

【程序6-2】兩段式狀態(tài)機描述。

modulefsm_two_seg

(

input

wireclk,reset,

input

wirea,b,

output

regy0,y1

);

//狀態(tài)常數(shù)聲明

localparam[1:0]s0=2'b00,

s1=2'b01,

s2=2'b10;

//信號聲明

reg[1:0]state_reg,state_next;

//同步狀態(tài)寄存器描述

always@(posedgeclk,posedgereset)

if(reset)

state_reg<=s0;

else

state_reg<=state_next;

//下一邏輯狀態(tài)和輸出邏輯

always@*

begin

state_next=state_reg; //默認下一狀態(tài)邏輯不變

y1=1'b0; //默認輸出為0

y0=1'b0; //默認輸出為0

case(state_reg)

s0:begin

y1=1'b1;

if(a)

if(b)

begin

state_next=s2;

y0=1'b1;

end

else

state_next=s1;

end

s1:begin

y1=1'b1;

if(a)

state_next=s0;

end

s2:state_next=s0;

default:state_next=s0;

endcase

end

endmodule

需要注意的是,輸出默認值需要在always語句開始時賦值。

下一狀態(tài)邏輯和輸出邏輯嚴格按照ASM圖產(chǎn)生。如果ASM圖有細微的改變,則轉(zhuǎn)換成HDL代碼的過程并不難,讀者可以將程序6-1和程序6-2作為這個轉(zhuǎn)換過程的模板來套用。因而XilinxISE包含一個StateCAD的工具,可以幫助用戶方便設(shè)計狀態(tài)轉(zhuǎn)換圖,并且自動產(chǎn)生HDL代碼。建議大家可以采用它練習(xí)一些簡單的狀態(tài)機的例子。

在上述狀態(tài)機描述中,輸出都是用組合邏輯描述的,而組合邏輯容易產(chǎn)生毛刺等不穩(wěn)定因素,并且在FPGA中,過多的組合邏輯會影響實現(xiàn)的速率。所以如果在上述狀態(tài)機描述中在后級電路對組合邏輯輸出用寄存器“打一拍”,則可以有效地消除毛刺。

6.2狀態(tài)機設(shè)計實例

6.2.1上升沿檢測電路

上升沿檢測電路在實際電路中應(yīng)用非常廣泛。其主要功能是當(dāng)被檢測信號一旦有一個從0到1的跳變時,則電路輸出一個脈寬為1個時鐘周期的脈沖。上升沿檢測電路經(jīng)常用來檢測緩慢變化的輸入信號。

下面分別采用摩爾狀態(tài)機和米利狀態(tài)機設(shè)計,并對比兩種狀態(tài)機的設(shè)計。

1.基于摩爾狀態(tài)機的設(shè)計

基于摩爾狀態(tài)機設(shè)計的上升沿檢測電路的狀態(tài)轉(zhuǎn)移圖和ASM圖如圖6-4所示。從idle跳變到get_edg狀態(tài),表示輸入信號從0變成1。當(dāng)狀態(tài)機處于idle狀態(tài)時,如果在時鐘的上升沿采集到輸入信號為1,則表示檢測到信號上升沿,狀態(tài)機轉(zhuǎn)換到edg狀態(tài),并且輸出tick信號有效,其時序如圖6-5所示,代碼如程序6-3所示。圖6-4基于摩爾狀態(tài)機的上升沿檢測電路狀態(tài)圖圖6-5兩種狀態(tài)機描述時序的對比

【程序6-3】基于摩爾狀態(tài)機的上升沿檢測電路的HDL描述。

moduleedge_detect_moore

(

input

wireclk,reset,

input

wires_in,

output

regtick

);

//狀態(tài)常量聲明

localparam[1:0]

idle=2'b00,

edg=2'b01,

get_edg=2'b10;

//信號聲明

reg[1:0]state_reg,state_next;

//狀態(tài)寄存器

always@(posedgeclk,posedgereset)

if(reset)

state_reg<=idle;

else

state_reg<=state_next;

//下一狀態(tài)邏輯和輸出邏輯

always@*

begin

state_next=state_reg; //默認狀態(tài)

tick=1'b0; //默認輸出為0

case(state_reg)

idle:

if(s_in)

state_next=edg;

edg:

begin

tick=1'b1;

if(s_in)

state_next=get_edg;

else

state_next=idle;

end

get_edg:

if(~s_in)

state_next=idle;

default:state_next=idle;

endcase

end

endmodule

2.基于米利狀態(tài)機的設(shè)計

基于米利狀態(tài)機設(shè)計的上升沿檢測電路的狀態(tài)轉(zhuǎn)移圖和ASM圖如圖6-6所示。idle和get_edg狀態(tài)具有同樣的意義,當(dāng)狀態(tài)寄存器處于idle狀態(tài)時,如果輸入信號從0變成了1,則輸出信號置位,下一個時鐘來臨時改變狀態(tài)為get_edge狀態(tài),輸出信號清零。具體時序?qū)Ρ热鐖D6-5所示。需要注意的是,在下一個時鐘的上升沿來臨時輸出信號依然有效。具體實現(xiàn)代碼如程序6-4所示。圖6-6基于米利狀態(tài)機的上升沿檢測電路

【程序6-4】基于米利狀態(tài)機的上升沿檢測電路。

modulemealy_edge_detect

(

input

wireclk,reset,

input

wires_in,

output

regtick

);

//狀態(tài)機狀態(tài)聲明

localparamidle=1'b0,

get_edg=1'b1;

//信號聲明

regstate_reg,state_next;

//狀態(tài)寄存器

always@(posedgeclk,posedgereset)

if(reset)

state_reg<=idle;

else

state_reg<=state_next;

//下一狀態(tài)邏輯和輸出邏輯

always@*

begin

state_next=state_reg; //默認狀態(tài)

tick=1'b0; //默認輸出為0

case(state_reg)

idle:

if(s_in)

begin

tick=1'b1;

state_next=get_edg;

end

get_edg:

if(~s_in)

state_next=idle;

default:state_next=idle;

endcase

end

endmodule

3.直接實現(xiàn)上升沿檢測

上升沿檢測電路非常簡單,完全可以不用狀態(tài)機實現(xiàn)。上升沿檢測電路的直接實現(xiàn)電路如圖6-7所示,可以簡單地描述為如果寄存器上個時鐘沿來臨時賦值為0(被暫時存儲在寄存器當(dāng)中),而當(dāng)前時鐘寄存器賦值為1,則輸出有效,具體代碼如程序6-5所示。圖6-7上升沿檢測電路的直接實現(xiàn)電路結(jié)構(gòu)圖

【程序6-5】直接實現(xiàn)上升沿檢測電路。

moduleedge_detect

(

input

wireclk,reset,

input

wirelevel,

output

wiretick

);

//信號聲明

regdelay_reg;

//延遲寄存器的描述

always@(posedgeclk,posedgereset)

if(reset)

delay_reg<=1'b0;

else

delay_reg<=level;

//譯碼邏輯

assigntick=~delay_reg&level;

endmodule

4.結(jié)果對比與分析

雖然采用摩爾狀態(tài)機和米利狀態(tài)機都可以產(chǎn)生檢測輸入信號上升沿的脈沖信號,但兩者依然有一些細微的差別。根據(jù)圖6-6結(jié)果所示,采用米利狀態(tài)機設(shè)計需要更少的狀態(tài)而且反應(yīng)速度更快,但是容易引入毛刺信號到輸出。所以選擇摩爾狀態(tài)機和米利狀態(tài)機需要根據(jù)子系統(tǒng)的輸出信號來決定。大部分情況下,子系統(tǒng)為同步系統(tǒng),采用同樣的時鐘,由于狀態(tài)機的輸出僅僅在時鐘上升沿采樣,脈沖和毛刺不會影響輸出信號在時鐘沿附近的穩(wěn)定性。注意到米利狀態(tài)機輸出信號在t1時刻有效,而摩爾狀態(tài)機在t2時刻有效,所以米利狀態(tài)機比摩爾狀態(tài)機的反應(yīng)快一個時鐘周期,適合子系統(tǒng)為同步系統(tǒng)情況下的應(yīng)用。6.2.2按鍵防抖動電路

開關(guān)和按鍵為機械部件,當(dāng)按鍵按下去時,會產(chǎn)生短暫的抖動,然后狀態(tài)才能穩(wěn)定??墒沁@短暫的抖動卻會引入信號的毛刺,從而導(dǎo)致誤操作。根據(jù)經(jīng)驗測試,反彈時間通常小于20ms。按鍵防抖動電路就是用來濾除按鍵按下去之后短暫的小于20ms的抖動信號,然后輸出正確的按鍵信號。其原理如圖6-8所示。圖6-8按鍵防抖動以及原始按鍵輸出對比時序圖采用基于FSM的設(shè)計方法進行設(shè)計,系統(tǒng)包含一個10ms自由計數(shù)器和一個狀態(tài)機,計數(shù)器每隔10ms產(chǎn)生一個時鐘脈寬的使能信號,然后狀態(tài)機根據(jù)使能信號判斷外部輸入是否穩(wěn)定。設(shè)計中,狀態(tài)機忽略短的毛刺,僅僅在輸入穩(wěn)定保持20ms時,輸出值才發(fā)生改變。狀態(tài)轉(zhuǎn)移如圖6-9所示,zero和one狀態(tài)顯示輸入信號sw穩(wěn)定在值0和1,如果狀態(tài)機在zero狀態(tài)初始化,則當(dāng)sw信號變?yōu)?時狀態(tài)改變到wait1_1狀態(tài)。在wait1_1狀態(tài),狀態(tài)機等待m_tick信號,如果此時sw變成0,則表示邏輯1的脈沖寬度不夠長,屬于毛刺,那么狀態(tài)機返回到zero狀態(tài),然后繼續(xù)重復(fù)wait1_2和wait1_3狀態(tài)。

由于10ms計數(shù)器是自由計數(shù)器,m_tick脈沖隨時可以被賦值,狀態(tài)機檢測三次確保sw信號至少穩(wěn)定20ms(事實上在20ms到30ms之間),具體實現(xiàn)代碼如程序6-6所示。圖6-9防抖動電路狀態(tài)轉(zhuǎn)移圖

【程序6-6】按鍵防抖動電路的HDL描述。

moduledb_fsm

(

input

wireclk,reset,

input

wiresw,

output

regdb

);

//狀態(tài)常數(shù)聲明

localparam[2:0]

zero=3'b000,

wait1_1=3'b001,

wait1_2=3'b010,

wait1_3=3'b011,

one=3'b100,

wait0_1=3'b101,

wait0_2=3'b110,

wait0_3=3'b111;

//計數(shù)器計數(shù)位寬值(2^N*20ns=10mstick)

localparamN=19;

//信號聲明

reg[N-1:0]q_reg;

wire[N-1:0]q_next;

wirem_tick;

reg[2:0]state_reg,state_next;

//程序主體

//========================================

//產(chǎn)生10ms的自由計數(shù)器

//========================================

always@(posedgeclk)

q_reg<=q_next;

//下一狀態(tài)邏輯

assignq_next=q_reg+1;

//輸出脈沖

assignm_tick=(q_reg==0)?1'b1:1'b0;

//========================================

//按鍵反彈檢測狀態(tài)機

//========================================

//狀態(tài)寄存器

always@(posedgeclk,posedgereset)

if(reset)

state_reg<=zero;

else

state_reg<=state_next;

//下一狀態(tài)邏輯和輸出邏輯

always@*

begin

state_next=state_reg; //默認狀態(tài)

db=1'b0; //默認輸出為0

case(state_reg)

zero:

if(sw)

state_next=wait1_1;

wait1_1:

if(~sw)

state_next=zero;

else

if(m_tick)

state_next=wait1_2;

wait1_2:

if(~sw)

state_next=zero;

else

if(m_tick)

state_next=wait1_3;

wait1_3:

if(~sw)

state_next=zero;

else

if(m_tick)

state_next=one;

one:

begin

db=1'b1;

if(~sw)

state_next=wait0_1;

end

wait0_1:

begin

db=1'b1;

if(sw)

state_next=one;

else

if(m_tick)

state_next=wait0_2;

end

wait0_2:

begin

db=1'b1;

if(sw)

state_next=one;

else

if(m_tick)

state_next=wait0_3;

end

wait0_3:

begin

db=1'b1;

if(sw)

state_next=one;

else

if(m_tick)

state_next=zero;

end

default:state_next=zero;

endcase

end

endmodule6.2.3電路硬件驗證

采用模擬抖動計數(shù)的方式來驗證上升沿檢測和反彈電路,驗證框圖如圖6-10所示。電路的輸入由按鍵產(chǎn)生,在上半部分,輸入信號直接送到上升沿電路而不經(jīng)過按鍵反彈濾波電路,每次按鍵同樣產(chǎn)生一個時鐘寬度的脈沖使能計數(shù)器計數(shù),計數(shù)值在左邊的七段數(shù)碼管上顯示。這部分電路其實每次按鍵反彈都會觸發(fā)計數(shù)器計數(shù)。圖6-10防抖動驗證框圖在下半部分,信號首先經(jīng)過按鍵反彈電路,然后進行上升沿檢測電路,所以,每次按鍵按下去然后松開將產(chǎn)生一個時鐘脈寬的脈沖。這個脈沖控制8位計數(shù)器的計數(shù)使能端,計數(shù)器的計數(shù)值通過LED動態(tài)掃描電路顯示在左邊的另外一個七段數(shù)碼管上。

具體實現(xiàn)代碼如程序6-7所示。

【程序6-7】測試抖動電路和上升沿檢測電路的HDL描述。

moduledebounce_test

(

input

wireclk,reset,

input

wire[1:0]btn,

output

wire[3:0]an,

output

wire[7:0]sseg

);

//信號聲明

reg[7:0]b_reg,d_reg;

wire[7:0]b_next,d_next;

regbtn_reg,db_reg;

wiredb_level,db_tick,btn_tick,clr;

//例化七段數(shù)碼管動態(tài)掃描電路

disp_hex_muxdisp_unit

(.clk(clk),.reset(reset),

.hex3(b_reg[7:4]),.hex2(b_reg[3:0]),

.hex1(d_reg[7:4]),.hex0(d_reg[3:0]),

.dp_in(4'b1011),.an(an),.sseg(sseg));

//例化防抖動電路

db_fsmdb_unit

(.clk(clk),.reset(reset),.sw(btn[1]),.db(db_level));

//沿檢測電路

always@(posedgeclk)

begin

btn_reg<=btn[1];

db_reg<=db_level;

end

assignbtn_tick=~btn_reg&btn[1];

assigndb_tick=~db_reg&db_level;

//兩個計數(shù)器

assignclr=btn[0];

always@(posedgeclk)

begin

b_reg<=b_next;

d_reg<=d_next;

end

assignb_next=(clr)?8'b0:

(btn_tick)?b_reg+1:b_reg;

assignd_next=(clr)?8'b0:

(db_tick)?d_reg+1:d_reg;

endmodule

6.3帶數(shù)據(jù)路徑的狀態(tài)機(FSMD)

6.3.1簡單寄存器傳輸操作

一個簡單寄存器傳輸(RT)操作如下面的公式所示,通過寄存器將源寄存器數(shù)據(jù)按照某種操作傳輸?shù)侥康募拇嫫髦校浩渲?,rdest為目的寄存器;rsrc1,rsrc2,…,rsrcn為源寄存器;表示執(zhí)行的操作。源寄存器為f(·)函數(shù)的輸入,由組合邏輯實現(xiàn),執(zhí)行的結(jié)果在下一個時鐘沿存儲到目的寄存器中。常用的RT操作及其功能有如下幾種:

(1)?r1←0:為r1寄存器賦值0;

(2)?r1←r1:r1寄存器的內(nèi)容寫回到自身;

(3)?r2←r2>>3:r2寄存器右移3位,然后寫回自身;

(4)?r2←r1:r1寄存器的內(nèi)容傳輸?shù)絩2寄存器中;

(5)?i←i+1:i寄存器內(nèi)容加1后的結(jié)果送到自身;

(6)?d←s1+s2+s3:s1、s2和s3寄存器的值相加之和送到d寄存器中;

(7)?y←a*a:a的平方值送到y(tǒng)寄存器中。簡單RT操作可以首先通過構(gòu)造組合電路實現(xiàn)的功能,然后連接寄存器的輸入輸出口。比如對于操作a←a-b+1,功能包括一個減法和一個加法,具體框圖如圖6-11(a)所示。為了描述清楚,我們采用_reg和_next后綴分別表示信號的輸入和輸出寄存器。需要注意的是,RT操作的輸入是同步的,的輸出結(jié)果在下個時鐘沿到來時將結(jié)果存儲到目的寄存器中。具體的時序如圖6-11(b)所示。圖6-11RT操作的原理框圖以及時序圖6.3.2FSMD狀態(tài)描述

在同步電路中,寄存器傳輸(RT)都是以時鐘為節(jié)拍的,所以基于RT操作的電路時序上也是以時鐘為單位單步執(zhí)行的,和有限狀態(tài)機(FSM)的狀態(tài)傳輸時序相類似。所以可以采用FSM來描述RT操作,也就是在原來的FSM圖上增加RT操作,形成新的被稱為ASMD(ASMWithDataChart)的新的狀態(tài)機描述圖,這時寄存器傳輸操作可以當(dāng)作另外一種邏輯輸出類型放在輸出信號中。我們舉例來講述ASMD圖的用法。如圖6-12所示ASMD圖,描述的功能是:初始化值為5的目的寄存器r1,與r2寄存器值相加之后再左移兩位,返回值到r1。在整個數(shù)據(jù)傳輸?shù)倪^程中,r1寄存器在每個寄存器傳輸狀態(tài)都要有確定的值,當(dāng)r1值不變時,需要采用操作r1←r1,使其保持當(dāng)前值,如圖6-12中的s3狀態(tài)。為了方便起見,經(jīng)常將操作r←r作為寄存器r的默認操作而不包含在ASMD圖中。

為了實現(xiàn)如圖6-12(a)所示的電路,需要采用多路選擇器配合D觸發(fā)器來完成,如圖6-12(b)所示。由狀態(tài)機的當(dāng)前狀態(tài)(狀態(tài)寄存器的輸出)控制選擇器的選擇信號,選擇合適的結(jié)果送到目的寄存器中。圖6-12ASMD圖舉例以及原理框圖6.3.3FSMD的模塊框圖

FSMD的模塊框圖主要分為數(shù)據(jù)路徑和控制路徑兩部分,如圖6-13所示。數(shù)據(jù)路徑執(zhí)行需要的寄存器傳輸操作,內(nèi)容包含:

(1)數(shù)據(jù)寄存器:存儲計算的立即結(jié)果;

(2)功能單元:通過RT操作執(zhí)行功能函數(shù);

(3)布線網(wǎng)絡(luò):在存儲器和功能單元之間傳輸數(shù)據(jù)。圖6-13FSMD模塊框圖數(shù)據(jù)路徑根據(jù)控制信號的狀態(tài)執(zhí)行所需要的RT操作并產(chǎn)生內(nèi)部狀態(tài)信號。

控制路徑實際上是一個狀態(tài)機(FSM),它包含狀態(tài)寄存器、下一狀態(tài)邏輯以及輸出邏輯。外部信號和數(shù)據(jù)路徑狀態(tài)作為狀態(tài)機狀態(tài)轉(zhuǎn)換的條件,控制數(shù)據(jù)路徑操作,狀態(tài)機同時產(chǎn)生額外的狀態(tài)信號來反映FSMD的狀態(tài)。

需要注意的是,雖然FSMD包含兩種類型的時序電路,但是都受同一時鐘控制,所以依然屬于同步系統(tǒng)。 6.4FSMD的HDL代碼開發(fā)

6.4.1基于FSMD描述的按鍵防抖動電路

為了形象地理解FSMD的HDL代碼開發(fā)方法,我們采用FSMD狀態(tài)機重新開發(fā)按鍵防抖動電路。在6.2.2節(jié)中,所設(shè)計的按鍵防抖動電路使用了狀態(tài)機和一個計數(shù)器來完成,由于兩個單元是完全獨立的,并且狀態(tài)機沒有控制計數(shù)器,所以不是采用寄存器傳輸(RT操作)方法來實現(xiàn)的?,F(xiàn)在重新分析這個電路,既然10ms使能脈沖可以隨時產(chǎn)生,所以當(dāng)狀態(tài)機檢測到第一個脈沖之后(處于wait1_1或者wait0_1狀態(tài)),實際上不知道已經(jīng)過了多少個時鐘周期,所以設(shè)計中等待20~30ms而不是一個精確的時間間隔,采用基于RT設(shè)計方法就可以完全避免這個問題。下面詳細討論基于FSMD的按鍵防抖動電路。

基于RT操作,可以使用狀態(tài)機控制計數(shù)器的初始化從而獲得精確的時間間隔。ASMD流程圖如圖6-14所示,電路包含兩個輸出信號db_lever和db_tick。圖6-14按鍵防抖動電路的ASMD方式實現(xiàn)

db_lever為經(jīng)過防抖動之后的輸出,而db_tick為zero到one狀態(tài)轉(zhuǎn)換時產(chǎn)生的長度為一個時鐘寬度的脈寬使能信號。zero和one狀態(tài)表示輸入信號處于穩(wěn)定的0和1狀態(tài),同時wait1和wait0狀態(tài)用來濾除毛刺信號。系統(tǒng)輸入信號必須在一定的時間間隔中保持穩(wěn)定,否則就被認為屬于毛刺信號而被濾除。數(shù)據(jù)路徑包含一個21位寬的寄存器q,假設(shè)FSMD從zero狀態(tài)開始,當(dāng)sw有輸入信號,為“1”時,F(xiàn)SMD將狀態(tài)改變到wait1狀態(tài)并且初始化q寄存器為“1…1”。在wait1狀態(tài),每來一個時鐘,q值便減1;如果sw保持為“1”,則FSMD狀態(tài)保持,直到q值為“0…0”時,返回到one狀態(tài)??紤]到驗證板上系統(tǒng)時鐘為50MHz,由于FSMD停留在wait1狀態(tài),為221個時鐘周期,時間長度應(yīng)為40ms。當(dāng)然,也可以修改q寄存器的初值而獲得合適的等待間隔。

實際用HDL代碼描述時,通常有兩種方法:一種是顯性描述數(shù)據(jù)路徑部分,另外一種是隱性描述數(shù)據(jù)路徑部分。下面就兩種描述方法分別作一介紹。6.4.2顯性描述數(shù)據(jù)路徑

顯性描述FSMD是將控制狀態(tài)機和關(guān)鍵數(shù)據(jù)路徑分開,在ASMD圖上,首先在數(shù)據(jù)路徑上羅列關(guān)鍵路徑以及相關(guān)聯(lián)的控制信號,然后在獨立的代碼段描述這些元件。

對于按鍵防抖動電路來說,關(guān)鍵數(shù)據(jù)路徑就是21位減法計數(shù)器,因為其擁有三項功能:

(1)可以被初始化為某一固定值;

(2)支持減法計數(shù)和計數(shù)暫停;

(3)當(dāng)計數(shù)器為0時為狀態(tài)信號賦值??梢栽O(shè)計一個帶置數(shù)和使能的二進制計數(shù)器,信號名分別為cnt_load和cnt_dec,計數(shù)器同樣產(chǎn)生一個cnt_zero狀態(tài)信號;當(dāng)計數(shù)器為0時置位,完整的數(shù)據(jù)路徑由q寄存器和減法計數(shù)器的下一狀態(tài)邏輯組成;比較電路用來產(chǎn)生cnt_zero狀態(tài)信號;控制路徑包括一個狀態(tài)機,用來接收sw輸入和cnt_zero狀態(tài),并且給控制信號cnt_load和cnt_dec賦值。根據(jù)ASMD圖的設(shè)計流程,HDL設(shè)計如程序6-8所示。

【程序6-8】基于RT操作的按鍵防抖動電路設(shè)計。

moduledebounce_explicit

(

input

wireclk,reset,

input

wiresw,

output

regdb_level,db_tick

);

//狀態(tài)機參數(shù)聲明

localparam[1:0]

zero=2'b00,

wait0=2'b01,

one=2'b10,

wait1=2'b11;

//計數(shù)器位寬(2^N*20ns=40ms)

localparamN=21;

//信號聲明

reg[1:0]state_reg,state_next;

reg[N-1:0]q_reg;

wire[N-1:0]q_next;

wirecnt_zero;

regcnt_load,cnt_dec;

//主體部分

//FSMD狀態(tài)和數(shù)據(jù)寄存器

always@(posedgeclk,posedgereset)

if(reset)

begin

state_reg<=zero;

q_reg<=0;

end

else

begin

state_reg<=state_next;

q_reg<=q_next;

end

//FSMD數(shù)據(jù)路徑(計數(shù)器)下一邏輯狀態(tài)

assignq_next=(cnt_load)?{N{1'b1}}: //置數(shù)全1

(cnt_dec)?q_reg-1: //減法計數(shù)

q_reg;

//狀態(tài)信號

assigncnt_zero=(q_next==0);

//FSMD控制路徑下一狀態(tài)邏輯

always@*

begin

state_next=state_reg; //默認狀態(tài)

cnt_load=1'b0; //默認輸出為0

cnt_dec=1'b0; //默認輸出為0

db_tick=1'b0; //默認輸出為0

case(state_reg)

zero:

begin

db_level=1'b0;

if(sw)

begin

state_next=wait1;

cnt_load=1'b1;

end

end

wait1:

begin

db_level=1'b0;

if(sw)

begin

q_dec=1'b1;

if(cnt_zero)

begin

state_next=one;

db_tick=1'b1;

end

end

else//sw==0

state_next=zero;

end

one:

begin

db_level=1'b1;

if(~sw)

begin

state_next=wait0;

cnt_load=1'b1;

end

end

wait0:

begin

db_level=1'b1;

if(~sw)

begin

cnt_dec=1'b1;

if(q_zero)

state_next=zero;

end

else//sw==1

state_next=one;

end

default:state_next=zero;

endcase

end

endmodule6.4.3隱含描述數(shù)據(jù)路徑

另外一種描述方法是在FSM控制路徑中嵌入RT操作,無需定義數(shù)據(jù)路徑模塊,只需在狀態(tài)機中列舉RT操作。此種描述方法稱為隱含描述數(shù)據(jù)路徑法。具體描述代碼如程序6-9所示。

【程序6-9】隱含描述數(shù)據(jù)路徑。

moduledebounce

(

input

wireclk,reset,

input

wiresw,

outputregdb_level,db_tick

);

//狀態(tài)常數(shù)聲明

localparam[1:0]

zero=2'b00,

wait0=2'b01,

one=2'b10,

wait1=2'b11;

//計數(shù)器位寬(2^N*20ns=40ms)

localparamN=21;

//信號聲明

reg[N-1:0]q_reg,q_next;

reg[1:0]state_reg,state_next;

//主體部分

//FSMD狀態(tài)及數(shù)據(jù)寄存器

always@(posedgeclk,posedgereset)

if(reset)

begin

state_reg<=zero;

q_reg<=0;

end

else

begin

state_reg<=state_next;

q_reg<=q_next;

end

//帶數(shù)據(jù)路徑功能的下一狀態(tài)邏輯

always@*

begin

state_next=state_reg; //默認狀態(tài)

q_next=q_reg; //q默認值

db_tick=1'b0; //默認輸出為0

case(state_reg)

zero:

begin

db_level=1'b0;

if(sw)

begin

state_next=wait1;

q_next={N{1'b1}}; //置數(shù)全1

end

end

wait1:

begin

db_level=1'b0;

if(sw)

begin

q_next=q_reg-1;

if(q_next==0)

begin

state_next=one;

db_tick=1'b1;

end

end

else//sw==0

state_next=zero;

end

one:

begin

db_level=1'b1;

if(~sw)

begin

state_next=wait0;

q_next={N{1'b1}};//置數(shù)全1

end

end

wait0:

begin

db_level=1'b1;

if(~sw)

begin

q_next=q_reg-1;

if(q_next==0)

state_next=zero;

end

else//sw==1

state_next=one;

end

default:state_next=zero;

endcase

end

endmodule

代碼包含存儲段和組合邏輯單元。前一部分代碼包含狀態(tài)寄存器和數(shù)據(jù)路徑數(shù)據(jù)寄存器,后一部分代碼基于狀態(tài)機控制路徑的下一狀態(tài)邏輯。

顯性和隱性兩種描述方法各有其優(yōu)缺點。相對來說,如果數(shù)據(jù)路徑的RT操作比較復(fù)雜,則最好采用顯性描述,因為這樣有利于模塊的劃分和使RTL的層次更加清晰,最主要的是在RT操作復(fù)雜時,有利于綜合工具的實現(xiàn)。

6.5設(shè)計舉例

6.5.1斐波納契序列(FibonacciNumber)實現(xiàn)電路

斐波納契序列定義方程為(6-1)最基本的方法就是根據(jù)斐波納契序列方程進行電路設(shè)計。分析方程式(6-1),很顯然需要兩個臨時寄存器存儲fib(i-1)和fib(i-2)的值,還需要一個索引計數(shù)器,用來追蹤當(dāng)前迭代運算的次數(shù)。ASMD圖如圖6-15所示,其中,t1和t0為臨時存儲器,n為索引計數(shù)器。系統(tǒng)除了需要數(shù)據(jù)輸入輸出信號i和f之外,還需要增加一個命令信號start,代表操作的開始;還有兩個狀態(tài)信號:idle和ready信號,分別代表電路處于空閑狀態(tài)和準備好接收新數(shù)據(jù)輸入狀態(tài);done_tick為單脈沖輸出信號,代表操作完成??紤]到斐波納契序列產(chǎn)生電路與其他系統(tǒng)之間的良好調(diào)用接口,以上羅列的信號都能夠與其他系統(tǒng)進行對接。圖6-15斐波納契序列產(chǎn)生電路ASMD圖該狀態(tài)機包含三個狀態(tài),即idle、op和done操作三個狀態(tài)。其中,idle狀態(tài)代表空閑狀態(tài),當(dāng)start信號有效時,電路進入操作狀態(tài);然后為三個寄存器裝載初始值,t0和t1寄存器分別被初始化為0和1,代表fib(0)和fib(1),同時寄存器n被初始化為輸入值i,代表序列迭代的次數(shù)。

主要的計算都在op狀態(tài)下進行,包含三個RT操作:

(1)?t1←t1+t0

(2)?t0←t1

(3)?n=n–1所有操作都在同一時鐘沿下并行執(zhí)行,且所有RT操作都在op狀態(tài)下執(zhí)行。如此一來,減少了運算的時間。需要注意的是,t1和t0寄存器的值在FSMD退出op狀態(tài)之后的下一個時鐘上升沿都確保完成了賦值。所以狀態(tài)done只是為了輸出單時鐘脈沖的done_tick時鐘信號,表示RT操作的結(jié)束。這個狀態(tài)其實在系統(tǒng)不需要時完全可以刪除。系統(tǒng)RTL代碼設(shè)計如程序6-10所示。需要注意的是,斐波納契序列產(chǎn)生的速度很快,所以輸出序列的位寬一定要設(shè)置的寬些。

【程序6-10】斐波納契序列產(chǎn)生電路。

modulefib

(

input

wireclk,reset,

input

wirestart,

input

wire[4:0]i,

output

regready,done_tick,

output

wire[19:0]f

);

//狀態(tài)聲明

localparam[1:0]

idle=2'b00,

op=2'b01,

done=2'b10;

//信號聲明

reg[1:0]state_reg,state_next;

reg[19:0]t0_reg,t0_next,t1_reg,t1_next;

reg[4:0]n_reg,n_next;

//主體部分

//FSMD狀態(tài)以及數(shù)據(jù)寄存器

always@(posedgeclk,posedgereset)

if(reset)

begin

state_reg<=idle;

t0_reg<=0;

t1_reg<=0;

n_reg<=0;

end

else

begin

state_reg<=state_next;

t0_reg<=t0_next;

t1_reg<=t1_next;

n_reg<=n_next;

end

//FSMD下一狀態(tài)邏輯

always@*

begin

state_next=state_reg;

ready=1'b0;

done_tick=1'b0;

t0_next=t0_reg;

t1_next=t1_reg;

n_next=n_reg;

case(state_reg)

idle:

begin

ready=1'b1;

if(start)

begin

t0_next=0;

t1_next=20'd1;

n_next=i;

state_next=op;

end

end

op:

if(n_reg==0)

begin

t1_next=0;

state_next=done;

end

else

if(n_reg==1)

state_next=done;

else

begin

t1_next=t1_reg+t0_reg;

t0_next=t1_reg;

n_next=n_reg-1;

end

done:

begin

done_tick=1'b1;

state_next=idle;

end

default:state_next=idle;

endcase

end

//輸出

assignf=t1_reg;

endmodule6.5.2頻率檢測器設(shè)計

頻率檢測器通常采用檢測輸入周期信號的周期,然后根據(jù)頻率f和周期p的換算關(guān)系(f=1/p)計算出頻率。為了測量周期輸入信號的周期時間寬度,通用的方法就是在輸入信號的兩個時鐘上升沿之間計數(shù)系統(tǒng)時鐘的脈沖值。由于系統(tǒng)時鐘的頻率值是已知的,所以很容易計算出輸入信號的周期值。假如系統(tǒng)時鐘的頻率為f,所計算的脈沖數(shù)為N,則輸入信號的周期值為。

本小節(jié)我們設(shè)計檢測毫秒級周期輸入信號的頻率。ASMD設(shè)計流程圖如圖6-16所示。圖6-16頻率檢測器ASMD圖當(dāng)start信號有效時,周期計數(shù)器開始計數(shù)。我們采用上升沿檢測電路來生成一個時鐘脈沖,代表信號輸入的上升沿來臨。當(dāng)start信號有效時,F(xiàn)SMD狀態(tài)機停留在waite狀態(tài),等待輸入信號第一個上升沿的到來。

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論