3. 算法加速需求分析与硬件映射

在把算法搬到 PolarFire FPGA 之前,最忌讳的动作是“先写 RTL,再想怎么接”。PolarFire 的逻辑规模、DSP 资源、LUT4 架构、片上存储(LSRAM/µSRAM)以及硬核接口(DDR、PCIe、SerDes)都是有限的,算法能不能加速、加速到什么程度、走哪条接口,取决于算法本身的四个特征:计算特征、数据流、并行度和存储访问模式。本节的任务就是把这四个特征量化,再映射到 PolarFire 的具体资源与接口约束上。

一、先看计算特征:算子类型决定资源去向

把算法拆成算子后,逐个判断它属于哪一类:

  • 乘加密集型:卷积、矩阵乘、FIR、FFT 蝶形。这类算子应优先映射到 PolarFire 的 DSP 硬核(Math Block),每个 Math Block 含 18×18 乘法器和 48 位累加器,适合做定点的乘累加。
  • 逻辑/位运算型:CRC、哈希、位域打包、LDPC 的异或网络。这类算子吃 LUT,应关注 LUT4 的级联深度和布线延迟。
  • 查表/非线性型:Sigmoid、Tanh、激活函数、坐标旋转。适合用 LSRAM 做查找表,或分段线性近似。
  • 控制/状态型:协议解析、状态机、调度。这类算子不适合并行展开,应放在控制路径,避免占用 DSP。

判断依据很直接:如果某个算子的乘加次数占总运算量的 70% 以上,它就是加速收益的主战场;如果它主要是分支和比较,加速收益有限,反而可能因为并行化而膨胀逻辑。

二、数据流:决定是流式还是块式

数据流描述数据在算子之间的传递方式,常见三种:

  • 流式(Streaming):数据按顺序流过,算子之间用 FIFO 或握手信号连接。适合图像行处理、FIR、实时协议解析。优点是延迟低、存储需求小;缺点是难以做跨行、跨帧的全局操作。
  • 块式(Block):先把一帧/一块数据写入片上缓存,再整体处理。适合 FFT、矩阵乘、二维卷积。优点是便于做转置和全局重排;缺点是需要 LSRAM 容量和带宽支撑。
  • 混合式:局部流式、全局块式。例如图像先做行缓冲的 3×3 卷积,再按块做池化。

在 PolarFire 上,流式路径通常用 AXI4-Stream 或自定义 valid/ready 握手;块式路径则要规划 LSRAM 的读写端口和乒乓缓冲。数据流一旦确定,接口的位宽、时钟域和背压策略也就基本确定了。

三、并行度:从算法里“挖”出可并行的维度

并行度不是拍脑袋定的,要从算法的循环结构里找。以二维卷积为例,输出特征图有 H×W 个点,每个点做 K×K 次乘加。可并行的维度包括:

  • 输出通道并行:同时算多个输出通道,每个通道一个 DSP 阵列。
  • 输入通道并行:把多个输入通道的乘积累加树并行展开。
  • 空间并行:同时算相邻的多个输出点,共享输入窗口。

并行度 P 与资源的关系可以粗略估算:DSP 用量 ≈ P × 每周期乘加数 / Math Block 每周期能力。PolarFire 的 Math Block 在 200 MHz 下每周期可完成一次 18×18 乘加,若目标算力是 50 GMAC/s,则至少需要 250 个 Math Block 在 200 MHz 下满负荷。实际还要留出 30% 余量给控制和流水线气泡。

并行度还受存储带宽约束。若每个周期要喂 P 个乘加,输入数据带宽就是 P × 数据位宽 × 时钟频率。例如 P=16、16 bit、200 MHz,则输入带宽约 51.2 Gbit/s,这已经接近单条 DDR4 通道的可用带宽,必须用片上缓存或宽总线来缓解。

四、存储访问模式:决定缓存架构和接口选择

存储访问模式是 PolarFire 映射中最容易翻车的地方。要问三个问题:

  1. 访问粒度:是连续突发,还是随机小颗粒?连续突发适合 DDR 和 AXI Burst;随机小颗粒适合片上 LSRAM 或带缓存的访问。
  2. 复用距离:同一个数据在被丢弃前会被复用多少次?复用距离短,用行缓冲/窗口寄存器;复用距离长,用 LSRAM 块缓存。
  3. 读写比例与冲突:是否存在读写同一块存储的冲突?若有,需要双端口 LSRAM 或乒乓缓冲。

