3. 组合逻辑设计:多路选择器、加法器、译码器、比较器、乘法器的FPGA实现

各位同学,今天咱们聊聊组合逻辑。说白了,组合逻辑就是那种「输入一变,输出立马跟着变」的电路,没有时钟,没有状态,纯粹靠逻辑门搭出来的硬功夫。

我在金融科技领域做低延迟交易系统时,组合逻辑用得特别多。比如行情解析中的协议字段提取,说白了就是一堆多路选择器和译码器在干活。你想想看,交易所的UDP包每秒几百万个,每个包里的字段位置还不一样,不用组合逻辑硬解,靠CPU软解?延迟直接爆炸。

好,咱们一个一个来。

3.1 多路选择器(MUX)—— 数据通道的「开关」

多路选择器,我习惯叫它MUX。功能很简单:从多个输入中选一个送到输出。

FPGA里实现MUX有两种方式:

  • case语句:最直观,适合选择路数不多的情况
  • 三元运算符:适合2选1,代码简洁

我个人习惯用case语句,因为可读性强,后期维护也方便。不过要注意,case语句要写完整,不然综合出来一堆锁存器,那可就麻烦了。

避坑指南: 我曾经在项目里漏写了case的default分支,结果综合出来一堆latch,时序直接崩了。后来养成了习惯——case语句必带default,哪怕你觉得所有情况都覆盖了。
// 4选1多路选择器
module mux_4to1 (
    input  [1:0] sel,
    input  [7:0] a, b, c, d,
    output reg [7:0] out
);
    always @(*) begin
        case (sel)
            2'b00: out = a;
            2'b01: out = b;
            2'b10: out = c;
            2'b11: out = d;
            default: out = 8'h00;  // 一定要写!
        endcase
    end
endmodule

在FPGA里,MUX其实是用LUT(查找表)实现的。一个6输入LUT可以实现4选1的MUX,还富余两个输入。所以别担心资源,FPGA天生就是干这个的。

3.2 加法器 —— 从半加器到超前进位

加法器是算术逻辑的基础。FPGA里实现加法,我建议直接用 + 运算符,综合器会帮你优化成最优结构。

但咱们得理解底层原理,不然出了问题都不知道怎么调。

类型 特点 适用场景
半加器 两个1位输入,产生和与进位 基础教学
全加器 三个1位输入(含进位),产生和与进位 级联构成多位加法器
行波进位加法器 全加器级联,延迟随位数线性增长 位数少(<8位)
超前进位加法器 并行计算进位,延迟固定 位数多(>16位),高频设计

嗯,这里要注意。在FPGA里,行波进位加法器其实没那么差。因为FPGA的进位链是专用的硬件资源,延迟很小。我测过,32位行波进位加法器在Xilinx的器件上能跑到400MHz以上。

小技巧: 如果你需要做加法,直接写 assign sum = a + b; 就行。综合器会自动选择最优结构。别自己手搓加法器,除非你在做教学或者有特殊要求。

3.3 译码器 —— 地址解析的利器

译码器,说白了就是把一个小的编码,翻译成大的控制信号。在FPGA里最常见的应用就是地址译码。

比如在交易所协议解析中,我们需要根据报文类型字段(比如4位)来生成不同的处理使能信号。这时候译码器就派上用场了。

// 3-8译码器
module decoder_3to8 (
    input  [2:0] in,
    output reg [7:0] out
);
    always @(*) begin
        out = 8'b0;
        out[in] = 1'b1;  // 一行搞定,简洁明了
    end
endmodule

你看,用 out[in] = 1'b1 这种方式,比写case语句简洁多了。而且综合出来的资源是一样的。

我曾经在项目中用译码器做寄存器组的地址映射。32个寄存器,用5位地址译码,每个寄存器对应一个写使能。这样CPU通过地址总线写数据时,只有目标寄存器被更新,其他寄存器纹丝不动。这个设计在金融交易系统的配置管理模块里用了好几年,稳得很。

3.4 比较器 —— 不只是大于小于

比较器,大家第一反应就是 ><==。但在FPGA里,比较器的实现方式会影响资源消耗和时序。

我总结了几种常见场景:

  • 相等比较:用XOR + NOR实现,资源最少
  • 大小比较:用减法器实现,看符号位
  • 范围比较:比如判断一个数是否在[10, 100]之间,可以用两个比较器+与门
实战经验: 在金融交易系统中,我们经常需要判断价格是否在涨跌停范围内。比如判断 price >= lower_limit && price <= upper_limit。这个逻辑如果用两个比较器,会消耗两个LUT。但如果你把范围比较写成 assign in_range = (price - lower_limit) <= (upper_limit - lower_limit);,只需要一个比较器,资源减半。
// 范围比较优化
module range_check (
    input  [15:0] price,
    input  [15:0] lower,
    input  [15:0] upper,
    output        in_range
);
    wire [15:0] range = upper - lower;
    wire [15:0] offset = price - lower;
    assign in_range = (offset <= range);  // 一个比较器搞定
endmodule

3.5 乘法器 —— 资源与速度的权衡

乘法器是组合逻辑里的「大块头」。FPGA里实现乘法,有几种选择:

  1. 直接用 * 运算符:综合器会调用DSP单元,速度快,资源可控
  2. 用LUT实现:适合小位宽(4位以下),不占DSP
  3. 用移位相加:适合常数乘法,比如乘以10可以写成 (a << 3) + (a << 1)

我个人建议:能用DSP就别用LUT。DSP是FPGA里专门为乘法优化的硬核,速度快、功耗低。你非要用LUT搭乘法器,不仅占资源,时序还容易崩。

注意: 我曾经接手过一个项目,前同事用LUT实现了16位乘法器,结果占用了400多个LUT,时序只能跑到100MHz。我改成DSP实现后,只用了4个DSP,时序直接跑到500MHz。所以,别跟FPGA的硬核过不去。
// 使用DSP的乘法器
module multiplier_dsp (
    input  [15:0] a, b,
    output [31:0] prod
);
    assign prod = a * b;  // 综合器自动映射到DSP
endmodule

// 常数乘法优化
module mul_by_10 (
    input  [15:0] a,
    output [19:0] result
);
    assign result = (a << 3) + (a << 1);  // a*8 + a*2 = a*10
endmodule

3.6 知识体系总览

说了这么多,咱们用一张图来总结一下这五种组合逻辑的关系和应用场景。

组合逻辑设计知识体系 组合逻辑设计 多路选择器 数据通道选择 case / 三元运算符 加法器 行波进位 / 超前进位 直接使用 + 运算符 译码器 地址解析 / 使能生成 out[in] = 1'b1 写法 比较器 相等 / 大小 / 范围 减法优化技巧 乘法器 DSP / LUT / 移位 优先使用DSP硬核 FPGA加速交易所协议解析中的应用 行情字段提取(MUX + 译码器) 价格计算与校验(加法器 + 比较器 + 乘法器)

这张图把咱们今天讲的内容串起来了。你看,五种组合逻辑在FPGA加速交易所协议解析中都有用武之地。MUX和译码器负责数据通路的选择和地址解析,加法器、比较器、乘法器负责数值计算和条件判断。

好了,这一章的内容就到这儿。记住一句话:组合逻辑是FPGA设计的基石,把这些基础打牢了,后面做复杂设计才能游刃有余。


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