状态机,从细节出发(一段式、两段式、三段式,moore型、mealy型)

article/2025/9/20 0:19:57

目录

前言

一、状态机要素

二、状态机描述方法

1、一段式描述方法

2、两段式描述方法

3、三段式描述方法

三、关系

1、一段式与三段式

2、两段式与三段式

3、三种FSM描述方法比较表

四、状态机的种类

1、Moore型状态机

2、Mealy型状态机

3、注意点

五、举例

1、三种描述风格

一段式描述风格

两段式描述风格

三段式描述风格

说明

2、两种状态机

moore型状态机

mealy型状态机

说明

总结


前言

今天更新一篇状态机的总结,可以说万物基于状态机了,哈哈。本篇博主将会用自己的经历为大家总结一下状态机的设计,同时也会提出一些其他博客都没有讲到的点,希望能给大家分享这些经验。

一、状态机要素

什么是RTL级好的状态机(Finite State Machine,FSM)描述?

1、FSM要安全,稳定性高(最重要,优先级最高),即FSM不会进入死循环,特别是不会进入非预知的状态,即要求FSM的综合实现结果无毛刺等扰动,要求状态机要完备;

2、FSM速度快,满足设计的频率要求;

3、FSM面积小,满足设计的面积要求;

4、FSM设计要清晰易懂,易维护。

二、状态机描述方法

1、一段式描述方法

概述:整个电路用一个进程描述,包含状态转移条件判断、状态输出和状态寄存器转移。

缺点:A、不符合时序和组合逻辑分开描述的代码风格;B、不利于修改、维护;C、不利于附加约束;D、不利于综合器和布局布线器对设计的优化;E、代码冗长。

2、两段式描述方法

概述:从左往右:第二个进程(纯组合逻辑always模块),描述状态转移条件的判断;第一个进程(同步时序always模块),格式化描述次态到现态的转移;一般情况下是组合逻辑输出,如果时序允许,尽量寄存器输出。

缺点:其输出一般使用组合逻辑描述,而组合逻辑易产生毛刺等不稳定因素。

3、三段式描述方法

概述:从左往右:第二个进程和第一个进程同两段式状态机的描述方法一样;第三个进程(同步时序always),格式化描述状态的寄存器输出。这里的第三个进程是使用next_state做判断的,所以不会消耗多余的时钟周期。

优点:A、FSM做到了同步寄存器输出;B、消除了组合逻辑输出的不稳定与毛刺的隐患;C、更利于时序路径分组;D、在FPGA/CPLD等可编程逻辑器件上的综合与布局布线效果更佳。

三、关系

1、一段式与三段式

一段式建模:必须考虑现态在何种状态转移条件下会进入哪些次态,然后在每个现态的case分支下分别描述每个次态的输出。

三段式建模:只需指定case敏感列表为次态寄存器,然后在每个次态的case分支中描述该状态的输出即可(根本不用考虑状态转移条件)。

2、两段式与三段式

两段式建模:状态寄存器分割了两部分组合逻辑(状态转移条件组合逻辑)(输出组合逻辑),电路时序路径较短,可以获得更高的性能。

三段式建模:从输入到寄存器的输出路径上,要经过两部分组合逻辑(状态转移条件组合逻辑)(输出组合逻辑),从时序上,这两部分组合逻辑完全可以看为一体,因此这条路径的组合逻辑就比较复杂,该路径的时序相对紧张。但其优点也很突出:可以改善输出的时序条件;还能避免组合电路的毛刺,因此更为推荐这种写法。

3、三种FSM描述方法比较表

比较项目一段式两段式三段式
推荐等级不推荐推荐最优推荐
代码简洁程度冗长最简洁简洁
always模块个数123
是否有利于时序约束不利于利于利于
是否有组合逻辑输出可以无组合逻辑输出多数情况下有组合逻辑输出无组合逻辑输出
是否有利于综合与布局布线不利于利于利于
代码的可靠性与可维护性最高
代码风格的规范性低,任意度较大格式化,规范格式化,规范

四、状态机的种类

1、Moore型状态机

状态机的输出至于当前的状态有关,如下图所示。

2、Mealy型状态机

状态机的输出不仅与当前的状态有关,还与当前的输入有关,如下图所示。

3、注意点

