FPGA Verilog编写状态机学习

1 二段式状态机

1.1 简介:

二段式状态机(Two-phase state machine)是一种常见的状态机实现方式,它将状态机的执行过程分为两个阶段:第一段是组合逻辑,用于确定下一个状态;第二段是时序逻辑,用于寄存状态。

1.2 实现步骤:

定义状态编码:首先,需要定义状态机的所有可能状态,并为每个状态分配一个唯一的编码。
创建状态寄存器:需要一个寄存器来存储当前的状态和下一个状态。
编写状态转移逻辑:这是状态机的第一段,通常是一个组合逻辑块,它根据当前状态和输入信号计算下一个状态。
编写状态输出:这是状态机的第二段,通常是一个时序逻辑块,它根据当前状态用always块中的非阻塞赋值输出信号。

1.3 例子

module fsm (input clk,                // 时钟信号input rst_n,              // 异步复位信号,低电平有效input condition,          // 控制状态转移的条件信号output reg action         // 执行的动作
);// 定义状态参数
parameter S0 = 2'b00;        // 状态0
parameter S1 = 2'b01;        // 状态1
parameter S2 = 2'b10;        // 状态2// 寄存当前状态和下一个状态
reg [1:0] current_state, next_state;// 组合逻辑部分,根据当前状态和输入条件计算下一个状态
always @(*) beginnext_state = current_state; // 默认保持当前状态case (current_state)S0: if (condition) next_state = S1;S1: if (condition) next_state = S2;S2: if (!condition) next_state = S0;default: next_state = S0;endcase
end// 时序逻辑部分,在每个时钟边沿根据下一个状态更新当前状态
always @(posedge clk or negedge rst_n) beginif (!rst_n) begincurrent_state <= S0;  // 异步复位,状态机回到初始状态action <= 1'b0;       // 复位动作输出end else begincurrent_state <= next_state; // 更新状态// 根据当前状态设置动作输出case (current_state)S0: action <= 1'b0;S1: action <= 1'b1;S2: action <= 1'bx; // 例如,不确定状态下的输出default: action <= 1'bx;endcaseend
endendmodule

在这个例子中,状态机的状态转移和动作输出都是在组合逻辑和时序逻辑中分别定义的。current_state 和 next_state 是寄存器,用于存储当前状态和下一个状态。condition 是一个输入信号,用于控制状态转移的条件。action 是一个输出信号,表示状态机在当前状态下应该执行的动作。
在组合逻辑部分,使用一个总是块(always @(*))来计算下一个状态。在这个块中,我们使用一个 case 语句来根据当前状态和输入条件来确定下一个状态。
在时序逻辑部分,使用另一个总是块(always @(posedge clk or negedge rst_n))来在每个时钟边沿更新当前状态。在这个块中,首先检查复位信号,如果复位为低,则将状态机重置为初始状态。否则,将 current_state 更新为 next_state。然后使用另一个 case 语句来根据当前状态设置动作输出。

2 三段式状态机

2.1 简介

三段式状态机(Three-phase state machine)是一种更加模块化和可维护的状态机实现方式。它将状态机的执行过程分为三个阶段:
时序逻辑阶段:在这个阶段,当前状态被寄存,以便在下一个时钟周期中使用。
组合逻辑阶段:在这个阶段,基于当前状态和输入条件,计算出下一个状态和输出。
输出逻辑阶段:在这个阶段,将计算出的输出赋值给输出信号。

2.2 实现步骤

定义状态编码:首先需要定义状态编码。一般是通过参数或常量来完成的。例如,你可以定义一个3位的参数来表示不同的状态。
声明状态和输出寄存器:接下来,需要声明用于存储当前状态和下一个状态的寄存器,以及任何输出信号。
时序逻辑部分:在这一部分,使用时序逻辑来在每个时钟边沿更新当前状态。这通常涉及到将下一个状态寄存器的值赋给当前状态寄存器。
组合逻辑部分:在这一部分,使用组合逻辑来根据当前状态和输入条件计算下一个状态和输出。这通常是通过一个总是块(always @(*))和一个 case 语句来完成的。
输出逻辑部分:在这一部分,使用时序逻辑来更新输出信号。这通常涉及到将计算出的输出赋值给输出信号。

2.3 例子

