1. 状态机基础回顾

各位同学好,我是老李。做数字芯片验证这么多年,我见过太多因为状态机出问题导致芯片翻车的案例。今天咱们先打好基础,聊聊状态机到底是什么玩意儿。

1.1 什么是状态机

状态机,说白了就是一个有记忆的逻辑系统。它能在不同状态之间跳来跳去,每次跳转都取决于当前状态和输入信号。我刚开始学的时候,总觉得这东西很玄乎,后来发现其实就是个有限状态的自动机。

举个例子,你想想看——一个自动售货机。它可能处于“等待投币”、“已投币”、“出货中”这几个状态。你投了币,它就从“等待投币”跳到“已投币”。这不就是状态机吗?

核心要点:状态机 = 当前状态 + 输入条件 → 下一状态 + 输出

1.2 状态机分类:Moore vs Mealy

实际项目中,我们主要用两种状态机。我个人的习惯是,先搞清楚需求再选类型,别一上来就拍脑袋。

对比项 Moore型 Mealy型
输出依赖 仅当前状态 当前状态 + 输入
响应速度 慢一拍(时钟沿后变化) 快(输入变化立即响应)
状态数量 通常较多 通常较少
抗毛刺能力 强 弱(组合逻辑输出)

Moore型:输出只跟当前状态有关。我在项目中遇到过,做SPI控制器时用了Moore型,调试起来特别省心——因为输出稳定,不会因为输入毛刺乱跳。

Mealy型:输出同时依赖当前状态和输入。说白了就是反应更快,但代价是容易受输入干扰。我曾经在一个高速数据通路里用了Mealy型,结果因为输入信号有毛刺,输出乱了一塌糊涂...嗯,从那以后我学会了加输出寄存器。

我的建议:新手先从Moore型入手。等你对时序有了感觉,再尝试Mealy型。别问我怎么知道的——都是泪。

1.3 状态转移图基础

画状态转移图,是设计状态机最重要的一步。你想想看,代码写错了还能改,但状态图画错了,整个设计方向就偏了。

下面这张图,是我用SVG画的一个简单状态机示例。它描述了一个两状态交替的序列检测器——检测到“101”就输出高电平。

S0 IDLE S1 DETECT S2 MATCH in=1 in=0 in=0 in=1 in=0/out=1 in=1 图例: S0 (IDLE) S1 (DETECT) S2 (MATCH)

画状态转移图时,我总结了几个要点:

  • 状态要完整——别漏了任何可能的状态。我曾经漏了一个“复位后”状态,结果仿真跑了一整天都没发现问题,直到上板测试才暴露。
  • 转移条件要互斥——同一个状态下,不能有两个转移条件同时成立。否则状态机就不知道往哪跳了。
  • 要有默认转移——每个状态都要考虑“其他情况”去哪。我习惯加一个default转移,回到IDLE状态。

注意:状态转移图不是画完就完事了。一定要做可达性分析——检查每个状态是否都能从初始状态到达,以及是否都能回到初始状态。我曾经吃过这个亏,有个状态进去了就出不来,芯片直接死锁。

1.4 状态编码的选择

状态编码这事,看着简单,其实坑不少。我常用的编码方式有三种:

  • 二进制编码:状态数少的时候用,省触发器。但跨时钟域时容易出问题。
  • 格雷码:相邻状态只变1位,适合跨时钟域。我在做异步FIFO时必用。
  • 独热码:每个状态一个触发器,译码逻辑简单。FPGA项目里我特别喜欢用,因为LUT资源多,触发器也多。

你想想看,如果状态机有16个状态,二进制编码只需要4个触发器,但译码逻辑复杂;独热码要16个触发器,但译码几乎不需要逻辑。怎么选?看你的资源情况。

我的经验:ASIC项目里,如果面积紧张,用二进制编码;FPGA项目里,如果时序紧张,用独热码。没有的好坏,只有合不合适。

好了,状态机基础就聊到这。记住一句话:状态机设计,七分在规划,三分在编码。把状态转移图画清楚了,代码写起来就是水到渠成的事。

可可精品资料库