以上说明moore型状态机和mealy型状态机的区别所用的是两段式状态机,也就是状态输出都是采用组合逻辑输出。如果状态输出采用寄存器输出,则需要在输出端加一个寄存器,这样会多消耗一个时钟周期,但是功能不会发生错误。

三段式状态机中为了不消耗一个额外的时钟周期,采用next_state作为判断条件,但是如果采用mealy型状态机,则此时的输入将会和next_state一起作为判断条件来判断输出,这样就会发生功能错误,如下图所示。

正确的做法是将输出_temp与当前输入再用组合逻辑输出,如下图所示,这样功能不会发生错误。但是其实这种做法是多此一举的,因为这样做输出还是组合逻辑,没有采用寄存器输出,并且这条通路的时序相对紧张。博主这样的画法只是想说明保证三段式mealy状态机功能正确的做法。

五、举例

本节中,博主选择了两道HDLbits中的题目,来为大家更好的描述三种状态机写法以及moore、mealy状态机之间的差异。

1、三种描述风格

状态转移图如上图所示,下面是一段式、两段式、三段式的描述风格。

一段式描述风格

module top_module(input clk,input areset,    // Asynchronous reset to state Binput in,output reg out);//  parameter A=1'b0, B=1'b1; reg state;always@(posedge clk or posedge areset)beginif(areset)beginstate <= B;out <= 1'b1;endelse begincase(state)B:beginif(in == 1'b1)beginstate <= B;out <= 1'b1;endelse beginstate <= A;out <= 1'b0;endendA:beginif(in == 1'b1)beginstate <= A;out <= 1'b0;endelse beginstate <= B;out <= 1'b1;endenddefault:beginstate <= B;out <= 1'b1;endendcaseendendendmodule

两段式描述风格

输出写在下一状态转移组合逻辑中。

module top_module(input clk,input areset,    // Asynchronous reset to state Binput in,output reg out);//  parameter A=1'b0, B=1'b1; reg current_state, next_state;always@(posedge clk or posedge areset)beginif(areset)begincurrent_state <= B;endelse begincurrent_state <= next_state;endendalways@(*)begincase(current_state)B:beginif(in == 1'b1)beginnext_state = B;endelse beginnext_state = A;endout = 1'b1;endA:beginout = 1'b0;if(in == 1'b1)beginnext_state = A;endelse beginnext_state = B;endout = 1'b0;endendcaseendendmodule

输出与下一状态转移组合逻辑分开。 

module top_module(input clk,input areset,    // Asynchronous reset to state Binput in,output reg out);//  parameter A=1'b0, B=1'b1; reg current_state, next_state;always@(posedge clk or posedge areset)beginif(areset)begincurrent_state <= B;endelse begincurrent_state <= next_state;endendalways@(*)begincase(current_state)B:beginif(in == 1'b1)beginnext_state = B;endelse beginnext_state = A;endendA:beginif(in == 1'b1)beginnext_state = A;endelse beginnext_state = B;endendendcaseendalways@(*)begin if(current_state == B)beginout = 1'b1;endelse beginout = 1'b0;endend/*//second way//assign out = (current_state == B);*//*//third wayalways@(*)begincase(current_state)B:beginout = 1'b1;endA:beginout = 1'b0;endendcaseend*/endmodule

三段式描述风格

module top_module(input clk,input areset,    // Asynchronous reset to state Binput in,output reg out);//  parameter A=1'b0, B=1'b1; reg current_state, next_state;always@(posedge clk or posedge areset)beginif(areset)begincurrent_state <= B;endelse begincurrent_state <= next_state;endendalways@(*)begincase(current_state)B:beginif(in == 1'b1)beginnext_state = B;endelse beginnext_state = A;endendA:beginif(in == 1'b1)beginnext_state = A;endelse beginnext_state = B;endendendcaseendalways@(posedge clk or posedge areset)beginif(areset)beginout <= 1'b1;endelse if(next_state == B)beginout <= 1'b1;endelse beginout <= 1'b0;endendendmodule

说明

一段式状态机描述中没有区分current_state和next_state,将所有的状态转移和输出逻辑写在一个always时序模块中,代码相对冗长,不利于分析电路结构。

两段式状态机描述中采用组合逻辑描述输出,其中两种大的写法,第一种是将输出逻辑融合到下一状态转移组合逻辑中,第二种是将输出和下一状态转移组合逻辑分开。大家要注意,这两种写法映射到电路中没有任何区别。有一点困扰的地方是大家通常将第二种写法叫做三段式状态机的第三段。从广义上来讲,这种叫法没有错,因为毕竟这三段分割明显,每一段做什么事情都很好理解,但是更细化,从电路结构来讲,这种写法只能称为两段式状态机,next_state到current_state采用时序逻辑,状态转移和输出采用组合逻辑,这是两段式状态机的标志。

三段式状态机描述中采用时序逻辑描述输出,为了节省一拍,采用next_state作为判断条件。

特别注意,这里只有A和B两个状态,只需要1bit,所以博主两段式和三段式的case中省略了default,这里建议不论条件是否列全,都应该加上default,博主没有加default的做法不值得提倡。

2、两种状态机

检测“101”序列,题目要求重叠检测(比如对于序列“101010”,重叠检测会输出两次高电平,不重叠检测会输出一次高电平)。

moore型状态机

状态转移图如下。

module top_module (input clk,input aresetn,    // Asynchronous active-low resetinput x,output reg z ); parameter S0 = 2'd0, S1 = 2'd1, S2 = 2'd2, S3 = 2'd3;reg [1:0]	current_state;reg [1:0]	next_state;always@(posedge clk or negedge aresetn)beginif(aresetn == 1'b0)begincurrent_state <= S0;endelse begincurrent_state <= next_state;endendalways@(*)begincase(current_state)S0:beginnext_state = x ? S1 : S0;endS1:beginnext_state = x ? S1 : S2;endS2:beginnext_state = x ? S3 : S0;endS3:beginnext_state = x ? S1 : S2;enddefault:beginnext_state = S0;endendcaseendalways@(posedge clk or negedge aresetn)beginif(aresetn == 1'b0)beginz <= 1'b0;endelse beginif(next_state == S3)beginz <= 1'b1;endelse beginz <= 1'b0;endendendendmodule

mealy型状态机

状态转移图如下。

module top_module (input clk,input aresetn,    // Asynchronous active-low resetinput x,output z ); parameter S0 = 2'd0, S1 = 2'd1, S2 = 2'd2;reg [1:0]	current_state;reg [1:0]	next_state;always@(posedge clk or negedge aresetn)beginif(aresetn == 1'b0)begincurrent_state <= S0;endelse begincurrent_state <= next_state;endendalways@(*)begincase(current_state)S0:beginnext_state = x ? S1 : S0;endS1:beginnext_state = x ? S1 : S2;endS2:beginnext_state = x ? S1 : S0;enddefault:beginnext_state = S0;endendcaseendassign z = ((current_state == S2) && (x == 1'b1)) ? 1'b1 : 1'b0;/*//second wayalways@(*)begincase(current_state)S0:beginz = 1'b0;endS1:beginz = 1'b0;endS2:beginz = x;endendcaseend*/endmodule
module top_module (input clk,input aresetn,    // Asynchronous active-low resetinput x,output z ); parameter S0 = 2'd0, S1 = 2'd1, S2 = 2'd2;reg [1:0]	current_state;reg [1:0]	next_state;reg			z_temp;always@(posedge clk or negedge aresetn)beginif(aresetn == 1'b0)begincurrent_state <= S0;endelse begincurrent_state <= next_state;endendalways@(*)begincase(current_state)S0:beginnext_state = x ? S1 : S0;endS1:beginnext_state = x ? S1 : S2;endS2:beginnext_state = x ? S1 : S0;enddefault:beginnext_state = S0;endendcaseendalways@(posedge clk or negedge aresetn)beginif(aresetn == 1'b0)beginz_temp <= 1'b0;endelse beginif(next_state == S2)beginz_temp <= 1'b1;endelse beginz_temp <= 1'b0;endendendassign z = z_temp == 1'b1 && x == 1'b1;endmodule

上面两组代码就是mealy型状态机分别使用“两段式状态机”和“三段式状态机”完成的写法,这里加了引号,因为不是标准的两段式和三段式,我们最常用的两段式和三段式主要都是针对moore型状态机所说。

说明

我们从上面的状态转移图可以看出,moore型状态机要比mealy型状态机多一个状态,也就意味着mealy型状态机要比moore型状态机快一个周期,因为mealy型状态机使用当前输入和当前状态共同判断,moore型状态机不需要当前输入。

总结

今天的这篇博客,基于博主自己对状态机的理解所写,包括博主曾经踩过的一些坑。博客中对三种状态机写法,两类状态机都有一些直观的描述,其中三种状态机的写法那部分参考了邸志雄老师在慕课的课程《芯动力——硬件加速设计方法》,感兴趣的同学可以去慕课观看,希望能给大家带来帮助。


http://chatgpt.dhexx.cn/article/TACs3h4J.shtml

相关文章

时间复杂度与空间复杂度分析(递归与非递归比较)

时间复杂度&#xff1a; 一般情况下&#xff0c;算法中基本操作重复的次数就是问题规模n的某个函数f&#xff08;n&#xff09;&#xff0c;进而分析f&#xff08;n&#xff09;随n的变化情况并确定T&#xff08;n&#xff09;的数量级。这里用‘o’来表示数量级&#xff0c;给…

数据结构:时间复杂度空间复杂度(递归)

转载文章 时间复杂度&#xff1a; 一般情况下&#xff0c;算法中基本操作重复执行的次数是问题规模n的某个函数f(n)&#xff0c;进而分析f(n)随n的变化情况并确定T(n)的数量级。这里用"O"来表示数量级&#xff0c;给出算法的时间复杂度。 T(n)O(f(n)); 它表示随着问…

递归理解以及时间复杂度计算

一.复杂度分析&#xff1a; 可以理解为递归的深度就是空间复杂度&#xff0c;时间复杂度就是O(T*depth),其中&#xff34;是每个递归函数的时间复杂度&#xff0c;depth是递归深度&#xff0e; #空间复杂度O(1) def sum1_(n):res 0for i in range(n1):resireturn res#递归 空…

递归的时间与空间复杂度

一、 递归的时间复杂度 递归算法的时间复杂度 递归次数 \times 每次递归的时间复杂度。 递归次数&#xff1a;可以通过画递归树&#xff0c;数递归树的节点数&#xff0c;得到递归次数。 二、递归的空间复杂度 递归算法的空间复杂度 递归深度 \times 每次入栈的空间…

【转】Tomcat相关面试题,看这一篇就够了!

转自公众号&#xff1a;Java思维导图 Tomcat相关的面试题出场的几率并不高&#xff0c;正是因为如此&#xff0c;很多人忽略了对Tomcat相关技能的掌握。下面这篇文章整理了Tocmat相关的系统架构&#xff0c;介绍了Server、Service、Connector、Container之间的关系&#xff0c…

10道Mybatis经典面试题,赶快上车吧!⚡⚡⚡⚡

1.Mybatis中#{}和${}的区别是什么&#xff1f; 1.1 #{}方式能够很大程度防止sql注入&#xff08;安全&#xff09;&#xff1b; ${}方式无法防止Sql注入。 1.2 在JDBC能使用占位符的地方&#xff0c;最好优先使用#{}&#xff1b; 在JDBC不支持使用占位符的地方&#xff0c;就…

mybatis面试题 一

一、MyBatis工作原理&#xff1f; 1、 创建SqlSessionFactory 2、 通过SqlSessionFactory创建SqlSession 3、 通过sqlsession执行数据库操作 4、 调用session.commit()提交事务 5、 调用session.close()关闭会话 1&#xff09;读取 MyBatis 配置文件&#xff1a;mybatis-c…

Java面试题Tomcat的优化经验

来源&#xff1a;传智论坛 Tomcat作为Web服务器&#xff0c;它的处理性能直接关系到用户体验&#xff0c;下面是几种常见的优化措施&#xff1a; 一、掉对web.xml的监视&#xff0c;把jsp提前编辑成Servlet。有富余物理内存的情况&#xff0c;加大tomcat使用的jvm的内存 二、服…

Tomcat相关面试题,看这篇就够了!保证能让面试官颤抖!

Tomcat相关的面试题出场的几率并不高&#xff0c;正式因为如此&#xff0c;很多人忽略了对Tomcat相关技能的掌握&#xff0c;下面这一篇文章最早发布在知识星球&#xff0c;整理了Tomcat相关的系统架构&#xff0c;介绍了Server、Service、Connector、Container之间的关系&…

【Tomcat专题】简单认识一下Tomcat总体架构

文章目录 什么是Tomcat&#xff1f;Tomcat的主要工作Tomcat总体架构连接器容器 请求定位流程 什么是Tomcat&#xff1f; 在Tomcat官方网站上是这样介绍的。 The Apache Tomcat software is an open source implementation of the Jakarta Servlet, Jakarta Server Pages, Jaka…

四张图带你了解Tomcat系统架构--让面试官颤抖的Tomcat回答系列!

俗话说&#xff0c;站在巨人的肩膀上看世界&#xff0c;一般学习的时候也是先总览一下整体&#xff0c;然后逐个部分个个击破&#xff0c;最后形成思路&#xff0c;了解具体细节&#xff0c;Tomcat的结构很复杂&#xff0c;但是 Tomcat 非常的模块化&#xff0c;找到了 Tomcat最…

Tomcat常见面试题

1、tomcat有哪些组件&#xff1f; 2、tomcat有哪些Connector&#xff1f; http ajp 3、tomcat的Valve的作用是什么&#xff1f; 给每一个虚拟主机定义访问日志 4、servlet的生命周期&#xff1f; Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过…

【金三银四】Tomcat面试题(2021最新版)

目录 前言 1、Tomcat的缺省端口是多少&#xff0c;怎么修改&#xff1f; 2、tomcat 有哪几种Connector 运行模式(优化)&#xff1f; 3、Tomcat有几种部署方式&#xff1f; 4、tomcat容器是如何创建servlet类实例&#xff1f;用到了什么原理&#xff1f; 5.tomcat 如何优化…

Tomcat面试题(2020最新版)

文章目录 Tomcat是什么&#xff1f;Tomcat的缺省端口是多少&#xff0c;怎么修改tomcat 有哪几种Connector 运行模式(优化)&#xff1f;Tomcat有几种部署方式&#xff1f;tomcat容器是如何创建servlet类实例&#xff1f;用到了什么原理&#xff1f;Tomcat工作模式Tomcat顶层架构…

「面试必背」Tomcat面试题(收藏)

「面试必背」Tomcat面试题&#xff08;建议收藏&#xff09; 2022-04-27 16:31java柚子茶 前言 在工作中&#xff0c;作为 Java 开发的程序员&#xff0c;Tomcat 服务器是大家常用的&#xff0c;也是很多公司现在正在用的。但是&#xff0c;在系统并发量比较大的情况下&…

Tomcat面试题(总结最全面的面试题)

Tomcat是什么&#xff1f; Tomcat 服务器Apache软件基金会项目中的一个核心项目&#xff0c;是一个免费的开放源代码的Web 应用服务器&#xff0c;属于轻量级应用服务器&#xff0c;在中小型系统和并发访问用户不是很多的场合下被普遍使用&#xff0c;是开发和调试JSP 程序的首…

【面试】Tomcat面试题

文章目录 Tomcat是什么&#xff1f;Tomcat的缺省端口是多少&#xff0c;怎么修改怎么在Linux上安装Tomcat怎么在Linux部署项目Tomcat的目录结构类似Tomcat&#xff0c;发布jsp运行的web服务器还有那些&#xff1a;tomcat 如何优化&#xff1f;tomcat 有哪几种Connector 运行模式…

Linux面试问题---常用命令

Linux面试问题---常用命令 1、cd命令 用于切换当前目录&#xff0c;参数是要切换到的目录的路径。 Cd /root/Documents #切换到/root/Documents目录Cd ./path 切换到当前目录下的path目录 Cd ../path 切换到上层目录下的path目录 2、ls命令 查看文件与目录的命令 3、grep…

Linux命令面试突击

Linux 命令常见面试题总结。 其它面试知识点突击整理&#xff1a; 序号文章1Java基础面试突击2JVM面试突击3设计模式面试突击4并发编程面试突击5消息队列Kafka面试突击6Redis面试突击7计算机网络面试突击8Spring面试突击9Dubbo面试突击10MyBatis面试突击11操作系统面试突击12…

Linux面试题(2020最新版)

Java面试总结&#xff08;2021优化版&#xff09;已发布在个人微信公众号【技术人成长之路】&#xff0c;优化版首先修正了读者反馈的部分答案存在的错误&#xff0c;同时根据最新面试总结&#xff0c;删除了低频问题&#xff0c;添加了一些常见面试题&#xff0c;对文章进行了…