首页/新闻资讯/正文详情

【Verilog/FPGA】存储器(数组)

发布时间:2026/9/27 21:54:33 来源:云帆数科 栏目:资讯中心
【Verilog/FPGA】存储器(数组)
这是 Verilog 里的存储器数组声明先读一下可视化技能然后我给你画个内存布局图讲清楚。reg [2:0] data_byte_pre [7:0];声明的是一个存储器数组不是一个大位宽信号reg [2:0]→ 每个元素是 3 bit 的寄存器bit2~bit0data_byte_pre→ 名字[7:0]→ 一共8 个元素下标 7~0也就是8 个 3 位寄存器总共 24 bit。内存布局如下示意访问方式data_byte_pre[i]→ 第 i 个元素整个 3 bitdata_byte_pre[i][b]→ 第 i 个元素的第 b 位数组不支持整体赋值data_byte_pre 24hxxx;编译报错必须逐元素操作初始化用 for 循环integer i; initial begin for (i 0; i 8; i i 1) data_byte_pre[i] 3b000; // 逐个元素初始化 end常见坑位宽和元素数别写反reg [7:0] mem [2:0]是 3 个 8 位元素和你的 8 个 3 位完全是两回事。下标越界超出 7~0仿真中会读/写出x。综合后通常是 24 个触发器寄存器组如果在 always 块里用变量下标data_byte_pre[addr]读写会综合成小 RAM/寄存器堆。结合你的 UART 工程如果你是想把 8 个字节8 bit先缓存再逐个发送那每个元素应该声明成 8 位即reg [7:0] data_byte_pre [7:0];——你现在的写法每个元素只有 3 bit存不下完整字节确认一下是不是笔误。根据您提供的 Verilog 存储器数组声明笔记内容我来为您撰写这篇 CSDN 技术博客文章。【Verilog/FPGA】存储器数组声明完全指南从语法到综合避坑必读前言在 Verilog 硬件描述语言中存储器Memory是一种非常重要的数据结构常用于数据缓存、查找表、FIFO 实现等场景。然而Verilog 的存储器声明语法与 C 语言等软件语言差异较大很多初学者容易把位宽和元素个数写反导致综合结果与预期完全不同。本文以reg [2:0] data_byte_pre [7:0];这一典型声明为例系统讲解 Verilog 存储器的声明语法、内存布局、访问方式、初始化方法以及常见陷阱并结合 UART 发送工程给出实际使用建议。一、存储器声明语法解析1.1 声明结构reg [2:0] data_byte_pre [7:0];这条语句声明的是一个存储器数组而不是一个大位宽信号。它的结构可以拆解为两部分语法部分含义reg [2:0]每个元素是 3 bit 的寄存器bit2 ~ bit0data_byte_pre存储器名称[7:0]一共8 个元素下标 7 ~ 0核心记忆口诀reg [位宽-1:0] 名字 [元素数-1:0];先写每个元素几位再写一共多少个元素。1.2 与 C 语言的对比在 C 语言中声明一个数组是这样的intdata[8];// 8 个 int 元素而在 Verilog 中位宽和元素数的声明是分开的且顺序相反// C 语言int data[8] → 8 个 32 位元素 // Verilog 等效写法 reg [31:0] data [7:0]; // 8 个 32 位元素 // C 语言char data[3] → 3 个 8 位元素 // Verilog 等效写法 reg [7:0] data [2:0]; // 3 个 8 位元素最常见的坑reg [7:0] mem [2:0]是3 个 8 位元素而reg [2:0] mem [7:0]是8 个 3 位元素两者完全不同位宽和元素数千万别写反。二、内存布局以reg [2:0] data_byte_pre [7:0];为例它的内存布局如下图1reg [2:0] data_byte_pre [7:0]的内存布局——8 个元素每个元素 3 bit共 24 bit具体展开下标位宽位编号初始值data_byte_pre[7]3 bit[2:0]3’b000data_byte_pre[6]3 bit[2:0]3’b000data_byte_pre[5]3 bit[2:0]3’b000data_byte_pre[4]3 bit[2:0]3’b000data_byte_pre[3]3 bit[2:0]3’b000data_byte_pre[2]3 bit[2:0]3’b000data_byte_pre[1]3 bit[2:0]3’b000data_byte_pre[0]3 bit[2:0]3’b000总计8 个元素 × 3 bit 24 bit三、访问方式Verilog 存储器支持两种访问粒度3.1 访问整个元素data_byte_pre[i] // 第 i 个元素整个 3 bit例如data_byte_pre[0] 3b101; // 给第 0 个元素赋值为 101 assign some_signal data_byte_pre[3]; // 读取第 3 个元素的值3.2 访问单个位data_byte_pre[i][b] // 第 i 个元素的第 b 位例如data_byte_pre[2][1] 1b1; // 第 2 个元素的第 1 位设为 1 assign bit_out data_byte_pre[5][0]; // 读取第 5 个元素的第 0 位3.3 拼接与拆分// 将 8 个 3bit 元素拼接成 24bit 宽信号 assign [23:0] flat_data {data_byte_pre[7], data_byte_pre[6], data_byte_pre[5], data_byte_pre[4], data_byte_pre[3], data_byte_pre[2], data_byte_pre[1], data_byte_pre[0]}; // 将 24bit 宽信号拆分到 8 个 3bit 元素 always (*) begin data_byte_pre[7] flat_data[23:21]; data_byte_pre[6] flat_data[20:18]; data_byte_pre[5] flat_data[17:15]; data_byte_pre[4] flat_data[14:12]; data_byte_pre[3] flat_data[11:9]; data_byte_pre[2] flat_data[8:6]; data_byte_pre[1] flat_data[5:3]; data_byte_pre[0] flat_data[2:0]; end四、初始化方法4.1 重要限制不支持整体赋值存储器不支持整体赋值操作。以下写法会编译报错// ❌ 编译报错不支持整体赋值 data_byte_pre 24h000000;4.2 正确做法使用 for 循环初始化在initial块中使用 for 循环逐个元素初始化integer i; initial begin for (i 0; i 8; i i 1) data_byte_pre[i] 3b000; // 逐个元素初始化为 0 end注意for 循环初始化只能在initial或always块中使用不能在模块顶层直接写。4.3 其他初始化方式方式一用 case 语句逐个赋值适合元素较少的情况initial begin data_byte_pre[0] 3b001; data_byte_pre[1] 3b010; data_byte_pre[2] 3b011; // ... 依此类推 end方式二用 $readmemh 从文件加载适合大数据量integer f; initial begin f $fopen(init_data.txt); if (f) begin for (integer i 0; i 8; i i 1) $fscanf(f, %h, data_byte_pre[i]); $fclose(f); end end五、综合结果综合后存储器通常会被映射为以下硬件结构综合场景综合结果静态索引下标为常量综合为 24 个触发器寄存器组动态索引下标为变量如data_byte_pre[addr]综合成小 RAM / 寄存器堆Register File只读存储器initial 赋值 只读访问可能综合为 ROM 或 LUT工程提示如果在always块里用变量下标data_byte_pre[addr]进行读写综合工具通常会将其实现为真正的 RAM 或寄存器堆Register File而不是 24 个独立的触发器。这意味着它的资源占用和时序行为会与普通寄存器不同需要特别注意。六、常见陷阱陷阱 1位宽和元素数写反// 意图8 个 3 位元素 reg [2:0] data_byte_pre [7:0]; // ✅ 正确 // 误写3 个 8 位元素完全不是想要的效果 reg [7:0] data_byte_pre [2:0]; // ❌ 错误陷阱 2下标越界// data_byte_pre 的下标范围是 [7:0] data_byte_pre[8] 3b000; // ❌ 越界仿真中会读/写出 x不确定值陷阱 3整体赋值报错data_byte_pre 24h000; // ❌ 编译错误必须逐元素操作陷阱 4在组合逻辑中未给所有分支赋值// ❌ 可能产生锁存器Latch always (*) begin if (en) data_byte_pre[idx] data_in; // 当 en0 时data_byte_pre[idx] 没有被赋值综合出锁存器 end // ✅ 正确写法给所有分支都赋值 always (*) begin for (integer i 0; i 8; i i 1) data_byte_pre[i] (i idx en) ? data_in : data_byte_pre[i]; end陷阱 5在时序逻辑中使用非阻塞赋值的注意事项// ✅ 时序逻辑中用非阻塞赋值 always (posedge clk) begin for (integer i 0; i 8; i i 1) data_byte_pre[i] new_data[i]; end七、与 UART 发送工程的结合在实际的 UART 发送工程中存储器常用于缓存待发送的数据。这里有一个非常关键的工程问题7.1 位宽匹配问题如果你是想把 8 个字节8 bit先缓存再逐个发送那每个元素应该声明成 8 位// 缓存 8 个字节每个字节 8 bit reg [7:0] data_byte_pre [7:0]; // 8 个 8 位元素共 64 bit而你当前的写法reg [2:0] data_byte_pre [7:0]; // 8 个 3 位元素共 24 bit每个元素只有 3 bit存不下完整的一个字节8 bit。如果你的 UART 发送逻辑是按字节发送的那这里就是一个 bug7.2 UART 发送缓存典型实现// UART 发送数据缓存8 个字节 reg [7:0] tx_buffer [7:0]; reg [3:0] tx_idx; reg tx_busy; // 数据加载并行写入 always (posedge clk) begin if (load_req !tx_busy) begin for (integer i 0; i 8; i i 1) tx_buffer[i] tx_data[i]; // 并行加载 8 个字节 tx_idx 4d0; tx_busy 1b1; end end // UART 逐个字节发送 always (posedge clk) begin if (tx_busy tx_ready) begin tx_dout tx_buffer[tx_idx]; // 输出当前字节 tx_idx tx_idx 1; if (tx_idx 4d7) tx_busy 1b0; // 发送完成 end end八、存储器 vs 二维数组 vs 一维数组很多开发者会混淆 Verilog 中的几种类数组写法写法含义总位宽reg [2:0] mem [7:0];8 个 3 位元素存储器24 bitreg [7:0] mem [2:0];3 个 8 位元素存储器24 bitreg [23:0] mem;1 个 24 位信号不是存储器24 bitreg [2:0] mem [7:0];按位访问mem[i][b]等价于二维数组mem[8][3]24 bit关键区别reg [23:0] mem;是一个 24 位宽的普通寄存器支持整体赋值mem 24hxxxx;而reg [2:0] mem [7:0];是存储器不支持整体赋值但支持按元素和按位访问。九、操作速查表操作语法示例说明声明存储器reg [2:0] mem [7:0];8 个 3 位元素访问整个元素mem[i]第 i 个元素3 bit访问单个位mem[i][b]第 i 个元素的第 b 位整体赋值不支持会编译报错初始化for 循环 initial逐个元素赋值从文件加载$readmemh()适合仿真初始化拼接{mem[7], mem[6], ..., mem[0]}展开为宽信号拆分mem[i] wide_sig[offset:3]用位选择切片十、常见问题Q1存储器可以综合成真正的 RAM 吗可以。当使用变量下标进行读写时如mem[addr]综合工具会将其实现为 RAM 或寄存器堆Register File。如果需要特定的 RAM 模板可以使用综合工具的(* ram_style block *)或(* ram_style distributed *)属性来指导综合。Q2存储器可以综合成 ROM 吗可以。如果在initial块中初始化且只在组合逻辑中读取不写综合工具通常会将其实现为 ROM 或 LUT。Q3for 循环初始化在综合时会占用资源吗不会。initial块中的 for 循环仅用于仿真初始化综合时会被优化掉不会生成额外的硬件资源。Q4可以用 $readmemh 初始化存储器吗可以这是大数据量初始化的推荐做法。文件内容格式为十六进制每行一个值// init_data.txt 01 02 03 04 05 06 07 08Q5Verilog-2001 和 Verilog-1995 在存储器声明上有区别吗Verilog-1995 不支持存储器数组声明Verilog-2001 才引入了reg [width-1:0] name [size-1:0]语法。现代综合工具默认都支持 Verilog-2001。Q6存储器可以跨模块传递吗不能。存储器是模块内部的局部数据结构不能直接作为模块端口传递。如果需要跨模块访问可以将其拆分为用reg [width-1:0]信号 地址总线 读写控制信号的方式实现接口化的 RAM。十一、总结Verilog 存储器数组声明是 FPGA/ASIC 设计中非常实用的数据结构核心要点归纳如下声明语法reg [位宽-1:0] 名字 [元素数-1:0];先写位宽再写元素数千万别写反内存布局8 个 3 位元素 24 bit支持按元素mem[i]和按位mem[i][b]两种访问粒度初始化不支持整体赋值必须用 for 循环逐个元素初始化综合结果静态索引 → 触发器组动态索引 → 寄存器堆/RAM常见陷阱位宽和元素数写反、下标越界、整体赋值报错、组合逻辑未全赋值产生锁存器工程匹配UART 发送缓存需要 8 bit 元素时应声明reg [7:0] mem [7:0]而非reg [2:0] mem [7:0]掌握存储器的正确用法能够让你的 Verilog 代码更加清晰、高效避免综合结果与预期不符的调试噩梦。标签Verilog FPGA 存储器 数组 寄存器 RAM 初始化 位宽 UART版权声明本文为原创技术分享转载请注明出处。如有疑问欢迎评论区交流

