一提 FPGA 片上存储,大家先想到 BRAM 和 UltraRAM。它们容量大,适合做大缓存和数据缓冲。但片上存储还有另一面:分布式 RAM 和移位寄存器。它们由 LUT 搭建,容量小、速度快、位置灵活,搭小容量高速缓存反而更合适。

分布式 RAM 的本质是把 LUT 当存储用。一个 6 输入 LUT 可以配成 64x1 的 RAM,多个 LUT 并联拼位宽、级联拼深度。它的读是异步的,地址一变输出立刻跟着变,写是同步的,随时钟沿写入。这意味着它可以当成组合逻辑的一部分,延迟只有一个 LUT 的量级,做小查表、系数表、状态映射非常顺手。

移位寄存器是分布式 RAM 的亲戚。SRL32 把一个 LUT 配成 32 级移位寄存器,数据每个时钟移一位,任意一级都能抽头输出。做延迟线、流水线对齐、串并转换时,一个 LUT 顶 32 个触发器,资源账非常划算。滤波器的延迟抽头、可变延迟补偿,常用它来实现。

但分布式 RAM 不是万能的。第一,容量一上去,LUT 消耗立刻失控:拼一个 1Kx32 的存储要上千个 LUT,还要大量布线,时序和拥塞都会恶化,这种规模就该交给 BRAM。第二,异步读是一把双刃剑:读路径是组合逻辑,地址来自上一级寄存器还好,一旦地址本身经过多级组合逻辑,关键路径很容易在这里变长。解决办法是给读地址加一级寄存器,或者改用同步读的 BRAM。

选型上可以按一条简单的决策树走:深度在几十到几百、位宽不大的小表和延迟线,优先分布式 RAM 和 SRL;深度上千、需要双端口大带宽的,用 BRAM;超大容量权重缓存再考虑 UltraRAM。写 RTL 时也有讲究:把小 RAM 写成综合工具能识别的模板,读地址别加多余逻辑,综合报告里核对一下到底生成了 LUTRAM 还是被推成了 BRAM。片上存储没有银弹,分层搭配、各归其位,才是资源和时序都划算的做法。

分布式 RAM 还有一个实战细节:复位。LUTRAM 上电后的初始值由配置 bitstream 决定,写 RTL 时可以用 initial 语句给定初值,综合工具会把它编进配置文件。但运行中复位一般清不掉分布式 RAM 的内容,需要清零时得显式写一遍,或者改用带复位的 BRAM。做查表 ROM 时这个特性反而是优点:系数表随 bitstream 一起固化,上电即用,不用再花启动时间从外部 Flash 加载。