状态机FSM的输出如何避免毛刺?

作者:孤独的单刀,文章来源:CSDN博客

写在前面
本文参考自《Coding And Scripting Techniques For FSM Designs WithSynthesis-Optimized, Glitch-Free Outputs》--Clifford E. Cummings。

主要讲述了如何避免FSM输出毛刺。正文中,黑字为内容,浅蓝色字体是我的啰嗦。如果需要英文原文文章,可以评论留邮箱给我。

建议先阅读:FPGA状态机(一段式、二段式、三段式)、摩尔型(Moore)和米勒型(Mealy)

1.0 简介
使用硬件描述语言(HDL)的状态机设计,可以采用诸如Verilog等多种形式,那么所有的形式都有利于综合吗?本文描述了一些常见的编码风格,并重点介绍了两种编码风格----它们使用寄存器输出,非常适合通用的综合技术。

本文将简要描述生成组合逻辑输出的编码风格,然后详细介绍生成寄存器输出的编码风格,并描述为什么寄存器输出的编码风格通常有利于综合策略。

2.0 基本 FSM 结构
有限状态机 (FSM) 的典型框图如图 1 所示。

Moore 状态机是输出只是当前状态的函数的状态机。
Mealy 状态机是输出是当前状态和输入的函数的状态机。

Moore 和 Mealy FSM 都已在数字设计中成功实现。如何为这些状态机生成输出是一个有意思的话题。输出有时由组合逻辑基于与一组状态的比较生成,而有时输出则可以直接从各个状态位导出。

示例 1 中的代码使用通用、高效的 Verilog编码风格来实现图2所示的状态图。


这种编码风格有时被称为具有连续赋值输出的双always块状态机编码风格。本例中的第一个always块用于生成时序状态寄存器,第二个always块用于生成组合的下一状态逻辑,连续赋值用于生成组合输出逻辑。

示例 2 中的代码用于综合处与示例 1 相同的基本逻辑,但输出的生成是通过将输出方程移动到用于生成组合下一状态逻辑的相同always块中来完成的。这是一种常用的双always块编码风格。

这两种编码风格(示例 1 和示例 2)生成的组合输出有两个主要缺点:

组合输出可能会在状态之间出现毛刺。
组合输出消耗总时钟周期的一部分,这些时钟周期可用于由 FSM 输出驱动的逻辑块。
当使用组合逻辑生成模块输出时,在有效时钟沿到来之前,接收模块通过输入和附加组合逻辑传递信号的时间更短。

这种代码风格可以算是三段式的状态机,但是输出是直接使用assign语句来赋值的,所有其输出是组合逻辑。众所周知,组合逻辑来作为输出最大的问题就是容易出现毛刺,从而导致系统出错。但是这种方法在多个使用状态机来解题的情境下经常出现吗,毕竟做题也不会特意来仿真一下毛刺不是?在实际使用中,这种方法是不推荐使用的。一般采用时序逻辑输出的三段式状态机,以便去除毛刺和改善时序。

3.0 综合划分
对设计进行划分以进行综合的一种通用且经过验证的技术是对设计进行划分,以便所有输出都被寄存,所有组合逻辑都在模块的输入端,如图 3 所示。这有时也被称为“cloud-register”划分。

相同综合技术的一种变体是对设计进行划分,以便所有组合逻辑都位于输入端或模块内的寄存器级之间,如图 4 所示。

这种技术之所以重要,并不是因为它一定会使设计变得更好,而是它极大地简化了约束综合设计的任务。

在模块划分的输入和输出上使用组合逻辑可以并且已经成功完成设计,但是这样的设计会使约束设计以便满足时序要求的任务复杂化。

如图 5 所示,如果一个设计需要 10ns 的时钟周期,并且如果模块 A 的输出组合逻辑消耗 3.5ns,那么模块 C 和 D 的输入以及模块 E 的一些输入必须被限制为仅使用6.5ns(包括寄存器的建立时间)。

如果模块 B 在输出组合逻辑中消耗 5ns,则模块 E 的其他输入必须被限制为仅使用 5ns(包括寄存器的建立时间)。

对于这个简单的 5 个模块的设计,制作这些约束的任务并不太难,但是你可以想象一下必须在更大的设计的数十或数百个模块上约束许多个输入,并确保所有约束都要被正确设置,是多大的工作量。这也是寄存模块输出的原因之一。

在时序分析与约束中,我们知道要满足寄存器的建立时间和保持时间。如果寄存器的输入存在过长的组合逻辑(即逻辑级数过大,组合逻辑延时长),则会压缩建立时间slack,导致时序紧张。在组合逻辑的输出添加寄存器是一种常见的时序优化方法,可以切断过长的组合逻辑,将其分为数段,从而将紧缺的slack下发到各个环节,但是也会使得系统的输出延迟(latency)变大。此外,添加寄存器输出也可以有效地滤除毛刺。

4.0 综合时间预算
在题为“Evolvable Makefiles and Scripts for Synthesis”的论文中,描述了一种巧妙的时间预算技术,用于通过将输入和输出约束到时序模块并将时间预算分配应用于纯组合模块来合成许多模块。如果移除纯组合逻辑模块并寄存所有时序模块的输出,则类似于 Ekstrandh 和 Bell 描述的技术将变得更容易实现。

反对寄存输出的一个主要论点是,多个接收模块的输入可能需要冗余组合逻辑。相反,将组合逻辑从某些模块输出移动到接收模块的输入可能有助于提出不同的、更优化的设计划分。

