状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,程序的运行其本质也是状态机,根据输入完成输出,得到新的状态。

在平时硬件电路的设计中经常需要用到状态机,例如CPU的取指、译码、执行,这个流程可以使用状态机来控制,相比于流水线能够有效的较少资源的消耗,再或者序列检测上,也可以使用状态机。

状态机有一段、二段、和三段式,三段式的写法复杂些,但是相比于两段式可以使输出信号由寄存器来驱动,能够有效的消除组合逻辑的不稳定与毛刺等隐患。

首先给出三段式状态机的通用形式:

三段式状态机

Mealy型(米勒型)三段式状态机

当前输出与当前状态和输入有关

parameter S0=3'b000,state1=3'b001,state2=3'b010,S3=3'b011;reg [2:0] current_state;
reg [2:0] next_state;//在第一个always块中只实现状态的迁移,将第二个always块中计算出的次态在时钟上升沿复制给current_state
always @(posedge clk or negedge rst_n)
beginif(!rst_n)begincurrent_state<=0;next_state<=0;endelsebegincurrent_state<=next_state;end
end//在第二个always块中计算next_state,使用组合逻辑来完成
always @(*)
begincase(current_state)S0:if(..) //当然此刻的if判断也能用三目运算法来实现,看上去会更便捷一些:next_state=S1;elsenext_state=S0;S1:if(..) next_state=state?;elsenext_state=state?;S2:if(..) next_state=state?;elsenext_state=state?;S3:if(..) next_state=state?;elsenext_state=state?;default:next_state=S0;endcase
end
//在第三个always块中计算输出,在满足什么情况下输出
always @(posedge clk or negedge rst_n)
beginif(!rst_n)beginsignal_out<=0;endelsebeginif(current_state==state?&&signal_in==?)signal_out<=1;elsesignal_out<=0;    end
end

Moore型(摩尔型)三段式状态机

当前输出仅仅与当前状态有关

parameter S0=3'b000,state1=3'b001,state2=3'b010,S3=3'b011;reg [2:0] current_state;
reg [2:0] next_state;//在第一个always块中只实现状态的迁移,将第二个always块中计算出的次态在时钟上升沿复制给current_state
always @(posedge clk or negedge rst_n)
beginif(!rst_n)begincurrent_state<=0;next_state<=0;endelsebegincurrent_state<=next_state;end
end//在第二个always块中计算next_state,使用组合逻辑来完成
always @(*)
begincase(current_state)S0:if(..) //当然此刻的if判断也能用三目运算法来实现,看上去会更便捷一些:next_state=S1;elsenext_state=S0;S1:if(..) next_state=state?;elsenext_state=state?;S2:if(..) next_state=state?;elsenext_state=state?;S3:if(..) next_state=state?;elsenext_state=state?;default:next_state=S0;endcase
end
//在第三个always块中计算输出,在满足什么情况下输出
always @(posedge clk or negedge rst_n)
beginif(!rst_n)beginsignal_out<=0;endelsebeginif(current_state==state?)signal_out<=1;elsesignal_out<=0;    end
end

两种三段式状态机的状态图会有区别

测试用例

接下来我们使用具体的场景来介绍两者不同

设计一个状态机,用来检测序列 10111,要求:

1、进行非重叠检测 即101110111 只会被检测通过一次

2、寄存器输出且同步输出结果

信号示意图:

输入描述:

输入信号 clk rst data
类型 wire

输出描述:

输出信号 flag
类型 reg

首先第一件事就是画出状态转移,在此刻我们一定要注意到,flag是在检测完成的这一个周期拉高的,而不是下个周期

Mealy型(米勒型)状态图——输出与输入和现态有关

这个时候我们来解析这张图

复位之后当前状态是S0,假设在第一个时钟上升沿之前,data输入1,则通过第二个always组合逻辑块,会计算出next_state=S1,在第一个时钟上升沿,next_state=S1就会被赋值给current_state,也就是说从第一个上升沿之后到第二个上升沿之前,current会一直保持S1的状态。

假设在第一个上升沿之后到第二个上升沿之前,data输入变为了0,那么同理,组合逻辑会计算出新的next_state=S2,在第二个时钟上升沿倘若data不发生变化,则新的next_state会被赋值给current_state,从第二个上升沿之后到第三个上升沿之前,current会一直保持S2的状态。

假设在第二个上升沿之后到第三个上升沿之前,data输入变为了1,那么同理,组合逻辑会计算出新的next_state=S3,在第三个时钟上升沿倘若data不发生变化,则新的next_state会被赋值给current_state,从第三个上升沿之后到第四个上升沿之前,current会一直保持S3的状态。

