FPGA学习笔记(七)——FSM(Finite State Machine,有限状态机)设计
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了FPGA学习笔记(七)——FSM(Finite State Machine,有限状态机)设计,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3612字,纯文字阅读大概需要6分钟。
内容图文
FPGA设计中,最重要的设计思想就是状态机的设计思想!状态机的本质就是对具有逻辑顺序和时序规律的事件的一种描述方法,它有三个要素:状态、输入、输出:状态也叫做状态变量(比如可以用电机的不同转速作为状态),输出指在某一个状态的特定输出,输入指状态机中进入每个状态的条件。根据状态机的输出是否和输入有关,可分为摩尔(Moore)型状态机和米勒型(Mealy)状态机:摩尔型状态机的输出只取决于当前状态,而米勒型状态机的输出不仅取决于当前状态,还与当前输入有关。通常,我们描述状态机有三种方法:状态转移图、状态转移表、HDL描述,状态转移图直观,设计用,而HDL语言方便描述,实现时用。
那么,如何用HDL描述一个好的状态机呢?主要有以下四点:安全、稳定性高,速度快,面积小,设计清晰; 在描述过程中,我们会引用两个新的verilog语法: localparam描述参数(等价于parameter)以及用task/endtask将输出功能块封装,增强代码可读性; 描述状态机的关键是要描述清楚状态机的三大要素:如何进行状态转移?每个状态的输出?状态输出是否和输入条件相关?通常有三种写法,下面通过一个实例说明;
实例.检测“Hello”序列状态机
1、功能:在输入一串字符中检测“Hello”序列,检测到后将led状态进行翻转;
2、根据设计的FSM状态转移图(visio绘制):
3、一段式描述法:在一个always块里既描述状态转移,又描述状态的输入和输出;
verilog代码如下:
// 检测“Hello”后led状态翻转 module check_hello( input clk, //50M时钟信号input rst, //低电平复位input [7:0]asci, //字符输入outputreg led //控制led); //状态寄存器reg [4:0]NS; //nextstate //状态独热编码localparam CHECK_H = 5‘b0_0001, CHECK_e = 5‘b0_0010, CHECK_la = 5‘b0_0100, CHECK_lb = 5‘b0_1000, CHECK_o = 5‘b1_0000;//一段式状态机always@(posedge clk,negedge rst) if(!rst)begin NS <= CHECK_H; led <= 1‘b1; //led熄灭endelsebegincase(NS) CHECK_H: beginif(asci == "H") NS <= CHECK_e; else NS <= CHECK_H; end CHECK_e: beginif(asci == "e") NS <= CHECK_la; else NS <= CHECK_H; end CHECK_la: beginif(asci == "l") NS <= CHECK_lb; else NS <= CHECK_H; end CHECK_lb: beginif(asci == "l") NS <= CHECK_o; else NS <= CHECK_H; end CHECK_o: beginif(asci == "o") led <= ~led; else led <= led; NS <= CHECK_H; enddefault//排除任意情况,增强FSM安全性begin NS <= CHECK_H; led <= 1‘b1;endendcaseendendmodule
testbench测试文件如下:
`timescale 1ns/1ps `define clk_period 20module check_hello_tb(); reg clk; //50M时钟信号reg rst; //低电平复位reg [7:0]asci; //字符输入wire led; //控制led //例化测试模块 check_hello check_hello_test( .clk(clk), //50M时钟信号 .rst(rst), //低电平复位 .asci(asci), //字符输入 .led(led) //控制led ); //产生50M时钟信号initial clk = 1; always #(`clk_period / 2)clk <= ~clk; //开始测试initialbegin rst = 0; //系统复位 asci = 3‘bx; #(`clk_period * 2); rst = 1; #(`clk_period); asci = "H"; #(`clk_period); asci = "e"; #(`clk_period); asci = "l"; #(`clk_period); asci = "l"; #(`clk_period); asci = "o"; #(`clk_period); asci = "2"; #(`clk_period); asci = "e"; #(`clk_period); asci = "h"; #(`clk_period); asci = "l"; #(`clk_period); $stop; endendmodule
测试结果如下,可以看到,刚开始输入数据是任意数据,FSM为CHECK_H状态,led输出高电平,保持熄灭;当检测到Hello序列时,led输出低电平,状态翻转:
状态转移图如下,可以看到按照预定设计执行:
综合出来的电路图如下,可以看到FSM实现的重点在于状态寄存器,耗费资源很少,由综合报告也可看出:
在一段式描述方法中可以看到,虽然一个alaways块就可以解决问题,但描述不清晰,不利于维护修改,并且不利用附加约束,不利于综合其和布局布线器对设计的优化;
4、两段式描述法:一个always块描述状态转移,另一个always块描述状态判断转移条件
verilog代码如下:
// 检测“Hello”后led状态翻转 module check_hello( input clk, //50M时钟信号input rst, //低电平复位input [7:0]asci,//字符输入outputreg led //控制led); //状态寄存器reg [4:0]NS; //nextstatereg [4:0]CS; //currentstate //状态独热编码localparam CHECK_H = 5‘b0_0001, CHECK_e = 5‘b0_0010, CHECK_la = 5‘b0_0100, CHECK_lb = 5‘b0_1000, CHECK_o = 5‘b1_0000;//两段式状态机 //第一个always块描述状态转移always@(posedge clk,negedge rst) if(!rst) CS <= CHECK_H; else CS <= NS; //状态转移到下一状态 //第二个always块描述状态输出以及判断状态转移 always@(*) case(CS) CHECK_H: begin led <= 1‘b1;if(asci == "H") NS <= CHECK_e; else NS <= CHECK_H; end CHECK_e: begin led <= 1‘b1;if(asci == "e") NS <= CHECK_la; else NS <= CHECK_H; end CHECK_la: begin led <= 1‘b1;if(asci == "l") NS <= CHECK_lb; else NS <= CHECK_H; end CHECK_lb: begin led <= 1‘b1;if(asci == "l") NS <= CHECK_o; else NS <= CHECK_H; end CHECK_o: beginif(asci == "o") led <= 1‘b0;else led <= 1‘b1; NS <= CHECK_H; enddefaultbegin NS <= CHECK_H; led <= 1‘b1;endendcaseendmodule
原文:https://www.cnblogs.com/Mculover666/p/9091216.html
内容总结
以上是互联网集市为您收集整理的FPGA学习笔记(七)——FSM(Finite State Machine,有限状态机)设计全部内容,希望文章能够帮你解决FPGA学习笔记(七)——FSM(Finite State Machine,有限状态机)设计所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。