FPGA开发基础之三段式状态机
状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,程序的运行其本质也是状态机,根据输入完成输出,得到新的状态。
在平时硬件电路的设计中经常需要用到状态机,例如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开发基础之三段式状态机相关推荐
- FPGA开发基础知识
FPGA开发基础知识 FPGA介绍 FPGA硬件内部结构 FPGA开发流程 数字信号和模拟信号的定义 常用数据类型 IP核的使用 Verilog HDL基本语法 注意点 结束语 FPGA介绍 FPGA ...
- FPGA开发基础——基于multisim以及Quartus实现的交通灯电路
作者:王子齐 学校:电子科技大学 学号:2018151202014 设计目的:完成对于FGPA开发的基础练习,建立FPGA开发思想. 目录 设计要求 基于multisim对于交通灯的电路搭建 1.1 ...
- FPGA平台开发基础
本篇文章介绍了FPGA平台的使用语言的基本语法,并用一个3-8译码器模块的实例引导嵌入式工程师熟悉FPGA开发的一般流程.FPGA的嵌入式程序最终都会映射成数字逻辑电路,在开发的过程中要保持对实际生成 ...
- 三、1【Verilog HDL】基础语法快速入门(FPGA开发)
参考资料: 参考野火FPGA开发视频的基础语法:[野火]FPGA系列Xilinx Artix7教学视频,真正的手把手教学,"波形图"教学法,现场画波形图写代码,硬件基于野火FPGA ...
- fpga时序逻辑(三段式状态机模板、rom实现、边沿检测)
目录 VL21 根据状态转移表实现时序电路 VL22 根据状态转移图实现时序电路 VL23 ROM的简单实现 VL24 边沿检测 VL21 根据状态转移表实现时序电路 题目分析: 1.使用三段式状态机 ...
- FPGA基础知识----第二章 FPGA 开发流程
第二章 FPGA 开发流程 FPGA 的设计流程就是利用 EDA 开发软件和编程工具对 FPGA 芯片进行开发的过程.原理图和HDL(Hardware description language,硬件描 ...
- 【FPGA基础】基于 Pango Design Suite(PDS) 的FPGA开发流程
导读:本文旨在通过 LED 的 Demo,实现快速上手基于PGL22G的FPGA开发. 文章目录 一.创建工程 二.编写流水灯的 verilog 代码 三.添加 UCE 约束 四. 生成位流文件 五. ...
- 【正点原子FPGA连载】 第二十章 LCD触摸屏实验摘自【正点原子】DFZU2EG/4EV MPSoC 之FPGA开发指南V1.0
1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670 3)全套实验源码+手册+视频下载地址: h ...
- 【正点原子FPGA连载】 第七章 Verilog HDL语法 摘自【正点原子】DFZU2EG/4EV MPSoC 之FPGA开发指南V1.0
1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670 3)全套实验源码+手册+视频下载地址: h ...
最新文章
- 万向锁的简单数学解释
- session_start() 对 HTTP_REQUEST扩展/fsockopen函数 的影响
- [方法提炼] 获取Android设备序列号方法
- 解决 Windows 系统使用 Homestead 运行 Laravel 本地项目响应缓慢问题
- 截止到2013年,核心Java帖子
- python 竖线 绘图_Python可视化 | Seaborn5分钟入门(二)——barplot countplot
- 虚拟化物理服务器参数,浅谈部署VMware物理系统虚拟化技术P2V(Physical to Virtual)
- 《Kotlin项目实战开发》第5章 函数与函数式编程
- The stacking context
- SpringApplication.run方法分析
- cad插件加载bplot成功用不了_教大家Batchplot使用常见问题的解决办法
- Hebb和Delta学习规则
- RFID图书馆管理系统的优势有哪些
- 大数据项目之深圳地铁大数据客流分析系统
- 红米1A显示器于笔记本win10环境下,如何设置颜色范围使得显示器亮度恢复成250nit
- html a5 尺寸,纸型尺寸大小(A1,A2,A3,A4,A5,A6,B1,B2,B3,B4,B5......)
- Redis 缓存清理策略
- allegro 警告怎么要怎么做呢进入光绘界面提示artwork will be rounder down because
- STM32MINI板写的超声波代码
- Promise的使用方法