一、有限状态机
- 基本概念
有限状态机(Finite State Machine, FSM)是电路设计的经典方法,通常可以认为是组合逻辑和寄存器逻辑的组合,其中组合逻辑用于状态译码和产生输出信号,寄存器用于存储状态。
- Moore和Mealy型状态机
摩尔型(Moore)状态机: 输出只是当前状态的函数
米利型(Mealy)状态机: 输出是当前状态和当前输入的函数
似乎不太好理解,我们结合状态机模型来看一下
可以看出,Moore型状态机输出只与当前状态(现态CS)有关
图中可以看出,Mealy型状态机相较于Moore型状态机,其输出逻辑多了一个输入端,即上述定义所说的Mealy型状态机输出由当前状态(现态CS)和当前输入决定。
- 两种状态机的区别
由于两者模型的差别,不难看出,Mealy型状态机当输入改变时输出也会立即改变,不依赖时钟,而Moore型状态机输入状态改变时,需要经过时钟同步后输出才会改变,即Moore型状态机比Mealy型状态机输出要多一个时钟周期。实用的状态机一般都设计成同步时序模式。
二、有限状态机的Verilog描述
-状态机的设计中主要包含以下3个对象:
-Verilog描述方式
-举例(可乐机:2.5¥出可乐,可以投入0.5¥、1¥)
1.先画出状态转移图,比较丑,但大概是这样,简单起见,不考虑找零,不投硬币也不算输入。
2.Verilog描述
2.1三段式描述
//三段式描述(CS、NS、OL)
module Coke_Machine //模块名
(
input wire sys_clk , //输入时钟
input wire sys_rst_n , //输入复位
input wire pi_money_half , //输入0.5
input wire pi_money_one , //输入1.0
output reg po_cola
);
parameter IDLE = 5'b00001, //状态编码,独热码
HALF = 5'b00010,
ONE = 5'b00100,
ONE_HALF = 5'b01000,
TWO = 5'b10000;
wire [1:0] pi_money;
reg [4:0] state,next_state;
assign pi_money = {pi_money_one,pi_money_half}; //合并输入,即输入0.5为01,输入1为10
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= IDLE; //定义起始状态
else
state <= next_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)
next_state <= HALF;
else if(pi_money == 2'b10)
next_state <= ONE;
else
next_state <= IDLE;
HALF: if(pi_money == 2'b01)
next_state <= ONE;
else if(pi_money == 2'b10)
next_state <= ONE_HALF;
else
next_state <= HALF;
ONE: if(pi_money == 2'b01)
next_state <= ONE_HALF;
else if(pi_money == 2'b10)
next_state <= TWO;
else
next_state <= ONE;
ONE_HALF: if(pi_money == 2'b01)
next_state <= TWO;
else if(pi_money == 2'b10)
next_state <= IDLE;
else
next_state <= ONE_HALF;
TWO: if(pi_money == 2'b01)
next_state <= IDLE;
else if(pi_money == 2'b10)
next_state <= HALF;
else
next_state <= TWO;
default: next_state <= IDLE;
endcase
always@(posedge sys_clk or negedge sys_rst_n) //输出逻辑
if(sys_rst_n == 1'b0)
po_cola <= 1'b0;
else if(((state == ONE_HALF) && (pi_money == 2'b10))
|| ((state == TWO) && (pi_money == 2'b01))
|| ((state == TWO) && (pi_money == 2'b10)))
po_cola <= 1'b1;
else
po_cola <= 1'b0;
endmodule
2.2两段式描述(CS+NS、OL)
//两段式描述(CS+NS、OL)
module Coke_Machine //模块名
(
input wire sys_clk , //输入时钟
input wire sys_rst_n , //输入复位
input wire pi_money_half , //输入01
input wire pi_money_one , //输入10
output reg po_cola
);
parameter IDLE = 5'b00001, //状态编码,独热码
HALF = 5'b00010,
ONE = 5'b00100,
ONE_HALF = 5'b01000,
TWO = 5'b10000;
wire [1:0] pi_money;
reg [4:0] state;
assign pi_money = {pi_money_one,pi_money_half}; //合并输入,即输入0.5为01,输入1为10
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;
else
state <= IDLE;
HALF: if(pi_money == 2'b01)
state <= ONE;
else if(pi_money == 2'b10)
state <= ONE_HALF;
else
state <= HALF;
ONE: if(pi_money == 2'b01)
state <= ONE_HALF;
else if(pi_money == 2'b10)
state <= TWO;
else
state <= ONE;
ONE_HALF: if(pi_money == 2'b01)
state <= TWO;
else if(pi_money == 2'b10)
state <= IDLE;
else
state <= ONE_HALF;
TWO: if(pi_money == 2'b01)
state <= IDLE;
else if(pi_money == 2'b10)
state <= HALF;
else
state <= TWO;
default: state <= IDLE;
endcase
always@(posedge sys_clk or negedge sys_rst_n) //输出逻辑
if(sys_rst_n == 1'b0)
po_cola <= 1'b0;
else if(((state == ONE_HALF) && (pi_money == 2'b10))
|| ((state == TWO) && (pi_money == 2'b01))
|| ((state == TWO) && (pi_money == 2'b10)))
po_cola <= 1'b1;
else
po_cola <= 1'b0;
endmodule
2.3单过程描述
//单段式描述
module Coke_Machine //模块名
(
input wire sys_clk , //输入时钟
input wire sys_rst_n , //输入复位
input wire pi_money_half , //输入01
input wire pi_money_one , //输入10
output reg po_cola
);
parameter IDLE = 5'b00001, //状态编码,独热码
HALF = 5'b00010,
ONE = 5'b00100,
ONE_HALF = 5'b01000,
TWO = 5'b10000;
wire [1:0] pi_money;
reg [4:0] state;
assign pi_money = {pi_money_one,pi_money_half}; //合并输入,即输入0.5为01,输入1为10
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)
begin
state <= HALF;
po_cola <= 1'b0;
end
else if(pi_money == 2'b10)
begin
state <= ONE;
po_cola <= 1'b0;
end
else
begin
state <= IDLE;
po_cola <= 1'b0;
end
HALF: if(pi_money == 2'b01)
begin
state <= ONE;
po_cola <= 1'b0;
end
else if(pi_money == 2'b10)
begin
state <= ONE_HALF;
po_cola <= 1'b0;
end
else
begin
state <= HALF;
po_cola <= 1'b0;
end
ONE: if(pi_money == 2'b01)
begin
state <= ONE_HALF;
po_cola <= 1'b0;
end
else if(pi_money == 2'b10)
begin
state <= TWO;
po_cola <= 1'b0;
end
else
begin
state <= ONE;
po_cola <= 1'b0;
end
ONE_HALF: if(pi_money == 2'b01)
begin
state <= TWO;
po_cola <= 1'b0;
end
else if(pi_money == 2'b10)
begin
state <= IDLE;
po_cola <= 1'b1;
end
else
begin
state <= ONE_HALF;
po_cola <= 1'b0;
end
TWO: if(pi_money == 2'b01)
begin
state <= IDLE;
po_cola <= 1'b1;
end
else if(pi_money == 2'b10)
begin
state <= HALF;
po_cola <= 1'b1;
end
else
begin
state <= TWO;
po_cola <= 1'b0;
end
default:
begin
state <= IDLE;
po_cola <= 1'b0;
end
endcase
endmodule
三、状态编码
常用编码方式:
**参考资料:
王金明.《FPGA设计与Verilog HDL实现》.北京:电子工业出版社,2021.