第二章:组合逻辑与时序逻辑

各位同学,今天我们来聊聊数字电路设计的两个基本概念——组合逻辑和时序逻辑。说实话,这两个概念就像硬币的两面,你搞懂了它们,FPGA设计的大门就算真正推开了。

我个人习惯把组合逻辑想象成「纯函数」——输入一变,输出立马跟着变,没有任何记忆能力。而时序逻辑呢,它是有「记忆」的,输出不仅看当前输入,还得看之前的状态。嗯,这个区别很关键。

2.1 基本门电路

先从最基础的开始。与门、或门、非门,这些是数字世界的「原子操作」。我在项目中遇到过一位新手,上来就用一堆门电路搭复杂逻辑,结果时序一塌糊涂。其实现在FPGA里都有现成的查找表(LUT),你写个 assign y = a & b; 就够了,综合工具会自动映射到LUT里。

但理解门电路还是有用的。比如你要做位宽转换、数据掩码,脑子里能快速反应出「这里应该用与门还是或门」,写代码就快很多。

核心要点:

  • 与门:全1出1,有0出0
  • 或门:有1出1,全0出0
  • 非门:取反
  • 异或门:相同出0,不同出1

2.2 多路选择器

多路选择器(MUX)在FPGA里太常见了。说白了就是「根据选择信号,从多个输入里挑一个输出」。我建议你写代码时尽量用 case 语句或者三元运算符 ? :,综合工具会帮你生成最优的MUX结构。

曾经有一次,我在做视频数据流切换时,用了嵌套的 if-else,结果综合出来一个巨大的优先级编码器,延迟超标。后来改成 case 语句,立马变成了并行MUX,时序就过了。嗯,这里要注意:case 是并行的,if-else 是串行的,别搞混了。

// 4选1多路选择器
always @(*) begin
    case(sel)
        2'b00: out = a;
        2'b01: out = b;
        2'b10: out = c;
        2'b11: out = d;
        default: out = a;
    endcase
end

2.3 加法器

加法器是算术运算的基础。最简单的就是全加器,一位一位地加,带进位传递。但如果你直接用 assign sum = a + b;,综合工具会自动帮你选最优的加法器结构——可能是超前进位加法器,也可能是进位选择加法器,取决于你的时序要求。

我个人经验是:对于位宽小于16位的加法,直接写 + 就行,工具处理得很好。但如果你在做32位甚至64位加法,尤其是高频设计,我建议你考虑流水线加法器——把加法拆成几级,每级插一个寄存器,这样能跑更高的频率。

小技巧: 加法器的进位链是FPGA里最长的路径之一。如果你发现时序不满足,试试把加法拆成两半,中间加一级流水线。我曾经用这招把一个200MHz的设计救活了。

2.4 触发器与寄存器

触发器(Flip-Flop)是时序逻辑的基本单元。FPGA里的触发器通常是D触发器,时钟上升沿采样数据。寄存器呢,就是一组触发器拼在一起,用来存多位数据。

你想想看,为什么我们需要触发器?因为组合逻辑的输出会随着输入变化而抖动,我们需要一个「快照」机制,在时钟边沿把稳定的值抓下来。这就是时序逻辑的核心思想。

我曾经调试过一个bug,数据总是错位。查了半天,发现是复位信号没处理好——异步复位和同步复位的用法搞混了。这里我给大家一个建议:

  • 异步复位:复位信号不依赖时钟,立即生效。适合上电初始化。
  • 同步复位:复位信号只在时钟边沿生效。适合避免毛刺。
// 带异步复位的D触发器
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        q <= 1'b0;
    else
        q <= d;
end

2.5 有限状态机设计

有限状态机(FSM)是数字设计里的「大脑」。你想想看,任何需要「记住当前状态、根据输入决定下一步」的逻辑,都可以用FSM来实现。比如图像处理里的像素流水线控制、协议解析、数据调度……

我习惯把FSM分成三段式来写:

  1. 第一段:状态转移(时序逻辑,用 always @(posedge clk))
  2. 第二段:次态逻辑(组合逻辑,根据当前状态和输入决定下一个状态)
  3. 第三段:输出逻辑(可以是组合逻辑,也可以是时序逻辑)

为什么要分三段?因为这样代码清晰,综合出来的电路也规整。我曾经接手过一个项目,前人把FSM写在一个always块里,状态和输出混在一起,调试起来简直想哭。后来我重构成了三段式,问题一目了然。

避坑指南: 写FSM时,一定要考虑「非法状态」。如果状态编码是二进制,万一受到干扰跳到了未定义状态,你的FSM可能就卡死了。我建议用 default 分支回到初始状态,或者用独热码编码——虽然浪费一点触发器,但容错性好很多。

// 三段式FSM示例
// 第一段:状态寄存器
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 = (start) ? RUN : IDLE;
        RUN:    next_state = (done) ? IDLE : RUN;
        default: next_state = IDLE;
    endcase
end

// 第三段:输出逻辑
assign busy = (state == RUN);

知识体系总览

下面这张图是我自己画的,把本章的知识结构串起来了。你可以看到,组合逻辑和时序逻辑是两条主线,最终在FSM这里汇合。

组合逻辑与时序逻辑知识体系 组合逻辑 基本门电路 多路选择器 加法器 时序逻辑 D触发器 寄存器 同步/异步复位 有限状态机 (FSM) 三段式写法 状态编码 非法状态处理

好了,这一章的内容就到这里。组合逻辑和时序逻辑是FPGA设计的根基,你花再多时间理解都不为过。下一章我们会深入时序约束和静态时序分析,到时候这些基础概念还会反复用到。

本章小结:

  • 组合逻辑:输出只取决于当前输入,无记忆
  • 时序逻辑:输出取决于当前输入和过去状态,有记忆
  • 触发器是时序逻辑的基本单元,寄存器是触发器的集合
  • FSM是复杂时序控制的核心,推荐三段式写法
  • 写代码时注意综合工具的行为,case 和 if-else 有本质区别

可可精品资料库