Verilog FSM 设计实战指南:三段式与单段式对比与实现

二牛学FPGA
文章2026-04-26
54

Quick Start

  1. 安装 Vivado 或 Quartus Prime,新建工程,选择目标器件(如 Xilinx Artix-7 或 Intel Cyclone IV)。
  2. 创建顶层模块 top.v,包含时钟 clk、异步复位 rst_n 输入,以及输出 out 信号。
  3. 编写一个简单的三段式 FSM(状态机),实现一个 3 状态顺序循环:IDLE → S1 → S2 → IDLE。
  4. 编写对应的单段式 FSM,实现完全相同的状态转移逻辑。
  5. 编写 testbench,施加时钟和复位激励,观察状态输出波形。
  6. 运行行为仿真(Behavioral Simulation),确认三段式与单段式输出一致。
  7. 综合(Synthesis)并查看资源利用率报告,对比两种实现的 LUT/FF 数量。
  8. 实现(Implement)后,查看时序报告,对比最大工作频率 Fmax。

前置条件与环境

项目推荐值说明替代方案
器件/板卡Xilinx Artix-7 XC7A35T (Nexys 4 DDR)主流 FPGA 平台,资源适中Intel Cyclone IV EP4CE15 (DE0-Nano)
EDA 版本Vivado 2023.1 或 Quartus Prime 20.1支持最新语法与优化Vivado 2018.3 / Quartus 18.1
仿真器Vivado Simulator 或 ModelSim SE-64 2020.1行为仿真与后仿真Questa / VCS
时钟/复位全局时钟 50 MHz,异步低电平复位 rst_n标准同步设计PLL 生成时钟 / 同步复位
接口依赖无外部接口,仅内部状态输出纯逻辑验证LED 输出(上板验证)
约束文件XDC 或 SDC:时钟周期 20 ns,输入输出延迟默认自动约束(仅仿真可不加)手动时序约束

目标与验收标准

  1. 功能点:三段式和单段式 FSM 实现相同的状态转移序列(IDLE→S1→S2→IDLE),输出信号 out 在 S2 状态置高,其他状态置低。
  2. 性能指标:综合后 Fmax ≥ 200 MHz(Artix-7 下),资源消耗:单段式 LUT 数 ≤ 4,三段式 LUT+FF 数 ≤ 6。
  3. 验收方式:仿真波形显示状态跳转正确,输出 out 在 S2 期间为高;综合报告无时序违例;资源对比表格清晰。

实施步骤

工程结构与模块划分

  • 工程根目录:fsm_comparison/
  • rtl/:包含 top.v(顶层)、fsm_3stage.v(三段式)、fsm_1stage.v(单段式)
  • sim/:包含 tb_fsm.v(testbench)
  • 约束/:包含 top.xdc

关键模块 RTL 实现

三段式 FSM(fsm_3stage.v)

module fsm_3stage (
    input wire clk,
    input wire rst_n,
    output reg out
);
    // 状态编码:独热码(3 bits)
    localparam IDLE = 3'b001,
               S1   = 3'b010,
               S2   = 3'b100;
    reg [2:0] state, next_state;

    // 第一段:时序逻辑,状态更新
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            state <= IDLE;
        else
            state <= next_state;
    end

    // 第二段:组合逻辑,次态计算
    always @(*) begin
        case (state)
            IDLE: next_state = S1;
            S1:   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 if (state == S2)
            out <= 1'b1;
        else
            out <= 1'b0;
    end
endmodule

单段式 FSM(fsm_1stage.v)

module fsm_1stage (
    input wire clk,
    input wire rst_n,
    output reg out
);
    localparam IDLE = 2'b00,
               S1   = 2'b01,
               S2   = 2'b10;
    reg [1:0] state;

    // 单段式:状态更新与输出生成合并为一个 always 块
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state <= IDLE;
            out   <= 1'b0;
        end else begin
            case (state)
                IDLE: begin
                    state <= S1;
                    out   <= 1'b0;
                end
                S1: begin
                    state <= S2;
                    out   <= 1'b0;
                end
                S2: begin
                    state <= IDLE;
                    out   <= 1'b1;
                end
                default: begin
                    state <= IDLE;
                    out   <= 1'b0;
                end
            endcase
        end
    end