将组合逻辑从模块输出中移开的最佳理由是,它显着减少了综合脚本编写工作,从而更容易满足整体时序约束。对驱动模块中的输出组合逻辑的严格约束和对接收模块中输入组合逻辑的严格时序约束通常不会产生相同的有效逻辑,如果所有组合逻辑都可以与更大的整体时序约束一起优化,则可以推断出相同的有效逻辑。

5.0 寄存FSM 输出
编码 FSM 以便寄存所有模块输出的两种好方法:

1. 生成和寄存"next-outputs"(次态)
2. 编码状态变量,以便每个输出都是寄存状态变量的编码位之一

5.1 三个always块的FSM(三段式状态机)
常用来寄存 FSM 输出的第一种方法是编写两个 always 块 FSM,与示例 1 中相同,但不是使用连续赋值生成输出,而是将第三个块编码为时序always 块以寄存"next outputs",如示例 3 所示。

这种方法需要仔细编码,因为这种风格迫使工程师检查当前状态和输入以确定"next outputs"将是什么。这种方法有点容易出错,但如果输出编码正确,则可以正常工作。

图 6 中的框图显示了由三个 always 块生成的两个顺序逻辑块和一个组合逻辑块。

5.2 输出编码FSM
寄存FSM 输出的第二种有趣方法是选择一种状态编码,该编码强制输出由各个状态寄存器位驱动,如图 7 的框图所示。

以下步骤概述了将输出编码为状态编码一部分的结构化方法:

1.计算状态机中的输出数 (x) 和状态数 (y),并制作一个包含 y+1 行和 x+1 列的表。

2.从左列的第二行开始,列出所有 FSM 状态,向下移动状态机中每个状态的列。这将填充左侧列除了左上角的列单元格。

3.从第一行第二列开始,向右移动,将每个 FSM 输出列为单独的列标题。

4.在列出的状态的输出为高的每个输出列中放置一个“1”,在列出的状态的输出为低的每个输出列中放置一个“0”。


5.填满整个表格后,搜索更多相同的不止一个状态的输出模式。如果没有重复的模式,则使用表中的输出模式作为状态编码。如果所有编码都是唯一的,则不需要额外的状态位,并且每个状态位不仅代表状态编码的一部分,还代表将成为寄存输出位的内容。

注意:FSM 输入不影响状态编码。只有状态数和输出数会影响状态编码。

一般来说,输出模式不会对任何一种状态都是唯一的,并且需要以下额外步骤:

6.圈出表中重复的输出模式,如表 1 所示。

7.如果有两个相同的输出模式,则需要一个额外的状态位来创建唯一的状态编码。如果有三个或四个相同的输出模式,则需要两个额外的状态位来创建唯一的状态编码。如果有五到八个相同的输出模式,则需要三个额外的状态位来创建唯一的状态编码等。

8.在状态名称列和第一个输出列之间添加一个空白列,并将此列标记为“x0”。为每个额外的所需状态位添加另一列,将每一列标记为“x1”、“x2”等。


用所有零填充添加的列,除了带圆圈的冗余编码行。添加二进制编码到冗余编码行的额外列中,以创建唯一的状态编码,如图 10 所示。

表 3 中的状态编码现在将用于进行 Verilog 参数分配以定义每个状态编码。

现在输出已被合并到状态编码中,一个或多个连续赋值语句可以直接驱动输出,其中实际状态位用于驱动输出。由于不需要额外的胶合逻辑来驱动输出,因此输出现在将无毛刺。

Verilog 状态机的输出现在可以通过从状态向量到每个输出进行位选择分配来轻松编码,或者通过将所有输出连接在一起成为一个连续赋值并将所有有效状态位分配给输出,如图所示在示例 4 中。如果需要额外的状态位来创建唯一的状态编码,则输出位将是状态向量的 LSB。

这方法看似说了一大堆,其实仔细看看就知道很简单了:直接将输出使用assign连接到reg变量state上。由于根据冗余数量来设置了多个状态,所以不存在输出逻辑上有组合运算。举个例子:

上图中的rd输出在状态READ和状态DLY均为1,所以直接使用assgin则必然存在组合逻辑--或运算。

使用上述方法后,存在2个冗余状态:READ、DLY,则将reg变量state扩宽1bit来表示,这样就可以直接区分这两个冗余变量,而无需使用组合逻辑。该方法的本质是对状态进行编码,将输出信息编码到状态变量之中。这种方法我个人感觉实用性不大,不如用独热码。

6.0 Mealy输出
异步 Mealy 输出违反了将设计划分为“cloud-register”分组的综合指南。异步 Mealy 输出是当前状态和一个或多个输入的函数的输出,它需要将组合逻辑放置在 Mealy 输
出上,在寄存器之后形成组合逻辑云,如 FSM 模块中所示图 11 的框图。

将异步 Mealy 输出从 FSM 模块移动到一个或多个模块(例如图 12 中所示的模块 C 和 D)的输入端或输入端通常是可行的,这些模块将由 Mealy 输出驱动。

将 Mealy 逻辑从 FSM 模块的输出传输到驱动模块的输入可能会导致推断出额外的逻辑,因为必须从单个输出“云”中获取逻辑并添加到可能的多个输入“云”中。由于添加冗余逻辑而导致的不需要的小幅增加通常可以通过大量简化设计工作和综合脚本来抵消。

7.0 结论

  • 对设计进行划分以使 FSM 的输出上没有组合逻辑,从而显着简化了综合多模块设计的任务。
  • 使用寄存输出对 FSM 进行编码消除了组合输出逻辑。
  • 使用寄存输出对 FSM 进行编码可确保输出无毛刺。
  • 输出编码 FSM 样式是一种有效的技术,用于对 FSM 进行编码以直接从状态寄存器位驱动已寄存的输出。
  • 最新文章

    最新文章