相关推荐

粉丝福利社:AI Agent智能体与MCP开发实践——基于Qwen3大模型的配置骨架与验证
粉丝福利社:AI Agent智能体与MCP开发实践——基于Qwen3大模型的配置骨架与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 21:54:27

高质量测试 Skill 编写手册:用渐进式披露拆解 SKILL.md 结构
高质量测试 Skill 编写手册:用渐进式披露拆解 SKILL.md 结构

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 21:54:27

PORON替代材料怎么选?3C电子产品国产PU泡棉选型指南
PORON替代材料怎么选?3C电子产品国产PU泡棉选型指南

在手机、平板电脑、笔记本电脑、智能穿戴设备以及其他3C电子产品中,PU聚氨酯泡棉是一种非常常见的功能性材料。 它可能不会出现在最终产品的显眼位置,却承担着缓冲、密封、减震、间隙填充、组件保护等重要功能。 尤其是在产品越来越轻薄、内部结构越来越… · 2026/9/27 21:54:27

做网站动图的软件怎么选?避开高价坑,新手看这篇就够
做网站动图的软件怎么选?避开高价坑,新手看这篇就够

做网站动图的软件怎么选?避开高价坑,新手看这篇就够 找建站公司最让人头疼的,就是报价单上一堆看不懂的名词,动不动就几万块,生怕被坑高价。很多河北转行做网站的新手,刚入行就被客户问倒:做个动图到底用什么软件?这钱该花多少?别急,咱们把【做网站… · 2026/9/28 0:16:57

