http://bbs.ednchina.com/BLOG_ARTICLE_53109.HTM
時序電路的狀態是一個狀態變量集合,這些狀態變量在任意時刻的值都包含了為確定電路的未來行為而必需考慮的所有歷史信息
狀態機采用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
三段式並不是一定要寫為3個always塊,如果狀態機更復雜,就不止3段了。
附一個比較好的狀態機范例:
01 module FSM(clk,rst,in,out); 02 input clk,rst; 03 input [7:0] in; 04 output [7:0] out; 05 06 parameter [1:0] //synopsys enum code 07 START = 2'd0, 08 SA = 1, 09 SB = 2, 10 SC = 3; 11 12 reg [1:0] CS,NS; 13 reg [7:0] tmp_out,out; 14 15 // state transfer 16 always @ (posedge clk or negedge rst) 17 begin 18 if (!rst) CS <= #1 START; 19 else CS <= #1 NS; 20 end 21 22 // state transfer discipline 23 always @ (in or CS) 24 begin 25 NS = START; 26 case (CS) 27 START: case (in[7:6]) 28 2'b11: NS = SA; 29 2'b00: NS = SC; 30 default: NS = START; 31 endcase 32 SA: if(in == 8'h3c) NS = SB; 33 SB: begin 34 if (in == 8'h88) NS = SC; 35 else NS = START; 36 end 37 SC: case(1'b1) //synopsys parallel_case full_case 38 (in == 8'd0): NS = SA; 39 (8'd0 < in && in < 8'd38): NS = START; 40 (in > 8'd37): NS = SB; 41 endcase 42 endcase 43 end 44 45 // temp out 46 always @ (CS) 47 begin 48 tmp_out = 8'bX; 49 case (CS) 50 START: tmp_out = 8'h00; 51 SA: tmp_out = 8'h08; 52 SB: tmp_out = 8'h18; 53 SC: tmp_out = 8'h28; 54 endcase 55 end 56 57 // reg out 58 always @ (posedge clk or negedge rst) 59 begin 60 if (!rst) out <= #1 8'b0; 61 else out <= #1 tmp_out; 62 end 63 64 endmodule
二、兩段式有限狀態機與三段式有限狀態機的區別:
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
4.FSM中的case最好加上default,默認態可以設為初始態
5.尤其注意:
第二段的always(組合部分,賦值用=)里面判斷條件一定要包含所有情況!可以用else保證包含完全。
6、第二段always中,組合邏輯電平要維持超過一個clock,仿真時注意。
三、總結
為了便於記憶,把二段、三段式的特點終結成幾句話:
二段式:狀態切換用時序邏輯,次態輸出和信號輸出用組合邏輯。
三段式:狀態切換用時序邏輯,次態輸出用組合邏輯,信號輸出用時序邏輯。信號輸出的process中,case語句用next state做條件,可以解決比組合邏輯輸出慢一拍的問題。
有時候判斷次態需要用到計數器怎么辦呢(計數器是時序電路,用組合邏輯是實現不了的)?方法是獨立實現一個計數器,而在組合邏輯里用使能信號(或清除、置位等)來控制它。
