数字IC笔面基础,师傅领进门,修行靠个人——人人心中都有一个状态机(状态机简介及Verilog模板)

写在前面的话

(1)状态机(Finite State Machine, FSM),是用来控制在有限状态之间跳变和时序电路,包含组合逻辑和时序逻辑,用来控制数字IC的流程。

(2)几乎所有的Verilog语法书中都会介绍状态机,而每本语法书中对状态机的描述都各有千秋,每个人对状态机的理解和代码风格也不同。真的算是师傅领进门,修行靠个人。

(3)状态机的基本要素包含状态个数、状态转移条件、输出以及输入。

(4)描述状态机有状态转移图(常考)、状态转移列表以及HDL语言描述(会基础的状态机写法)。

(5)按照代码风格,分为一段式、两段式和三段式(推荐使用)

状态机简介

状态机类型

状态机分两类,米利型(Mealy)和摩尔型(Moore)

米利状态机:输出取决于当前状态和输入。
摩尔状态机:输出只取决于当前状态。

我是这么记的:当前是摩尔时代,输出只与当前状态有关,就是摩尔状态机。

米利状态机框图:
在这里插入图片描述
摩尔状态机框图:
在这里插入图片描述
看输出和谁相关。

一段、两端还是三段?

状态机的Coding Style要求:

(1)易于调整,便于修改状态和状态机风格。
(2)简介紧凑、简单、易懂、便于调试。
(3)能够综合,且综合效率高。

几点规则:

(1)使用localparam 定义状态编码,避免使用`define 和parameter
(2)时序always块中,使用非阻塞赋值<=
(3)组合always块中,使用阻塞赋值=
(4)组合逻辑敏感列表使用always@(*)
(5)case语句不要忘记default:
(6)FPGA设计中编码方式用One-hot(速度更快),采用二进制编码时候,若是顺序执行,可用Gray码(避免亚稳态)。

什么是一段、两段、三段?

一段、两段、三段指的是状态机的写法。有几个always块,就是几段式。

(1)一段式:
状态机所有部分都写到一个always块中,并且这个always块敏感列表只能是时钟clk。
一个always块要兼顾描述状态转移和输入输出。

在这里插入图片描述
(2)两段式:
状态机分为两个always块来写,一个用时序逻辑描述状态转移。
另一个用组合逻辑描述状态转移条件、转移规律以及输出。

在这里插入图片描述
(3)三段式:
状态机分为三个always块来写。
一个用时序逻辑描述状态转移;
一个用组合逻辑描述状态转移条件和转移规律;
一个描述状态输出(可以是时序逻辑,也可以是组合逻辑)

在这里插入图片描述

一段、两段、三段优缺点

一段式优点: 简单,适用于状态数少的状态机。
一段式缺点:
(1)不符合时序逻辑和组合逻辑分开描述的Coding Style;
(2)不利于维护修改,时间久了,自己理解也很困难;
(3)不利于附加约束,在时序分析和面积功耗约束时难优化;
(4)不利于综合软件的布局、布线以及对设计的自动优化。

两段式优点: 时序逻辑和组合逻辑分开,便于分析。
两段式缺点: 由于输出只能采用组合逻辑,容易产生毛刺,造成亚稳态。

三段式优点:
(1)时序逻辑和组合逻辑分开,便于分析。
(2)利于综合软件的分析和优化。
(3)代码简介明了,便于维护。

三段式缺点:
(1)代码结构相较两段式复杂。
(2)采用时序逻辑输出避免了亚稳态,但是增加了触发器的使用。

Verilog模板

推荐使用三段式,这里也列举三段式状态机模板。

// -----------------------------------------------------------------------------
// Copyright (c) 2014-2022 All rights reserved
// -----------------------------------------------------------------------------
// Author : HFUT904  1320343336@qq.com
// File   : fsm.v
// Create : 2022-11-03 11:07:12
// Revise : 2022-11-03 11:07:12
// Editor : HFUT Integrated Circuit Design & Research Center
// Verdion: v1.0
// Description: FSM 三段式模板
// -----------------------------------------------------------------------------


// localparam
module fsm (
	input 		 clk 		,    	// Clock
	input 		 rst_n 		, 		// Asynchronous reset active low
	output	reg  out 	 			// output
	
);

//状态定义
localparam 	IDLE 	= 4'b0001 ;
localparam 	S0  	= 4'b0010 ;
localparam 	S1  	= 4'b0100 ;
localparam 	S2  	= 4'b1000 ;



//定义当前状态和下一状态寄存器

reg 	[3:0]		CS 	;	//当前状态
reg 	[3:0]		NS 	;	//下一状态


//第一段时序逻辑 描述状态转移
always @(posedge clk or negedge rst_n) begin 
	if(~rst_n) begin
		CS <= IDLE;
	end 
	else begin
		CS <= NS;
	end
end



//第二段组合逻辑 描述状态转移条件和规律
always @(*) begin 
	case(CS)
		IDLE : 	 NS = S0   ;
		S0   : 	 NS = S1   ;
		S1   : 	 NS = S2   ;
		S2   : 	 NS = IDLE ;
		default: NS = IDLE ;
	endcase 

end


//第三段组合逻辑或时序逻辑 描述状态输出
always@(posedge  clk or negedge rst_n) begin
	if(~rst_n)
		out <= 1'b0 ;
	else begin
		case (CS)
			IDLE 	: out <= 1'b0 ;
			S0      : out <= 1'b1 ;
			S1 		: out <= 1'b1 ;
			S2 		: out <= 1'b0 ;
			default : out <= 1'b0 ;
		endcase
	end

end

endmodule 

总结

状态机的风格因人而异,每个人都有自己熟悉的状态机风格,状态机的关键在于:
(1)简介明了,将多余的状态进行化简;
(2)代码可综合,使用三段式状态机在debug和综合过程中占据优势;
(3)掌握三段式状态机的写法;
(4)编码方式也会影响状态机的性能,体会独热码和格雷码的优缺点。

最后,状态机相关的知识点都是大差不差,重要的还是多加练习,在项目中体会不同状态机的用处,多学习别人的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值