A.20 时序逻辑实例四:状态机(三段式描述)

什么叫做三段式描述的状态机?

三段,可以理解为三个always程序块。

(1)第一个always程序块

采用同步时序逻辑电路描述状态转移。

(2)第二个always程序块

采用组合逻辑电路判断状态转移条件并描述状态转移规律。

(3)第三个always程序块

采用同步时序逻辑将结果寄存后输出。

两者的区别是将原先第二个always程序块中对y和z的组合逻辑输出改为了第三个always块的时序逻辑的寄存输出

其实就这么简单,不少网络以及相关书籍上把它讲复杂了,甚至还给讲错了。

网络上随便搜索“三段式状态机”,基本给出的第三段always块的例子基本都是基于next_state输出的,很少看到有基于current_state输出的,这就形成了一种思维定势,认为三段式的第三段只能基于next_state描述,其实这是不对的。

应该说不管基于current_state还是next_state,目的都是要将最后输出的结果进行时钟同步后寄存器输出,并不拘泥于实现的形式,比如本节给出的例子中的第三个always块就并不是像书上和网络上那样都基于next_state来描述实现的。

这种错误的地方,除了网上以外,书本上要么没讲,要么提到的地方存在问题,至少我看到的地方有出现这种类似的错误,比如:EDA先锋工作室的《设计与验证Verilog HDL》就出现了这种错误。

下面用二段式改三段式的过程来给大家说明这两种描述方式的区别。

两段式改三段式过程

这是原本的两段式实现的代码:

//文件路径:a.19/src/sell.v
module sell(clk,rst_n,a,b,y,z);parameter S0 = 1'b0;parameter S1 = 1'b1;input clk;input rst_n;input a,b;output reg y,z;reg current_state;reg next_state;always@(posedge clk or negedge rst_n)beginif(!rst_n)current_state <= S0;elsecurrent_state <= next_state;endalways@(current_state or a or b)beginy = 0;z = 0;case(current_state)S0: beginif((a == 1'b0) && (b == 1'b1))beginy = 1;next_state = S0;endelse if((a == 1'b1) && (b == 1'b0))next_state = S1;elsenext_state = S0;endS1: beginif((a == 1'b0) && (b == 1'b0))next_state = S1;else if((a == 1'b0) && (b == 1'b1))beginy = 1;z = 1;next_state = S0;endelse if((a == 1'b1) && (b == 1'b0))beginy = 1;next_state = S0;endelsenext_state = S0;endendcaseendendmodule

下面对其一步步改造。

第一步

将第二个always程序块中的输出y和z部分挪到第三个always块中,注意第三个always块为时序逻辑,采用非阻塞赋值。

module sell(clk,rst_n,a,b,y,z);parameter S0 = 1'b0;parameter S1 = 1'b1;input clk;input rst_n;input a,b;output reg y,z;reg current_state;reg next_state;always@(posedge clk or negedge rst_n)beginif(!rst_n)current_state <= S0;elsecurrent_state <= next_state;endalways@(current_state or a or b)beginy = 0;z = 0;case(current_state)S0: beginif((a == 1'b0) && (b == 1'b1))beginy = 1;next_state = S0;endelse if((a == 1'b1) && (b == 1'b0))next_state = S1;elsenext_state = S0;endS1: beginif((a == 1'b0) && (b == 1'b0))next_state = S1;else if((a == 1'b0) && (b == 1'b1))beginy = 1;z = 1;next_state = S0;endelse if((a == 1'b1) && (b == 1'b0))beginy = 1;next_state = S0;endelsenext_state = S0;endendcaseendalways@(posedge clk or negedge rst_n)beginif(!rst_n)beginy <= 0;z <= 0;endelse begincase(current_state)S0: beginif((a == 1'b0) && (b == 1'b1))beginy <= 1;endelse beginy <= 0;z <= 0;endendS1: beginif((a == 1'b0) && (b == 1'b1))beginy <= 1;z <= 1;endelse if((a == 1'b1) && (b == 1'b0))beginy = 1;z = 0;endelse beginy <= 0;z <= 0;endendendcaseendend    endmodule

第二步

删除第二个always块中的y和z部分。

