有限狀態機FSM(自動售報機Verilog實現)
FSM
- 狀態機就是一種能夠描述具有邏輯順序和時序順序事件的方法。
狀態機有兩大類:Mealy型和Moore型。
Moore型狀態機的輸出只與當前狀態有關,而Mealy型狀態機的輸出不僅取決於當前狀態,還受到輸入的直接控制,並且可能與狀態無關。
當使用Verilog來描述一個簡單狀態機的設計時,應將狀態寄存器的控制器的控制和狀態機狀態里的組合邏輯分開。

- 分離功能使得在邏輯部分的代碼中可以使用阻塞賦值語句
狀態更新邏輯包含狀態寄存器,不能被外設讀取。組合邏輯使用輸入和當前狀態值來對輸出賦值,並改變狀態機的下一狀態。
同步時序電路的設計方法
- 邏輯抽象,得出電路的狀態轉換圖或者狀態轉換表
- 狀態化簡
- 狀態分配(狀態編碼:Binary,Gray,One-Hot)
- Verilog根據最簡狀態轉換圖編程,檢查設計的電路能否自啟動
四個要素
- 當前輸入
- 當前狀態
- 下一狀態
- 當前輸出值
代碼風格
一段式
當前狀態、下一狀態、當前輸出值都寫在一個always塊中
二段式
當前狀態、下一狀態、當前輸出值寫在兩個always塊中
- 注意:這樣三種組合方式,及有三種方式寫這兩個always塊。
三段式
當前狀態、下一狀態、當前輸出值分別寫在各自的always塊中,這樣需要3個always塊。
自動售報機Verilog實現
設計說明
設計一個簡單的數字電路用於電子的報紙售賣機的投幣器。
- 假設報紙的價格為15分。
- 投幣器只能接受5分和1角的硬幣。
- 必須提供適當的數目的零錢,投幣器不找零。
- 合法的硬幣組合包括1個5分的硬幣和1個一角的硬幣,3個5分的硬幣,1個1角的硬幣和1個5分的硬幣。2個1角的硬幣是合法的,但是投幣器不找零。
電路說明
- 當投入硬幣時,一個兩位的信號coin[1:0]被傳送到數字電路。該信號在全局clock信號的下一個下降沿取值,並且准確地保持一個始終周期。
- 數字電路的輸出是一位的。每次當投入硬幣總數為15分或者超過15分時,輸出信號newspaper變為高電平,並且保持一個時鍾周期。售賣機的門也被打開。
- 可以用一個reset信號復位有限狀態機。假設為同步復位。
有限狀態機FSM
可以用有限狀態機表示該數字電路的功能。
- 輸入:2位,coin[1:0]。沒有硬幣時,x0 = 2'b00;有一個5分的硬幣時,x5 = 2'b01;有一個1角的硬幣時,x10 = 2'b10。
- 輸出:1位,newspaper。當newspaper = 1'b1時,打開門。
- 狀態:4個狀態。s0 = 0分,s5 = 5分,s10 = 10分,s15 = 15分。
狀態機轉換圖
| 狀態 | 錢數 | 輸入 | 硬幣[1:0] |
|---|---|---|---|
| s0 | 0分 | x0 | 2'b00 |
| s5 | 5分 | x5 | 2'b01 |
| s10 | 10分 | x10 | 2'b10 |
| s15 | 15分 | - | 無關 |
verilog描述
design code
module vend(
input [1:0] coin,
input clock,
input reset,
output newspaper
);
//聲明有限狀態機的內部狀態
wire [1:0] NEXT_STATE;
reg [1:0] PRES_STATE;
//狀態編碼
parameter s0 = 2'b00;
parameter s5 = 2'b01;
parameter s10 = 2'b10;
parameter s15 = 2'b11;
//用同步復位、時鍾正跳變沿觸發的狀態觸發器
always@(posedge clock)
begin
if(reset == 1'b1)
PRES_STATE <= s0;
else
PRES_STATE <= NEXT_STATE;
end
//組合邏輯
function [2:0] fsm; //狀態變化及輸出組合邏輯
input [1:0] fsm_coin;
input [1:0] fsm_PRES_STATE;
reg fsm_newspaper;
reg [1:0] fsm_NEXT_STATE;
begin
case(fsm_PRES_STATE)
s0: //狀態為s0
begin
if(fsm_coin == 2'b10)
begin
fsm_newspaper = 1'b0;
fsm_NEXT_STATE = s10;
end
else if(fsm_coin == 2'b01)
begin
fsm_newspaper = 1'b0;
fsm_NEXT_STATE = s5;
end
else
begin
fsm_newspaper = 1'b0;
fsm_NEXT_STATE = s0;
end
end
s5: //狀態為s5
begin
if(fsm_coin == 2'b10)
begin
fsm_newspaper = 1'b0;
fsm_NEXT_STATE = s15;
end
else if(fsm_coin == 2'b01)
begin
fsm_newspaper = 1'b0;
fsm_NEXT_STATE = s10;
end
else
begin
fsm_newspaper = 1'b0;
fsm_NEXT_STATE = s5;
end
end
s10: //狀態為s10
begin
if(fsm_coin == 2'b10)
begin
fsm_newspaper = 1'b0;
fsm_NEXT_STATE = s15;
end
else if(fsm_coin == 2'b01)
begin
fsm_newspaper = 1'b0;
fsm_NEXT_STATE = s15;
end
else
begin
fsm_newspaper = 1'b0;
fsm_NEXT_STATE = s10;
end
end
s15: //狀態為s15
begin
fsm_newspaper = 1'b1;
fsm_NEXT_STATE = s0;
end
endcase
fsm = {fsm_newspaper,fsm_NEXT_STATE};
end
endfunction
//每當硬幣放入或當前狀態改變時,組合邏輯動作
assign {newspaper,NEXT_STATE} = fsm(coin,PRES_STATE);
endmodule
testbench
module vend_tb;
reg clock;
reg reset;
reg [1:0] coin;
wire newspaper;
always #20 clock = ~clock;
initial
begin
clock = 0;
reset = 1;
#100;
reset = 0;
@(posedge clock) coin[1:0] = 2'b00;
@(posedge clock);
@(posedge clock) coin[1:0] = 2'b01;
@(posedge clock);
@(posedge clock) coin[1:0] = 2'b10;
@(posedge clock);
@(posedge clock) coin[1:0] = 2'b10;
@(posedge clock);
@(posedge clock) coin[1:0] = 2'b10;
@(posedge clock);
@(posedge clock) coin[1:0] = 2'b00;
@(posedge clock);
@(posedge clock) coin[1:0] = 2'b01;
@(posedge clock);
@(posedge clock) coin[1:0] = 2'b01;
@(posedge clock);
@(posedge clock) coin[1:0] = 2'b01;
#200 $finish;
end
initial begin
$fsdbDumpfile("test.fsdb");
$fsdbDumpvars();
end
vend u_vend(
.coin(coin),
.clock(clock),
.reset(reset),
.newspaper(newspaper)
);
endmodule
仿真結果
參考資料
[1]. Verilog HDL數字設計與綜合(第二版) [美]Simir Palnitkar 著 夏宇聞 等譯
[2]. Verilog 數字VLSI設計教程 [美] John Willianms 著 李林 等譯
[3]. 有限狀態機 FSM 設計
[4]. 有限狀態機FSM coding style整理 (SOC) (Verilog)




