博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[笔记][FPGA]有限状态机FSM学习笔记(三)
阅读量:5076 次
发布时间:2019-06-12

本文共 5216 字,大约阅读时间需要 17 分钟。

0. 简介

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

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

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

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

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

 

图2, 三段式always块

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

1 //    第一个always块,描述当前状态的状态寄存器,non-blocking 2 always @ (posedge clk or negedge rst_n)    begin 3     if (!rst_n) 4         curr_state    <= idle; 5     else 6         curr_state    <= next_state; 7 end 8  9 //    第二个always块,描述状态转移,即下一状态的状态寄存器,blocking10 always @ (*)    begin11     next_state    = idle;    //    初始化12     case (curr_state)13         idle:    begin14             if (...)15                 next_state    = sx;16             else17                 next_state    = sy;18         end19         ...20         default:21             next_state    = sz;22     endcase23 end24 25 //    第三个always块,组合逻辑描述输出,blocking26 always @ (*)    begin27     if (!rst_n)    begin28         o1    = 1'b0;29     end30     else    begin31         case (curr_state)32             s1:    begin33                 o1 = 1'b1;34             end35             ...36             default:    begin37                 o1    = 1'b0;38             end39         endcase40     end41 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。

1 //    第一个always块,描述状态转移和状态寄存器,non-blocking 2 always @ (posedge clk or negedge rst_n)    begin 3     if (!rst_n)    begin 4         curr_state    <= idle; 5     end 6     else    begin 7         case (curr_state) 8         idle:    begin 9             if (...)10                 curr_state    = sx;11             else12                 curr_state    = sy;13         end14         ...15         default:16             curr_state    = sz;17         endcase18     end19 end20 21 //    第二个always块,组合逻辑描述输出,blocking22 always @ (*)    begin23     if (!rst_n)    begin24         o1    = 1'b0;25     end26     else    begin27         case (curr_state)28             s1:    begin29                 o1 = 1'b1;30             end31             ...32             default:    begin33                 o1    = 1'b0;34             end35         endcase36     end37 end

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

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

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

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

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

图4, 一段式always块

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

1 //    一个always块,描述状态转移,状态寄存器,逻辑输出,non-blocking 2 always @ (posedge clk or negedge rst_n)    begin 3     if (!rst_n)    begin 4         curr_state    <= idle; 5         o1            <= 1'b0; 6     end 7     else    begin 8         case (curr_state) 9         idle:    begin10             if (...)    begin11                 curr_state    = sx;12                 if (isignal)    o1 = 1'b1;13                 else            o1 = 1'b0;14             end15             else    begin16                 curr_state    = sy;17                 if (isignal)    o1 = 1'b1;18                 else            o1 = 1'b0;19             end20         end21         ...22         default:    begin23             curr_state    = sz;24             if (isignal)    o1 = 1'b1;25             else            o1 = 1'b0;26         end27         endcase28     end29 end

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

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

4. Mealy状态机相关

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

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

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

1 //    组合逻辑描述输出,blocking 2 always @ (*)    begin 3     if (!rst_n)    begin 4         o1    = 1'b0; 5     end 6     else    begin 7         case (curr_state) 8             s1:    begin 9                 //    添加输入条件判断10                 if (isignal)    o1 = 1'b1;11                 else            o1 = 1'b0;12             end13             ...14             default:    begin15                 o1    = 1'b0;16             end17         endcase18     end19 end

 

转载于:https://www.cnblogs.com/airbird/p/FPGA_FSM_study_3.html

你可能感兴趣的文章
C# 打印机Win32 API,用来探测打印状态
查看>>
hdu 5339 递归枚举
查看>>
mysql 使用积累
查看>>
编程王道,唯“慢”不破
查看>>
Ubuntu16.04.3安装并配置samba方法
查看>>
根据构建类型动态设置AndroidManifest.xml文件中的meta-data
查看>>
[转载] Oracle10g安装
查看>>
[转载] 百科全说——漆浩:怎样健康饮酒远离误区(11-03-10)
查看>>
类数组对象:arguments
查看>>
directive(E).点击显示收起
查看>>
js中的关键字 var
查看>>
L2-005 集合相似度
查看>>
C语言拾遗(四):分析switch语句机制---上篇
查看>>
前端图片压缩上传(纯js的质量压缩,非长宽压缩)
查看>>
unity 中Canvas MatchHeight
查看>>
Quartz.NET-1.0.3 遇到个问题 卡住我差不多大半天 最后发现 原来那个配置文件app.config 关于...
查看>>
PHP快速排序算法
查看>>
PHP违禁词敏感词 全站文件扫描
查看>>
Codevs 2449 骑士精神 2005年省队选拔赛四川
查看>>
learn linux connect
查看>>