FPGA-状态机

状态机

状态机FSM(Finite State Machine)又被称为有限状态机,其能在有限步中处理完整个流程。

状态机的分类

状态机的分类根据其输出是否跟,输入有关可以分为摩尔(Moore)型状态机和米勒(Mealy) 型状态机。

moore摩尔类型

其输出跟输入无关,只与状态有关

mealy米勒类型

其输出不仅跟状态有关,与当前输入也有关

moore类型和mealy类型的区别
为什么moore类型会比mealy类型多一个状态

moore类型的输出只取决于状态,

状态机的写法

一段式状态机

一段式状态机把所有的东西,状态的转移、新状态的生成、各状态应做的事情,都写在一个时序逻辑always块中。硬件实现上不利于综合和布局布线,工程方面不利于理解和维护,不建议使用一段式状态机。

二段式状态机

二段式状态机将,状态的转移写成一个时序逻辑always块,新状态的生成和各状态应做的事情写成一个组合逻辑always块,一共分成了两个always块来写,便于理解。但组合逻辑输出易带有毛刺,可以考虑在后面加一个触发器来解决。更建议采用后面的三段式状态机。

三段式状态机

三段式状态机,其将状态的转移(时序逻辑always块)、新状态的生成(组合逻辑always块)、各状态应做的事情(时序逻辑always块)分别用三个always段表达。这里之所以用段而不是块,是因为各状态应该做的事情,可以按事情分always块,不用都写到同一个块中。

状态机实例分析

实例分析部分详见参考链接,你现在需要做的是理解为什么

  1. Mealy 状态机比Moore状态机的状态个数要少
  2. Mealy 状态机比Moore状态机的输出要早一个时钟周期

接下来对一个简单的可乐售卖系统使用状态机的思想进行分析。

可乐机每次只能投入 1 枚 1 元硬币,每瓶可乐卖 3 元钱,即投入 3 个硬币就可以让可乐机出可乐,如果投币不够 3 元想放弃投币需要按复位键,否则之前投入的钱不能退回。

首先分析会有哪些输入、输出信号:

输入信号:

sys_clk_n:既然是同步状态机,那么时钟是肯定少不了的,这里设定时钟是50MHz;

sys_rst_n:一个稳健的系统肯定需要一个复位,这里设定位低电平有效;

money:投币输入,高电平表示投入一元,低电平表示没有投币;

输出信号:

cola:可乐输出,高电平表示掉落一瓶可乐,低电平表示没有可乐掉落;

Moore 状态机(输出和输入无关)
  1. IDLE:首先是系统复位后的默认状态,这个状态下售卖机里没有钱,没有可乐输出;接下来的状态有两种情况:投了1元硬币则跳转状态ONE、没有投硬币则保持IDLE状态;
  2. ONE:这个状态下售卖机里有1元硬币,所以也没有可乐输出;接下来的状态有两种情况:投了1元硬币则跳转状态TWO、没有投硬币则保持ONE状态;
  3. TWO:这个状态下售卖机里有2元硬币,所以也没有可乐输出;接下来的状态有两种情况:投了1元硬币则跳转状态THREE、没有投硬币则保持TWO状态;
  4. THREE:这个状态下售卖机里有3元硬币,但是因为是使用的时序逻辑,所以在这个时钟周期,是不会有可乐输出的,可乐会在状态跳转后(下一个时钟周期输出);接下来的状态有两种情况:投了1元硬币则跳转状态ONE、没有投硬币则跳转状态IDLE状态;而且状态跳转后会输出一瓶可乐(实际上可以理解为THREE状态来自于TWO状态投的一元硬币,也就是这个时钟周期如果输出发生了变化,则输出是和输入有关的了,那就不是Moore 状态机了);
    根据上面列出的这些状态可以绘制出如下的状态转移图(1/0:前面的1代表输入,后面的0代表输出):
Mealy 状态机(输出和输入相关)
  1. IDLE:首先是系统复位后的默认状态,没有可乐输出(分两种情况,投币和不投币);接下来的状态有两种情况:投了1元硬币则跳转状态ONE且没有可乐输出、没有投硬币则保持IDLE状态且没有可乐输出;
  2. ONE:这个状态下售卖机里有1元硬币;接下来的状态有两种情况:投了1元硬币则跳转状态TWO且没有可乐输出、没有投硬币则保持ONE状态且没有可乐输出;
  3. TWO:这个状态下售卖机里有2元硬币;接下来的状态有两种情况:投了1元硬币则跳转状态IDLE且输出可乐(根据和输入相关要求,此时输入一元,加上原来的2元,一共有三元,满足输出可乐的条件)、没有投硬币则保持TWO状态且没有可乐输出;
    根据上面列出的这些状态可以绘制出如下的状态转移图(1/0:前面的1代表输入,后面的0代表输出):
