当前位置:   article > 正文

有限状态机设计(Verilog HDL)

有限状态机设计

一、有限状态机

- 基本概念
有限状态机(Finite State Machine, FSM)是电路设计的经典方法,通常可以认为是组合逻辑和寄存器逻辑的组合,其中组合逻辑用于状态译码和产生输出信号,寄存器用于存储状态。

- Moore和Mealy型状态机
摩尔型(Moore)状态机: 输出只是当前状态的函数
米利型(Mealy)状态机: 输出是当前状态和当前输入的函数

似乎不太好理解,我们结合状态机模型来看一下

![在这里插入图片描述](https://img-blog.csdnimg.cn/c703df85f31c4ff1995701978f8be5f2.png
可以看出,Moore型状态机输出只与当前状态(现态CS)有关

在这里插入图片描述
图中可以看出,Mealy型状态机相较于Moore型状态机,其输出逻辑多了一个输入端,即上述定义所说的Mealy型状态机输出由当前状态(现态CS)和当前输入决定。

- 两种状态机的区别
由于两者模型的差别,不难看出,Mealy型状态机当输入改变时输出也会立即改变,不依赖时钟,而Moore型状态机输入状态改变时,需要经过时钟同步后输出才会改变,即Moore型状态机比Mealy型状态机输出要多一个时钟周期。实用的状态机一般都设计成同步时序模式。

二、有限状态机的Verilog描述

-状态机的设计中主要包含以下3个对象:

  • 当前状态,或称为现态(Current State, CS)
  • 下一状态,或称为次态(Next State, NS)
  • 输出逻辑(Out Logic, OL)

-Verilog描述方式

  • 三段式描述(CS、NS、OL)
  • 两段式描述(CS+NS、OL)或(CS、NS+OL)
  • 单段式描述(CS+NS+OL)

-举例(可乐机: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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112

三、状态编码

常用编码方式:

  1. 顺序编码 采用顺序的二进制数编码每个状态,例有4个状态:00、01、10、11。优点是占用位数少,缺点是从一个状态转换到相邻状态时,可能有多个比特位同时变化,容易产生毛刺,引发逻辑错误。
  2. 格雷编码 采用格雷码的方式编码每个状态,例有4个状态:00、01、11、10.优点是位数少节约了逻辑单元,因为相邻状态跳转只有一个比特位的改变,也减少了瞬变次数和毛刺产生的可能。
  3. 约翰逊编码 在约翰逊计数器的基础上引出约翰逊码,把输出最高位取反再反馈到最低位,例有6个状态:000、001、011、111、110、100,同样相邻两个状态只有一个比特位不同,但占用位宽多了。
  4. 1位热码编码(独热码) 采用n个触发器编码n个状态,例有4个状态:0001、0010、0100、1000 。独热码占用位数最多,但可以有效节省和简化译码电路,用的也较多。

**参考资料:
王金明.《FPGA设计与Verilog HDL实现》.北京:电子工业出版社,2021.

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/915600
推荐阅读
相关标签
  

闽ICP备14008679号