ddr3理论带宽计算:
若最大时钟频率400MHZ,数据位宽是16位,也就是16根数据线,ddr是双沿传输,则理论带宽为2*400MHZ*16 = 12800Mbit/s = 1600Mbyte/s = 1.5625Gbyte/s
 
1:在IP核列表里的Memory interface generator可调用ddr控制器并对参数进行设置
2:对IP核进行初始化
 
在调取 DDR3 SDRAM 控制器之后,并不可以立即使用该 IP 核完成 DDR3SDRAM 的读和写的,而是要在该 IP 核初始化成功之后,才可以进行读和写
(1)例化IP核
  首先建立一个顶层文件,复制IP核的实例化模板到顶层,观察实例化模板会发现有一部分信号是以 ddr3 开头的,此类的信号均为DDR3 SDRAM 芯片的引脚变量,因此在顶层模块需要将其设置为端口变量,我们需要将此类信号写入到顶层模块名后面的小括号内,并设定好输入/输出类型,以及变量的位宽。
  在我们调取 IP 核 之 后 , 会 在 Vivado 工程目录下生成一个 .\project_1.srcs\sources_1\ip\ddr3_ctrl(ddr3_ctrl 为调取 IP 核的名称)的路径,该路径下文件夹内会有三个子文件夹。其中,docs 中为该 IP 核相关的文档文件,比如该 IP 核的使用方法等文档都在该文件夹中涉及;example_design 文件夹中为 Xilinx 官方提供的该 IP 核参考文件,假如不知道如何使用该 IP 核,可以参考该文件夹内提供的相关例程
(2)仿真测试IP核
  在调取 IP 核时,我们已经生成了 DDR3 SDRAM 控制器 IP 核的仿真模型文件。打开 example_design 文件夹中的sim文件夹。会看到一个 ddr3_model.sv 文件,该文件即为我们的仿真模型文件,将该文件添加到 Vivado 工程的 simulation sources 内,然后将仿真模型 ddr3_model.sv 实例化到 tb 文件。
  查看 init_calib_complete 波形是否变成高电平,若是变成高电平,则 DDR3 SDRAM 控制器 IP 核初始化成功,不然则不成功
3:DDR3 Sdram写时序的实现
  DDR3 SDRAM控制器IP核主要预留了两组总线,一组可以直接绑定到DDR3SDRAM 芯片端口,一组是留给用户端使用的。中 IP 核与存储芯片之间的总线大部分以ddr 作为开头,这部分总线我们只需要在 top 模板设为端口即可,无需我们控制。用户端与 IP 核之间的总线大部分以 app 作为开头,并且从用户端输出到 IP 核的信号线需要我们产生
![]()
 
  如图 1 所示的中间部分为我们调取的 IP 核,user FPGA Logic 为用户端逻辑,DDR2/DDR3 SDRAM 为存储芯片。其中 IP 核与存储芯片之间的总线大部分以ddr 作为开头,这部分总线我们只需要在 top 模板设为端口即可,无需我们控制。用户端与 IP 核之间的总线大部分以 app 作为开头,并且从用户端输出到 IP 核的信号线需要我们产生
  首先通过以 app 为开头的总线实现对 IP写控制操作。为了更好的了解相关的参数,我们可以登录 Xilinx 官网下载 FPGA上DDR3芯片的UG手册。通过阅读手册了解各个信号的含义和作用,以及不同模式读写的时序,突发长度等,
  在了解了写命令和写数据的时序及相应关系之后,我们画出写控制模块的框图
  
 
  当 wr_cmd_start 有效时启动本次的写突发,根据由外部输入的 wr_cmd_bl 可以确定本次突发需要写多少数据;wr_cmd_start 有效时,wr_cmd_addr 代表本次突发写的起始地址,由于 128bit = 8x16bit,因此每个 128bit 数据需要占用 8 个DDR3 SDRAM 的地址,因此每次传入一个 128bit 的数据,该地址需要加 8;由于该模块只实现写控制,因此 wr_cmd_instr 可以一直保持为写状态;可以根据是否需要保持写入的数据有效,来调整 wr_cmd_mask 的值;当本次突发写进行时,当写入一个数据,则可以由 data_req 向外界请求一个新的输入本次突发的数据;
可以由 wr_end 可以告知外界模块,本次突发写结束。
4:读时序的实现
   ![]()
 
  读模块的接口与写模块基一致。当 rd_cmd_start 有效时,启动本次的读突发,根据由外部输入的 rd_cmd_bl可以确定本次突发需要读出多少数据;rd_cmd_start 有效时,rd_cmd_addr 代表本次突发读的起始地址,由于 128bit = 8x16bit,因此每个 128bit 数据需要读出 8 个DDR3 SDRAM 的地址内数据,因此每发送一次 rd_cmd_start,rd_cmd_addr 需要加 8;由于该模块只实现读控制,因此 rd_cmd_instr 可以一直保持为读状态;可以由 rd_end 可以告知外界模块,本次突发读结束。
5:读写仲裁模块的实现
  在我们实现了 DDR3 控制器 IP 核的读、写之后会发现读和写是共用一组命令线的,因此读、写需要分时的使用IP 核中的命令总线,具体的解决方法是:
  对于 wr_ctrl 和 rd_ctrl 模块的 app_addr信号,我们可以在不使用时将其置为 0,这样我们将 wr_ctrl 和 rd_ctrl 模块的 app_addr 进行按位或,结果即为 IP 核的 app_addr。同理,IP 核的 app_en 也可以通过 wr_ctrl 和 rd_ctrl 模块的 app_en 按位或得到。对于app_cmd信号,当读模块工作时即app_wr_en = 1'b1时,让app_cmd = app_wr_cmd,否则让app_cmd = app_rd_cmd。下面是仲裁模块的状态机和接口图。
![]()