3个坑搞定wordpress文章对齐完整流程
3个坑搞定wordpress文章对齐完整流程

3个坑搞定wordpress文章对齐完整流程 刚接了个单子,客户指着屏幕上歪歪扭扭的正文骂街:“这模板网站太丑不够用,看着就像地摊货!”我一看后台,确实是典型的 WordPress 默认样式没调好,加上主题作者偷懒,CSS 写得乱七八糟。… · 2026/9/28 0:16:51

佛山网络公司排名前十避坑指南:3个实战案例拆解
佛山网络公司排名前十避坑指南:3个实战案例拆解

佛山网络公司排名前十避坑指南:3个实战案例拆解 别再被那些花里胡哨的模板网站骗了。 你花几万块做的站,上线后客户只说了一句“好丑”,然后转头去找了隔壁那家看起来更土但更实在的公司。 这就是佛山网站建设圈子里最残酷的真相:… · 2026/9/28 0:16:45

搞懂网站外链有什么用及完整流程
搞懂网站外链有什么用及完整流程

搞懂网站外链有什么用及完整流程 网站被黑挂马不知道怎么办?别慌,这往往和外链管理失控有关。很多站长盯着SEO排名,却忽略了外链的“毒性”,导致网站权重暴跌。其实,解决这个问题的 完整流程… · 2026/9/28 0:16:33

