[笔记][FPGA]有限状态机FSM学习笔记(三)
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学习笔记(三)的更多相关文章
- [原创][FPGA]有限状态机FSM学习笔记(一)
		
1. 概述--何为有限状态机FSM? 有限状态机-Finite State Machine,简写为FSM,是表示有限个状态及在这些状态之间的转移和动作等行为的数学模型,在计算机领域有着广泛的应用.通常 ...
 - [转载][FPGA]有限状态机FSM学习笔记(二)
		
1. Mealy和Moore状态机的互换 对于给定的时序逻辑功能,可以用Mealy机实现,也可以用Moore机实现.根据Moore机比Mealy机输出落后一个周期的特性,可以实现两种状态机之间的转换. ...
 - 【神经网络与深度学习】学习笔记:AlexNet&Imagenet学习笔记
		
学习笔记:AlexNet&Imagenet学习笔记 ImageNet(http://www.image-net.org)是李菲菲组的图像库,和WordNet 可以结合使用 (毕业于Caltec ...
 - 【web开发学习笔记】Structs2 Result学习笔记(三)带參数的结果集
		
Result学习笔记(三)带參数的结果集 第一部分:代码 //前端 <head> <meta http-equiv="Content-Type" content= ...
 - 【工作笔记】BAT批处理学习笔记与示例
		
BAT批处理学习笔记 一.批注里定义:批处理文件是将一系列命令按一定的顺序集合为一个可执行的文本文件,其扩展名为BAT或者CMD,这些命令统称批处理命令. 二.常见的批处理指令: 命令清单: 1.RE ...
 - 【MarkMark学习笔记学习笔记】javascript/js 学习笔记
		
1.0, 概述.JavaScript是ECMAScript的实现之一 2.0,在HTML中使用JavaScript. 2.1 3.0,基本概念 3.1,ECMAScript中的一切(变量,函数名,操作 ...
 - 【web开发学习笔记】Structs2 Result学习笔记(一)简介
		
Structs2 Result学习笔记(一)简介 问题一 <struts> <constant name="struts.devMode" value=" ...
 - 【web开发学习笔记】Structs2 Action学习笔记(两)
		
action学习笔记2-大约action method讨论 Action运行的时候并不一定要运行execute方法,能够在配置文件里配置Action的时候用method=来指定运行哪个方法 也能够在u ...
 - 【web开发学习笔记】Structs2 Result学习笔记(二)动态结果集
		
Result学习笔记(二) - 动态结果集 动态结果 一定不要忘了为动态结果的保存值设置set get方法 第一部分:代码 //前端 <% String context = reques ...
 
随机推荐
- python学习博客推荐
			
https://www.liaoxuefeng.com/
 - LeetCode(168) Excel Sheet Column Title
			
题目 Given a positive integer, return its corresponding column title as appear in an Excel sheet. For ...
 - #2 create and populate a database && realistic and practical applications
			
The Chapter3 & Chapter4 of this book tells you how to create a realistic app on the web through ...
 - Python之多线程与多进程(二)
			
多进程 上一章:Python多线程与多进程(一) 由于GIL的存在,Python的多线程并没有实现真正的并行.因此,一些问题使用threading模块并不能解决 不过Python为并行提供了一个替代方 ...
 - day08 多线程socket 编程,tcp粘包处理
			
复习下socket 编程的步骤: 服务端: 1 声明socket 实例 server = socket.socket() #括号里不写 默认地址簇使用AF_INET 即 IPv4 ...
 - 利用委托实现自己的数据缓存仓库(附上Demo)
			
Demo源码 写在前面的话 写完这篇博客后,总觉得少了些什么,后来想了下,感觉自己只是把结果给亮了出来,自己为什么想到这么做,这个类库出生的缘由未详述,因此,在本段作下说明,如有不足之处,希望能和大家 ...
 - Oracle 10g Data Pump Expdp/Impdp 详解
			
Data Pump 介绍 在第一部分看了2段官网的说明, 可以看出数据泵的工作流程如下: (1)在命令行执行命令 (2)expdp/impd 命令调用DBMS_DATAPUMP PL/SQL包. 这个 ...
 - 如何通过 Vue-Cli3 - Vuex 完成一个 TodoList
			
昨天大概粗糙的了解了一下Vue的概况之后,并没有从框架.语法的细节来进一步学习.那今天通过一个简单的实例来继续完善一下Vue这方面的空白,用一些看得见的效果摸的着的代码在不断完成小目标的过程中慢慢消化 ...
 - 洛谷9月月赛II 赛后瞎写
			
看错比赛时间了....结果发现的时候已经开始了半个小时,并且当时正准备睡午觉qwq 于是就水了个t1就 去睡 跑了 T2 写着写着然后看了一发评讲被辣鸡思路给绕了进去最后发现自己宛若一个智障 类似桶的 ...
 - cobbler dell r730安装问题(四)
			
环境介绍: 服务器硬件:dell-13代 R730 Intel xeon E5-2600系列CPU:E5-2609 v4.E5-2620 v4.E5-2650 v4 cobbler版本:cobbler ...