FPGA 硬件加速基础:架构、并行与流水线
各位同学,欢迎来到第二章。这一章我们不讲具体算法,先聊聊 FPGA 这个“加速器”到底凭什么能干活。我见过不少做图像算法的朋友,一上来就写 Verilog,结果资源爆了、时序乱了,最后问我“为什么我的 ISP 在 FPGA 上跑不快?”——说白了,就是没搞懂 FPGA 的底层逻辑。
这一章,我会从三个角度拆解:FPGA 架构、并行计算原理、流水线设计思想。最后再聊聊,为什么 ISP 算法天生适合 FPGA 加速。
FPGA 架构:你手里拿的不是 CPU
很多人第一次接触 FPGA,会下意识把它当成“可以重新编程的 CPU”。其实完全不是一回事。CPU 是冯·诺依曼结构,指令一条条取、一条条执行。FPGA 呢?它是一块“空白电路板”,你可以把逻辑电路直接“画”上去。
FPGA 内部主要由三部分组成:
- 可编程逻辑单元(Logic Cell / LUT + FF)——实现组合逻辑和寄存器
- 可编程互连资源(Routing)——把各个逻辑单元连起来
- 可编程 I/O 引脚——跟外部世界打交道
我习惯把 FPGA 比作乐高积木。CPU 是已经拼好的模型,你只能按说明书操作;FPGA 是一箱散装积木,你想搭什么就搭什么。当然,搭得好不好,就看你的手艺了。
关键认知:FPGA 的“程序”不是指令序列,而是硬件电路描述。你写的 Verilog 代码,最终会变成真实的逻辑门和连线。
举个例子,你要做一个 3x3 的均值滤波。在 CPU 上,你得写一个循环,逐像素读取、累加、求平均。在 FPGA 上,你可以直接例化 9 个乘法器、1 个加法树,一个时钟周期就把结果算出来。这就是本质区别。
并行计算原理:同时干很多事
FPGA 的并行能力,体现在两个层面:
- 数据并行——多个处理单元同时处理不同数据
- 任务并行——不同功能模块同时运行
我记得有一次做 Bayer 去马赛克算法,需要在同一帧图像里同时处理 R、G、B 三个通道。如果用 DSP 做,得串行处理,一帧图像要等三个周期。FPGA 上呢?我直接例化三套处理逻辑,每个通道独立运行,一拍搞定。
为什么会这样?因为 FPGA 的并行是“物理级”的。你写了一个 always 块,它就对应一份硬件;你写了三个 always 块,它就对应三份硬件。硬件之间天然独立,不需要操作系统调度,没有上下文切换开销。
| 对比项 | CPU | GPU | FPGA |
|---|---|---|---|
| 并行粒度 | 指令级(有限) | 线程级(SIMT) | 门级(任意粒度) |
| 并行方式 | 流水线 + 多核 | 大量线程 | 硬件复制 + 流水线 |
| 延迟 | 高(缓存缺失) | 高(线程切换) | 低(确定性) |
| 适合场景 | 控制密集型 | 计算密集型(大吞吐) | 流处理 + 低延迟 |
嗯,这里要注意:FPGA 的并行不是无限的。你的芯片有多少逻辑单元、多少 DSP、多少 BRAM,决定了你能并行到什么程度。我曾经在一个项目中贪多,想在一个中端芯片上同时跑 4 路 4K 视频处理,结果资源爆了,最后只能砍到 2 路。所以,并行设计一定要跟资源预算对齐。
流水线设计思想:让每一拍都不闲着
流水线,说白了就是“分工合作”。你想想看,一个 ISP 算法链通常很长:黑电平校正 → 去噪 → 去马赛克 → 白平衡 → 颜色校正 → Gamma 校正……如果每个模块都串行执行,整帧图像处理完得等多久?
流水线的核心思想是:把一个大任务拆成多个小阶段,每个阶段用寄存器隔开,所有阶段同时工作。
我画个简单的流水线结构图,你一看就明白:
你看,流水线的好处是:虽然单个像素的处理延迟没变,但系统的吞吐量提升了 N 倍(N 是流水线级数)。我做过一个 12 级流水线的 ISP 设计,处理 1080p 60fps 的视频流,延迟只有 3 行像素的时间,吞吐量却达到了 148.5 MHz 的像素时钟。
我的经验:流水线设计最怕“气泡”——某个阶段因为数据依赖或资源冲突而停顿。我曾经在去噪模块里用了一个行缓存,结果缓存没准备好,导致整条流水线每 8 个周期就停一次。后来加了乒乓缓冲,才把吞吐量拉满。
为什么 FPGA 适合 ISP 加速?
ISP 算法有几个特点,跟 FPGA 的“脾气”特别合:
- 流式处理——图像数据是一行一行、一帧一帧来的,天然适合流水线
- 固定计算模式——滤波、插值、矩阵变换,计算模式固定,适合硬件固化
- 低延迟要求——比如自动驾驶的 ISP,延迟必须控制在毫秒级,FPGA 能做到
- 高带宽需求——4K 60fps 的原始数据带宽超过 12 Gbps,FPGA 的并行 I/O 能扛住
我举个例子你就明白了。一个简单的 3x3 中值滤波,在 CPU 上需要:读取 9 个像素 → 排序 → 取中间值。在 FPGA 上呢?我可以用 3 个行缓存 + 9 个寄存器 + 一个排序网络,每个时钟周期输出一个结果。而且,我可以把排序网络做成全流水线,一拍出一个结果,延迟只有几个时钟周期。
注意:FPGA 不是万能的。如果算法分支多、动态性强(比如自适应参数调整),FPGA 实现起来会很痛苦。我建议的做法是:把计算密集、模式固定的部分放到 FPGA 上,把控制逻辑、参数更新放到 CPU 上。异构才是王道。