FPGA开发基础之三段式状态机

这篇具有很好参考价值的文章主要介绍了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)
begin
    if(!rst_n)
        begin
           current_state<=0;
           next_state<=0;
        end
    else
        begin
            current_state<=next_state;
        end
end

//在第二个always块中计算next_state,使用组合逻辑来完成
always @(*)
begin
    case(current_state)
    S0:
        if(..) //当然此刻的if判断也能用三目运算法来实现,看上去会更便捷一些:
            next_state=S1;
        else
            next_state=S0;
    S1:
        if(..) 
            next_state=state?;
        else
            next_state=state?;
    S2:
        if(..) 
            next_state=state?;
        else
            next_state=state?;
    S3:
        if(..) 
            next_state=state?;
        else
            next_state=state?;
    default:
        	next_state=S0;
    endcase   
end
//在第三个always块中计算输出,在满足什么情况下输出
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
           signal_out<=0;
        end
    else
        begin
            if(current_state==state?&&signal_in==?)
                signal_out<=1;
            else
                signal_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)
begin
    if(!rst_n)
        begin
           current_state<=0;
           next_state<=0;
        end
    else
        begin
            current_state<=next_state;
        end
end

//在第二个always块中计算next_state,使用组合逻辑来完成
always @(*)
begin
    case(current_state)
    S0:
        if(..) //当然此刻的if判断也能用三目运算法来实现,看上去会更便捷一些:
            next_state=S1;
        else
            next_state=S0;
    S1:
        if(..) 
            next_state=state?;
        else
            next_state=state?;
    S2:
        if(..) 
            next_state=state?;
        else
            next_state=state?;
    S3:
        if(..) 
            next_state=state?;
        else
            next_state=state?;
    default:
        	next_state=S0;
    endcase   
end
//在第三个always块中计算输出,在满足什么情况下输出
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
           signal_out<=0;
        end
    else
        begin
            if(current_state==state?)
                signal_out<=1;
            else
                signal_out<=0;    
        end
end

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

测试用例

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

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

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

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

信号示意图:

三段式状态机,FPGA,fpga开发

输入描述:

输入信号 clk rst data
类型 wire

输出描述:

输出信号 flag
类型 reg

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

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

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

三段式状态机,FPGA,fpga开发

复位之后当前状态是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/1ns

module 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)
  begin
	  if(!rst)
	  begin
		current_state<=0;
		next_state<=0;
	  end
	  else
	  begin
		current_state<=next_state;
	  end
  end

  always @(*)
  begin
	case(current_state)
	  	S0:begin
			next_state<=data==1?S1:S0;
	  	end
		S1:begin
			next_state<=data==0?S2:S0;
	  	end
		S2:begin
			next_state<=data==1?S3:S0;
	  	end
		S3:begin
			next_state<=data==1?S4:S0;
	  	end
	  	S4:begin
			next_state<=S0;
	  	end
	  	end
        default:
            nex_state<=S0;
	endcase
  end

  always @(posedge clk or negedge rst)
  begin
	  if(!rst)
	  begin
		flag<=0;
	  end
	  else
	  begin
          if(current_state==S4&&data==1) 
		flag<=1;
		else
		flag<=0;
	  end
  end

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

三段式状态机,FPGA,fpga开发

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

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

代码如下

`timescale 1ns/1ns

module 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)
  begin
	  if(!rst)
	  begin
		current_state<=0;
		next_state<=0;
	  end
	  else
	  begin
		current_state<=next_state;
	  end
  end

  always @(*)
  begin
	case(current_state)
	  	S0:begin
			next_state<=data==1?S1:S0;
	  	end
		S1:begin
			next_state<=data==0?S2:S0;
	  	end
		S2:begin
			next_state<=data==1?S3:S0;
	  	end
		S3:begin
			next_state<=data==1?S4:S0;
	  	end
	  	S4:begin
			next_state<=data==1?S5:S0;
	  	end
	  	S5:begin
			next_state<=S0;
	  	end
        default:
            nex_state<=S0;
	endcase
  end

  always @(posedge clk or negedge rst)
  begin
	  if(!rst)
	  begin
		flag<=0;
	  end
	  else
	  begin
          if(current_state==S5) ,
		flag<=1;
		else
		flag<=0;
	  end
  end

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

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

`timescale 1ns/1ns

module 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)
  begin
	  if(!rst)
	  begin
		current_state<=0;
		next_state<=0;
	  end
	  else
	  begin
		current_state<=next_state;
	  end
  end

  always @(*)
  begin
	case(current_state)
	  	S0:begin
			next_state<=data==1?S1:S0;
	  	end
		S1:begin
			next_state<=data==0?S2:S0;
	  	end
		S2:begin
			next_state<=data==1?S3:S0;
	  	end
		S3:begin
			next_state<=data==1?S4:S0;
	  	end
	  	S4:begin
			next_state<=data==1?S5:S0;
	  	end
	  	S5:begin
			next_state<=S0;
	  	end
        default:
            nex_state<=S0;
	endcase
  end

  always @(posedge clk or negedge rst)
  begin
	  if(!rst)
	  begin
		flag<=0;
	  end
	  else
	  begin
          if(next_state==S5) ,
		flag<=1;
		else
		flag<=0;
	  end
  end

