简介:这份资源面向FPGA与嵌入式系统开发者,聚焦XILINX平台上DDR3内存条的读写测试与仿真验证,适合已具备Verilog基础、希望掌握高速存储接口设计的中高级学习者。内容围绕DDR3协议特性、MIG IP核配置、用户逻辑与内存控制器连接,以及基于VIVADO 2015.2的功能仿真展开,可帮助读者理解地址、命令、数据与控制信号的时序关系,排查读写冲突、数据丢失与延迟等问题。压缩包共379个文件,约36.56MB,以Verilog源码、XML配置、仿真日志、Tcl脚本、XDC约束及DCP综合检查点为主,另含少量VHDL、SystemVerilog与批处理脚本,完整保留了工程从综合到仿真的中间产物。已有3540人学习下载,读者可借此获得一套可直接复用的DDR3读写测试工程,对照仿真波形与报告验证设计正确性,为实际硬件调试打下基础。
1. 从一块掉进 DDR3 时序坑里的板子说起
手里这块 FPGA 开发板跑飞了好几次,最后定位到 DDR3 读写时序上——这是很多做 Verilog FPGA DDR3 项目的开发者都会撞上的墙。这个项目就是干这件事的:在 XILINX 平台上,用 VIVADO 2015.2 搭一个 DDR3 内存条的读写测试工程,仿真跑通,能实际下载到板子上验证数据通路。它适合两类人:一类是刚接触 FPGA 存储接口、想找一个能跑通的 DDR3 读写例程来改的新手;另一类是手上有 XILINX 板子、需要快速验证 DDR3 硬件链路是否正常的熟手。整个工程围绕 MIG(Memory Interface Generator)IP 核展开,用 Verilog 写测试逻辑,仿真波形能看到完整的写命令、读命令和数据返回。下面按「这工程长什么样 → 怎么跑起来 → 怎么改」的顺序拆一遍。
2. 工程架构拆解:MIG IP 核加测试逻辑的两层结构
2.1 整体数据通路
这个 DDR3 读写测试工程的结构不复杂,核心就两层:底层是 XILINX 提供的 MIG IP 核,负责把用户侧的简单读写请求翻译成 DDR3 颗粒能听懂的命令、地址、时序信号;上层是自己写的测试逻辑,产生写数据、发起读写命令、校验读回的数据对不对。
数据从测试逻辑出发,经过 MIG 的用户接口(User Interface),再经过物理层送到 DDR3 颗粒,读的时候反过来走一遍。MIG 的用户接口是这套设计里最需要盯住的地方,它把 DDR3 复杂的 bank 管理、刷新、时序参数全部封装掉,留给用户的是一组相对干净的信号:app_addr、app_cmd、app_en、app_wdf_data、app_rd_data 这些。
常见做法是测试逻辑用一个简单的状态机来驱动这套接口,先写一段数据进去,再读出来比对。这个工程也是这个思路,状态机不复杂,但每个信号的握手时序必须对齐,否则仿真能过、上板就翻车。
2.2 目录结构
VIVADO 工程的目录结构大致是这样:
ddr3_test/ ├── ddr3_test.xpr # VIVADO 工程文件 ├── ddr3_test.srcs/ │ ├── sources_1/ │ │ ├── new/ │ │ │ ├── ddr3_test_top.v # 顶层,例化 MIG 和测试逻辑 │ │ │ └── ddr3_rw_test.v # 读写测试状态机 │ │ └── ip/ │ │ └── mig_7series_0/ # MIG IP 核生成的文件 │ ├── constrs_1/ │ │ └── new/ │ │ └── ddr3_test.xdc # 引脚和时序约束 │ └── sim_1/ │ └── new/ │ └── tb_ddr3_test.v # 仿真 testbench └── ddr3_test.runs/ # 综合实现输出顶层文件 ddr3_test_top.v 做两件事:例化 MIG IP 核,把它的用户接口信号引出来接到测试模块;例化测试模块,把读写请求发下去。测试模块 ddr3_rw_test.v 是真正要改的地方,状态机、地址生成、数据比对都在这里。
2.3 MIG IP 核的关键配置
MIG 在 VIVADO 2015.2 里的配置界面有几个参数必须和板子上的 DDR3 颗粒对上,对不上就是仿真过、上板挂:
| 配置项 | 说明 | 常见取值 |
|---|---|---|
| Memory Type | 内存类型 | DDR3 SDRAM |
| Memory Part | 颗粒型号 | 按板子实际颗粒选 |
| Data Width | 数据位宽 | 16 / 32 / 64 |
| Burst Length | 突发长度 | 8 |
| Input Clock Period | 输入时钟周期 | 按板子晶振填 |
| Memory Speed Grade | 速度等级 | 按颗粒手册填 |
这些参数在 MIG 向导里填错一个,仿真可能看不出来,上板就是读回全 0 或者全 F。我一般会先把板子的原理图和 DDR3 颗粒手册翻出来,把型号、位宽、速度等级确认一遍再开 MIG 向导。
2.4 用户接口的握手信号
MIG 用户接口里,写和读是分开的。写的时候要同时处理命令通道和数据通道:
// 写命令通道 app_en <= 1'b1; // 命令有效 app_cmd <= 3'b000; // 000 表示写 app_addr <= wr_addr; // 写地址 // 写数据通道 app_wdf_wren <= 1'b1; // 写数据有效 app_wdf_data <= wr_data; // 写数据 app_wdf_end <= 1'b1; // 突发结束 app_wdf_mask <= 8'h00; // 字节掩码,全 0 表示都写读的时候只走命令通道,数据从 app_rd_data 回来,配合 app_rd_data_valid 有效:
app_en <= 1'b1; app_cmd <= 3'b001; // 001 表示读 app_addr <= rd_addr; // 读数据返回 if (app_rd_data_valid) begin rd_data <= app_rd_data; // 锁存读回数据 end这里有个容易忽略的点:app_en 和 app_wdf_wren 不要求同一拍拉高,MIG 允许写命令和写数据之间有几个周期的偏移,但偏移不能超过 MIG 配置里设定的写数据延迟。仿真里如果看到写数据丢了,先查这个偏移。
3. 仿真跑通:从 testbench 到波形验证
3.1 仿真环境搭建
VIVADO 2015.2 自带仿真器,不用额外装 ModelSim 也能跑。工程建好后,在 Simulation Sources 里加一个 testbench,例化顶层模块,给时钟和复位,然后等状态机自己跑完。
testbench 的核心是产生时钟和复位:
// 200MHz 差分时钟,按 MIG 配置的输入时钟来 initial begin sys_clk_p = 0; forever #2.5 sys_clk_p = ~sys_clk_p; // 200MHz end assign sys_clk_n = ~sys_clk_p; // 复位保持一段时间 initial begin sys_rst = 1'b1; #200; sys_rst = 1'b0; end时钟周期要和 MIG 向导里填的输入时钟周期一致,不一致的话 MIG 内部 PLL 锁不住,仿真里能看到 init_calib_complete 一直不拉高。
3.2 仿真步骤
在 VIVADO 里跑仿真的步骤:
- 打开工程,确认 Simulation Sources 里 testbench 已设为 top。
- 左侧 Flow Navigator 点 Simulation → Run Simulation → Run Behavioral Simulation。
- 等波形窗口打开,把 init_calib_complete、app_rd_data_valid、app_rd_data 这几个信号加到波形里。
- 点 Run All,等状态机跑完。
仿真跑通的标准是:init_calib_complete 拉高,说明 MIG 校准完成;然后能看到 app_en 拉高发起写命令,过一段时间 app_en 再拉高发起读命令,app_rd_data_valid 拉高时 app_rd_data 上的数据和写进去的一致。
3.3 波形里要盯的信号
波形窗口里信号很多,但真正要盯的就几个:
- init_calib_complete:MIG 校准完成标志,不拉高后面都不用看。
- app_en + app_cmd:命令通道,看写命令和读命令有没有发出去。
- app_wdf_wren + app_wdf_data:写数据通道,看数据有没有跟上。
- app_rd_data_valid + app_rd_data:读数据返回,看数据对不对。
如果 init_calib_complete 一直不拉高,先查时钟和复位,再查 MIG 配置里的颗粒参数。如果命令发出去了但读数据不对,查地址对齐和写数据延迟。
3.4 仿真通过但上板失败的原因
仿真通过只说明逻辑时序在理想条件下没问题,上板还要过物理层这一关。常见原因有三个:一是 MIG 配置里的颗粒参数和板子实际颗粒不一致,仿真用的是行为模型,不校验这个;二是引脚约束文件里的引脚分配和板子原理图对不上;三是输入时钟频率和板子晶振不一致。这三个都是仿真阶段看不出来的,必须对着原理图和手册逐个核对。
4. 上板验证与常见问题排查
4.1 生成比特流并下载
仿真通过后,在 VIVADO 里跑综合和实现,生成比特流,然后用 Hardware Manager 下载到板子上。下载前确认两件事:约束文件里的引脚分配和板子原理图一致;MIG 配置里的输入时钟频率和板子晶振一致。
下载后可以通过 ILA(Integrated Logic Analyzer)抓内部信号看实际运行情况。ILA 的用法是在综合前把要抓的信号标记出来,VIVADO 会自动插入逻辑分析核,下载后在 Hardware Manager 里能看到实时波形。
4.2 常见问题排查
现象一:init_calib_complete 一直不拉高。原因:MIG 校准没完成,通常是时钟或复位有问题,或者颗粒参数配错。 解决:先用示波器或 ILA 确认输入时钟有没有、频率对不对;再核对 MIG 配置里的颗粒型号、位宽、速度等级和板子实际颗粒是否一致。
现象二:写命令发出去了,但读回来全是 0。原因:写数据没真正写进去,或者读地址和写地址没对上。 解决:在波形里看 app_wdf_wren 和 app_wdf_data 有没有在写命令附近拉高;检查写地址和读地址是不是同一个地址。
现象三:仿真通过,上板读回数据错位。原因:写命令和写数据之间的延迟超过了 MIG 配置的写数据延迟。 解决:把 app_wdf_wren 相对 app_en 的延迟调小,或者查 MIG 配置里的写数据延迟参数。
现象四:读回数据偶尔对偶尔错。原因:时序约束没做好,或者 DDR3 颗粒的刷新和读写冲突。 解决:检查 XDC 里的时序约束,确认输入时钟约束和引脚约束都写了;如果还不行,降低读写频率试试。
现象五:ILA 抓不到信号。原因:要抓的信号被综合优化掉了,或者 ILA 核没正确插入。 解决:给要抓的信号加 (* keep = "true" *) 属性,防止被优化;确认综合日志里 ILA 核插入成功。
4.3 上板验证的检查清单
上板前按这个清单过一遍,能省不少时间:
- MIG 配置里的颗粒型号、位宽、速度等级和板子实际颗粒一致。
- 输入时钟频率和板子晶振一致。
- XDC 里的引脚分配和板子原理图一致。
- 复位信号极性正确,复位保持时间足够。
- 仿真里 init_calib_complete 能拉高,读写数据一致。
5. 二次开发:把测试工程改成你自己的存储应用
5.1 改造思路
这个工程本质是一个 DDR3 读写的最小闭环,二次开发就是在这个闭环上长出你自己的应用。常见的改造方向有三个:一是把测试状态机换成真正的数据流控制,比如视频帧缓存、数据采集缓存;二是加一个仲裁模块,让多个模块共享 DDR3 带宽;三是把读写地址从固定值改成动态生成,支持大块数据的连续读写。
改造时最需要注意的是 MIG 用户接口的握手时序不能乱。测试工程里状态机简单,命令和数据之间的延迟是固定的;一旦换成复杂的数据流,命令通道和数据通道的配合就容易出问题。我一般会先写一个简单的读写仲裁模块,把命令和数据分开管理,再往上叠应用逻辑。
5.2 加一个简单的读写仲裁
如果多个模块要同时访问 DDR3,需要一个仲裁模块来决定谁先发命令。下面是一个简单的轮询仲裁示例:
// 两路请求的轮询仲裁 always @(posedge clk) begin if (rst) begin grant <= 2'b01; // 默认给通道 0 end else if (req[0] && req[1]) begin grant <= {grant[0], grant[1]}; // 轮询切换 end else if (req[0]) begin grant <= 2'b01; end else if (req[1]) begin grant <= 2'b10; end end // 根据 grant 把对应通道的命令接到 MIG assign app_en = grant[0] ? req[0] : req[1]; assign app_cmd = grant[0] ? cmd[0] : cmd[1]; assign app_addr = grant[0] ? addr[0] : addr[1];这个仲裁只处理命令通道,数据通道要根据命令通道的 grant 同步切换。实际用的时候还要考虑读写优先级、带宽分配,但作为改造起点够用了。
5.3 验证改造结果
改造后不能直接上板,先在仿真里验证。仿真时重点看三件事:仲裁切换时命令通道有没有断流;数据通道和命令通道有没有对齐;读写数据比对有没有错。仿真通过后再上板,用 ILA 抓实际波形,对比仿真和上板的差异。
我自己的习惯是每次改完 MIG 用户接口附近的逻辑,都强制走一遍「仿真 → ILA 抓波形 → 数据比对」这个流程,不跳过任何一步。有一次偷懒跳过仿真直接上板,结果仲裁模块在切换时丢了一个写命令,数据写了一半,查了一整天才定位到。从那以后我每次改完接口逻辑都强制走一遍仿真加 ILA 验证,再急也不省这一步。希望帮到你。
本文还有配套的精品资源,点击获取