假设在第三个上升沿之后到第四个上升沿之前,data输入变为了1,那么同理,组合逻辑会计算出新的next_state=S4,在第四个时钟上升沿倘若data不发生变化,则新的next_state会被赋值给current_state,从第四个上升沿之后到第五个上升沿之前,current会一直保持S4的状态。

假设在第四个上升沿之后到第五个上升沿之前,data输入变为了1,此时注意,前面我们谈到过,在这个题目中,在完成序列检测的这一个周期,flag就要拉高,此时我们需要第五个上升沿将flag拉高,因此需要在第三个always语句块中定位到这个时刻,也就是current_state= =S4&&data= =1,这也就是输出和现态以及输入都有关,之后current_state将变为S0,重新进行一轮新的检测。

`timescale 1ns/1nsmodule sequence_test1(input wire clk  ,input wire rst  ,input wire data ,output reg flag
);parameter S0=0,S1=1,S2=2,S3=3,S4=4,S5=5;reg [2:0] current_state;reg [2:0] next_state;always @(posedge clk or negedge rst)beginif(!rst)begincurrent_state<=0;next_state<=0;endelsebegincurrent_state<=next_state;endendalways @(*)begincase(current_state)S0:beginnext_state<=data==1?S1:S0;endS1:beginnext_state<=data==0?S2:S0;endS2:beginnext_state<=data==1?S3:S0;endS3:beginnext_state<=data==1?S4:S0;endS4:beginnext_state<=S0;endenddefault:nex_state<=S0;endcaseendalways @(posedge clk or negedge rst)beginif(!rst)beginflag<=0;endelsebeginif(current_state==S4&&data==1) flag<=1;elseflag<=0;endendendmodule

Moore型(摩尔型)状态图——输出只与现态有关

Moore型(摩尔型)状态机与米勒型稍有不同,下面我们尝试用摩尔状态机来解决这个问题

倘若在某个时钟上升沿时,当前current_state=S4时,此时若data=1,按照题目的要求,在这个上升沿结束之后flag就应该立刻拉高,而Moore型状态机的输出只与现态有关,在这个时刻current_state=S4,仅仅根据这个条件我们无法判断输出是0还是1,若将flag拉高了,但是data为0,那就是错误的,因此在当前时刻必须结合输入才能得出正确的输出,在下一个时钟上升沿,检测到current_state=S5时才能将flag拉高,这是才是正确的,因此Moore型状态机相比Mealy状态机会延迟一个周期。

代码如下

`timescale 1ns/1nsmodule sequence_test1(input wire clk  ,input wire rst  ,input wire data ,output reg flag
);parameter S0=0,S1=1,S2=2,S3=3,S4=4,S5=5;reg [2:0] current_state;reg [2:0] next_state;always @(posedge clk or negedge rst)beginif(!rst)begincurrent_state<=0;next_state<=0;endelsebegincurrent_state<=next_state;endendalways @(*)begincase(current_state)S0:beginnext_state<=data==1?S1:S0;endS1:beginnext_state<=data==0?S2:S0;endS2:beginnext_state<=data==1?S3:S0;endS3:beginnext_state<=data==1?S4:S0;endS4:beginnext_state<=data==1?S5:S0;endS5:beginnext_state<=S0;enddefault:nex_state<=S0;endcaseendalways @(posedge clk or negedge rst)beginif(!rst)beginflag<=0;endelsebeginif(current_state==S5) ,flag<=1;elseflag<=0;endendendmodule

修改后的Moore型(摩尔型)状态机

我们可以通过将判断条件改为next_state==S5,这种方式将输出提前一个周期,因为next_state本就是根据current_state和data得出的,所以提前一个周期用也无妨。