endmodule

这种方法相比于Mealy机多了一个状态S5文章来源地址https://www.toymoban.com/news/detail-762283.html

到了这里,关于FPGA开发基础之三段式状态机的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【零基础玩转BLDC系列】无刷直流电机无位置传感器三段式启动法详细介绍及代码分享

    无刷直流电动机基本转动原理等内容请参考《基于霍尔传感器的无刷直流电机控制原理》、《基于反电动势过零检测法的无刷直流电机控制原理》与《以GD32F30x为例定时器相关功能详解》,BLDC基本原理及基础知识本篇不再赘述。 直流无刷电机由于定子绕组的反电动势与电机的

    2023年04月08日
    浏览(75)
  • Flutter BottomSheet 三段式拖拽

    前面倒是有讲过Android原生的BottomSheetBehavior,使用场景还是蛮多的,最近在用Flutter做一款地图App,有用到BottomSheet的功能,但是 Flutter 自带的BottomSheet有点拉,只能显示和隐藏销毁,不支持折叠为最小高度状态也不支持三段式拖动 ,那就自己撸一个吧: 既然是基于系统的Bot

    2024年02月09日
    浏览(33)
  • [Daimayuan] 三段式(C++,数组前缀和)

    有一个长度为 n n n 的序列,现在我们想把它切割成三段(每一段都是连续的),使得每一段的元素总和都相同,请问有多少种不同的切割方法 输入描述 第一行给出一个数 n n n ,( 1 ≤ n ≤ 1 0 5 1≤n≤10^5 1 ≤ n ≤ 1 0 5 ) 第二行给出序列 a 1 a_1 a 1 ​ , a 2 a_2 a 2 ​ , a 3 a_3 a 3 ​

    2024年02月05日
    浏览(27)
  • 电力系统电流三段式保护MATLAB仿真模型

    完整资源请查看主页置顶博客(专享优惠) 整体模型如下: Matlab/Simulink搭建的电力系统电流保护模型采用辐射型单电源供电的运行方式 Ⅰ段保护的搭建 Ⅰ段保护为瞬时速断保护,根据Ⅰ段整定原则确定整定值。线路发生短路故障时,短路电流急剧增大;超过设置的整定值时

    2024年02月14日
    浏览(31)
  • 三段式电流保护与自动重合闸MATLAB仿真模型

    微 ❤ 关注“电气仔推送”获得资料(专享优惠) 前加速、后加速的区别: 前加速是保护装置不判别是永久性故障还是瞬时故障,直接跳闸,然后经重合闸装置来纠正;后加速是保护装置是先判别故障类型有选择性跳闸 以下只叙述后加速的相关内容,前加速不在赘述!!!

    2024年02月02日
    浏览(27)
  • 【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现)

    🎉欢迎来到FPGA专栏~按键消抖模块设计与验证 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ 🥝 模块设计: 🥝 按键消

    2024年02月12日
    浏览(33)
  • 【FPGA零基础学习之旅#9】状态机基础知识

    🎉欢迎来到FPGA专栏~状态机基础知识 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ 🔸 Hello状态机例程 : RTL视图: 状态

    2024年02月16日
    浏览(35)
  • FPGA在校学习记录系列---实验4不同状态的LED+开发板(Verilog HDL)

    此系列记录FPGA在学校的学习过程。 FPGA系列 需要用到的软硬件: 软件:Quartus II 15.0 (64-bit) 硬件: 5CEBA4F23C7芯片 链接: FPGA在校学习记录系列—新建一个FPGA工程编写程序并仿真(Verilog HDL) 创建的工程名字为:LED (这次不用仿真,直接用开发板验证) 编译文件 按键资源:

    2024年04月09日
    浏览(37)
  • FPGA设计开发(基础课题):分频器设计

    一、设计目的 1、掌握分频器的设计原理; 2、用HDL语言设计分频器。 二、设计原理 分频器与计数器类似,也是要对时钟脉冲进行计数,但其输出的不是对时钟脉冲个数的计数值,而是其频率与时钟的频率成固定比例关系的脉冲信号。整数分频是所有分频器中最简单,最容易

    2024年02月13日
    浏览(38)
  • FPGA开发基础篇之一(接口篇)UART串口

    写在前面 从本文开始,将连载fpga开发基础知识,将这几年浅显的fpga开发经验整理出来,一是梳理一下这几年给别人做fpga的经历,同时也是分享给大家,也希望大牛批评指正。 一、UART串口通信基本概念 串口通信是非常基本且应用十分广泛的低速通信接口,无论是在dsp、单片

    2024年02月02日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包