0. 简介

  在数电FPGA中,FSM是一个重要的部分,藉此可以完成一些复杂算法的硬件实现等。其中有关于FSM的写法按照always块的个数来划分,又分为一段式、两段式、三段式状态机。顾名思义,一段式就是状态机由一个always块组成;同理,两段式为两个always块,三段式为三个always块组成。

  我们以Moore状态机来进行一段、两段、三段式状态机的讨论,Moore状态机的结构如图1所示。

图1, 时钟同步的Moore状态机结构

1. 三段式状态机(推荐使用)

  上文中我们说道三段式状态机为三个always块,那么根据图1我们可以划分出三段式状态机的三个always块的功能,如图2所示。

图2, 三段式always块

  其中三个always块各自对应三个逻辑块。则可以得出其书写一般如下,其中状态寄存器书写时放在前面,美观整洁,实质上放在第几个always里没有差别。

 //    第一个always块,描述当前状态的状态寄存器,non-blocking
 always @ (posedge clk or negedge rst_n)    begin
     if (!rst_n)
         curr_state    <= idle;
     else
         curr_state    <= next_state;
 end

 //    第二个always块,描述状态转移,即下一状态的状态寄存器,blocking
 always @ (*)    begin
     next_state    = idle;    //    初始化
     case (curr_state)
         idle:    begin
             if (...)
                 next_state    = sx;
             else
                 next_state    = sy;
         end
         ...
         default:
             next_state    = sz;
     endcase
 end

 //    第三个always块,组合逻辑描述输出,blocking
 always @ (*)    begin
     if (!rst_n)    begin
         o1    = 'b0;
     end
     else    begin
         case (curr_state)
             s1:    begin
                 o1 = 'b1;
             end
             ...
             default:    begin
                 o1    = 'b0;
             end
         endcase
     end
 end

其中,有些地方需要注意

a) 第一个always块描绘状态寄存器,为时序逻辑;后两个描述转移和输出,为组合逻辑。
b) 第二个和第三个always块的敏感列表使用always@(*)时,可以减少综合时的error和warning(可能)。
c) 第二块中,描述状态转移时的next_state = idle;其目的为上电初始化后可以使得next_state正常,不加大多数情况也可以,最好加上,避免未知情况的出现。
d) 由于第三段是组合逻辑输出,那么其输出可能产生毛刺,如果时序要求不高,可以在其后使用寄存器打一拍进行优化处理。
e) 在使用到case的情况下,最好做到"full-case"的情况,default不可或缺。

综合上面的代码结构及编写风格,我们可以总结出三段式状态机一些特点三段式状态机是一种推荐的写法

a) 三段式状态机可以清晰完整的显示出状态机的结构。
b) 可以轻易的将状态图state diagram转换为verilog code。
c) 代码清晰,降低编写维护复杂度。d) 在简单状态机(状态少,转移条件少这类)的应用上,三段式代码量和一二段的比较起来长些。

2. 两段式状态机(推荐使用)

  从图1我们得出,若是将三个逻辑块写在两个always块中,有着三种方法,在此我们介绍比较推荐的一种将状态寄存器和状态跳转写在一个always块中,组合逻辑输出写在另一个always块中的形式,如图3所示。

图3, 两段式always块

书写时可以参照以下的格式来书写,由于状态寄存器和状态转移放在了一起,所以为non-blocking,组合逻辑输出仍为blocking。

 //    第一个always块,描述状态转移和状态寄存器,non-blocking
 always @ (posedge clk or negedge rst_n)    begin
     if (!rst_n)    begin
         curr_state    <= idle;
     end
     else    begin
         case (curr_state)
         idle:    begin
             if (...)
                 curr_state    = sx;
             else
                 curr_state    = sy;
         end
         ...
         default:
             curr_state    = sz;
         endcase
     end
 end

 //    第二个always块,组合逻辑描述输出,blocking
 always @ (*)    begin
     if (!rst_n)    begin
         o1    = 'b0;
     end
     else    begin
         case (curr_state)
             s1:    begin
                 o1 = 'b1;
             end
             ...
             default:    begin
                 o1    = 'b0;
             end
         endcase
     end
 end

  由于状态跳转和状态寄存器组合在一起,所以可以去除next_state变量,但对于综合或结构上是没有太大的影响的。

  在编写过程中的一些注意事项和三段式里写的都差不多,在此不做赘述。下面来简单写一下两段式状态机(逻辑跳转和状态寄存器组合一起)的一些特点。

