轉載自https://blog.csdn.net/woshiyuzhoushizhe/article/details/95866063
一、有限狀態機定義
有限狀態機(Finite-State Machine,FSM),又成為有限狀態自動機,簡稱狀態機,是表示有限個狀態以及在這些狀態之間的轉移和動作等行為的數學模型。筆者常在電機控制、通信協議解析等應用場景下應用FSM。 本文所講的是基於硬件描述語言Verilog HDL的有限狀態機的編寫技巧及規范。眾所周知FPGA以其並行性和可重構性為世人所知,而在當今的電子世界,基本所有的器件都是串行的,所以作為控制單元或者是可編程單元的FPGA需要進行並行轉串行與外界進行通信、控制等,而有限狀態機以其簡單實用、結構清晰而恰如其分的充當着這個角色。
有限狀態機是由寄存器組和組合邏輯構成的硬件時序電路,其狀態(即由寄存器組的1和0的組合狀態所構成的有限個狀態)只可能在同一時鍾跳變沿的情況下才能從一個狀態轉向另一個狀態,究竟轉向哪一狀態還是留在原狀態不但取決於各個輸入值,還取決於當前所在狀態。
二、設計思想:
狀態機的本質是對具有邏輯順序或時序規律事件的一種描述方法。這個論斷的最重要的兩個詞就是“邏輯順序”和“時序邏輯”,這兩點就是狀態機所要描述的核心和強項,換言之,所有具有邏輯順序和時序規律的事情都適合用狀態機描述。
狀態機的兩種應用思路。第一種思路,從狀態變量入手。如果一個電路具有時序邏輯或者邏輯順序,我們就可以自然而然地規划出狀態,從這些狀態入手,分析每個狀態的輸入,狀態轉移和輸出,從而完成電路功能;第二種思路,需要首先明確電路的輸出關系,這些輸出相當於狀態的輸出,回溯規划每個狀態,和狀態轉移條件與狀態輸入。兩種思路殊途同歸,都要通過使用狀態機的目的來達到控制某部分電路的目的,完成某種具有邏輯順序或時序規律的電路設計。
在設計狀態機之前首先應該畫出問題的狀態轉移圖,狀態轉移圖的例子如下所示:
三、狀態機分類:
(1):mealy型和moore型
狀態機有兩大類:Mealy型和Moore型。Moore型狀態機的輸出只與當前狀態有關,而Mealy型狀態機的輸出不僅取決於當前狀態,還受到輸入的直接控制,並且可能與狀態無關,其狀態機結構請看下圖:
Mealy型狀態機結構圖
Moore型狀態機結構圖
(2):按照狀態編碼來分類:
1、Gray(格雷碼)碼狀態機
2、one-ho碼(獨熱碼)狀態機
3、二進制碼狀態機
詳解:
有限狀態機編碼時采用格雷碼和采用獨熱碼的選擇
格雷碼:相鄰之間只變1bit,編碼密度高。
獨熱碼:任何狀態只有1bit為1,其余皆為0,編碼密度低。
比如說,表示4個狀態,那么狀態機寄存器采用格雷碼編碼只需要2bit:00(S0),01(S1),11(S2),10(S3);
采用獨熱碼需要4bit:0001(S0),0010(S1),0100(S2),1000(S3)。所以很明顯采用格雷碼可以省2bit寄存器。
難理解的是,為什么獨熱碼更節省組合邏輯:
其實很簡單,
例一:
假如我們要在代碼中判斷狀態機是否處於某狀態S1,
對於格雷碼的狀態機來說,代碼是這樣的:assign S1 = (STATUS==2'b01);
對於獨熱碼來說,代碼是這樣的就行:assign S1=STATUS[1];
所以獨熱碼的譯碼非常簡單。
例二:
考慮最簡單的跳變,當A為1時,狀態機會從S0跳到S1:。
采用格雷碼寫:
STATUS[1:0] <= (STATUS==2'h00) & A ? 2'h01 : 2'h00;
采用獨熱碼寫:
STATUS[1] <= STATUS[0] & A;
有人懷疑這里的邏輯,認為只check獨熱碼的一個bit有問題。當然是沒問題的,0110,0011等編碼屬於不care的編 碼,在卡諾圖化簡中,不care的編碼可以與其余的有效編碼合並化簡。實際上綜合器也會這么做,所以獨熱碼非常容 易化簡。假如說S0跳到S1條件為A;S1跳到S2條件為B;S2跳到S3條件為C;S3跳到S0條件為D;那么整個狀態機 化簡之后代碼就是:
STATUS[0] <= STATUS[3] & D;
STATUS[1] <= STATUS[0] & A;
STATUS[2] <= STATUS[1] & B;
STATUS[3] <= STATUS[2] & C;
總結一下:
獨熱碼適合寫條件復雜但是狀態少的狀態機;
格雷碼適合寫條件不復雜但是狀態多的狀態機。
獨熱碼 使用的觸發器較多,但可減少實現狀態機的組合邏輯數目,減少復雜性,提高系統的速度,即工作時鍾頻率可 以做到最高。格雷碼是使用最小數目的觸發器來編碼狀態機,但形成的組合邏輯比較復雜。
使用獨熱碼編碼時,會出現很多未使用的狀態,而使用二進制編碼和格雷碼編碼時,如果狀態機的狀態數不是2的指 數 次方時,也會出現未使用狀態。
格雷碼每個相鄰的狀態切換只有一個bit的信號跳變,適用於異步握手的情況,比如異步FIFO的指針計數。
(3):在Verilog中描述有限狀態機,可以有三種形式,可分為一段式、二段式和三段式。這三種描述主要根據其輸入、輸出和狀態來分類。
一段式狀態機:一段式狀態機只選擇一個狀態標志位,這個狀態標志位會在輸入的決定下選擇跳轉到下一個狀態還是維持原有狀態,在每一個狀態下檢測狀態標志位及輸入來決定其狀態的跳轉及輸出。其輸出和狀態的切換在一個always循環塊中執行。
-
eg:
-
-
always()
-
-
begin
-
-
S0: begin state = (in)? S0:s1;out = ; end
-
-
S1: begin state = (in)? S1:s2;out = ; end
-
-
S2:.....................................
-
-
end
-
-
二段式狀態機:二段式狀態機將狀態分為當前狀態和此狀態,其系統會自動將次狀態更新到當前狀態,其輸入更新在次狀態上,其決定系統的狀態切換和輸出。其輸出和狀態的切換在兩個個always循環塊中執行,第一個always塊決定系統狀態標志的自動跳轉,第二個always塊決定系統根據不同狀態下的輸入進行狀態的跳轉及輸出。
-
eg: always()
-
-
begin
-
-
state=next_state
-
-
end
-
-
-
-
always()
-
-
begin
-
-
S0: begin next_state = (in)? S0:s1;out = ; end
-
-
S1: begin next_state = (in)? S1:s2;out = ; end
-
-
S2:.....................................
-
-
end
三段式狀態機:二段式狀態機將狀態分為當前狀態和此狀態,其系統會自動將次狀態更新到當前狀態,系統的輸入更新在次狀態上,其決定系統的狀態切換,系統會根據其當前狀態決定輸出的值。其輸出和狀態更新和狀態切換在三個always塊中,第一個always塊決定系統狀態標志的自動跳轉,第二個always塊決定系統根據不同狀態下的輸入進行狀態的切換,第三個always塊根據系統的當前狀態決定輸出的值。
-
eg: always()
-
-
begin
-
-
state=next_state
-
-
end
-
-
-
-
-
-
always()
-
-
begin
-
-
S0:next_state = ( in)? S0:s1;
-
-
S1:next_state = ( in)? S1:s2;
-
-
S2:.....................................
-
-
end
-
-
-
-
always()
-
-
begin
-
-
S0: out = ;
-
-
S1: out = ;
-
-
S2:.....................................
-
-
end
(4),三段式狀態機子詳細解釋:
-
摩爾狀態機的架構
-
狀態轉換圖
-
-
module finite_fsm(
-
z_o,
-
clk,
-
Rst_n,
-
w_i
-
);
-
//輸出端口
-
output z_o;
-
-
//輸入端口
-
input clk;
-
input Rst_n;
-
input w_i;
-
-
//輸出端口類型聲明
-
reg z_o;
-
-
//參數聲明
-
parameter IDLE = 2'b00;
-
parameter S0 = 2'b01;
-
parameter S1 = 2'b10;
-
-
//內部信號聲明
-
-
-
//狀態寄存器
-
always @ (posedge clk or negedge Rst_n) begin
-
if(!Rst_n)
-
current_state <= IDLE;
-
else
-
current_state <= next_state;
-
end
-
//次態的組合邏輯
-
always @ (w_i or current_state) begin
-
case(current_state)
-
IDLE:begin
-
-
else next_state = IDLE;
-
end
-
S0: begin
-
-
else next_state = IDLE;
-
end
-
S1: begin
-
-
else next_state = IDLE;
-
end
-
default : next_state = 2'bxx;
-
endcase
-
end
-
//輸出邏輯
-
always @ (*) beign
-
case(current)
-
IDLE: z_o = 1'b0;
-
S0: z_o = 1'b0;
-
S1: z_o = 1'b1;
-
default: z_0 = 1'b0;
-
endcase
-
end
-
endmodule
關於三段式狀態機的一點總結
1確定輸入輸出信號,及其類型(是wire還是reg);
2聲明內部信號,一般需要定義current_state和next_state;
3用3個always語句描述狀態機;第一個用來次態和現態的轉換,第二個always用於現態在輸入情況下轉換為次態的組合邏輯;第三個語句用於現態到輸出的組合邏輯輸出。 -
-
參考文章:https://blog.csdn.net/u013352499/article/details/47076635
參考文章:https://www.zhihu.com/question/40994717/answer/89125204
參考文章:https://blog.csdn.net/jason_child/article/details/60466050