module sell(clk,rst_n,a,b,y,z);parameter S0 = 1'b0;parameter S1 = 1'b1;input clk;input rst_n;input a,b;output reg y,z;reg current_state;reg next_state;always@(posedge clk or negedge rst_n)beginif(!rst_n)current_state <= S0;elsecurrent_state <= next_state;endalways@(current_state or a or b)begincase(current_state)S0: beginif((a == 1'b0) && (b == 1'b1))beginnext_state = S0;endelse if((a == 1'b1) && (b == 1'b0))next_state = S1;elsenext_state = S0;endS1: beginif((a == 1'b0) && (b == 1'b0))next_state = S1;else if((a == 1'b0) && (b == 1'b1))beginnext_state = S0;endelse if((a == 1'b1) && (b == 1'b0))beginnext_state = S0;endelsenext_state = S0;endendcaseendalways@(posedge clk or negedge rst_n)beginif(!rst_n)beginy <= 0;z <= 0;endelse begincase(current_state)S0: beginif((a == 1'b0) && (b == 1'b1))beginy <= 1;endelse beginy <= 0;z <= 0;endendS1: beginif((a == 1'b0) && (b == 1'b1))beginy <= 1;z <= 1;endelse if((a == 1'b1) && (b == 1'b0))beginy = 1;z = 0;endelse beginy <= 0;z <= 0;endendendcaseendend    endmodule

第三步

化简合并第二个always块中的逻辑即可得到最终的三段式状态机描述代码。

//文件路径:a.20/src/sell.v
module sell(clk,rst_n,a,b,y,z);parameter S0 = 1'b0;parameter S1 = 1'b1;input clk;input rst_n;input a,b;output reg y,z;reg current_state;reg next_state;always@(posedge clk or negedge rst_n)beginif(!rst_n)current_state <= S0;elsecurrent_state <= next_state;endalways@(current_state or a or b)begincase(current_state)S0: beginif((a == 1'b1) && (b == 1'b0))next_state = S1;elsenext_state = S0;endS1: beginif((a == 1'b0) && (b == 1'b0))next_state = S1;elsenext_state = S0;endendcaseendalways@(posedge clk or negedge rst_n)beginif(!rst_n)beginy <= 0;z <= 0;endelse begincase(current_state)S0: beginif((a == 1'b0) && (b == 1'b1))beginy <= 1;endelse beginy <= 0;z <= 0;endendS1: beginif((a == 1'b0) && (b == 1'b1))beginy <= 1;z <= 1;endelse if((a == 1'b1) && (b == 1'b0))beginy = 1;z = 0;endelse beginy <= 0;z <= 0;endendendcaseendendendmodule

注意这里用二段式改三段式的过程只是为了给大家说明这两种描述方式的区别,并不是让你通过先写两段式,再写三段式的过程来做设计实现。

实际上, 你完全可以直接编写实现三段式的Verilog代码,比如就上面的这个代码,我们来好好思考一下内部的转换逻辑就知道该怎么写了。

下面带着大家来走一遍这个思考过程。

测试模块

和之前一样,这里不再列出。

仿真验证

运行本章节对应目录的run.do脚本进行仿真,可以看到波形如下:

首先可以判断结果也是正确的。

对比之前的波形:

可以发现,三段式状态机描述通过将结果y和z寄存器后输出,使得其与时钟进行同步,输出电平以时钟周期为单位进行了整型。

简单说,之前采用组合逻辑输出,因此输出结果是会立刻变化的,而现在采用了与时钟同步的寄存器对结果进行寄存后再输出,因此输出的y和z波形是以时钟周期为电平单位变化的,只有在时钟的跳变沿才会产生变化,即不像组合逻辑那样会立刻产生变化。

这样一来的好处主要是改善了时序条件,便于后期满足电路的时序要求,消除了组合逻辑带来的毛刺。

但是三段式要相对复杂一点,多写了一个always块来将结果寄存器输出的时序逻辑,从而综合后的电路面积可能会(不一定)相对更多一些。

但为了提高设计的稳定性,推荐采用三段式描述进行状态机的设计。

公众号:程序员Marshall