一段式状态机写法
mealy一段式写法
verilog 复制代码
//==================================================================
//--    1段式状态机(Mealy)
//==================================================================
 
//------------<模块及端口声明>----------------------------------------
module FSM_Mealy_1(
	input 		sys_clk		,			//输入系统时钟、50M
	input 		sys_rst_n	,       	//复位信号、低电平有效
	input 		money		,       	//投币输入,高电平有效
										
	output reg	cola                	//可乐输出,高电平有效
);
 
//------------<状态机参数定义>------------------------------------------
//这里使用独热码编码节省组合逻辑资源
//此外还可以使用格雷码 、二进制码
localparam	IDLE  = 3'b001,
			ONE   = 3'b010,
			TWO   = 3'b100;
//------------<reg定义>------------------------------------------------
reg	[2:0]	state;						//定义状态寄存器
//-----------------------------------------------------------------------
//--    1段式状态机(Mealy)
//-----------------------------------------------------------------------
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)begin
		cola <= 1'b0;					//复位初始状态
		state <= IDLE;					//复位初始状态
	end
	else
		case(state)						//根据当前状态、输入进行状态转换判断
										//根据当前状态、输入进行输出
			IDLE:begin				
				if(money)begin			//投入1元
					state <= ONE;		//状态跳转到ONE
					cola <= 1'b0;		//一共1元 ,没有可乐输出
				end	
				else begin				//没有投入
					state <= IDLE;		//保持原有状态
					cola <= 1'b0;		//一共0元 ,没有可乐输出
				end	
			end				
			ONE:begin				
				if(money)begin			//投入1元
					state <= TWO;		//状态跳转到TWO
					cola <= 1'b0;       //一共2元 ,没有可乐输出
				end                     
				else begin              //没有投入
					state <= ONE;       //保持原有状态
					cola <= 1'b0;       //一共1元 ,没有可乐输出
				end
			end
			TWO:begin					
				if(money)begin			//投入1元
					state <= IDLE;      //状态跳转到IDLE(一共3元了,需要输出可乐)
					cola <= 1'b1;       //一共3元 ,输出可乐
				end                     
				else begin              //没有投入
					state <= TWO;       //保持原有状态
					cola <= 1'b0;       //一共2元 ,没有可乐输出
				end
			end 		
			default:begin				//默认状态同初始状态
				if(money)begin
					state <= ONE;
					cola <= 1'b0;
				end
				else begin
					state <= IDLE;
					cola <= 1'b0;
				end	
			end		
		endcase
end
 
endmodule
moore一段式写法
verilog 复制代码
//==================================================================
//--    1段式状态机(Moore)
//==================================================================
 
//------------<模块及端口声明>----------------------------------------
module FSM_Moore_1(
	input 		sys_clk		,		//输入系统时钟、50M
	input 		sys_rst_n	,		//复位信号、低电平有效
	input 		money		,		//投币输入,高电平有效
	
	output reg	cola				//可乐输出,高电平有效
);
 
//------------<状态机参数定义>------------------------------------------
//这里使用独热码编码节省组合逻辑资源
//此外还可以使用格雷码 、二进制码
localparam	IDLE  = 4'b0001,
			ONE   = 4'b0010,
			TWO   = 4'b0100,
			THREE = 4'b1000;
			
//------------<reg定义>-------------------------------------------------
reg	[3:0]	state;					//定义状态寄存器
 
//-----------------------------------------------------------------------
//--    1段式状态机(Moore)
//-----------------------------------------------------------------------
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)begin
		cola <= 1'b0;				//复位初始状态
		state <= IDLE;
	end
	else
		case(state)					//根据当前状态、输入进行状态转换判断
									//根据当前状态进行输出
			IDLE:begin
				cola <= 1'b0;		//初始状态无可乐输出
				if(money)				
					state <= ONE;	//投币1元则状态跳转到ONE
				else
					state <= IDLE;	//否则保持原有状态
			end				
			ONE:begin
				cola <= 1'b0;		//该状态只有1元,无可乐输出
				if(money)
					state <= TWO;	//投币1元则状态跳转到TWO
				else
					state <= ONE;	//否则保持原有状态
			end
			TWO:begin
				cola <= 1'b0;		//该状态只有2元,无可乐输出
				if(money)
					state <= THREE;	//投币1元则状态跳转到THREE
				else
					state <= TWO;	//否则保持原有状态
			end 
			THREE:begin
				cola <= 1'b1;		//该状态有3元,有可乐输出
									//但是时序逻辑输出会落后一个时钟周期
				if(money)
					state <= ONE;	//投币1元则状态跳转到ONE
				else
					state <= IDLE;	//否则状态跳转到IDLE
			end			
			default:begin			//默认状态同IDLE
				cola <= 1'b0;
				if(money)
					state <= ONE;
				else
					state <= IDLE;
			end	
		endcase