`timescale 1ns/1nsmodule sequence_test1(input wire clk  ,input wire rst  ,input wire data ,output reg flag
);parameter S0=0,S1=1,S2=2,S3=3,S4=4,S5=5;reg [2:0] current_state;reg [2:0] next_state;always @(posedge clk or negedge rst)beginif(!rst)begincurrent_state<=0;next_state<=0;endelsebegincurrent_state<=next_state;endendalways @(*)begincase(current_state)S0:beginnext_state<=data==1?S1:S0;endS1:beginnext_state<=data==0?S2:S0;endS2:beginnext_state<=data==1?S3:S0;endS3:beginnext_state<=data==1?S4:S0;endS4:beginnext_state<=data==1?S5:S0;endS5:beginnext_state<=S0;enddefault:nex_state<=S0;endcaseendalways @(posedge clk or negedge rst)beginif(!rst)beginflag<=0;endelsebeginif(next_state==S5) ,flag<=1;elseflag<=0;endendendmodule

这种方法相比于Mealy机多了一个状态S5

FPGA开发基础之三段式状态机相关推荐

  1. FPGA开发基础知识

    FPGA开发基础知识 FPGA介绍 FPGA硬件内部结构 FPGA开发流程 数字信号和模拟信号的定义 常用数据类型 IP核的使用 Verilog HDL基本语法 注意点 结束语 FPGA介绍 FPGA ...

  2. FPGA开发基础——基于multisim以及Quartus实现的交通灯电路

    作者:王子齐 学校:电子科技大学 学号:2018151202014 设计目的:完成对于FGPA开发的基础练习,建立FPGA开发思想. 目录 设计要求 基于multisim对于交通灯的电路搭建 1.1 ...

  3. FPGA平台开发基础

    本篇文章介绍了FPGA平台的使用语言的基本语法,并用一个3-8译码器模块的实例引导嵌入式工程师熟悉FPGA开发的一般流程.FPGA的嵌入式程序最终都会映射成数字逻辑电路,在开发的过程中要保持对实际生成 ...

  4. 三、1【Verilog HDL】基础语法快速入门(FPGA开发)

    参考资料: 参考野火FPGA开发视频的基础语法:[野火]FPGA系列Xilinx Artix7教学视频,真正的手把手教学,"波形图"教学法,现场画波形图写代码,硬件基于野火FPGA ...

  5. fpga时序逻辑(三段式状态机模板、rom实现、边沿检测)

    目录 VL21 根据状态转移表实现时序电路 VL22 根据状态转移图实现时序电路 VL23 ROM的简单实现 VL24 边沿检测 VL21 根据状态转移表实现时序电路 题目分析: 1.使用三段式状态机 ...

  6. FPGA基础知识----第二章 FPGA 开发流程

    第二章 FPGA 开发流程 FPGA 的设计流程就是利用 EDA 开发软件和编程工具对 FPGA 芯片进行开发的过程.原理图和HDL(Hardware description language,硬件描 ...

  7. 【FPGA基础】基于 Pango Design Suite(PDS) 的FPGA开发流程

    导读:本文旨在通过 LED 的 Demo,实现快速上手基于PGL22G的FPGA开发. 文章目录 一.创建工程 二.编写流水灯的 verilog 代码 三.添加 UCE 约束 四. 生成位流文件 五. ...

  8. 【正点原子FPGA连载】 第二十章 LCD触摸屏实验摘自【正点原子】DFZU2EG/4EV MPSoC 之FPGA开发指南V1.0

    1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670 3)全套实验源码+手册+视频下载地址: h ...

  9. 【正点原子FPGA连载】 第七章 Verilog HDL语法 摘自【正点原子】DFZU2EG/4EV MPSoC 之FPGA开发指南V1.0

    1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670 3)全套实验源码+手册+视频下载地址: h ...

最新文章

  1. 万向锁的简单数学解释
  2. session_start() 对 HTTP_REQUEST扩展/fsockopen函数 的影响
  3. [方法提炼] 获取Android设备序列号方法
  4. 解决 Windows 系统使用 Homestead 运行 Laravel 本地项目响应缓慢问题
  5. 截止到2013年,核心Java帖子
  6. python 竖线 绘图_Python可视化 | Seaborn5分钟入门(二)——barplot countplot
  7. 虚拟化物理服务器参数,浅谈部署VMware物理系统虚拟化技术P2V(Physical to Virtual)
  8. 《Kotlin项目实战开发》第5章 函数与函数式编程
  9. The stacking context
  10. SpringApplication.run方法分析
  11. cad插件加载bplot成功用不了_教大家Batchplot使用常见问题的解决办法
  12. Hebb和Delta学习规则
  13. RFID图书馆管理系统的优势有哪些
  14. 大数据项目之深圳地铁大数据客流分析系统
  15. 红米1A显示器于笔记本win10环境下,如何设置颜色范围使得显示器亮度恢复成250nit
  16. html a5 尺寸,纸型尺寸大小(A1,A2,A3,A4,A5,A6,B1,B2,B3,B4,B5......)
  17. Redis 缓存清理策略
  18. allegro 警告怎么要怎么做呢进入光绘界面提示artwork will be rounder down because
  19. STM32MINI板写的超声波代码
  20. Promise的使用方法

热门文章

  1. 从《江南百景图》厨艺大赛说起,聊聊博弈和“奶油系统”
  2. 为什么说施工是最蛋疼的工程行业
  3. 穗社保条例获准 职工医保需缴到退休最少15年
  4. 深度强化学习与APS的一些感想
  5. Web应用程序的身份验证机制
  6. SQL2005 使用证书实现数据库镜像
  7. C++ Primer 5 ,众里寻他千百度,下载的大虾别忘了后面买一本正版的支持作者
  8. linux 串口 loopback,友善NanoPC T2 4418开发板Linux下串口回环测试 -申嵌
  9. 信号完整性分析3——阻抗和电气模型
  10. 润乾——润乾报表错误