FPGA ROM学习笔记:从原理到Vivado IP实战
作为FPGA初学者,存储模块是绕不开的核心知识点,而ROM(只读存储器)作为“预存固定数据”的常用模块,其在Vivado中的实现方式曾让我困惑许久——明明都是生成ROM,为何有两个不同的IP可选?经过一番实操验证,我终于理清了其中的关键,这篇笔记就把从“概念理解”到“IP实战”的完整过程分享给大家。
一、先搞懂:FPGA里的ROM不是“一块芯片”
在传统电路中,ROM是独立的存储芯片,但在FPGA里,ROM是通过底层硬件资源“配置”出来的——FPGA本身没有专门的“ROM芯片”,而是利用内部的存储资源(LUT或Block Memory),通过IP核配置成ROM的功能,实现“断电后数据不丢失”(需提前固化数据)或“上电即加载预设数据”的效果。
这就引出了Vivado中两个ROM相关IP的核心差异:它们占用的FPGA底层资源完全不同,而资源的差异直接决定了ROM的性能、容量和适用场景。
二、核心辨析:两个ROM IP的本质差异
在Vivado的IP Catalog中搜索“rom”,会在“Memories & Storage Elements”下找到两个核心IP:Distributed Memory Generator和Block Memory Generator。两者的核心区别用一句话概括:用“兼职存储资源”还是“专职存储资源”实现ROM。

1.FPGA的两类存储资源
要理解IP差异,必须先明确FPGA的两种底层存储单元,这是一切差异的根源:
-
LUT(查找表):FPGA的“基本逻辑单元”,本质是一个小容量SRAM(比如Xilinx 7系列的LUT6是6输入1输出,对应64bit存储)。它的本职工作是存储逻辑真值表(实现与或非、状态机等组合逻辑),但可被“复用”为存储资源,也就是“分布式存储”。
-
Block Memory(嵌入式块存储器):FPGA中独立的“专职存储模块”,是厂商集成的硬件RAM(比如Xilinx 7系列的BRAM有18Kb/36Kb规格)。它不参与逻辑运算,专门为大容量、高带宽存储设计,物理上与逻辑阵列分离。
2.两个IP的核心特性
基于上述资源差异,两个IP的特性、适用场景完全不同,我做了一张对比表,一目了然:
| 对比维度 | Distributed Memory Generator | Block Memory Generator |
|---|---|---|
| 核心资源 | LUT(复用逻辑资源) | Block Memory(专用存储资源) |
| 容量上限 | 极小(单LUT 64bit,总容量通常<1KB) | 极大(单BRAM 18Kb/36Kb,可级联到MB级) |
| 访问延迟 | 极低(组合逻辑,地址输入直接出数据,无时钟延迟) | 较高(1~2个时钟周期延迟,需时钟沿采样) |
| 访问方式 | 支持异步+同步 | 仅支持同步(必须依赖时钟) |
| 资源利用率 | 小容量(<1KB)利用率高,大容量浪费严重 | 大容量(>1KB)利用率高,小容量浪费(如存64bit用18Kb BRAM) |
| 功能丰富度 | 简单(仅基础读写,无高级功能) | 丰富(支持双端口、ECC校验、读写位宽不匹配等) |
| 功耗 | 小容量低,大容量剧增 | 大容量远低于分布式,小容量反而浪费 |
通俗比喻:Distributed ROM像“兼职的逻辑工人”,本职是做逻辑运算,临时帮着存点小东西;Block ROM像“专职的仓库管理员”,只干存储,不抢逻辑的活,适合存大量货物。
分布式 ROM 原理图示意图和其实现框图如下。


三、Vivado中如何选、如何用?
理论终究要落地,结合我的实操经验,分享“IP选择原则”和“基础配置步骤”,新手直接套用即可。
1. 核心选择原则:看容量和访问需求
不用纠结,按以下场景对号入座:
-
选Distributed Memory Generator的场景: 存储容量极小(比如数码管译码表:16个数字×7段=112bit;状态机跳转表:几十bit);
-
需要异步访问(无时钟,地址输入立即出数据,比如高速校准参数表);
-
BRAM资源紧张(比如项目中BRAM已被大容量RAM占用,小ROM用LUT复用)。
选Block Memory Generator的场景: 存储容量较大(比如1024点正弦波表:10bit地址×12bit幅值=12KB;串口数据包缓存:32KB);
系统是同步设计(有统一主时钟,BRAM的同步访问能匹配时序);
需要高级功能(比如双端口ROM:FPGA和外部芯片同时读;加载初始化文件固化波形数据)。
2. 基础配置步骤(以Block Memory Generator为例)
Block ROM是项目中更常用的场景,这里以“生成1KB正弦波ROM”为例,讲关键步骤:
-
添加IP:新建工程→IP Catalog→搜索“Block Memory Generator”→双击打开配置界面;
-
选择ROM模式:在“Memory Type”中选“Single Port ROM”(单端口ROM,最常用);
-
配置容量:设置“Write Width”(数据位宽,如12bit)、“Write Depth”(存储深度,如1024),总容量=12×1024=12KB;
-
加载初始化数据:在“Other Options”中勾选“Load Init File”,导入提前用Matlab或Excel生成的.coe文件(存储正弦波数据);
-
生成IP:点击“OK”→“Generate”,IP核就生成完成,后续例化调用即可。
3. 新手避坑点
-
Distributed ROM不要存大容量数据:比如存10KB数据,需要占用10×1024/64=160个LUT,会严重挤占逻辑资源,导致其他模块无法实现;
-
Block ROM的初始化文件格式要正确:.coe文件首行必须是“MEMORY_INITIALIZATION_RADIX=16;”(指定进制),后续每行是数据,否则IP无法识别;
-
同步访问要注意时序:Block ROM依赖时钟,例化后要确保地址信号在时钟沿前稳定,避免时序违规。
四、ROM学习的延伸方向
掌握基础后,可以进一步探索:
-
双端口ROM的应用:实现FPGA与DMA的并行数据读取;
-
ROM与RAM的结合:用ROM存初始化参数,RAM存实时数据;
-
时序优化:Block ROM的延迟优化、Distributed ROM的毛刺处理。
希望这篇笔记能帮到和我一样的FPGA新手,少走弯路,把时间花在“实操验证”上,比单纯看理论高效10倍。如果有疑问,欢迎在评论区交流~

浙公网安备 33010602011771号