a) 两段式状态机可以较清晰完整的显示出状态机的结构。
b) 可以轻易的将状态图state diagram转换为verilog code。
c) 代码清晰,降低编写维护复杂度。

3. 一段式状态机(不推荐)

  上文中我们说道一段式状态机为一个always块,那么根据图1我们可以知道,一段式状态机要同时包含状态跳转和信号输出,即如图2中红色框线所示。

图4, 一段式always块

  其中将状态跳转、状态寄存器、输出组合逻辑放在一起,所以其中为non-blocking。其写法可参考如下,但是大多情况下不推荐此种写法。

 //    一个always块,描述状态转移,状态寄存器,逻辑输出,non-blocking
 always @ (posedge clk or negedge rst_n)    begin
     if (!rst_n)    begin
         curr_state    <= idle;
         o1            <= 'b0;
     end
     else    begin
         case (curr_state)
         idle:    begin
             if (...)    begin
                 curr_state    = sx;
                 'b1;
                 'b0;
             end
             else    begin
                 curr_state    = sy;
                 'b1;
                 'b0;
             end
         end
         ...
         default:    begin
             curr_state    = sz;
             'b1;
             'b0;
         end
         endcase
     end
 end

  使用三段式后,整体写在一个non-blocking的逻辑块中,但是又由于Moore状态机的输出只是跟当前状态有关的,若将两种逻辑单元使用一个时钟去探测,可能会出现问题,在此的解决办法就是逻辑单元输出时的输出判断使用前一个时钟的next_state状态进行判断或者将输出提前一个时钟,在此需要注意。因为是写在一个always块中,所以next_state也省了,故此只有将输出提前判断一个时钟周期。在此简单总结下使用一段式状态机的一些特点。

a) 将所有的逻辑写在一个always块中,增加代码复杂度,给后期更改维护带来不便。
b) 由于其中有状态寄存器,整体使用non-blockin,描述输出组合逻辑时,需要提前一个时钟,需要额外注意。

4. Mealy状态机相关

  以上都是根据Moore状态机来对各种状态机进行举例,现在对于Mealy状态机的写法大致说明下。

  三段式和二段式(状态跳转和状态寄存器写在一起)的写法仍是推荐写法。但是由于Mealy状态机的输出和输入和状态均有关,此时二段式中的状态寄存器和输出逻辑组合在一起无法和一段式状态机无法正常的表述出Mealy状态机。

  其推荐写法和上述Moore状态机中描述大致相似,只是在逻辑输出时添加上输入判断条件即可,如下。

 //    组合逻辑描述输出,blocking
 always @ (*)    begin
     if (!rst_n)    begin
         o1    = 'b0;
     end
     else    begin
         case (curr_state)
             s1:    begin
                 //    添加输入条件判断
                 'b1;
                 'b0;
             end
             ...
             default:    begin
                 o1    = 'b0;
             end
         endcase
     end
 end

