状态机基础:概念、分类与状态转移图

各位同学,今天我们来聊聊状态机。说实话,状态机是数字IC设计里最基础、也最核心的内容之一。我刚开始做设计那会儿,总觉得状态机不就是几个状态来回跳嘛,有什么难的?直到有一次,我写的一个通信协议控制器因为状态机设计不合理,导致数据包老是丢包……嗯,从那以后,我再也不敢小看它了。

一、什么是状态机?

状态机,全称是有限状态机(Finite State Machine,FSM)。说白了,就是一个系统在有限个状态之间来回切换的模型。你想想看,我们生活中的红绿灯、电梯、自动售货机,其实都是状态机。

在数字电路里,状态机由三部分组成:

  • 状态寄存器:记住当前在哪个状态
  • 组合逻辑:决定下一个状态是什么
  • 输出逻辑:根据当前状态(或加上输入)产生输出

我个人习惯把状态机想象成一个「有记忆的电路」。组合逻辑没有记忆,但状态机有——它知道之前发生了什么,所以能做出不同的反应。

核心要点:状态机 = 状态 + 转移条件 + 输出。缺一不可。

二、状态机的分类:Moore vs Mealy

状态机主要分两类:Moore型和Mealy型。很多教材讲得特别绕,我换个说法:

  • Moore型:输出只跟当前状态有关。输入变了,输出不会立刻变,要等到下一个时钟沿状态变了才变。
  • Mealy型:输出跟当前状态和输入都有关。输入一变,输出可能立刻跟着变。

我在项目中遇到过这样一个场景:设计一个序列检测器,检测到"101"就输出高电平。用Moore型做,检测到序列后要等一个时钟周期才输出;用Mealy型做,检测到的瞬间就能输出。你想想看,如果这个信号要送给下一级电路做使能,Mealy型就快了一个周期。

特性 Moore型 Mealy型
输出依赖 仅当前状态 当前状态 + 输入
输出时序 时钟沿后变化 输入变化即变化
状态数量 通常较多 通常较少
抗毛刺能力 较强 较弱(组合输出易有毛刺)
典型应用 控制逻辑、协议解析 高速数据通路、流水线控制

我的建议:如果对时序要求严格、怕毛刺,优先用Moore型。如果追求速度、能接受组合输出,Mealy型更合适。

三、状态转移图怎么画?

状态转移图,说白了就是把状态机的逻辑画成一张图。我见过很多新手直接上手写代码,结果状态跳来跳去把自己绕晕了。我的习惯是:先画图,再写代码。图画清楚了,代码就是翻译工作。

画图的基本规则:

  • 圆圈表示状态,里面写上状态名
  • 箭头表示转移方向,箭头上标注转移条件
  • 输出:Moore型写在圆圈里,Mealy型写在箭头上

下面我画一个简单的例子:一个两状态的Moore型状态机,检测输入信号a为高电平时翻转输出b。

S0 b=0 S1 b=1 a=1 a=0 a=0 a=1 Moore型状态转移图示例 检测输入a=1时翻转输出b

这张图里,S0状态输出b=0,S1状态输出b=1。当a=1时从S0跳到S1,a=0时从S1跳回S0。每个状态还有自环,表示条件不满足时保持当前状态。

避坑指南:我曾经犯过一个低级错误——画状态转移图时漏了自环。结果综合出来的电路,状态机在条件不满足时会跑到未知状态去。所以记住:每个状态都要画清楚「条件不满足时怎么办」,要么自环,要么有明确的默认转移。

四、实际设计中的几个要点

讲到这里,我分享几个实际项目中总结的经验:

  1. 状态编码要谨慎:二进制编码省寄存器,但组合逻辑复杂;独热码费寄存器,但组合逻辑简单、速度快。我一般状态少于8个用独热码,多于8个用二进制。
  2. 一定要有默认状态:case语句里一定要写default,把状态机引导到已知的初始状态或IDLE状态。否则综合工具会给你生成锁存器,那玩意儿在FPGA里特别坑。
  3. 状态转移条件要互斥:同一个时钟周期里,不能有两个转移条件同时成立。否则状态机不知道该往哪跳,这叫「竞争」,是设计大忌。
  4. 输出寄存器化:如果怕毛刺,Mealy型的输出最好加一级寄存器打一拍。代价是多一个时钟周期的延迟,但换来的是干净的信号。

一句话总结:状态机设计,图要画清楚,编码要选对,条件要互斥,输出要干净。做到这四点,你的状态机基本不会出大问题。

好了,状态机的基础概念就讲到这里。下一节我们会用实际的Verilog代码来实现这些状态机,到时候我会带着大家一步步写代码、仿真、看波形。嗯,那才是真正见功夫的地方。