有限狀態(tài)機(jī)(Finite-State Machine,F(xiàn)SM),簡(jiǎn)稱狀態(tài)機(jī),是表示有限個(gè)狀態(tài)以及在這些狀態(tài)之間的轉(zhuǎn)移和動(dòng)作等行為的數(shù)學(xué)模型。狀態(tài)機(jī)不僅是一種電路的描述工具,而且也是一種思想方法,在電路設(shè)計(jì)的系統(tǒng)級(jí)和 RTL 級(jí)有著廣泛的應(yīng)用。
狀態(tài)機(jī)類型
Verilog 中狀態(tài)機(jī)主要用于同步時(shí)序邏輯的設(shè)計(jì),能夠在有限個(gè)狀態(tài)之間按一定要求和規(guī)律切換時(shí)序電路的狀態(tài)。狀態(tài)的切換方向不但取決于各個(gè)輸入值,還取決于當(dāng)前所在狀態(tài)。
狀態(tài)機(jī)可分為 2 類:Moore 狀態(tài)機(jī)和 Mealy 狀態(tài)機(jī)。
◆Moore 型狀態(tài)機(jī)
Moore 型狀態(tài)機(jī)的輸出只與當(dāng)前狀態(tài)有關(guān),與當(dāng)前輸入無(wú)關(guān)。
輸出會(huì)在一個(gè)完整的時(shí)鐘周期內(nèi)保持穩(wěn)定,即使此時(shí)輸入信號(hào)有變化,輸出也不會(huì)變化。輸入對(duì)輸出的影響要到下一個(gè)時(shí)鐘周期才能反映出來(lái)。這也是 Moore 型狀態(tài)機(jī)的一個(gè)重要特點(diǎn):輸入與輸出是隔離開(kāi)來(lái)的。
◆Mealy 型狀態(tài)機(jī)
Mealy 型狀態(tài)機(jī)的輸出,不僅與當(dāng)前狀態(tài)有關(guān),還取決于當(dāng)前的輸入信號(hào)。
Mealy 型狀態(tài)機(jī)的輸出是在輸入信號(hào)變化以后立刻發(fā)生變化,且輸入變化可能出現(xiàn)在任何狀態(tài)的時(shí)鐘周期內(nèi)。因此,同種邏輯下,Mealy 型狀態(tài)機(jī)輸出對(duì)輸入的響應(yīng)會(huì)比 Moore 型狀態(tài)機(jī)早一個(gè)時(shí)鐘周期。
◆狀態(tài)機(jī)設(shè)計(jì)流程
根據(jù)設(shè)計(jì)需求畫(huà)出狀態(tài)轉(zhuǎn)移圖,確定使用狀態(tài)機(jī)類型,并標(biāo)注出各種輸入輸出信號(hào),更有助于編程。一般使用最多的是 Mealy 型 3 段式狀態(tài)機(jī),下面用通過(guò)設(shè)計(jì)一個(gè)自動(dòng)售賣(mài)機(jī)的具體實(shí)例來(lái)說(shuō)明狀態(tài)機(jī)的設(shè)計(jì)過(guò)程。
自動(dòng)售賣(mài)機(jī)
◆自動(dòng)售賣(mài)機(jī)的功能描述如下。
飲料單價(jià) 2 元,該售賣(mài)機(jī)只能接受 0.5 元、1 元的硬幣??紤]找零和出貨。投幣和出貨過(guò)程都是一次一次的進(jìn)行,不會(huì)出現(xiàn)一次性投入多幣或一次性出貨多瓶飲料的現(xiàn)象。每一輪售賣(mài)機(jī)接受投幣、出貨、找零完成后,才能進(jìn)入到新的自動(dòng)售賣(mài)狀態(tài)。
◆該售賣(mài)機(jī)的工作狀態(tài)轉(zhuǎn)移圖如下所示,包含了輸入、輸出信號(hào)狀態(tài)。
其中,coin = 1 代表投入了 0.5 元硬幣,coin = 2 代表投入了 1 元硬幣。
狀態(tài)機(jī)設(shè)計(jì):3 段式(推薦)
◆狀態(tài)機(jī)設(shè)計(jì)如下。
(0) 首先,根據(jù)狀態(tài)機(jī)的個(gè)數(shù)確定狀態(tài)機(jī)編碼。利用編碼給狀態(tài)寄存器賦值,代碼可讀性更好。
(1) 狀態(tài)機(jī)第一段,時(shí)序邏輯,非阻塞賦值,傳遞寄存器的狀態(tài)。
(2) 狀態(tài)機(jī)第二段,組合邏輯,阻塞賦值,根據(jù)當(dāng)前狀態(tài)和當(dāng)前輸入,確定下一個(gè)狀態(tài)機(jī)的狀態(tài)。
(3) 狀態(tài)機(jī)第三代,時(shí)序邏輯,非阻塞賦值,因?yàn)槭?Mealy 型狀態(tài)機(jī),根據(jù)當(dāng)前狀態(tài)和當(dāng)前輸入,確定輸出信號(hào)。
// vending-machine
// 2 yuan for a bottle of drink
// only 2 coins supported: 5 jiao and 1 yuan
// finish the function of selling and changing
module vending_machine_p3 (
input clk ,
input rstn ,
input [1:0] coin , //01 for 0.5 jiao, 10 for 1 yuan
output [1:0] change ,
output sell //output the drink
);
//machine state decode
parameter IDLE = 3'd0 ;
parameter GET05 = 3'd1 ;
parameter GET10 = 3'd2 ;
parameter GET15 = 3'd3 ;
//machine variable
reg [2:0] st_next ;
reg [2:0] st_cur ;
//(1) state transfer
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
st_cur <= 'b0 ;
end
else begin
st_cur <= st_next ;
end
end
//(2) state switch, using block assignment for combination-logic
//all case items need to be displayed completely
always @(*) begin
//st_next = st_cur ;//如果條件選項(xiàng)考慮不全,可以賦初值消除latch
case(st_cur)
IDLE:
case (coin)
2'b01: st_next = GET05 ;
2'b10: st_next = GET10 ;
default: st_next = IDLE ;
endcase
GET05:
case (coin)
2'b01: st_next = GET10 ;
2'b10: st_next = GET15 ;
default: st_next = GET05 ;
endcase
GET10:
case (coin)
2'b01: st_next = GET15 ;
2'b10: st_next = IDLE ;
default: st_next = GET10 ;
endcase
GET15:
case (coin)
2'b01,2'b10:
st_next = IDLE ;
default: st_next = GET15 ;
endcase
default: st_next = IDLE ;
endcase
end
//(3) output logic, using non-block assignment
reg [1:0] change_r ;
reg sell_r ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
change_r <= 2'b0 ;
sell_r <= 1'b0 ;
end
else if ((st_cur == GET15 && coin ==2'h1)
|| (st_cur == GET10 && coin ==2'd2)) begin
change_r <= 2'b0 ;
sell_r <= 1'b1 ;
end
else if (st_cur == GET15 && coin == 2'h2) begin
change_r <= 2'b1 ;
sell_r <= 1'b1 ;
end
else begin
change_r <= 2'b0 ;
sell_r <= 1'b0 ;
end
end
assign sell = sell_r ;
assign change = change_r ;
endmodule