数电和Verilog-时序逻辑实例四:状态机(三段式描述)相关推荐

  1. (40)Verilog实现序列10111【状态机三段式】

    (40)Verilog实现序列10111[状态机三段式] 1.1 目录 1)目录 2)FPGA简介 3)Verilog HDL简介 4)Verilog实现序列10111[状态机三段式] 5)结语 1. ...

  2. Verilog时序逻辑硬件建模设计(四)移位寄存器

    Verilog时序逻辑硬件建模设计(四)移位寄存器 -Shift Register 没有任何寄存器逻辑,RTL设计是不完整的.RTL是寄存器传输级或逻辑,用于描述依赖于当前输入和过去输出的数字逻辑. ...

  3. 数电基础:时序逻辑电路

    虽然每个数字电路系统可能包含有组合电路,但是在实际应用中绝大多数的系统还包括存储元件,我们将这样的系统描述为时序电路. 时序电路是由最基本的逻辑门电路加上反馈逻辑回路(输出到输入)或器件组合而成的电路 ...

  4. 电赛经历--记难忘的四天三夜

    一个很菜很菜的菜鸡的电赛经历,但对于本人却意义深刻,对别人或许有启发,大佬勿喷 从大一起还没有参加过一个需要连续熬夜的比赛,记得第一次了解到电子设计大赛时,了解到他需要熬过四天三夜之后做出一个电子作品 ...

  5. verilog状态机 三段式 状态机 (代码 可以运行)

    代码在git link "硬件设计很讲究并行设计思想,虽然用Verilog描述的电路大都是并行实现的,但是对于实际的工程应用,往往需要让硬件来实现一些具有一定顺序的工作,这就要用到状态机思想 ...

  6. 【数电】Verilog GDL 语言

    目录: 新建的时候: 查看波形的时候. 查看原理图: 后缀是 bsf 这个是看RTL的 组合器件图: 后缀是 bdf 期中考试 ,触发器以及 之前的内容. File -> New Project ...

  7. 【数电】同步时序电路与异步时序电路

    中小规模电路常使用同步,因为设计简单 大规模(如现在的芯片),常采用局部同步,整体异步的方式,以减小同步电路下管子同时打开的动态功耗 Mealy型和Moore型的区别在于:输出Y是否与时钟同步 Mea ...

  8. 基于FPGA的数字电子琴——数电小系统设计【数字电子技术】(使用Vivado中的verilog语言)含piano代码文件(全)

    目录 一.电路功能描述 二.方案设计 1. 总体设计方案 2. 对原理框图或程序流程图做出简单解释 3. 各模块介绍 3.1 音频驱动模块 3.2 LED显示模块 3.3 数码管显示模块 3.4 矩阵 ...

  9. Verilog时序电路设计指南

    Verilog时序电路设计指南 没有时序电路设计准则的RTL设计可能会导致性能低下. 本文关键指南包括在顺序设计中使用非阻塞赋值.使用同步复位和时钟选通.详细描述了在设计中使用流水线阶段的指南,这些指 ...

最新文章

  1. 【透明版九宫格背景图片】仅依靠background的几个属性组合搭配出酷炫的透明背景卡片效果→适用于大数据可视化、数据大屏展示页面
  2. 统计学习导论 基于R应用——作业 3
  3. SublimeText3: ImportError: No module named ‘urllib2′
  4. 百善计算机学习,党建引领学做合一,志愿服务助力乡村振兴——计算机工程学院开展“百善孝为先”主题宣传文化墙墙绘涂鸦活动...
  5. 《代码大全》阅读笔记-5-软件构建中的设计
  6. mariadb数据库服务
  7. 学习计算机如何有一个质的飞越?
  8. 33个训练大脑的小方法
  9. element table实现前端分页
  10. 大专计算机档案,大专档案自我鉴定(精选5篇)
  11. 苹果用计算机加个微信怎么弄的,教你苹果怎么用双开微信,就是这么简单!
  12. 教育培训行业市场营销推广的主要方式有哪些
  13. IntelliJ IDEA 快捷键及模板Templates设置
  14. Linux学习笔记:DNS
  15. #来陀螺问答,问大V#交易所专场优质问答精选
  16. createjs中的Graphics
  17. 华一:5年资深工具控告诉你 “ AI 时代” 最重要的技能是什么?
  18. 如何查看隐藏的文件夹
  19. CC2640R2F BLE5.0 蓝牙协议栈GAP GATT 服务(GGS)
  20. sldprt文件用什么软件打开(手机sldprt文件查看器)

热门文章

  1. html5 小游戏 404页面,原来404页面可以这样做
  2. Exadata 机器介绍
  3. 连毕马威也看好这家金融科技公司,面对AI不跟风、有理想!
  4. java.lang.IllegalArgumentException: Can not set int field com.yhq.domain.BookBorrow.fine to null val
  5. 基于室内导航的现有的6种解决方案
  6. 双摄像头立体成像(二)-摄像头标定
  7. XML 文件结构与语法
  8. Linux中more命令的使用,Linux中more命令使用详解教程
  9. 采用蒙特卡洛法实现机器人工作空间仿真 附matlab源码
  10. 一篇文章带你了解业务流程图与功能流程图的区别