1. 程式人生 > >徹底搞懂狀態機(一段式、兩段式、三段式)

徹底搞懂狀態機(一段式、兩段式、三段式)

例項:FSM實現10010串的檢測

狀態轉移圖:初始狀態S0,a = 0,z = 0.如果檢測到1,跳轉到S1。

            下一狀態S1,a = 1,z = 0.如果檢測到0,跳轉到S2。             下一狀態S2,a = 0,z = 0.如果檢測到0,跳轉到S3。             下一狀態S3,a = 0,z = 0.如果檢測到1,跳轉到S4。             下一狀態S4,a = 1,z = 0.如果檢測到0,跳轉到S5。             下一狀態S5,a = 0,z = 1.如果檢測到1,跳轉到S1;如果檢測到0,跳轉到S3(因為之前S4已經是1,S5是0,若再檢測到0,就是100,因此跳轉到S4)。

 

程式中將一段式(one_fsm)、兩段式(two_fsm)、三段式(three_fsm)以及對應的模擬檔案(XXX_tb)包含在了一個工程中。要單獨執行、模擬每一種方式,只需將他們(one_fsm.v、two_fsm.v、three_fsm.v)分別設為頂層檔案(選中右擊,然後選擇Set as Top-Level Entity),然後在模擬設定裡面選擇對應的模擬檔案即可。見下圖:

 

補充:(轉)PART1

1、好的狀態機標準

好的狀態機的標準很多,最重要的幾個方面如下:

第一,狀態機要安全,是指FSM不會進入死迴圈,特別是不會進入非預知的狀態,而且由於某些擾動進入非設計狀態,也能很快的恢復到正常的狀態迴圈中來。這裡面有兩層含義:其一要求該FSM的綜合實現結果無毛刺等異常擾動;其二要求FSM要完備,即使受到異常擾動進入非設計狀態,也能很快恢復到正常狀態。

第二,狀態機的設計要滿足設計的面積和速度的要求。

第三,狀態機的設計要清晰易懂、易維護。

 

2、狀態機描述方法

狀態機描述時關鍵是要描述清楚幾個狀態機的要素,即如何進行狀態轉移,每個狀態的輸出是什麼,狀態轉移的條件等。具體描述時方法各種各樣,最常見的有三種描述方式:

(1)一段式:整個狀態機寫到一個always模組裡面,在該模組中既描述狀態轉移,又描述狀態的輸入和輸出;

(2)二段式:用兩個always模組來描述狀態機,其中一個always模組採用同步時序描述狀態轉移;另一個模組採用組合邏輯判斷狀態轉移條件,描述狀態轉移規律以及輸出;

(3)三段式:在兩個always模組描述方法基礎上,使用三個always模組,一個always模組採用同步時序描述狀態轉移,一個always採用組合邏輯判斷狀態轉移條件,描述狀態轉移規律,另一個always模組描述狀態輸出(可以用組合

電路輸出,也可以時序電路輸出)。

 

一般而言,推薦的FSM 描述方法是後兩種。這是因為:FSM和其他設計一樣,最好使用同步時序方式設計,以提高設計的穩定性,消除毛刺。狀態機實現後,一般來說,狀態轉移部分是同步時序電路而狀態的轉移條件的判斷是組合邏輯。

 

第二種描述方法同第一種描述方法相比,將同步時序和組合邏輯分別放到不同的always模組中實現,這樣做的好處不僅僅是便於閱讀、理解、維護,更重要的是利於綜合器優化程式碼,利於使用者新增合適的時序約束條件,利於佈局佈線器實現設計。

在第二種方式的描述中,描述當前狀態的輸出用組合邏輯實現,組合邏輯很容易產生毛刺,而且不利於約束,不利於綜合器和佈局佈線器實現高效能的設計。

第三種描述方式與第二種相比,關鍵在於根據狀態轉移規律,在上一狀態根據輸入條件判斷出當前狀態的輸出,從而在不插入額外時鐘節拍的前提下,實現了暫存器輸出。

 

PART2

時序電路的狀態是一個狀態變數集合,這些狀態變數在任意時刻的值都包含了為確定電路的未來行為而必需考慮的所有歷史資訊。

狀態機採用VerilogHDL語言編碼,建議分為三個always段完成。

 

三段式建模描述FSM的狀態機輸出時,只需指定case敏感表為次態暫存器,然後直接在每個次態的case分支中描述該狀態的輸出即可,不用考慮狀態轉移條件。

三段式描述方法雖然程式碼結構複雜了一些,但是換來的優勢是:使FSM做到了同步暫存器輸出,消除了組合邏輯輸出的不穩定與毛刺的隱患,而且更利於時序路徑分組,一般來說在FPGA/CPLD等可程式設計邏輯器件上的綜合與佈局佈線效果更佳。

示列模板如下:

//第一個程序,同步時序always模組,格式化描述次態暫存器遷移到現態暫存器

always @ (posedge clk or negedge rst_n) //非同步復位

if(!rst_n)

current_state <= IDLE;

else

current_state <= next_state; //注意,使用的是非阻塞賦值

//第二個程序,組合邏輯always模組,描述狀態轉移條件判斷

always @ (current_state) //電平觸發

begin

next_state = x; //要初始化,使得系統復位後能進入正確的狀態

case(current_state)

S1: if(...)

next_state = S2; //阻塞賦值

...

endcase

end

//第三個程序,同步時序always模組,格式化描述次態暫存器輸出

always @ (posedge clk or negedge rst_n)

...//初始化

case(next_state)

S1:

out1 <= 1'b1; //注意是非阻塞邏輯

S2:

out2 <= 1'b1;

default:... //default的作用是免除綜合工具綜合出鎖存器

endcase

end

兩段式有限狀態機與三段式有限狀態機的區別

FSM將時序部分(狀態轉移部分)和組合部分(判斷狀態轉移條件和產生輸出)分開,寫為兩個always語句,即為兩段式有限狀態機。
將組合部分中的判斷狀態轉移條件和產生輸入再分開寫,則為三段式有限狀態機。
區別:
二段式在組合邏輯特別複雜時適用,但要注意需在後面加一個觸發器以消除組合邏輯對輸出產生的毛刺。三段式沒有這個問題,由於第三個always會生成觸發器。
設計時注意方面:
1.編碼原則

binary和gray-code適用於觸發器資源較少,組合電路資源豐富的情況(CPLD),對於FPGA,適用one-hot code。這樣不但充分利用FPGA豐富的觸發器資源,還因為只需比較一個bit,速度快,組合電路簡單。

2.FSM初始化問題:
GSR(Gobal Set/Reset)只是在加電時清零所有的reg和片內ram,並不保證FSM能進入初始化狀態,要利用GSR,方案是適用one-hot code with zero idle,即初始狀態編碼為全零。已可以適用非同步復位rst
3.FSM輸出可以適用task
4FSM中的case最好加上default,預設態可以設為初始態
5.尤其注意
第二段的always(組合部分,賦值用=)裡面判斷條件一定要包含所有情況!可以用else保證包含完全。
6第二段always中,組合邏輯電平要維持超過一個clock,模擬時注意。