告别模板丑站!5个实战案例揭秘html网页制作动态效果安全防线
告别模板丑站!5个实战案例揭秘html网页制作动态效果安全防线

告别模板丑站!5个实战案例揭秘html网页制作动态效果安全防线 别再被那些千篇一律的模板网站恶心了。看着满屏的廉价感,客户嫌丑,自己看着也心累。 想做出有灵魂的站点,html网页制作动态效果是关键。但光好看没用,安全才是底线。… · 2026/9/28 0:15:26

网站建设是属于软件开发费吗进阶技巧
网站建设是属于软件开发费吗进阶技巧

网站建设属于软件开发费吗 3个实操细节教你选对服务商 很多老板一上来就问:我想做个官网,这钱算软件费还是服务?其实你不用纠结财务科目,真正该关心的是: 自己不会代码想做网站,到底找谁做才不踩坑?… · 2026/9/28 0:15:07

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

制作网页比较方便的软件怎么选?一文搞懂避坑指南
制作网页比较方便的软件怎么选?一文搞懂避坑指南

制作网页比较方便的软件怎么选?一文搞懂避坑指南 很多老板一上来就问:做个网站多少钱?但我反问他:你的域名买了吗?服务器租了吗?他一脸懵。这就是典型的“域名服务器搞不懂”。别急,今天咱们不聊虚的,直接 一文搞懂 那些让你头秃的技术名词。… · 2026/9/28 0:00:06

婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量
婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量

婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量 找婚恋网站建站公司,最怕的就是被坑高价。很多同行跟我吐槽,报价单上写得模棱两可,功能栏里全是“高级定制”、“专属UI”,结果落地全是套壳。今天不聊虚的,直接甩几个我经手的 实战案例… · 2026/9/28 0:00:19

济南做网站多少钱:3个案例拆解,防黑源码下载全攻略
济南做网站多少钱:3个案例拆解,防黑源码下载全攻略

济南做网站多少钱:3个案例拆解,防黑源码下载全攻略 上周济南一个做建材的老板找我,脸都绿了。他的官网首页弹出了赌博广告,后台被植入了挖矿脚本。他慌得问我:“网站被黑挂马不知道怎么办?能不能直接找之前的外包公司要源码下载,看看哪里被动了手脚?… · 2026/9/28 0:00:25

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码