第四章 Verilog进阶:时序逻辑与状态机设计

各位同学,欢迎来到第四章。前面我们聊完了组合逻辑,说白了就是那些“输入一变,输出立马跟着变”的电路。但真实的芯片里,大部分功能都依赖时序逻辑——也就是带记忆的电路。

我个人习惯把时序逻辑比作“有节拍的舞蹈”。每个时钟上升沿,就是一声鼓点。鼓点一响,大家统一行动。没有时钟,整个系统就乱套了。好,我们直接进入正题。

4.1 时钟与复位——芯片的“心跳”和“重启键”

时钟信号,是芯片里最干净的信号之一。为什么说“干净”?因为它的抖动、毛刺必须严格控制。我在项目中遇到过因为时钟树没做好,导致芯片在高频下直接罢工的情况。嗯,那真是血泪教训。

复位信号呢?它让所有寄存器回到一个已知的初始状态。上电瞬间,复位信号拉低,所有寄存器清零。然后复位释放,系统开始跑。

看一个最简单的D触发器代码:

module dff (
    input  clk,
    input  rst_n,   // 低电平复位
    input  d,
    output reg q
);

always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        q <= 1'b0;
    else
        q <= d;
end

endmodule

这里有个细节:always @(posedge clk or negedge rst_n)。敏感列表里同时写了时钟和复位。这叫异步复位——复位信号不需要等时钟,直接生效。

⚠️ 我曾经踩过的坑:异步复位的释放时机很关键。如果复位释放时刚好靠近时钟沿,可能产生亚稳态。解决办法是加一个“复位同步器”,把异步复位信号打两拍再释放。

同步复位呢?写法是这样的:

always @(posedge clk) begin
    if (!rst_n)
        q <= 1'b0;
    else
        q <= d;
end

同步复位只认时钟沿。好处是时序分析简单,坏处是复位信号宽度必须大于一个时钟周期。你想想看,如果复位脉冲太窄,时钟沿没抓到,那就等于没复位。

💡 我的建议:实际项目中,我倾向于用异步复位、同步释放的方式。既保证了复位及时,又避免了亚稳态问题。代码模板我放在后面的章节里。

4.2 状态机设计——Moore vs Mealy

状态机,说白了就是“根据当前状态和输入,决定下一步去哪”。芯片里的控制逻辑,十有八九都是状态机。

两种经典类型:Moore型Mealy型

类型 输出依赖 特点 典型场景
Moore 仅当前状态 输出稳定,无毛刺 按键消抖、协议解析
Mealy 当前状态 + 输入 响应快,可能产生毛刺 高速数据通路、握手协议

我个人习惯:能用Moore就用Moore。为什么?因为输出只跟状态有关,时序分析简单,不容易出幺蛾子。Mealy虽然响应快,但输入直接跑到输出,组合逻辑路径长,容易产生毛刺。

来看一个Moore状态机的例子——一个简单的“01序列检测器”:

module seq_detector_moore (
    input  clk,
    input  rst_n,
    input  din,
    output reg dout
);

// 状态编码
localparam IDLE = 2'b00;
localparam S1   = 2'b01;  // 收到0
localparam S2   = 2'b10;  // 收到01

reg [1:0] state, next_state;

