關於狀態機 一段式 二段式 三段式 (網上資料搜集)
對於自認很有軟件編程經驗的我,初識狀態機,覺得沒什么大不了的,實現起來沒什么難度,
初學FPGA時學的是verilog, 看夏宇聞的書上狀態機的例子使用的一段式,當然他沒有說明這種寫法是一段式,當時覺得挺簡單明了.
后來用VHDL, 看的一本E文的書上, 狀態機的例子是典型的二段式(作者也沒說明這是兩段式),當時還覺得這種寫法挺麻煩的,沒有一段式的看起來舒服, 當時還沒有切身的體會兩種的區別以及一段式的劣處.
后來在一段式狀態機上吃了虧, 才想到去重新思考和認識狀態機,才知道了一段式 二段式 三段式的概念.
關於詳細地概念,我就不復述了,看兩篇網上轉載的文章就可以了:
Verilog三段式狀態機描述(轉載)
時序電路的狀態是一個狀態變量集合,這些狀態變量在任意時刻的值都包含了為確定電路的未來行為而必需考慮的所有歷史信息。
狀態機采用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,仿真時注意。
