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博客

相关推荐
仲南音2 天前
Xilinx FPGA——时钟IP核MMCM、PLL
fpga开发
I'm a winner2 天前
基于Xilinx FPGA的LVDS高速串行通信系统(三)--数据训练及握手机制【文末源码】
fpga开发
upper20202 天前
coremark移植坑之-nostartfiles -nostdlib参数
学习·fpga开发·coremark移植·riscv设计
Eloudy3 天前
Vivado 纯命令行构建 FPGA 项目教程
fpga开发
Rambo.xia3 天前
AXI跨时钟域与数据一致性——CDC FIFO深度不够、写后读冒险、多Master仲裁、乱序返回,出了Bug根本查不出来
fpga开发·bug
upper20203 天前
FPGA部署卷积神经网络识别MINST图片
fpga开发·卷积神经网络·minst·minst识别·部署神经网络·神经网络识别图片
你是我的解忧王子3 天前
嵌入式 ADC采样 原始数据分析上层(平均值 波动率 正态分布 线性补偿 系统误差)
fpga开发·数据挖掘·数据分析
9527华安4 天前
FPGA纯verilog代码ISP图像处理培训教程,基于IMX214,提供工程源码+视频教程+FPGA开发板
图像处理·fpga开发·isp·imx214·mipi
千寻xun4 天前
二、实战篇-NVME SSD控制之ZYNQ实现(六)-读写NVME SSD硬盘数据
fpga开发·nvme·nvme ssd
千寻xun4 天前
二、实战篇-NVME SSD控制之ZYNQ实现(三)
fpga开发·nvme ssd·nvme协议