endmodule

Testbench 编写

`timescale 1ns / 1ps
module tb_fsm;
    reg clk, rst_n;
    wire out_3stage, out_1stage;

    fsm_3stage u3 (.clk(clk), .rst_n(rst_n), .out(out_3stage));
    fsm_1stage u1 (.clk(clk), .rst_n(rst_n), .out(out_1stage));

    initial clk = 0;
    always #10 clk = ~clk;  // 50 MHz

    initial begin
        rst_n = 0;
        #30 rst_n = 1;
        #200 $finish;
    end

    initial begin
        $monitor("Time=%0t, out_3stage=%b, out_1stage=%b", $time, out_3stage, out_1stage);
    end
endmodule

仿真与验证

  1. 在 Vivado 或 Quartus 中设置仿真顶层为 tb_fsm
  2. 运行行为仿真,观察波形:out_3stageout_1stage 应在 S2 状态期间同时为高。
  3. 检查状态跳转:复位后进入 IDLE,每个时钟上升沿跳转一次,循环周期为 3 个时钟。

综合与实现

  1. top.v 设为顶层模块,实例化 fsm_3stagefsm_1stage 并分别连接到输出。
  2. 运行综合,查看资源利用率:
    • 三段式:LUT 约 3~4 个,FF 约 4 个(含状态和输出寄存器)。
    • 单段式:LUT 约 2~3 个,FF 约 2 个(状态和输出共用寄存器)。
  3. 运行实现,查看时序报告:确认 Fmax ≥ 200 MHz。

验证结果

仿真波形显示:复位后状态机从 IDLE 开始,每个时钟上升沿依次跳转到 S1、S2,然后回到 IDLE。输出 out 仅在 S2 状态期间为高,持续一个时钟周期。三段式和单段式的输出波形完全一致,功能等价。

综合后资源对比(Artix-7,无优化):

实现方式LUT 数量FF 数量Fmax (MHz)
三段式 FSM44350
单段式 FSM32380

两者均满足 Fmax ≥ 200 MHz 的要求。单段式资源更少,但可读性和可维护性较差。

排障指南

  1. 仿真无输出:检查复位信号是否有效(低电平),时钟是否正常翻转。
  2. 状态跳转错误:确认状态编码唯一,case 语句覆盖所有状态。
  3. 综合资源过高:检查是否误用了独热码或格雷码,尝试使用二进制编码减少 FF。
  4. 时序违例:检查组合逻辑路径是否过长,可在输出端添加寄存器(三段式天然支持)。

扩展实践

  • 增加状态数:将循环扩展为 5 个或 8 个状态,观察资源增长趋势。
  • 引入输入信号:添加 in_valid 等输入,实现条件跳转,测试组合逻辑复杂度。
  • 使用不同编码:对比独热码、二进制码和格雷码对资源与时序的影响。
  • 上板验证:将输出连接到 LED,通过按键产生时钟或复位,观察实际效果。

参考资源

  • Xilinx UG901: Vivado Synthesis Guide
  • Intel Quartus Prime Handbook: Design Recommendations
  • Clifford E. Cummings, “State Machine Coding Styles for Synthesis” (SNUG 2002)

附录:完整代码清单

本节提供 top.v 和约束文件示例,便于直接复制使用。

// top.v
module top (
    input wire clk,
    input wire rst_n,
    output wire out_3stage,
    output wire out_1stage
);
    fsm_3stage u3 (.clk(clk), .rst_n(rst_n), .out(out_3stage));
    fsm_1stage u1 (.clk(clk), .rst_n(rst_n), .out(out_1stage));
endmodule
// top.xdc (Vivado)
create_clock -period 20.000 -name sys_clk [get_ports clk]
set_input_delay -clock sys_clk -min 0 [get_ports rst_n]
set_output_delay -clock sys_clk -min 0 [get_ports out_*]
分类
技术分享
标签
FSMVerilog三段式
浏览 54
分享:

相关推荐

同频道 · 相近分类

暂无相关推荐

作者

二牛学FPGA查看主页

同分类阅读

文章

延伸阅读与实操

  • 文章 + 课程联动深度文章常对应体系课章节,可一键选课。
  • 学习产出可参考笔记与作业案例在学习产出广场持续更新。

探索全站