// 状态寄存器
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 (din == 1'b0) next_state = S1;
        S1:   if (din == 1'b1) next_state = S2;
               else            next_state = S1;
        S2:   if (din == 1'b0) next_state = S1;
               else            next_state = IDLE;
        default: next_state = IDLE;
    endcase
end

// 输出逻辑(Moore型:只跟state有关)
always @(*) begin
    dout = (state == S2) ? 1'b1 : 1'b0;
end

endmodule

注意看,输出dout只跟state有关,跟din没关系。这就是Moore的典型特征。

换成Mealy呢?输出逻辑变成这样:

// Mealy型输出:同时依赖state和din
always @(*) begin
    dout = (state == S1 && din == 1'b1) ? 1'b1 : 1'b0;
}

你看,Mealy在S1状态下,只要输入为1,立刻输出1。比Moore少了一个状态(不需要S2)。但代价是输出路径上多了组合逻辑。

🔑 核心要点:

  • Moore:输出稳定,状态数多
  • Mealy:响应快,状态数少,但输出可能有毛刺
  • 选型原则:控制逻辑用Moore,高速数据通路用Mealy

4.3 Testbench编写基础——怎么验证你的设计?

写完了RTL,总得测一测吧?Testbench就是用来干这个的。说白了,就是模拟一个“测试环境”,给设计喂激励,看输出对不对。

一个基本的testbench结构:

`timescale 1ns/1ps

module tb_seq_detector;

// 信号声明
reg  clk;
reg  rst_n;
reg  din;
wire dout;

// 实例化DUT
seq_detector_moore u_dut (
    .clk  (clk),
    .rst_n(rst_n),
    .din  (din),
    .dout (dout)
);

// 时钟生成
initial begin
    clk = 0;
    forever #5 clk = ~clk;  // 10ns周期,100MHz
end

// 测试激励
initial begin
    // 初始化
    rst_n = 0;
    din   = 0;
    #20;
    rst_n = 1;
    #10;

    // 输入序列:0 1 0 1 1 0 1
    din = 0; #10;
    din = 1; #10;
    din = 0; #10;
    din = 1; #10;
    din = 1; #10;
    din = 0; #10;
    din = 1; #10;

    #50;
    $finish;
end

// 波形dump
initial begin
    $dumpfile("wave.vcd");
    $dumpvars(0, tb_seq_detector);
end

endmodule

这里有几个关键点:

  • 时钟生成:用forever循环产生周期信号。我习惯用#5翻转,这样周期就是10ns,对应100MHz。
  • 激励时序:每个数据保持一个时钟周期。注意复位释放后要等一拍再给数据。
  • 波形dump$dumpfile$dumpvars是SystemVerilog的波形输出命令。用GTKWave或者Verdi打开就能看波形。

💡 我的经验:写testbench时,别只测正常情况。一定要测边界——比如复位释放瞬间给数据、连续输入相同值、时钟抖动等。我曾经因为没测“复位后立即输入”这个场景,流片回来发现状态机初始化有问题,那叫一个后悔。

4.4 本章知识体系

下面这张图,是我自己总结的时序逻辑设计核心脉络。你看一眼,心里就有谱了。

时序逻辑设计核心知识体系 时钟与复位 • 时钟:芯片心跳 • 异步复位 vs 同步复位 • 亚稳态问题 • 复位同步器 • 时钟域交叉 状态机设计 • Moore型:输出仅依赖状态 • Mealy型:输出依赖状态+输入 • 状态编码:二进制/格雷/独热 • 三段式写法 • 状态转移图 Testbench编写 • 时钟生成 • 激励时序 • 波形dump • 自检查机制 • 覆盖率收集 三者关系:时钟提供节拍 → 状态机实现控制逻辑 → Testbench验证功能正确性

这张图把本章的三个核心模块串起来了。时钟是基础,状态机是骨架,testbench是验证手段。三者缺一不可。

📌 本章小结:

  • 时钟和复位是时序逻辑的“基础设施”,设计时务必考虑亚稳态问题
  • Moore状态机输出稳定,适合控制逻辑;Mealy响应快,适合数据通路
  • Testbench要覆盖正常和边界情况,别偷懒
  • 写代码时,三段式状态机写法(状态寄存器、次态逻辑、输出逻辑分开)最清晰

好了,这一章就到这里。记住我说的:时序逻辑设计,时钟是灵魂,复位是保障,状态机是骨架,testbench是照妖镜。下一章我们聊更深入的东西——但今天先把这些基础打牢。


公众号:蓝海资料掘金营,微信deep3321