Verilog基础语法——状态机(类型、写法、状态编码方式)

Verilog基础语法——状态机(类型、写法、状态编码方式)

  • 写在前面
  • 一、状态机类型
  • 二、状态机写法
    • 2.1 一段式
    • 2.2 两段式
    • 2.3 三段式
  • 三、状态机状态编码方式
  • 写在后面

写在前面

  在FPGA设计过程,经常会设计状态机用于控制整个硬件电路的工作进程,也称为有限状态机(Finite State Machine,FSM)。本文将对状态机的类型、写法以及状态编码方式进行介绍。

一、状态机类型

  状态机根据类型可以分为Moore型状态机和Mealy型状态机,其中Moore型状态机的输出只与当前状态有关,如下图所示。其中包含三个部分:(1)用于产生次态的组合逻辑;(2)用于寄存器现态的状态寄存器;(3)用于产生输出的组合逻辑;

在这里插入图片描述

  而Mealy型状态机不仅与当前状态有关,且与当前时刻的输入有关,如下图所示。Mealy型状态机产生次态的组合逻辑和状态寄存器与Moore型状态机是一致的,而不同的是,Mealy型状态机的输出不仅与现态有关,而且与当前时刻的输入也相关

在这里插入图片描述
  进一步地,可以通过状态转换图来详细分析两者之间的不同之处。以”101“的非重叠序列检测为例,Moore型状态机的状态转换图如下图所示。

Tip:非重叠序列检测是指检测到的多组“101”序列之间是非重叠、独立的,比如序列110101进行“101”的非重叠序列检测,输出检测结果为000100。而重叠序列检测值检测到的多组“101”序列之间可以重叠,即第一组“101”和第二组“101”之间可以有重叠部分,第一组“101”序列的最后一个1是第二组“101”序列的第一个1,比如序列110101进行“101”的重叠序列检测,输出检测结果为000101。

在这里插入图片描述

  而Mealy型状态机的状态转换图如下图所示。

在这里插入图片描述
  在这里可以看出,同样情况下Moore型状态机要比Mealy型状态机多一个状态,也就是说在实际设计中Moore型状态机会比Mealy型状态机多一个时钟周期。总结来说,Moore型状态机的相比于Mealy型状态机会慢一拍,但是时序会更好,而Mealy状态机相比于Moore状态机快一拍,速度会更快,但时序会差一些。在设计中一般考虑使用Moore型状态机。

二、状态机写法

  对于状态机的写法,可以分为一段式、两段式和三段式,不同的写法将在下面三个小节介绍。

2.1 一段式

  一段式状态机中只有一个always块,在该always块中同时描述状态寄存、状态转移条件的判断与数据输出。对于大规模电路设计,状态机控制的数据输出有多个,该写法会导致状态机代码复杂且杂乱,后续开发过程难以修改和维护。以”101“序列的Moore型状态机为例,其一段式状态机写法如下:

module check1(input    wire    clk       ,input    wire    rst_n     ,input    wire    din       ,output   reg     check_pass
);localparam S0 = 4'b0001; // 初始化状态
localparam S1 = 4'b0010; // 计数状态
localparam S2 = 4'b0100; // 计算状态
localparam S3 = 4'b1000; // 结束状态reg             din_r;
reg    [3:0]    state;// 输入数据打拍
always @(posedge clk) din_r <= din;//-------- 一段式状态机 --------//
always @(posedge clk or negedge rst_n) beginif(!rst_n) beginstate <= S0;check_pass <= 1'b0;endelse begincase(state)S0 :beginif(din_r == 1'b1) beginstate <= S1;check_pass <= 1'b0;endelse beginstate <= S0;check_pass <= 1'b0;endendS1 : beginif(din_r == 1'b0) beginstate <= S2;check_pass <= 1'b0;endelse beginstate <= S1;check_pass <= 1'b0;endendS2 : beginif(din_r == 1'b1) beginstate <= S3;check_pass <= 1'b0;endelse beginstate <= S2;check_pass <= 1'b0;endendS3 : beginif(din_r == 1'b1) beginstate <= S1;check_pass <= 1'b1;endelse beginstate <= S0;check_pass <= 1'b1;endenddefault: beginstate <= S0;check_pass <= 1'b0;endendcaseend 
endendmodule

2.2 两段式

  一段式状态机写法中代码杂乱,不利于后续修改和维护,两段式状态机则克服了该缺点,将三个部分(状态转移寄存器、状态转移条件判断、输出)分成三个always块进行描述,同时输出使用组合逻辑进行赋值,而组合逻辑赋值会导致毛刺等现象,增加电路的不稳定性。以”101“序列的Moore型状态机为例,其两段式状态机写法如下:

module check2(input    wire    clk       ,input    wire    rst_n     ,input    wire    din       ,output   reg     check_pass
);localparam S0 = 4'b0001; // 初始化状态
localparam S1 = 4'b0010; // 计数状态
localparam S2 = 4'b0100; // 计算状态
localparam S3 = 4'b1000; // 结束状态reg             din_r;
reg    [3:0]    curr_state;
reg    [3:0]    next_state;// 输入数据打拍
always @(posedge clk) din_r <= din;//-------- 两段式状态机 --------//
// 第一段(时序逻辑,用于描述状态寄存器)
always @(posedge clk or negedge rst_n) beginif(!rst_n)curr_state <= S0; //初始化状态elsecurr_state <= next_state;
end// 第二段(组合逻辑,用于状态转移条件判断与输出)
always @(*) beginnext_state = S0;case(curr_state)S0 :beginif(din_r == 1'b1) beginnext_state = S1;check_pass = 1'b0;endelse beginnext_state = S0;check_pass = 1'b0;endendS1 :beginif(din_r == 1'b0) beginnext_state = S2;check_pass = 1'b0;endelse beginnext_state = S1;check_pass = 1'b0;endendS2 :beginif(din_r == 1'b1) beginnext_state = S3;check_pass = 1'b0;endelse beginnext_state = S2;check_pass = 1'b0;endendS3 :begincheck_pass = 1'b1;if(din_r == 1'b1) beginnext_state = S1;endelse beginnext_state = S0;endenddefault:beginnext_state = S0;check_pass = 1'b0;endendcase
endendmodule

  有一点值得注意的是,在两段式状态机中数据输出check_pass与次态next_state采用组合逻辑进行控制,一定要补全if-else中else情况下的数值,否则在电路综合时会产生Latch。

2.3 三段式

  三段式状态机在两段式状态机的基础上,将控制输出数据赋值的组合逻辑改成时序逻辑,消除了组合逻辑输出中存在毛刺

module check3(input    wire    clk       ,input    wire    rst_n     ,input    wire    din       ,output   reg     check_pass
);localparam S0 = 4'b0001; // 初始化状态
localparam S1 = 4'b0010; // 计数状态
localparam S2 = 4'b0100; // 计算状态
localparam S3 = 4'b1000; // 结束状态reg             din_r;
reg    [3:0]    curr_state;
reg    [3:0]    next_state;// 输入数据打拍
always @(posedge clk) din_r <= din;//-------- 三段式状态机 --------//
// 第一段(时序逻辑,用于描述状态寄存器)
always @(posedge clk or negedge rst_n) beginif(!rst_n)curr_state <= S0; //初始化状态elsecurr_state <= next_state;
end// 第二段(组合逻辑,用于状态转移条件判断)
always @(*) beginnext_state = S0;case(curr_state)S0 :beginif(din_r == 1'b1)next_state = S1;elsenext_state = S0;endS1 :beginif(din_r == 1'b0)next_state = S2;elsenext_state = S1;endS2 :beginif(din_r == 1'b1)next_state = S3;elsenext_state = S2;endS3 :beginif(din_r == 1'b1)next_state = S1;elsenext_state = S0;enddefault:next_state = S0;endcase
end// 第三段(时序逻辑,用于描述输出)
always @(posedge clk or negedge rst_n) beginif(!rst_n)check_pass <= 1'b0;elsecase(curr_state)S0 : check_pass <= 1'b0;S1 : check_pass <= 1'b0;S2 : check_pass <= 1'b0;S3 : check_pass <= 1'b1;default: check_pass <= 1'b0;endcase
endendmodule

Tip:这里需要注意的是,两段式状态机于三段式状态机的区别之处并不是状态机有几个always块,而是输出由组合逻辑还是时序逻辑控制。两段式状态机的输出由组合逻辑控制,容易产生毛刺,三段式状态机的输出由时序逻辑控制,避免了两段式状态机输出存在毛刺的问题。

  总结来说,一段式、两段式、三段式状态机的特点与优缺点如下表所示:

一段式写法两段式写法三段式写法
特点一个always块(时序逻辑),同时描述状态寄存器、状态转移条件判断与数据输出两个always块,第一个always块(时序逻辑)描述状态寄存器,第二个always块(组合逻辑)描述状态转移条件判断与数据输出三个always块,第一个always块(时序逻辑)描述状态寄存器,第二个always块(组合逻辑)描述状态转移条件判断,第三个always块(时序逻辑)描述数据输出
优点结构简单,易于实现代码清晰,易于修改和调试便于修改和维护,输出输出不存在毛刺
缺点不利于修改和维护数据输出存在毛刺

问题1:一段式、两段式和三段式状态机写法不同,在RTL电路与时序上具体差异是什么样的?

(1)RTL电路
  下图分别为一段式、两段式和三段式状态机的RTL电路,由于一段式状态机中输出check_pass均由时序逻辑控制,区别在于将写在一个always块中的三个部分(状态转移寄存器、状态转移条件判断、输出)分成三个always块进行描述,所以两者的RTL电路一致。而两段式状态机中输出check_pass采用组合逻辑进行控制,所以与两段式、三段式状态机的RTL电路是不一致的。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
(2)时序波形

  为了对比三种不同写法状态机的时序差异,编写测试文件TestBench如下:

`timescale 1ns/1ns
module tb_check();
reg clk,rst_n,din;
wire check_pass1,check_pass2,check_pass3;initial beginclk = 1'b1;rst_n = 1'b0;din = 1'b0;#100rst_n = 1'b1;#20din = 1'b1;#20din = 1'b1;#20din = 1'b0;#20din = 1'b1;#20din = 1'b1;#20din = 1'b0;#20din = 1'b1;
endalways #10 clk = ~clk;check1 check1_inst(.clk       (clk        ),.rst_n     (rst_n      ),.din       (din        ),.check_pass(check_pass1)
);check2 check2_inst(.clk       (clk        ),.rst_n     (rst_n      ),.din       (din        ),.check_pass(check_pass2)
);check3 check3_inst(.clk       (clk        ),.rst_n     (rst_n      ),.din       (din        ),.check_pass(check_pass3)
);endmodule

  仿真波形如下图所示,有图可知,两段式状态机输出要比一段式状态机和三段式状态机快一拍

在这里插入图片描述

三、状态机状态编码方式

  常用的状态机状态编码方式有二进制码(Binary)、格雷码(Gray)、独热码(One-Hot)等,不同的编码方式适用于不同的应用场景。以8个状态的状态机为例,介绍不同编码方式的优缺点,如下表所示。

二进制码(Binary)格雷码(Gray)独热码(One-Hot)
8个状态3’b000
3’b001
3’b010
3’b011
3’b100
3’b101
3’b110
3’b111
3’b000
3’b001
3’b011
3’b010
3’b110
3’b111
3’b101
3’b100
8’b00000001
8’b00000010
8’b00000100
8’b00001000
8’b00010000
8’b00100000
8’b01000000
8’b10000000
优点使用寄存器较少,编码方式简单使用寄存器较少,且出现毛刺的可能性低编码方式简单,容易增加状态
缺点每次状态变化涉及多个比特位反转,容易出现毛刺,且消耗较多LUT编码方式复杂,状态跳转需要较多组合逻辑使用寄存器多
适用场景小型设计(状态数小于4)大型状态机(状态个数大于24)状态数在4~24之间,适用于判断条件复杂但是状态少的情况下

  对于上述表述,在学习的过程中仍然存在下面几个问题:

问题1:如果状态机的状态个数不为 2 n 2^n 2n,或者状态机的状态跳转不仅仅是按照相邻的状态跳转(如下图红色箭头),那么格雷码相对于二进制码是否存在优势?

在这里插入图片描述

回答这个问题没有比较明确的答案,后续更新… …

问题2:独热码的状态不是用了更多的位宽,又是如何做到节省资源的?

回答:比如一个8个状态的状态机,独热码编码方式需要8位宽,在使用到状态时,无需将8位数值进行比较,只需比较单个位宽即可,如下:

assign dout = curr_state[0] ? 1'b1 : 1'b0;
assign check_pass = curr_state[3] ? 1'b1 : 1'b0;

  而如果使用二进制编码或者格雷编码,需要3位宽表示8个状态,在使用到状态时,需要将3位数值全部进行比较,如下:

assign dout = (curr_state == S0) ? 1'b1 : 1'b0;
assign check_pass = (curr_state == S3) ? 1'b1 : 1'b0;

写在后面

  在本文中我们学习了FPGA设计中状态机的一些基础知识,包括状态机类型、状态机的写法与状态机的编码方式。其中,状态机的类型包括Moore型和Mealy型两种,Moore型状态机输出仅与当前状态有关,与当前输入无关,Mealy型状态机输出不仅与当前状态有关,而且与当前输入有关。状态机的写法包括一段式、两段式和三段式写法,三种状态机中,一段式状态机不符合时序逻辑和组合逻辑分开描述的代码风格,代码冗长,不利于修改和维护;两段式状态机中,输出一般使用组合逻辑描述,而组合逻辑容易产生毛刺;三段式状态机既解决了一段式状态机中代码冗长与代码风格混乱、不利于修改维护的问题,也解决了两段式状态机中组合逻辑输出产生毛刺的问题,是目前设计中常用的状态机设计方法。状态机常用的编码方式包括二进制码格雷码独热码三种,三种不同编码方式适用于不同的场景下,在实际设计过程中应根据状态的个数与设计的复杂度等多方面综合考虑。

  本文到此结束,欢迎评论区交流探讨。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/5229.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Vue3的Axios异步请求

基于Vue3的Axios异步请求 1. Axios安装与应用2. Axios网络请求封装3. axios网络请求跨域前端解决方案server.proxy 1. Axios安装与应用 Axios是一个基于promise的网络请求库&#xff0c;Axios.js.中文文档&#xff1a;https://axios.js.cn/ 安装&#xff1a;npm install --sa…

有没有一种可能性,你不投递简历,让HR主动联系你

你是否觉得自己得主动给某个公司投递了简历,他们才会联系你,亦或者是自己得主动在招聘APP上联系那个BOSS,他才会反过来跟你说话,又或者是你千方百计的跟他打招呼了,还是没有回应,这一节有可能让你明白,有时候是可以,你不主动,他也会主动联系你的。 目录 1 简历是如何…

QT:小项目:登录界面 (下一个连接数据库)

一、效果图 登录后&#xff1a; 二、项目工程结构 三、登录界面UI设计 四主界面 四、源码设计 login.h #ifndef LOGIN_H #define LOGIN_H#include <QDialog>namespace Ui { class login; }class login : public QDialog {Q_OBJECTpublic:explicit login(QWidge…

Spark原理之Cache Table的工作原理及实现自动缓存重复表的思考

CACHE TABLE的能力 使用此语法&#xff0c;可以由用户自定义要缓存的结果集&#xff0c;实际上就是一个临时表&#xff0c;不过数据存储在Spark集群内部&#xff0c;由Application所分配的executors管理。 一旦定义了一个缓存表&#xff0c;就可以在SQL脚本中随处引用这个表名…

Ansible自动化运维工具主机清单配置

作者主页&#xff1a;点击&#xff01; Ansible专栏&#xff1a;点击&#xff01; 创作时间&#xff1a;2024年4月24日12点21分 Ansible主机清单文件用于定义要管理的主机及其相关信息。它是Ansible的核心配置文件之一&#xff0c;用于Ansible识别目标主机并与其建立连接。 …

小猫咪邮件在线发送系统源码v1.1,支持添加附件

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 小猫咪邮件在线发送系统源码v1.1&#xff0c;支持添加附件 一款免登录发送邮件&#xff0c;支持发送附件&#xff0c;后台可添加邮箱,前台可选择发送邮箱 网站数据采取本地保存&…

Java将文件目录转成树结构

在实际开发中经常会遇到返回树形结构的场景&#xff0c;特别是在处理文件系统或者是文件管理系统中。下面就介绍一下怎么将文件路径转成需要的树形结构。 在Java中&#xff0c;将List<String>转换成树状结构&#xff0c;需要定义一个树节点类&#xff08;TreeNode&#…

分享一个网站实现永久免费HTTPS访问的方法

免费SSL证书作为一种基础的网络安全工具&#xff0c;以其零成本的优势吸引了不少网站管理员的青睐。要实现免费HTTPS访问&#xff0c;您可以按照以下步骤操作&#xff1a; 一、 选择免费SSL证书提供商 选择一个提供免费SSL证书的服务商。如JoySSL&#xff0c;他们是国内为数不…

排序算法大总结

引言 排序算法&#xff08;sorting algorithm&#xff09;是用于对一组数据按照特定顺序进行排列。排序算法有着广泛的应用&#xff0c;因为有序数据通常能够被更高效地查找、分析和处理。 如图 1-1 所示&#xff0c;排序算法中的数据类型可以是整数、浮点数、字符或字符串等…

读懂一本书笔记

文章目录 引言 我是一个用读书改变自己生活的人01 会读书&#xff0c;更要会讲书复杂时代&#xff0c;阅读是大众反脆弱的武器你焦虑吗&#xff1f;如何从“单向度的人”变为“多向度的人”第一&#xff0c;读书是主动的学习方式第二&#xff0c;读书是有针对性的学习方式 讲书…

学习CSS3,实现红色心形loading特效

试想一下&#xff0c;如果你的网站在加载过程中&#xff0c;loading图由一个老旧的菊花转动图片&#xff0c;变为一个红色的心形loading特效&#xff0c;那该有多炫酷啊。 目录 实现思路 初始化HTML部分 延迟动画是重点 设定动画效果 完整源代码 最后 实现思路 每个…

内地家长送孩子去香港上学,这4种途径一定要清楚

为了规划好孩子的升学路&#xff0c;不少大湾区的家长&#xff0c;都想把小孩送去香港上学。 但家长和孩子都没有香港身份的话&#xff0c;是没有办法申请香港本地学校的。 内地户籍的孩子要到香港上学&#xff0c;需要家长办理了香港身份&#xff0c;然后为孩子申请“受养人…

ArrayList线程安全问题解决方案

jdk8 Stream API的出现大大简化了我们对于集合元素的处理代码&#xff0c;对于串行流来说&#xff0c;无需考虑线程安全问题&#xff1b;但是&#xff0c;对于并行流来说&#xff0c;由于它是以多线程的方式并行处理同一个集合中的数据元素的&#xff0c;因此&#xff0c;存在着…

V23 中的新增功能:LEADTOOLS React Medical Web 查看器

LEADTOOLS (Lead Technology)由Moe Daher and Rich Little创建于1990年&#xff0c;其总部设在北卡罗来纳州夏洛特。LEAD的建立是为了使Daher先生在数码图象与压缩技术领域的发明面向市场。在过去超过30年的发展历程中&#xff0c;LEAD以其在全世界主要国家中占有的市场领导地位…

游戏视频录制软件有哪些?这3款推荐给你

在数字化时代的今天&#xff0c;游戏视频录制已经成为广大游戏爱好者和职业玩家的必需品&#xff0c;那么游戏视频录制软件有哪些&#xff1f;哪个更适合您呢&#xff1f; 本文将为您推荐3款游戏视频录制软件&#xff0c;帮助您记录下游戏中的精彩瞬间&#xff0c;也可以通过录…

光伏风电智能互联:IEC104转MQTT网关解决方案

背景情况 IEC60870-5-104&#xff0c;是为适应电力系统&#xff0c;包括能源管理系统&#xff08;EMS&#xff09;、数据采集&#xff08;SCADA&#xff09;系统、配电自动化系统以及其他公用事业&#xff0c;安全监控而制定的传输规约。IEC104规约将IEC101的应用层与TCP/IP提…

鸿蒙内核源码分析(用栈方式篇) | 程序运行场地谁提供的

精读内核源码就绕不过汇编语言&#xff0c;鸿蒙内核有6个汇编文件&#xff0c;读不懂它们就真的很难理解以下问题. 1.系统调用是如何实现的? 2.CPU是如何切换任务和进程上下文的? 3.硬件中断是如何处理的? 4.main函数到底是怎么来的? 5.开机最开始发生了什么? 6.关机…

Allegro画PCB中如何旋转器件

PCB中如何旋转器件 鼠标点击器件&#xff0c;然后右击&#xff0c;选择“Rotate”&#xff0c;然后再“Options”里选择旋转的角度和旋转中心&#xff0c;如下图&#xff1a; 然后鼠标转动就可以转动器件了。

数据结构——时间复杂度与空间复杂度

文章目录 一、算法效率算法的复杂度 二、时间复杂度1.时间复杂度的概念2.大O的渐进表示法3.例子 三、空间复杂度1.空间复杂度概念2.例子 四、常见复杂度对比 一、算法效率 算法的复杂度 算法在编写成可执行程序后&#xff0c;运行时需要耗费时间资源和空间(内存)资源 。 因此…

【算法刷题 | 贪心算法07】4.29(用最少数量的箭引爆气球、无重叠区间)

文章目录 12.用最少数量的箭引爆气球12.1题目12.2解法&#xff1a;贪心12.2.1贪心思路12.2.2代码实现 13.无重叠区间13.1题目13.2解法&#xff1a;贪心13.2.1贪心思路13.2.2代码实现 12.用最少数量的箭引爆气球 12.1题目 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面…