end
 
endmodule
一段式moore和mealy的对比

见下图,可以看出moore型状态机在进入状态后先执行该状态的输出,该动作不依赖于当前输入。mealy型状态机,在进入状态后,会根据当前输入来决定要输出什么。

为什么moore类型会比mealy类型多一个状态?

moore类型的输出只取决于状态,其要输出一杯可乐,就必须得进入到投三个硬币there状态。而mealy类型可以在投入两个硬币时,判断当前是否有输入来判断是否输出一杯可乐。

为什么moore类型其最后一个状态,可以进两个。mealy只能进一个

现象见[[#状态机实例分析]]中的图。因为moore类型的输出比mealy类型的输出晚了一个周期,在there阶段,其就可能有新的硬币投进来,需要进入one状态。但在mealy类型的最后一个状态,two有硬币投入,其就输出一瓶可乐,并进入了最开始的准备态。

二段式状态机写法
  • 与一段式状态机不同,可乐的输出不会滞后一个时钟周期,这是因为采用了组合逻辑来描述输出;
三段式状态机写法
Moore型(摩尔型)三段式状态机
verilog 复制代码
//==================================================================
//--    3段式状态机(Moore)
//==================================================================
 
//------------<模块及端口声明>----------------------------------------
module FSM_Moore_3(
	input 		sys_clk		,			//输入系统时钟、50M
	input 		sys_rst_n	,   		//复位信号、低电平有效
	input 		money		,   		//投币输入,高电平有效
										
	output reg	cola            		//可乐输出,高电平有效
);
 
//------------<状态机参数定义>------------------------------------------
localparam	IDLE  = 4'b0001,
			ONE   = 4'b0010,
			TWO   = 4'b0100,
			THREE = 4'b1000;
			
//------------<reg定义>-------------------------------------------------
reg	[3:0]	cur_state;					//定义现态寄存器
reg	[3:0]	next_state;					//定义次态寄存器
 
//-----------------------------------------------------------------------
//--状态机第一段:同步时序描述状态转移
//-----------------------------------------------------------------------
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		cur_state <= IDLE;				//复位初始状态
	else
		cur_state <= next_state;		//次态转移到现态
end
 
//-----------------------------------------------------------------------
//--状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
//-----------------------------------------------------------------------
always@(*)begin
	case(cur_state)						//组合逻辑
										//根据当前状态、输入进行状态转换判断										
		IDLE:begin				
			if(money)					
				next_state = ONE;		//投币1元,则状态转移到ONE
			else 
				next_state = IDLE;		//没有投币,则状态保持	
		end					
		ONE:begin				
			if(money)
				next_state = TWO;		//投币1元,则状态转移到TWO
			else 
				next_state = ONE;		//没有投币,则状态保持
		end
		TWO:begin				
			if(money)
				next_state = THREE;		//投币1元,则状态转移到THREE
			else                        
				next_state = TWO;       //没有投币,则状态保持
		end	
		THREE:begin				
			if(money)
				next_state = ONE;		//投币1元,则状态转移到ONE
			else                        
				next_state = IDLE;      //没有投币,则状态保持
		end
		default:begin					//默认状态同IDLE
			if(money)
				next_state = ONE;
			else 
				next_state = IDLE;	
		end
	endcase
end
 
//-----------------------------------------------------------------------
//--状态机第三段:时序逻辑描述输出
//-----------------------------------------------------------------------
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		cola <= 1'b0;					//复位、初始状态 
	else
		case(next_state)					//根据当前状态进行输出
			IDLE:	cola <= 1'b0;		//无可乐输出			
			ONE:	cola <= 1'b0;		//无可乐输出
			TWO:	cola <= 1'b0;		//无可乐输出
			THREE:	cola <= 1'b1;		//输出可乐
			default:cola <= 1'b0;		//默认无可乐输出
		endcase
end
 
endmodule
Mealy型(米勒型)三段式状态机
verilog 复制代码
//==================================================================
//--    3段式状态机(Mealy)
//==================================================================
 
//------------<模块及端口声明>----------------------------------------
module FSM_Mealy_3(
	input 		sys_clk		,			//输入系统时钟、50M
	input 		sys_rst_n	,   		//复位信号、低电平有效
	input 		money		,   		//投币输入,高电平有效
										
	output reg	cola            		//可乐输出,高电平有效
);
 
//------------<状态机参数定义>------------------------------------------
localparam	IDLE  = 3'b0001,
			ONE   = 3'b0010,
			TWO   = 3'b0100;
			
//------------<reg定义>-------------------------------------------------
reg	[3:0]	cur_state;					//定义现态寄存器
reg	[3:0]	next_state;					//定义次态寄存器
//-----------------------------------------------------------------------
//--状态机第一段:同步时序描述状态转移
//-----------------------------------------------------------------------
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		cur_state <= IDLE;				//复位初始状态
	else
		cur_state <= next_state;		//次态转移到现态
end
//-----------------------------------------------------------------------
//--状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
//-----------------------------------------------------------------------
always@(*)begin
	case(cur_state)						//组合逻辑
										//根据当前状态、输入进行状态转换判断										
		IDLE:begin				
			if(money)					
				next_state = ONE;		//投币1元,则状态转移到ONE
			else 
				next_state = IDLE;		//没有投币,则状态保持	
		end					
		ONE:begin				
			if(money)
				next_state = TWO;		//投币1元,则状态转移到TWO
			else 
				next_state = ONE;		//没有投币,则状态保持
		end
		TWO:begin				
			if(money)
				next_state = IDLE;		//投币1元,则状态转移到IDLE
			else                        
				next_state = TWO;       //没有投币,则状态保持
		end	
		default:begin					//默认状态同IDLE
			if(money)
				next_state = ONE;
			else 
				next_state = IDLE;	
		end
	endcase
end
//-----------------------------------------------------------------------
//--状态机第三段:时序逻辑描述输出
//-----------------------------------------------------------------------
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		cola <= 1'b0;					//复位、初始状态 
	else
		case(cur_state)					//根据当前状态进行输出
			IDLE:	cola <= 1'b0;		//无可乐输出(因为输入不管是0、1都是输出0,所以省略写法)			
			ONE:	cola <= 1'b0;		//无可乐输出(因为输入不管是0、1都是输出0,所以省略写法)	
			TWO:begin					
				if(money)
					cola <= 1'b1;		//如果输入1,则输出可乐
				else
					cola <= 1'b0;		//如果输入0,则无可乐输出
			end
			default:cola <= 1'b0;		//默认无可乐输出
		endcase
end
endmodule

状态机的编码方式

verilog中状态机的三种编码方式的比较(二进制码、独热码、格雷码)_状态机的三种写法和优劣势-CSDN博客

参考链接

【FPGA/IC】状态机FSM的各种写法(一段式、二段式、三段式、摩尔型Moore、米勒型Mealy)_一段式状态机-CSDN博客

相关推荐
GateWorld6 小时前
FPGA设计中的“幽灵信号:一条走线,两种命运——浅析路径延迟导致的逻辑错误
fpga开发
云雾J视界10 小时前
RISC-V开源处理器实战:从Verilog RTL设计到FPGA原型验证
fpga开发·开源·verilog·risc-v·rtl·数字系统
我爱C编程16 小时前
【仿真测试】基于FPGA的完整BPSK通信链路实现,含频偏锁定,帧同步,定时点,Viterbi译码,信道,误码统计
fpga开发·bpsk·帧同步·viterbi译码·频偏锁定·定时点
tiger11918 小时前
FPGA在AI时代的定位?
人工智能·fpga开发
白杨树田20 小时前
【EDA软件】【文件合并烧录操作方法】
fpga开发
FPGA_小田老师20 小时前
FPGA基础知识(八):时序约束深度解析--从基础理论到工程实践
fpga开发·时钟约束·fpga基础·create clock·时序问题
秋风战士1 天前
通信算法之336 :3GPPMixed Mode Turbo Decoder
算法·matlab·fpga开发·信息与通信·基带工程
国科安芯1 天前
国产MCU芯片在船舶压力传感器中的应用探索与实践
网络·单片机·嵌入式硬件·fpga开发·车载系统
学工科的皮皮志^_^1 天前
PCIE学习
经验分享·嵌入式硬件·学习·fpga开发·pcie