module fsm (input clk,                // 时钟信号input rst_n,              // 异步复位信号,低电平有效input condition,          // 控制状态转移的条件信号output reg action         // 执行的动作
);// 定义状态参数
parameter S0 = 3'b000;       // 状态0
parameter S1 = 3'b001;       // 状态1
parameter S2 = 3'b010;       // 状态2
parameter S3 = 3'b011;       // 状态3
parameter S4 = 3'b100;       // 状态4// 寄存当前状态和下一个状态
reg [2:0] current_state, next_state;// 时序逻辑部分,在每个时钟边沿寄存当前状态
always @(posedge clk or negedge rst_n) beginif (!rst_n) begincurrent_state <= S0;  // 异步复位,状态机回到初始状态end else begincurrent_state <= next_state; // 更新状态end
end// 组合逻辑部分,根据当前状态和输入条件计算下一个状态和输出
always @(*) beginnext_state = current_state; // 默认保持当前状态action = 1'b0;              // 默认输出为0case (current_state)S0: if (condition) beginnext_state = S1;action = 1'b1;endS1: if (condition) beginnext_state = S2;action = 1'b0;end else beginnext_state = S0;action = 1'b0;endS2: if (condition) beginnext_state = S3;action = 1'b1;endS3: if (condition) beginnext_state = S4;action = 1'b0;end else beginnext_state = S0;action = 1'b0;endS4: if (!condition) beginnext_state = S0;action = 1'b0;enddefault: beginnext_state = S0;action = 1'b0;endendcase
end// 输出逻辑部分,将计算出的输出赋值给输出信号
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginaction <= 1'b0;       // 异步复位,输出为0end else beginaction <= action;     // 在这里,输出逻辑可以更复杂,例如使用额外的组合逻辑end
endendmodule

在这个例子中,定义了一个有三个状态的状态机,每个状态都可以根据输入条件 condition 转移到另一个状态,并且根据当前状态设置输出 action。
在时序逻辑部分,使用一个总是块(always @(posedge clk or negedge rst_n))来在每个时钟边沿更新当前状态。如果复位信号为低,则状态机被重置为初始状态 S0。
在组合逻辑部分,使用另一个总是块(always @(*))来计算下一个状态和输出。在这个块中,使用一个 case 语句来根据当前状态和输入条件来确定下一个状态和输出。
在输出逻辑部分,再次使用时序逻辑来更新输出信号 action。

3 尽量用三段式编写代码 容易懂 好维护

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

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

相关文章

nestjs10.x使用jwt生成token

1 安装依赖&#xff1a; pnpm install --save nestjs/jwtpnpm install passport passport-jwt nestjs/jwtpnpm install types/passport-jwt --save-dev 2 可以使用命令新建auth鉴权文件夹 nest g mo auth // auth.module.ts nest g s auth // auth.service.ts nest g co …

杠杆和保证金有什么关系?WeTrade众汇一个公式讲清楚

在交易中杠杆其实就是一种期权&#xff0c;它能增加交易者作为抵押品的资金&#xff0c;以建立和维持头寸。 例如&#xff0c;1:100的操作杠杆&#xff0c;在这种情况下&#xff0c;意味着开立1000单位基础货币的头寸&#xff0c;交易者将需要少100倍的资金&#xff0c;即10个…

Node.js基础---JSONP 接口

1. 概念及特点 概念&#xff1a;浏览器通过 <script> 标签的 src 属性&#xff0c;请求服务器上的数据&#xff0c;同时服务器返回一个函数的调用。这种请求数据的方式叫做 JSONP 特点&#xff1a; ① JSONP 不属于真正的 Ajax 请求&#xff0c;因为它没有使用 XMLHtt…

Linux 进程的 status 注解。

我们知道 Linux 一切都是面向文件的&#xff0c;所以我们可以通过文件来获取到正在运行的ELF程序的状态信息。 本文会注解进程状态里面的各项输出参数的作用&#xff0c;以便于人们在写SH脚本程序的时候可以作为一个参照信息表。 当我们知道了进程ID时可以用这个命令来查看进…

C++常量和变量

甲流疫情死亡率 甲流并不可怕&#xff0c;在中国&#xff0c;它的死亡率并不是很高。根据截至2009年12月22日各省报告的甲流确诊数和死亡数&#xff0c;计算甲流在各省的死亡率 输入 一行&#xff0c;有两个整数&#xff0c;第1个为确诊数&#xff0c;第2个为死亡数 输出 一…

学习Java的第四天

目录 一、if选择结构 1、基本if选择结构 语法结构&#xff1a; 流程图&#xff1a; 示例&#xff1a; 2、if-else 选择结构 语法结构&#xff1a; 流程图&#xff1a; 示例&#xff1a; 3、多重if选择结构 语法结构&#xff1a; 流程图&#xff1a; 示例&#xff1a…

探秘分布式神器RMI:原理、应用与前景分析(二)

本系列文章简介&#xff1a; 本系列文章将深入探究RMI远程调用的原理、应用及未来的发展趋势。首先&#xff0c;我们会详细介绍RMI的工作原理和基本流程&#xff0c;解析其在分布式系统中的核心技术。随后&#xff0c;我们将探讨RMI在各个领域的应用&#xff0c;包括分布式计算…

【Docker】若依ruoyi项目部署

