第四节 状态表设计:从逻辑到表格的转化

状态表,说白了就是状态机的「身份证」。它把状态机里那些抽象的状态跳转、输出逻辑,全部整理成一张清清楚楚的表格。我刚开始学状态机时,总觉得画状态图就够了,直到有一次项目里状态多了起来,才发现没有状态表,调试起来简直像在迷宫里找路。

今天我们就来聊聊状态表设计的三个核心问题:表的结构长什么样?状态怎么编码?如何从状态图推导出状态表?

一、状态表的结构:三列定乾坤

一张标准的状态表,其实就三列:当前状态、下一状态、输出。嗯,就这么简单。但你别小看这三列,它们把状态机的全部行为都装进去了。

我习惯把状态表写成这样:

当前状态 输入条件 下一状态 输出
S0 in=0 S0 out=0
S0 in=1 S1 out=0
S1 in=0 S0 out=1
S1 in=1 S1 out=1

你看,每一行就是一个「如果当前在某个状态,遇到某个输入,那么下一步去哪、输出什么」。这就是状态机的全部逻辑。

核心要点:状态表是状态图的「表格化翻译」。状态图里每个箭头,对应状态表里的一行。箭头越多,行数越多。

二、状态编码:三种常见套路

状态编码,就是把状态名字(比如S0、S1)换成二进制数。为什么?因为硬件只认识0和1。这里我给大家介绍三种最常见的编码方式,每种都有它的脾气。

1. 二进制编码

最直观的方式。比如4个状态,就用2位二进制数:00、01、10、11。说白了就是按顺序编号。

优点:用的触发器最少。4个状态只需要2个触发器。
缺点:状态跳转时可能有多位同时变化,容易产生毛刺。我在一个高速计数器项目里吃过这个亏,当时状态跳转时出现了短暂的错误状态,排查了好久才发现是二进制编码的锅。

2. 格雷码编码

格雷码的特点是:相邻状态之间只有1位不同。比如:00→01→11→10。你想想看,这样跳转时就不会有多位同时变化的问题了。

优点:抗干扰能力强,适合高速电路。
缺点:编码逻辑比二进制复杂一点。

我的建议:如果你的状态机是顺序跳转的(比如计数器、流水线控制),格雷码是首选。我曾经在一个DDR控制器里用了格雷码,时序收敛轻松了很多。

3. 独热码编码

独热码,就是每个状态用一个独立的触发器。比如4个状态,就用4位:0001、0010、0100、1000。任何时候只有1位是1,其他都是0。

优点:译码逻辑超级简单,速度快。而且状态跳转时只有2位变化(旧状态变0,新状态变1)。
缺点:用的触发器多。N个状态需要N个触发器。

注意:独热码虽然浪费触发器,但在FPGA里反而很受欢迎。因为FPGA的触发器资源丰富,而查找表资源有限。独热码的译码逻辑简单,能省查找表。我做过一个项目,状态机有20多个状态,用二进制编码时序跑不过,换成独热码后一次通过。

三、状态表推导:从图到表的实战

好了,理论说完了,我们来动手。假设有一个简单的状态机:检测输入序列「101」,检测到后输出1。

状态图是这样的:

S0 S1 S2 in=0 in=1 in=0 in=1 in=0 in=1 S2输出out=1

从这张图推导状态表,其实就三步:

  1. 列出所有状态:S0、S1、S2
  2. 对每个状态,列出所有可能的输入:in=0和in=1
  3. 根据箭头,填写下一状态和输出

推导出来的状态表是这样的:

当前状态 输入 下一状态 输出
S0 0 S0 0
S0 1 S1 0
S1 0 S2 0
S1 1 S1 0
S2 0 S0 1
S2 1 S2 1

推导口诀:「每个状态每个输入,看箭头找下一站,看圆圈找输出。」

嗯,这里要注意一点:如果某个状态在某个输入下没有箭头,那说明这个组合不会出现。但在实际设计中,我建议你还是补上这一行,让下一状态指向一个「非法状态」或者回到初始状态。为什么?因为硬件不会「不会出现」,万一干扰信号来了,状态机跑飞了怎么办?

四、编码后的状态表

假设我们用二进制编码:S0=00, S1=01, S2=10。那么状态表就变成了:

当前状态(Q1Q0) 输入(in) 下一状态(D1D0) 输出(out)
00 0 00 0
00 1 01 0
01 0 10 0
01 1 01 0
10 0 00 1
10 1 10 1

你看,到了这一步,状态表已经可以直接用来写Verilog代码了。D1和D0就是触发器的输入,out就是组合逻辑输出。

避坑指南:我曾经在编码时漏掉了一个状态(比如11没用到),结果仿真没问题,上板子就出bug。后来养成了习惯:编码时把未用状态也写上,指向一个安全状态。这叫「容错设计」,说白了就是给状态机买个保险。

五、三种编码的对比总结

编码方式 触发器数量 速度 抗干扰 适用场景
二进制 最少(log2N) 中等 一般 状态少、资源紧张
格雷码 最少(log2N) 中等 好 顺序跳转、高速电路
独热码 最多(N个) 快 好 FPGA、状态多、要求速度

我个人习惯是:FPGA项目用独热码,ASIC项目用二进制或格雷码。当然,这不是铁律,具体用哪种,还得看你的资源情况和时序要求。

好了,状态表设计就聊到这里。记住:状态表是状态机的「施工图纸」,画好了它,后面的代码实现就是照图施工的事。


可可精品资料库