一、状态机基础回顾

状态机这东西,说白了就是数字电路里的「大脑」。我做了十几年RTL设计,可以负责任地告诉你——状态机写得好不好,直接决定了你芯片的成败。今天咱们就从最基础的东西聊起。

1.1 Moore机与Mealy机的区别

这两种状态机的区别,我当年刚入行时也搞混过。其实记住一句话就行:Moore机的输出只跟当前状态有关,Mealy机的输出还跟输入有关。

对比项 Moore机 Mealy机
输出依赖 仅当前状态 当前状态 + 输入
输出时序 比状态变化晚一个时钟 输入变化后立即响应
状态数量 通常较多 通常较少
抗毛刺能力 较强 较弱

我的经验之谈:做控制逻辑时,我偏爱Moore机。为什么?因为输出稳定,不容易出毛刺。但如果你对延迟敏感,比如高速数据通路,Mealy机反而更合适。

举个例子。你设计一个自动售货机,投入硬币后输出饮料。用Moore机的话,你得先进入一个「已投币」状态,下一个时钟才输出饮料。用Mealy机呢?投币瞬间就输出饮料,但万一输入有毛刺,饮料可能就白给了——嗯,这问题我在项目里真遇到过。

1.2 状态编码方式

编码方式选不对,后面优化起来可费劲了。我见过太多新手在这上面栽跟头。

二进制编码

最省触发器的方式。n个状态只需要log₂(n)个触发器。但问题是——状态跳转时多个比特同时变化,容易产生竞争冒险。

// 二进制编码示例
localparam IDLE  = 2'b00;
localparam S1    = 2'b01;
localparam S2    = 2'b10;
localparam S3    = 2'b11;

格雷码编码

相邻状态只有1比特变化。我建议在跨时钟域场景下优先考虑它。为什么?因为亚稳态概率大大降低。

// 格雷码编码示例
localparam IDLE  = 2'b00;
localparam S1    = 2'b01;
localparam S2    = 2'b11;
localparam S3    = 2'b10;

独热码编码

每个状态对应一个触发器,只有1位为1。面积大,但译码逻辑简单,速度最快。

// 独热码编码示例
localparam IDLE  = 4'b0001;
localparam S1    = 4'b0010;
localparam S2    = 4'b0100;
localparam S3    = 4'b1000;
编码方式 触发器数 组合逻辑 速度 适用场景
二进制 最少 复杂 慢 状态数多、面积敏感
格雷码 较少 中等 中等 跨时钟域、低功耗
独热码 最多 简单 快 状态数少(<16)、高速

我曾经踩过的坑:有个项目用了16个状态的独热码,综合后面积爆炸。后来改成格雷码,面积直接砍了一半。所以别盲目追求独热码,状态数超过8个就得掂量掂量。

1.3 三段式写法规范

三段式状态机,我个人认为是RTL设计里最优雅的写法之一。它把状态机拆成三个always块,各司其职。

// 三段式状态机模板
// 第一段:状态转移
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        state <= IDLE;
    else
        state <= next_state;
end

// 第二段:次态逻辑
always @(*) begin
    next_state = state;
    case (state)
        IDLE:   if (start) next_state = S1;
        S1:     if (done)  next_state = S2;
        S2:     next_state = IDLE;
        default: next_state = IDLE;
    endcase
end

// 第三段:输出逻辑
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        out <= 1'b0;
    else begin
        case (state)
            IDLE: out <= 1'b0;
            S1:   out <= 1'b1;
            S2:   out <= 1'b0;
            default: out <= 1'b0;
        endcase
    end
end

我的习惯:第二段用组合逻辑写next_state,第三段用时序逻辑输出。这样综合工具能更好地优化时序。你想想看,如果输出也写成组合逻辑,那毛刺问题就够你喝一壶的。

三段式的核心优势在于:状态转移、次态计算、输出生成完全解耦。改输出逻辑不会影响状态机跳转,调试起来特别方便。

避坑指南:我曾经见过有人把三段式写成两段式,把次态逻辑和输出逻辑混在一起。结果呢?综合后时序一塌糊涂。所以老老实实按三段式来,别耍小聪明。

知识体系总览

下面这张图,是我自己总结的状态机设计核心脉络。你把它记在心里,后面学优化技巧就轻松多了。

状态机设计核心知识体系 状态机类型 Moore机 Mealy机 状态编码方式 二进制 格雷码 独热码 三段式写法 状态转移 次态逻辑 输出生成 核心原则:根据应用场景选择合适类型 → 权衡面积与速度选择编码 → 用三段式保证代码质量 类型决定行为,编码影响性能,写法决定可维护性

好了,第一章的内容就这些。记住:基础不牢,地动山摇。Moore和Mealy的区别、三种编码的取舍、三段式的规范——这些是你后面学优化技巧的根基。

可可精品资料库