一 搭建局域网 1 # 搭建net-ry局域网&#xff0c;用于部署若依项目docker network create net-ry --subnet172.68.0.0/16 --gateway172.68.0.1 # 注意1&#xff1a;关闭宿主机的防火墙&#xff0c;否者容器内部的MySQL、redis等服务&#xff0c;外部访问不了&#xff1b;开放…

【REST2SQL】12 REST2SQL增加Token生成和验证

【REST2SQL】01RDB关系型数据库REST初设计 【REST2SQL】02 GO连接Oracle数据库 【REST2SQL】03 GO读取JSON文件 【REST2SQL】04 REST2SQL第一版Oracle版实现 【REST2SQL】05 GO 操作 达梦 数据库 【REST2SQL】06 GO 跨包接口重构代码 【REST2SQL】07 GO 操作 Mysql 数据库 【RE…

如何使用 window 的.bat 完全拷贝一个文件到另外一个文件全部替换

比如你的文件夹是 A 你想拷贝 A的文件到 B并且全部替换 那么你可以这样子做 1.在 window 桌面新建一个文件夹,在这文件里面新建两个文件,文件 A和文件 B 2.然后新建后缀命名为 copy.bat 回车,然后选择编辑这个 copy.bat 你可以使用文本编辑即可; 3.然后你在这个 copy.bat 编…

Docker_搭建跨服务器网络通讯(swarm 集群)

本文目录 一、如何搭建docker的跨服务器网络1、在主服务器上初始化docker swarm 集群2、其他服务器节点加入到创建好的集群中3、检验集群是否搭建成功4、创建overlay类型的docker网络 二、如何部署服务1、docker部署2、docker-compose部署 一、如何搭建docker的跨服务器网络 1…

《小学科学》是什么级别的期刊?是正规期刊吗?能评职称吗?

问题解答&#xff1a; 问&#xff1a;《小学科学》期刊是正规期刊吗&#xff1f; 答&#xff1a;是正规期刊&#xff0c;下面会有具体介绍 问&#xff1a;《小学科学》期刊是什么级别的&#xff1f; 答&#xff1a;省级&#xff1b;主管单位&#xff1a;长春出版传媒集团有…

unicloud 创建云函数并使用云函数

云函数是什么 云函数即在云端&#xff08;服务器端&#xff09;运行的函数。 从 HBuilderX 3.4起&#xff0c;新增了云函数的扩展版&#xff0c;云对象。 开发者无需购买、搭建服务器&#xff0c;只需编写代码并部署到云端即可在客户端&#xff08;App/Web/小程序等&#xf…

【Linux】第一个小程序--进度条

这篇博客要综合利用以前的知识&#xff0c;来实现一个进度条程序~ 目录 换行&回车 缓冲区 实现简单的倒计时 实现进度条 version1 version2 在开始写这个小程序之前&#xff0c;我们先学习一些预备知识&#xff1a; 换行&回车 缓冲区 在我们运行这个程序时&…

git workflow

分支策略 按分支属性分类 主干分支&#xff1a;master特性分支&#xff1a;feature-[序号]、fix-[序号]、hotfix-[序号]开发分支&#xff1a;dev-[序号]-[开发者]发布分支&#xff1a;release-[版本号]部署分支&#xff1a;release&#xff08;正式&#xff09;、test&#xf…

如何阅读“计算机界三大神书”之一 ——《计算机程序的构造和解释》SICP

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

如何使用 @font-face 和 font-display 在 CSS 中定义自定义字体

介绍 font-face 是一个 CSS at-rule&#xff0c;用于定义自定义字体。通过 font-face&#xff0c;您可以提供一个路径到与您的 CSS 文件托管在同一服务器上的字体文件。这个规则已经存在了相当长的时间&#xff0c;但是有一个更新的属性 font-display&#xff0c;它带来了新的…

STM32CubeMX学习笔记17--- FSMC

1.1 TFTLCD简介 TFT-LCD&#xff08;thin film transistor-liquid crystal display&#xff09;即薄膜晶体管液晶显示器。液晶显示屏的每一个像素上都设置有一个薄膜晶体管&#xff08;TFT&#xff09;&#xff0c;每个像素都可以通过点脉冲直接控制&#xff0c;因而每个节点都…

论文阅读:Scalable Diffusion Models with Transformers

Scalable Diffusion Models with Transformers 论文链接 介绍 传统的扩散模型基于一个U-Net骨架&#xff0c;这篇文章提出了一种新的扩散模型结构&#xff0c;将U-Net替换为一个transformer&#xff0c;并将这种结构称为Diffusion Transformers (DiTs)。他们还发现&#xff…

python77-Python的函数参数,个数可变参数

很多编程语言都允许定义个数可变的参数,这样可以在调用函数时传入任意多个参数。Python当然也不例外,Python 允许在形参前面添加一个星号(*),这样就意味着该参数可接收多个参数值,多个参数值被当成元组传入。下面程序定义了一个形参个数可变的函数。 # !/usr/bin/env pyth…