[笔记][FPGA]有限状态机FSM学习笔记(三)的更多相关文章

  1. [原创][FPGA]有限状态机FSM学习笔记(一)

    1. 概述--何为有限状态机FSM? 有限状态机-Finite State Machine,简写为FSM,是表示有限个状态及在这些状态之间的转移和动作等行为的数学模型,在计算机领域有着广泛的应用.通常 ...

  2. [转载][FPGA]有限状态机FSM学习笔记(二)

    1. Mealy和Moore状态机的互换 对于给定的时序逻辑功能,可以用Mealy机实现,也可以用Moore机实现.根据Moore机比Mealy机输出落后一个周期的特性,可以实现两种状态机之间的转换. ...

  3. 【神经网络与深度学习】学习笔记:AlexNet&Imagenet学习笔记

    学习笔记:AlexNet&Imagenet学习笔记 ImageNet(http://www.image-net.org)是李菲菲组的图像库,和WordNet 可以结合使用 (毕业于Caltec ...

  4. 【web开发学习笔记】Structs2 Result学习笔记(三)带參数的结果集

    Result学习笔记(三)带參数的结果集 第一部分:代码 //前端 <head> <meta http-equiv="Content-Type" content= ...

  5. 【工作笔记】BAT批处理学习笔记与示例

    BAT批处理学习笔记 一.批注里定义:批处理文件是将一系列命令按一定的顺序集合为一个可执行的文本文件,其扩展名为BAT或者CMD,这些命令统称批处理命令. 二.常见的批处理指令: 命令清单: 1.RE ...

  6. 【MarkMark学习笔记学习笔记】javascript/js 学习笔记

    1.0, 概述.JavaScript是ECMAScript的实现之一 2.0,在HTML中使用JavaScript. 2.1 3.0,基本概念 3.1,ECMAScript中的一切(变量,函数名,操作 ...

  7. 【web开发学习笔记】Structs2 Result学习笔记(一)简介

    Structs2 Result学习笔记(一)简介 问题一 <struts> <constant name="struts.devMode" value=" ...

  8. 【web开发学习笔记】Structs2 Action学习笔记(两)

    action学习笔记2-大约action method讨论 Action运行的时候并不一定要运行execute方法,能够在配置文件里配置Action的时候用method=来指定运行哪个方法 也能够在u ...

  9. 【web开发学习笔记】Structs2 Result学习笔记(二)动态结果集

    Result学习笔记(二) - 动态结果集     动态结果 一定不要忘了为动态结果的保存值设置set get方法 第一部分:代码 //前端 <% String context = reques ...

随机推荐

  1. 科学计算库Numpy——概述

    Numpy主要用于数组的各种计算. 导入Numpy import numpy as np 数组类型 Numpy的数组类型为numpy.ndarray. array=np.array([1,2,3,4, ...

  2. MyBatis的增删改查操作

    搭建好mybatis之后 进行对数据库的操作 添加语句 在映射文件中添加语句 insert into student(name,age,score) values(#{name},#{age},#{s ...

  3. python基本操作(四)

    与用户交互 为什么交互? 计算机取代人类,解放劳动力 如何交互 print('-'*100) input('请输入你的姓名:') print(""100) Python2和Pyth ...

  4. python3与python2的编码问题

    在讲这个问题之前,我们先说说unicode的工作原理.unicode包含了跟全球所有国家编码的映射关系,就是不管你用哪个国家的编码,unicode都能找到它在unicode中的编码.那么无论你用什么编 ...

  5. stm32定时器学习二——PWM设置

    /* STM32 嵌入式学习入门(5)——PWM的实现 上一篇博文介绍了定时器和PWM的基本的原理,本篇博文从代码层面来介绍PWM的具体实现.同样,还是以博主所用的开发板——正点原子开发板STM32F ...

  6. ACM-ICPC 2018 徐州赛区网络预赛 F. Features Track

    262144K   Morgana is learning computer vision, and he likes cats, too. One day he wants to find the ...

  7. Python虚拟机函数机制之闭包和装饰器(七)

    函数中局部变量的访问 在完成了对函数参数的剖析后,我们再来看看,在Python中,函数的局部变量时如何实现的.前面提到过,函数参数也是一种局部变量.所以,其实局部变量的实现机制与函数参数的实现机制是完 ...

  8. Model View Controller(MVC) in PHP

    The model view controller pattern is the most used pattern for today’s world web applications. It ha ...

  9. sgen.exe 未能运行

    指定的任务可执行文件“sgen.exe”未能运行.文件名或扩展名太长. 解决方式,右键项目属性->生成  把下图红框的“开”设置成“自动”

  10. client三大家族区别(三大家族总结)

    目录 目录 2 今日内容: 4 第1章 第三大家族client 4 1.1 主要成员 4 1.2 三大家族区别(三大家族总结) 5 1.2.1 Width和height 5 1.2.2 top和lef ...