例如,3×3 卷积的输入窗口在行方向复用 3 次、列方向复用 3 次,复用距离短,用行缓冲即可;而 FFT 的旋转因子需要按蝶形级数反复读取,复用距离长,应放在 LSRAM 中并做地址重排。

五、映射到 PolarFire:加速路径与接口约束

把上述四个特征汇总,可以得到一张映射决策图。下图展示了从算法特征到 PolarFire 资源与接口的对应关系,以及关键约束的检查点。

算法特征 → PolarFire 资源与接口映射决策图 算法特征 计算特征 乘加密集 / 逻辑型 查表型 / 控制型 数据流 流式 / 块式 混合式 并行度 通道 / 空间 / 流水 P 值估算 存储访问模式 粒度 / 复用距离 读写冲突 PolarFire 加速路径 DSP 阵列 Math Block 乘加 流水线 / 并行通道 LSRAM / µSRAM 行缓冲 / 块缓存 乒乓 / 双端口 LUT 逻辑 位运算 / 控制 状态机 / 调度 硬核接口 DDR / PCIe / SerDes AXI4 / AXI-Stream 接口与资源约束检查 带宽约束 输入带宽 = P × 位宽 × 频率 需 ≤ DDR 可用带宽或片上带宽 DSP 数量约束 DSP 用量 ≈ P × 每周期乘加数 留 30% 余量给控制与气泡 存储容量与端口约束 LSRAM 块数 ≥ 缓存需求 读写冲突需双端口或乒乓 时钟域与握手约束 跨时钟域需异步 FIFO 背压策略决定吞吐上限 约束不满足 → 回退调整并行度或数据流 示例:3×3 卷积,P=16,16 bit,200 MHz → 输入带宽约 51.2 Gbit/s,DSP 约 250 个,需 LSRAM 行缓冲与 DDR 突发配合 (以上为教学示例估算,非实测结果)

图中左侧是算法特征,中间是 PolarFire 可用的加速资源,右侧是必须检查的接口与资源约束。箭头表示映射方向,底部虚线表示当约束不满足时需要回退调整并行度或数据流。以 3×3 卷积为例:若并行度 P=16、数据位宽 16 bit、时钟 200 MHz,则输入带宽约 51.2 Gbit/s,DSP 需求约 250 个 Math Block,同时需要 LSRAM 做行缓冲,DDR 侧要用 AXI Burst 保证突发效率。这些数字是教学示例估算,实际工程中必须用 Libero 的综合报告和时序报告核对。

六、接口约束的落地检查

在 PolarFire 上,接口约束不是抽象概念,而是具体到引脚、时钟和协议:

  • DDR 接口:PolarFire 的 DDR 控制器支持 AXI4,突发长度和位宽决定有效带宽。若算法需要 51.2 Gbit/s,单通道 DDR4-2400 理论带宽 19.2 GB/s,实际可用约 60%~70%,即 11.5~13.4 GB/s,约 92~107 Gbit/s,单通道可以满足;但若并行度再翻倍,就需要考虑多通道或提高片上缓存命中率。
  • PCIe 接口:若算法作为加速卡与主机交互,PCIe Gen2 x4 理论 20 Gbit/s,实际约 12~14 Gbit/s。此时算法输入输出必须做分块和流水,避免一次性搬运整帧。
  • SerDes:用于板间或传感器直连,注意参考时钟、均衡和协议层封装。
  • AXI4-Stream:流式路径的首选,注意 valid/ready 握手和背压。若下游不能持续接收,上游必须能暂停,否则数据丢失。
在需求分析阶段,建议先写一张“算子—资源—接口”对照表:每个算子一行,列出计算类型、并行度、存储需求、目标资源和接口。这张表不需要复杂,但能让你在写 RTL 之前就发现带宽或 DSP 瓶颈。
常见误区:只算 DSP 数量,不算存储带宽。PolarFire 的 Math Block 可以跑满,但数据喂不进去,实际算力会打对折。另一个误区是忽略跨时钟域:算法核跑 200 MHz,DDR 控制器跑 333 MHz,中间必须用异步 FIFO,否则会出现亚稳态和丢数。

总结来说,算法加速需求分析的核心是把“算法想做什么”翻译成“PolarFire 能做什么”。计算特征决定资源类型,数据流决定缓存架构,并行度决定资源用量,存储访问模式决定接口和带宽。四者相互制约,任何一项超出约束,都要回到上一层重新调整。只有把这四个特征量化清楚,后续的 RTL 实现和性能评估才有可靠的起点。