1. 摘要
文章為學習記錄。主要介紹狀態機概述、狀態轉移圖、狀態編碼、狀態機寫法、狀態機代碼示例。
2. 狀態機概述
狀態機 (Finite State Machine),也稱為同步有限狀態機,用于描述有先后順序或時序規律的事情。
“同步”:狀態機中所有的狀態跳轉都是在時鐘的作用下進行的。
“有限”:狀態的個數是有限的。
Moore 型狀態機:最后的輸出只和當前狀態有關而與輸入無關。
Mealy 型狀態機: 最后的輸出不僅和當前狀態有關還和輸入有關。
3. 狀態轉移圖
狀態轉移圖能夠表達出狀態機的狀態和狀態跳轉的條件。
狀態轉移圖三要素:
(a)輸入:根據輸入可以確定是否需要進行狀態跳轉以及輸出,是影響狀態機系統執行過程的重要驅動力;
(b)輸出:根據當前時刻的狀態以及輸入確定,是狀態機系統最終要執行的動作;
(c)狀態:根據輸入和上一狀態決定當前時刻所處的狀態,是狀態機系統執行的一個穩定的過程。
輸入有多少種情況,每個狀態的跳轉就有多少種情況。
常見的狀態轉移圖如下圖所示。
4. 狀態編碼
以3個狀態數為例:
(a) 獨熱碼:3’b001,3’b010,3’b100; 使用的寄存器資源多,組合邏輯資源少。
(b) 二進制碼:2’b00,2’b01,2’b10;使用的寄存器資源少,組合邏輯資源多。
(c)格雷碼:2’b00,2’b01,2’b11;使用的寄存器資源少,組合邏輯資源多。其相鄰狀態轉換時只有1bit不同。
狀態編碼方式如下表所示。
5. 狀態機寫法
一段式:在一段狀態機中使用時序邏輯既描述狀態的轉移,也描述數據的輸出;
二段式:在第一段狀態機中使用時序邏輯描述狀態轉移,在第二段狀態機中使用組合邏輯描述數據的輸出;
三段式:在第一段狀態機中采用時序邏輯描述狀態轉移,在第二段在狀態機中采用組合邏輯判斷狀態轉移條件描述狀態轉移規律,在第三段狀態機中描述狀態輸出,可以用組合電路輸出,也可以時序電路輸出;
新二段式:使用兩個均采用時序邏輯的 always 塊。第一個 always 塊描述狀態的轉移為第一段狀態機,第二個 always 塊描述數據的輸出為第二段狀態機(如果我們遵循一個 always 塊只描述一個變量的原則,如果有多個輸出時第二段狀態機就可以分為多個always 塊來表達)。
6. 狀態機代碼示例
module complex_fsm
(input wire sys_clk , //系統時鐘50MHzinput wire sys_rst_n , //全局復位input wire pi_money_one , //投幣1元input wire pi_money_half , //投幣0.5元output reg po_money , //po_money為1時表示找零//po_money為0時表示不找零output reg po_cola //po_cola為1時出可樂//po_cola為0時不出可樂
);//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************////parameter define
//只有五種狀態,使用獨熱碼
parameter IDLE = 5'b00001;
parameter HALF = 5'b00010;
parameter ONE = 5'b00100;
parameter ONE_HALF = 5'b01000;
parameter TWO = 5'b10000;//reg define
reg [4:0] state;//wire define
wire [1:0] pi_money;//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************////pi_money:為了減少變量的個數,我們用位拼接把輸入的兩個1bit信號拼接成1個2bit信號
//投幣方式可以為:不投幣(00)、投0.5元(01)、投1元(10),每次只投一個幣
assign pi_money = {pi_money_one, pi_money_half};//第一段狀態機,描述當前狀態state如何根據輸入跳轉到下一狀態
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)state <= IDLE; //任何情況下只要按復位就回到初始狀態else case(state)IDLE : if(pi_money == 2'b01) //判斷一種輸入情況state <= HALF;else if(pi_money == 2'b10)//判斷另一種輸入情況state <= ONE;elsestate <= IDLE;HALF : if(pi_money == 2'b01)state <= ONE;else if(pi_money == 2'b10)state <= ONE_HALF;elsestate <= HALF;ONE : if(pi_money == 2'b01)state <= ONE_HALF;else if(pi_money == 2'b10)state <= TWO;elsestate <= ONE;ONE_HALF: if(pi_money == 2'b01)state <= TWO;else if(pi_money == 2'b10)state <= IDLE;elsestate <= ONE_HALF;TWO : if((pi_money == 2'b01) || (pi_money == 2'b10))state <= IDLE;elsestate <= TWO;//如果狀態機跳轉到編碼的狀態之外也回到初始狀態default : state <= IDLE;endcase//第二段狀態機,描述當前狀態state和輸入pi_money如何影響po_cola輸出
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)po_cola <= 1'b0;else if((state == TWO && pi_money == 2'b01) || (state == TWO && pi_money == 2'b10) || (state == ONE_HALF && pi_money == 2'b10))po_cola <= 1'b1;elsepo_cola <= 1'b0;//第二段狀態機,描述當前狀態state和輸入pi_money如何影響po_money輸出
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)po_money <= 1'b0;else if((state == TWO) && (pi_money == 2'b10))po_money <= 1'b1;elsepo_money <= 1'b0;endmodule