FPGA_DDR3_Ctrl/rtl /ddr3_test.v

 

 

突发写时序#

  写数据时序图如下。

image

 

AXI4突发写可以分为7个状态,分别为:
  1.写空闲:等待突发写触发信号。
  2.写通道地址等待:准备好写地址AWADDR,然后拉高AWVALID。
  3.写通道写地址:从机接受到AWVALID,发出AWREADY。
  4.写数据等待:准备好写数据WDATA,拉高WVALID。
  5.写数据循环:从机接受WVALID,确认数据WDATA有效并且接受,发出WREADY,AXI是突发传输:循环该操作到接受到WLAST最后一个数据标志位。
  6.接受写应答:接受到从机发出的BVALID,主机发出BREADY。
  7.写结束:拉低未拉低的信号,进入写空闲。

突发读时序#

  读数据时序图如下。

image

 AXI4突发读可以分为6个状态,分别为:
  1.读空闲:等待突发读触发信号。
  2.读通道写地址等待:准备好写地址ARADDR,然后拉高ARVALID。
  3.读通道写地址:从机接收到ARVALID,发出ARREADY。
  4.读数据等待:从机准备好读数据RDATA,并拉高RVALID。
  5.读数据循环:主机接收RVALID,确认数据RDATA有效并接收,发出RREADY给从机,AXI是突发传输:循环该操作到接收到RLAST最后一个数据标志位。
  6.读结束:拉低未拉低的信号,进入读空闲。

 

ddr3-ip-核

AXI4的接口描述,左侧是IP核生成的接口信号,括号里的是工程中(本工程如s00_axi_awid,其他信号类推)定义的信号。可以发现,接口信号中以“s_axi_aw”开头的是写地址通道信号,以“s_axi_w”开头的是写数据通道信号,以“s_axi_b”开头的是写响应通道信号,以“s_axi_ar”开头的是读地址通道信号,以“s_axi_r”开头的是读数据响应通道信号。

 

DDR3 IP核所有的接口描述一下。带ddr3的信号是引脚信号,与外部ddr3存储器相连,不需要管;带app的信号是本地接口维护命令信号,不用使用,输入信号给0,输出信号空接;带ui的信号是给用户侧使用的时钟信号和复位信号,注意复位信号是高电平有效;sys_clk_i是ip核系统时钟,一般设置为200M,这样参考时钟可以选择use system clk,所以这里的clk_ref_i被注释了;还要注意ip系统复位输入信号sys_rst,是低电平有效。

 

 

***********************************************************************************************************************************************

 

AX7101/AX7102/AX7103 开发板上使用了 2 个 Micron DDR3 的颗粒 MT41J256M16HA,每个 DDR 芯片的容量为 4Gb。两个 DDR3 芯片组合成 32 位的数据总线宽度和 FPGA 相连接。

 

核心板两片DDR原理图

这里可以看到两片DDR是并联的,两片DDR地址线共享;数据位宽,单片DDR数据位宽为16位,两片DDR数据位宽为32位;

DDR3外部接口:左侧是单片,右侧是两片

外部引脚,由于两片DDR的地址线共享,数据分开存放,所以两片DDR的dm(数据选通)、dqs(数据同步)、dq(数据总线)信号位宽为单片的两倍,而地址线(addr)位宽相同。

 

1.基本介绍
DDR3 SDRAM 英 文 全 称 “ Double-Data-Rate Three Synchronous Dynamic Random Access Memory”,译为“第三代双倍速率同步动态随机存取内存”或“同步动态随机存储器”,是动态随机存储器(Dynamic Random Access Memory,简称 DRAM)家族的一份子。


同步、动态、随机是其性能特点的外在说明,也是其区别其他存储器的特色标签。这三个概念性的标签,我们要好好理解掌握。


双倍速率(Double-Data-Rate):DDR3 SDRAM 存储器与 SDRAM 有一个很大的不同,DDR3 SDRAM 或者说带 DDR 开头的。包括 DDR1、DDR2、DDR3、DDR4、DDR4,他们都有一个很大的相似点,就是双边沿输出输入数据,通俗来讲就是在一个周期内输出 2 次数据,上升沿输出一次数据,下降沿输出一次数据。而 SDRAM 则是在一个周期内的上升沿输出一次数据,下降沿不输出,所以同频率的 DDR3 SDRAM 与 SDRAM 相比速度快一倍。


同步(Synchronous):与通常的异步 DRAM 不同,DDR3 SDRAM 存在一个同步接口,其工作时钟的时钟频率与对应控制器(CPU/FPGA)的时钟频率相同,并且 SDRAM 内部的命令发送与数据传输均以此时钟为基准,实现指令或数据的同步操作;


动态(Dynamic):DDR3 SDRAM 需要不断的刷新来保证存储阵列内数据不丢失;


随机(Random):数据在 DDR3 SDRAM 中并不是按照线性依次存储,而是可以自由指定地址进行数据的读写。

 

2.存储原理
简单来说,DDR3 SDRAM 内部可以理解为一个存储阵列,这是 DDR3 SDRAM 区别于管道式存储,实现随机地址存取的结构特点。为方便理解,可以将 DDR3 SDRAM 内部存储阵列类比于一张表格,表格中的每一个单元格可以类比为存储阵列的单个存储单元。若想要实现存储阵列中的某一存储单元的数据读写操作,我们要通过行地址(RowAddress)和列地址(Column Address)(先行后列)精确定位到这一存储单元,进而进行数据的读写操作,这就是所谓的随机地址存取。DDR3 SDRAM 存储阵列类比图,如下图所示:

DDR3 SDRAM 的基本存储单位是存储单元,而一个存储单元的容量为若干个 Bit,对于 DDR3 SDRAM 而言就是芯片的位宽,每个Bit存放于一个单独的存储体中,存储体是利用电容能够保持电荷以及可充放电的特性制成,主要由行选通三极管、列选通三极管、存储电容以及刷新放大器构成。电容所存储的电荷会随时间慢慢释放,这就需要不断刷新为电容充电,以保证存储数据可靠性。

如图所示:

 

将每个存储单元简化为单 Bit 的存储体,再将若干存储体排列为矩阵,同一行将行地址线相连,同一列将列地址线相连,就构成了一个存储阵列的简化模型。DDR3 SDRAM:内部存储阵列的简化模型,具体见图:

 

3.内部逻辑功能图

 

相关参考链接:https://blog.csdn.net/weixin_46628093/article/details/115558116

AXI-DDR相关篇参考文档:

1.https://juejin.cn/post/7387581121520205833

2. https://developer.aliyun.com/article/1136407

3.https://blog.csdn.net/weixin_46188211/article/details/124099759

AXI-ddr-接口相关参数

 

突发传输大小(burst size)

突发传输大小对应3位的AWSIZE和ARSIZE,这个信号代表的是传输的数据位宽,单位为8bit的字节。

Bytes=2^Burst_size

 

突发传输种类(burst type)

突发传输的种类对应的信号为ARBURST和AWBURST,这两个信号均为2bit,用以区分Burst传输的种类

FIXED Type

在Fixed种类的burst传输中,每一次访问的地址是相同的,这意味着我们需要对同一个地址进行读写操作;典型的是FIFO,用AXI连接作为从设备的FIFO,只需要考虑Fixed Type的burst传输,这是因为FIFO不涉及到具体的地址来控制读写,数据只需要先入先出即可。

需要注意的是Fixed Type的burst length仅支持1-16

INCR Type

在INCR Type的burst传输中,主设备给出首个地址和控制信号,接下来从设备会自发的计算出接下来传输数据所需要的,递增的,新的地址信号。

换言之,第一次传输的地址是1,并约定INCR Type的传输,之后的递增地址为2,3,4,5,6,7,8。之后的地址都由从设备自行计算得到。这种形式的传输,经常的用在对于连续内存的读写上。

需要注意的是,协议规定,INCR Type的burst length支持1-256

 

WRAP Type

WRAP Type又被称作回旋型的burst传输类型

假如第一次的传输地址是1,约定WRAP Type的传输类型,那么之后的回旋地址类似于2,3,4,0,1这样,地址绕了一个圈。

需要注意的是WRAP Type的burst length仅支持2,4,8,16(即AxLEN = 1/3/7/15)

 

********************************************************************************************************************************************

 

axi_ctrl模块检测到突发完成信号,需要进行突发地址的更新,

即在上次突发地址的基础上加上突发长度 * AXI数据位宽 / 8,因为AXI地址是一个字节一个地址。

更新地址完成,还需判断是否超过用户设置的结束地址,若超过,则需将突发地址设置为起始地址。

 https://www.cnblogs.com/xzjfindgoodjob/p/18254505#:~:text=%E4%BA%A7%E7%94%9F%E7%AC%AC%E4%B8%80%E6%AC%A1%E5%86%99%E7%AA%81%E5%8F%91%E5%90%8E%EF%BC%8C%E5%B0%86%E7%AA%81%E5%8F%91%E9%95%BF%E5%BA%A6%E3%80%81%E7%AA%81%E5%8F%91%E5%9C%B0%E5%9D%80%EF%BC%88%E7%AC%AC%E4%B8%80%E6%AC%A1%E5%8D%B3%E4%B8%BA%E9%A6%96%E5%9C%B0%E5%9D%80%EF%BC%89%E4%BC%A0%E8%BE%93%E7%BB%99%E7%AA%81%E5%8F%91%E5%86%99%E6%A8%A1%E5%9D%97%EF%BC%8C%E6%8E%A5%E4%B8%8B%E6%9D%A5%E5%86%99%E7%AA%81%E5%8F%91%E6%A8%A1%E5%9D%97%E4%BC%9A%E4%BA%A7%E7%94%9F%E8%AF%BB%E5%86%99fifo%E4%BD%BF%E8%83%BD%E4%BF%A1%E5%8F%B7%EF%BC%8C%E7%84%B6%E5%90%8E%E4%BA%A7%E7%94%9F%E7%AA%81%E5%8F%91%E5%AE%8C%E6%88%90%E4%BF%A1%E5%8F%B7%EF%BC%8Caxi_ctrl%E6%A8%A1%E5%9D%97%E6%A3%80%E6%B5%8B%E5%88%B0%E7%AA%81%E5%8F%91%E5%AE%8C%E6%88%90%E4%BF%A1%E5%8F%B7%EF%BC%8C%E9%9C%80%E8%A6%81%E8%BF%9B%E8%A1%8C%E7%AA%81%E5%8F%91%E5%9C%B0%E5%9D%80%E7%9A%84%E6%9B%B4%E6%96%B0%EF%BC%8C%E5%8D%B3%E5%9C%A8%E4%B8%8A%E6%AC%A1%E7%AA%81%E5%8F%91%E5%9C%B0%E5%9D%80%E7%9A%84%E5%9F%BA%E7%A1%80%E4%B8%8A%E5%8A%A0%E4%B8%8A%E7%AA%81%E5%8F%91%E9%95%BF%E5%BA%A6%20%2A%20AXI%E6%95%B0%E6%8D%AE%E4%BD%8D%E5%AE%BD,%2F%208%EF%BC%8C%E5%9B%A0%E4%B8%BAAXI%E5%9C%B0%E5%9D%80%E6%98%AF%E4%B8%80%E4%B8%AA%E5%AD%97%E8%8A%82%E4%B8%80%E4%B8%AA%E5%9C%B0%E5%9D%80%E3%80%82%20%E6%9B%B4%E6%96%B0%E5%9C%B0%E5%9D%80%E5%AE%8C%E6%88%90%EF%BC%8C%E8%BF%98%E9%9C%80%E5%88%A4%E6%96%AD%E6%98%AF%E5%90%A6%E8%B6%85%E8%BF%87%E7%94%A8%E6%88%B7%E8%AE%BE%E7%BD%AE%E7%9A%84%E7%BB%93%E6%9D%9F%E5%9C%B0%E5%9D%80%EF%BC%8C%E8%8B%A5%E8%B6%85%E8%BF%87%EF%BC%8C%E5%88%99%E9%9C%80%E5%B0%86%E7%AA%81%E5%8F%91%E5%9C%B0%E5%9D%80%E8%AE%BE%E7%BD%AE%E4%B8%BA%E8%B5%B7%E5%A7%8B%E5%9C%B0%E5%9D%80%E3%80%82

 

 

DDR3 地址线
DDR3为减少地址线,把地址线分为行地址线和列地址线,在硬件上是同一组地址线;地址线和列地址线是分时复用的,即地址要分两次送出,先送出行地址,再送出列地址。

一般来说列地址线是10位,及A0...A9;行地址线数量根据内存大小,BANK数目,数据线位宽等决定(感觉也应该是行地址决定其他) ;

BANK
bank是存储库的意思,也就是说,一块内存内部划分出了多个存储库,访问的时候指定存储库编号,就可以访问指定的存储库,内存中划分了多少个bank,要看地址线中有几位BA地址,如果有两位,说明有4个bank,如果有3位,说明有8个bank

原文链接:https://blog.csdn.net/dagefeijiqumeiguo/article/details/46455567

 

 双片:

 

AX7101/AX7102/AX7103 开发板上使用了 2 个 Micron DDR3 的颗粒 MT41J256M16HA,每个 DDR 芯片的容量为 4Gb。两个 DDR3 芯片组合成 32 位的数据总线宽度和 FPGA 相连接。

 

 

 

 

image

 

 

https://blog.csdn.net/taowei1314520/article/details/128747170

 

行列地址复用:假设你的存储器容量是16bit,那么可以将这16个比特组织成一个4*4的矩阵,为了找到某个你想要找的bit,比如第1行第2列的那个bit。你先发送二进制的01,表示要找的数据在第1行;接着发送二进制的10,表示要找的数据在第2列。这样一来你就找到了第1行第2列的那个bit。可以发现只要两根地址线就能寻找16个bit了,但是要发送两次地址(一次行地址,一次列地址)‍

行列独立:同样的16bit存储器,这16个bit不是组织成一个矩阵,而是一个数组,标号0~15,所以需要四根地址线来寻找,譬如要找第12个bit,你发送地址线信号1100就能找到。可以发现行列独立的地址线数量比行列地址复用要多,但是地址数据只要一次就能传输完成。

DRAM一般使用行列地址复用技术,而SRAM一般使用行列独立技术。


DRAM 普遍采用的是行与列地址分时复用技术进行寻址。在 DRAM 的矩阵存储单元中,地址可以分成行地址和列地址。在寻址时,必须先进行行寻址然后在进行列寻址,这是由 DRAM 的硬件电路所决定的。所以,对行地址线和列地址线进行共用,传送时只需要一半地址,先传送至缓冲区,再传送给译码器即可。既节省了地址线,也不会降低 DRAM 原有的工作速率(因为 DRAM 的行地址和列地址就是要分时传送的)。

如果是 SRAM 采用这种寻址方式的话,则会大大降低其工作速度。Cache多为SRAM,存储单元是线性排列,不像DRAM那样分行列,所以不适用行列地址线复用方式。不过说到底是因为Cache就是为了快才存在的,容量又小,所以SRAM也用得起。

https://www.cnblogs.com/exungsh/p/15957909.html

 双片:

 

//------------- u_axi_ddr -------------
//xilinx提供的mig ip核,开启axi4接口

axi_ddr  u_axi_ddr
(
// Memory interface ports
  .ddr3_addr (ddr3_addr ),     //地址线
  .ddr3_ba   (ddr3_ba   ),     //bank线
  .ddr3_cas_n(ddr3_cas_n),     //列使能信号,低电平有效
  .ddr3_ck_n (ddr3_ck_n ),     //ddr3差分时钟
  .ddr3_ck_p (ddr3_ck_p ),     //ddr3差分时钟 
  .ddr3_cke  (ddr3_cke  ),     //ddr3时钟使能信号  
  .ddr3_ras_n(ddr3_ras_n),     //行使能信号,低电平有效
  .ddr3_reset_n(ddr3_reset_n), //ddr3复位
  .ddr3_we_n (ddr3_we_n ),     //写使能信号,低电平有效  
  .ddr3_dq   (ddr3_dq   ),     //数据线
  .ddr3_dqs_n(ddr3_dqs_n),     //数据选取脉冲差分信号
  .ddr3_dqs_p(ddr3_dqs_p),     //数据选取脉冲差分信号
  .init_calib_complete(init_calib_complete) , //ip核初始化完成
  
  .ddr3_cs_n (ddr3_cs_n ),     //ddr3片选信号
  .ddr3_dm   (ddr3_dm   ),     //ddr3掩码
  .ddr3_odt  (ddr3_odt  ),     //odt阻抗 
// Application interface ports 
  .ui_clk   (ui_clk),          //用户端口时钟
  .ui_clk_sync_rst(ui_clk_sync_rst),    //复位
  .mmcm_locked(),
  .aresetn    (1'b1),    
  .app_sr_req ('b0),
  .app_ref_req('b0),
  .app_zq_req ('b0),
  .app_sr_active(),
  .app_ref_ack(),
  .app_zq_ack(),  
// System Clock Ports  
  .sys_clk_i(sys_clk),        //ip核时钟
//  .clk_ref_i(ddr3_clk),        //ip核参考时钟  
  .sys_rst(rst_n)                //ip核复位   
  
  //axi写通道地址与控制信号
  .s_axi_awid    (s00_axi_awid    ), //写地址ID                        输入[3:0]
  .s_axi_awaddr  (s00_axi_awaddr  ), //写地址                          输入[29:0]
  .s_axi_awlen   (s00_axi_awlen   ), //突发长度                        输入[7:0]
  .s_axi_awsize  (s00_axi_awsize  ), //突发大小                        输入[2:0]
  .s_axi_awburst (s00_axi_awburst ), //突发类型                        输入[1:0]
  .s_axi_awlock  (s00_axi_awlock  ), //总线锁信号                      输入[0:0]
  .s_axi_awcache (s00_axi_awcache ), //内存类型                        输入[3:0]
  .s_axi_awprot  (s00_axi_awprot  ), //保护类型                        输入[2:0]
  .s_axi_awqos   (s00_axi_awqos   ), //质量服务QoS                     输入[3:0]
  .s_axi_awvalid (s00_axi_awvalid ), //有效信号                        输入[0:0]
  .s_axi_awready (s00_axi_awready ), //握手信号awready                 输出[0:0]
  //axi写通道数据
  .s_axi_wdata   (s00_axi_wdata   ), //写数据                          输入[63:0]
  .s_axi_wstrb   (s00_axi_wstrb   ), //写数据有效的字节线              输入[7:0]
  .s_axi_wlast   (s00_axi_wlast   ), //表明此次传输是最后一个突发传输  输入[0:0]
  .s_axi_wvalid  (s00_axi_wvalid  ), //写有效,表明此次写有效          输入[0:0]
  .s_axi_wready  (s00_axi_wready  ), //表明从机可以接收写数据          输出[0:0]
  //axi写通道应答                    
  .s_axi_bid     (s00_axi_bid     ), //写响应ID TAG                    输出[3:0]
  .s_axi_bresp   (s00_axi_bresp   ), //写响应,表明写传输的状态        输出[1:0]
  .s_axi_bvalid  (s00_axi_bvalid  ), //写响应有效                      输出[0:0]
  .s_axi_bready  (s00_axi_bready  ), //表明主机能够接收写响应          输入[0:0]
  //axi读通道地址与控制信号                                            
  .s_axi_arid    (s00_axi_arid    ), //读地址ID                        输入[3:0]
  .s_axi_araddr  (s00_axi_araddr  ), //读地址                          输入[29:0]
  .s_axi_arlen   (s00_axi_arlen   ), //突发长度                        输入[7:0]
  .s_axi_arsize  (s00_axi_arsize  ), //突发大小                        输入[2:0]
  .s_axi_arburst (s00_axi_arburst ), //突发类型                        输入[1:0]
  .s_axi_arlock  (s00_axi_arlock  ), //总线锁信号                      输入[0:0]
  .s_axi_arcache (s00_axi_arcache ), //内存类型                        输入[3:0]
  .s_axi_arprot  (s00_axi_arprot  ), //保护类型                        输入[2:0]
  .s_axi_arqos   (s00_axi_arqos   ), //质量服务QOS                     输入[3:0]
  .s_axi_arvalid (s00_axi_arvalid ), //有效信号                        输入[0:0]
  .s_axi_arready (s00_axi_arready ), //握手信号arready                 输出[0:0]
  //axi读通道数据,包括应答          
  .s_axi_rid     (s00_axi_rid     ), //读ID tag                        输出[3:0]  
  .s_axi_rdata   (s00_axi_rdata   ), //读数据                          输出[63:0]
  .s_axi_rresp   (s00_axi_rresp   ), //读响应,表明读传输的状态        输出[1:0]
  .s_axi_rlast   (s00_axi_rlast   ), //表明读突发的最后一次传输        输出[0:0]
  .s_axi_rvalid  (s00_axi_rvalid  ), //表明此通道信号有效              输出[0:0]
  .s_axi_rready  (s00_axi_rready  ), //表明主机能够接收读数据          输入[0:0]
                                     


);
MIG 注释

 

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/06/21 15:48:17
// Design Name: 
// Module Name: tb_ddr3_test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module tb_ddr3_test(

    );

// reg                 clk     ;
reg                sys_clk_p;
reg                sys_clk_n;
reg                 rst_n   ;
    
wire [14:0] ddr3_addr       ;  
wire [2:0]  ddr3_ba         ;
wire        ddr3_cas_n      ;
wire        ddr3_ck_n       ;
wire        ddr3_ck_p       ;
wire        ddr3_cke        ;
wire        ddr3_ras_n      ;
wire        ddr3_reset_n    ;
wire        ddr3_we_n       ;
wire [31:0] ddr3_dq         ;
wire [3:0]  ddr3_dqs_n      ;
wire [3:0]  ddr3_dqs_p      ;
wire        ddr3_cs_n       ;
wire [3:0]  ddr3_dm         ;
wire        ddr3_odt        ;

initial                                                
begin                                                  
    // clk = 1   ;  
    sys_clk_p = 1;  
    sys_clk_n = 0;  
end                                                    
// always #10 clk = ~clk ;
always #2.5 sys_clk_p = ~sys_clk_p ;//200Mhz
always #2.5 sys_clk_n = ~sys_clk_n ;

 
initial                                                
begin                                                  
    rst_n = 0   ;    
    #100
    rst_n = 1   ;          
end 
    
ddr3_test   ddr3_test_uut(
    // .clk          (clk            )   ,
    .sys_clk_p(sys_clk_p),      
    .sys_clk_n(sys_clk_n),        
    .rst_n        (rst_n          )   ,

    .ddr3_addr    ( ddr3_addr )   ,
    .ddr3_ba      (   ddr3_ba   )   ,
    .ddr3_cas_n   (ddr3_cas_n)   ,
    .ddr3_ck_n    ( ddr3_ck_n )   ,
    .ddr3_ck_p    ( ddr3_ck_p )   ,
    .ddr3_cke     (  ddr3_cke  )   ,
    .ddr3_ras_n   (ddr3_ras_n   )   ,
    .ddr3_reset_n (ddr3_reset_n )   ,
    .ddr3_we_n    ( ddr3_we_n   )   ,
    .ddr3_dq      (   ddr3_dq   )   ,
    .ddr3_dqs_n   (ddr3_dqs_n   )   ,
    .ddr3_dqs_p   (ddr3_dqs_p   )   ,
    .ddr3_cs_n    ( ddr3_cs_n   )   ,
    .ddr3_dm      (   ddr3_dm   )   ,
    .ddr3_odt     (  ddr3_odt   )   

);
 
// ddr3_model    ddr3_model_inst
// (    
    // .rst_n           (rst_n            ),    
    // .ck              (ddr3_ck_p        ),    
    // .ck_n            (ddr3_ck_n        ),    
    // .cke             (ddr3_cke        ),    
    // .cs_n            (ddr3_cs_n        ),    
    // .ras_n           (ddr3_ras_n        ),    
    // .cas_n           (ddr3_cas_n        ),    
    // .we_n            (ddr3_we_n        ),    
    // .dm_tdqs         (ddr3_dm        ),    
    // .ba              (ddr3_ba        ),    
    // .addr            (ddr3_addr        ),    
    // .dq              (ddr3_dq        ),    
    // .dqs             (ddr3_dqs_p        ),    
    // .dqs_n           (ddr3_dqs_n        ),    
    // .tdqs_n          (                ),            //NULL
    // .odt             (ddr3_odt        )    
// );    
 
/////////////////////////
//例化DDR3模型    
/////////////////////////
ddr3_model    ddr3_model_inst0
(    
    .rst_n                           (rst_n        ),    
    .ck                              (ddr3_ck_p            ),    
    .ck_n                            (ddr3_ck_n            ),    
    .cke                             (ddr3_cke            ),    
    .cs_n                            (ddr3_cs_n            ),    
    .ras_n                           (ddr3_ras_n            ),    
    .cas_n                           (ddr3_cas_n            ),    
    .we_n                            (ddr3_we_n            ),    
    .dm_tdqs                         (ddr3_dm[1:0]        ),    
    .ba                              (ddr3_ba            ),    
    .addr                            (ddr3_addr            ),    
    .dq                              (ddr3_dq[15:0]        ),    
    .dqs                             (ddr3_dqs_p[1:0]    ),    
    .dqs_n                           (ddr3_dqs_n[1:0]    ),    
    .tdqs_n                          (                    ),            
    .odt                             (ddr3_odt            )    
);
ddr3_model    ddr3_model_inst1
(    
    .rst_n                           (rst_n        ),    
    .ck                              (ddr3_ck_p            ),    
    .ck_n                            (ddr3_ck_n            ),    
    .cke                             (ddr3_cke            ),    
    .cs_n                            (ddr3_cs_n            ),    
    .ras_n                           (ddr3_ras_n            ),    
    .cas_n                           (ddr3_cas_n            ),    
    .we_n                            (ddr3_we_n            ),    
    .dm_tdqs                         (ddr3_dm[3:2]        ),    
    .ba                              (ddr3_ba            ),    
    .addr                            (ddr3_addr            ),    
    .dq                              (ddr3_dq[31:16]        ),    
    .dqs                             (ddr3_dqs_p[3:2]    ),    
    .dqs_n                           (ddr3_dqs_n[3:2]    ),    
    .tdqs_n                          (                    ),            
    .odt                             (ddr3_odt            )    
);

endmodule
tb_ddr3_test

 

/////////////////////////
//例化DDR3模型    
/////////////////////////
ddr3_model    ddr3_model_inst0
(    
    .rst_n                           (ddr3_reset_n        ),    
    .ck                              (ddr3_ck_p            ),    
    .ck_n                            (ddr3_ck_n            ),    
    .cke                             (ddr3_cke            ),    
    .cs_n                            (ddr3_cs_n            ),    
    .ras_n                           (ddr3_ras_n            ),    
    .cas_n                           (ddr3_cas_n            ),    
    .we_n                            (ddr3_we_n            ),    
    .dm_tdqs                         (ddr3_dm[1:0]        ),    
    .ba                              (ddr3_ba            ),    
    .addr                            (ddr3_addr            ),    
    .dq                              (ddr3_dq[15:0]        ),    
    .dqs                             (ddr3_dqs_p[1:0]    ),    
    .dqs_n                           (ddr3_dqs_n[1:0]    ),    
    .tdqs_n                          (                    ),            
    .odt                             (ddr3_odt            )    
);
ddr3_model    ddr3_model_inst1
(    
    .rst_n                           (ddr3_reset_n        ),    
    .ck                              (ddr3_ck_p            ),    
    .ck_n                            (ddr3_ck_n            ),    
    .cke                             (ddr3_cke            ),    
    .cs_n                            (ddr3_cs_n            ),    
    .ras_n                           (ddr3_ras_n            ),    
    .cas_n                           (ddr3_cas_n            ),    
    .we_n                            (ddr3_we_n            ),    
    .dm_tdqs                         (ddr3_dm[3:2]        ),    
    .ba                              (ddr3_ba            ),    
    .addr                            (ddr3_addr            ),    
    .dq                              (ddr3_dq[31:16]        ),    
    .dqs                             (ddr3_dqs_p[3:2]    ),    
    .dqs_n                           (ddr3_dqs_n[3:2]    ),    
    .tdqs_n                          (                    ),            
    .odt                             (ddr3_odt            )    
);
ddr3_model

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: lauchinyuan
// Email: lauchinyuan@yeah.net
// Create Date: 2023/09/21 11:21:52
// Module Name: ddr3_test 
// Description: DDR3读写功能测试模块, 包含DDR3接口、测试数据生成模块、时钟生成模块
// 输出线输出到DDR3物理端口, 使用在线逻辑分析仪进行DDR3逻辑功能分析
//////////////////////////////////////////////////////////////////////////////////
module ddr3_test
#(parameter WR_BEG_ADDR     = 30'd0     ,
  parameter WR_END_ADDR     = 30'd5121  ,//5120--1280*32(写入bit数==5120*8=40960 //数据源只有1300个32bit数
  parameter WR_BURST_LEN    = 8'd31     ,//0
  parameter RD_BEG_ADDR     = 30'd0     ,
  parameter RD_END_ADDR     = 30'd5121  ,//2047 //5120
  parameter RD_BURST_LEN    = 8'd31     ,//15
  parameter FIFO_WR_WIDTH   = 6'd32     ,
  parameter FIFO_RD_WIDTH   = 6'd32     
  )
    (
       input    wire sys_clk_p,    //system clock positive
       input    wire sys_clk_n,    //system clock negative     
    
        // input   wire        clk           ,//50MHz时钟输入
        input   wire        rst_n         ,
        
        //DDR3接口                              
        output  wire [14:0] ddr3_addr     ,  
        output  wire [2:0]  ddr3_ba       ,
        output  wire        ddr3_cas_n    ,
        output  wire        ddr3_ck_n     ,
        output  wire        ddr3_ck_p     ,
        output  wire        ddr3_cke      ,
        output  wire        ddr3_ras_n    ,
        output  wire        ddr3_reset_n  ,
        output  wire        ddr3_we_n     ,
        inout   wire [31:0] ddr3_dq       ,
        inout   wire [3:0]  ddr3_dqs_n    ,
        inout   wire [3:0]  ddr3_dqs_p    ,
        output  wire        ddr3_cs_n     ,
        output  wire [3:0]  ddr3_dm       ,
        output  wire        ddr3_odt      
    );
    
    
    //时钟模块相关连线
    wire        clk_fifo       ; //FIFO读写时钟
    wire        clk_ddr        ; //提供给DDR MIG的参考时钟
    wire        locked         ;
    wire        locked_rst_n   ;
    
    //ddr_interface相关连线
    //关键信号线, 不进行在线调试时使用下面这一段
/*  wire        wr_en          ; //写FIFO写请求
    wire [15:0] wr_data        ; //写FIFO写数据 
    wire        rd_mem_enable  ; //读存储器使能,防止存储器未写先读
    wire        rd_en          ; //读FIFO读请求
    wire [15:0] rd_data        ; //读FIFO读数据
    wire        rd_valid       ; //读FIFO有效标志,高电平代表当前处理的数据有效
    wire        calib_done     ; //DDR3初始化完成 */
    
    //进行ILA在线调试时, 使用这一段代码
    (*mark_debug="true", dont_touch="true"*)wire                        wr_en          ; //写FIFO写请求
    (*mark_debug="true", dont_touch="true"*)wire [FIFO_WR_WIDTH-1:0]    wr_data        ; //写FIFO写数据 
    (*mark_debug="true", dont_touch="true"*)wire                        rd_mem_enable  ; //读存储器使能,防
    (*mark_debug="true", dont_touch="true"*)wire                        rd_en          ; //读FIFO读请求
    (*mark_debug="true", dont_touch="true"*)wire [FIFO_RD_WIDTH-1:0]    rd_data        ; //读FIFO读数据
    (*mark_debug="true", dont_touch="true"*)wire                        rd_valid       ; //读FIFO有效标志   
    (*mark_debug="true", dont_touch="true"*)wire                        calib_done     ; //DDR3初始化完成    
    
    wire        ui_clk         ; //MIG IP核输出的用户时钟, 用作AXI控制器时钟
    wire        ui_rst         ; //MIG IP核输出的复位信号, 高电平有效
       
    
    //测试数据生成模块
    testdata_gen_valid 
    #(.FIFO_WR_WIDTH(FIFO_WR_WIDTH))
    testdata_gen_valid_inst
    (
        .clk             (clk_fifo        ),  //和FIFO时钟保持一致
        .rst_n           (locked_rst_n    ),
        .calib_done      (calib_done      ),  //DDR3初始化完成标志
            
        //写端口   
        .wr_data         (wr_data         ),   //向写FIFO中写入的数据
        .wr_en           (wr_en           ),   //写FIFO写使能
        
        //读端口
        .rd_en           (rd_en           ),   //读FIFO读使能
        .rd_mem_enable   (rd_mem_enable   ),   //读存储器使能, 为高时才能从DDR3 SDRAM中读取数据
        .rd_valid        (rd_valid        )    //读有效信号, 为高时代表读取的数据有效
        
    );
    
    
    
     // 时钟生成模块,产生FIFO读写时钟及AXI读写主机工作时钟
/*       clk_gen clk_gen_inst(
        .clk_ddr    (clk_ddr    ),     
        .clk_fifo   (clk_fifo   ),   
        // Status and control signals
        .reset      (~rst_n     ), 
        .locked     (locked     ),     
        // Clock in ports
        .clk_in1    (clk        )      //50MHz时钟输入
    );  */
wire sys_clk;
IBUFGDS sys_clk_ibufgds 
(
.O       (sys_clk    ),
.I       (sys_clk_p  ),
.IB      (sys_clk_n  )
);
 
  clk_gen clk_gen_inst
   (
    // Clock out ports
    .clk_ddr(clk_ddr),     // output clk_ddr
    .clk_fifo(clk_fifo),     // output clk_fifo
    // Status and control signals
    .reset (~rst_n ), // input reset
    .locked(locked),       // output locked
   // Clock in ports
    .clk_in1(sys_clk) );     //
    // .clk_in1_p(sys_clk_p),    // input clk_in1_p
    // .clk_in1_n(sys_clk_n));   // input clk_in1_n
 
    assign locked_rst_n = rst_n & locked;
    
    
    //DDR3接口模块
    ddr_interface 
    #(.FIFO_WR_WIDTH(FIFO_WR_WIDTH),  //用户端FIFO读写位宽
      .FIFO_RD_WIDTH(FIFO_RD_WIDTH))
    ddr_interface_inst
    (
        .clk                 (clk_ddr             ), //DDR3时钟, 也就是DDR3 MIG IP核参考时钟
        .rst_n               (locked_rst_n        ), 
                    
        //用户端       
        .wr_clk              (clk_fifo            ), //写FIFO写时钟
        .wr_rst              (~locked_rst_n       ), //写复位
        .wr_beg_addr         (WR_BEG_ADDR         ), //写起始地址
        .wr_end_addr         (WR_END_ADDR         ), //写终止地址
        .wr_burst_len        (WR_BURST_LEN        ), //写突发长度
        .wr_en               (wr_en               ), //写FIFO写请求
        .wr_data             (wr_data             ), //写FIFO写数据 
        .rd_clk              (clk_fifo            ), //读FIFO读时钟
        .rd_rst              (~locked_rst_n       ), //读复位
        .rd_mem_enable       (rd_mem_enable       ), //读存储器使能,防止存储器未写先读
        .rd_beg_addr         (RD_BEG_ADDR         ), //读起始地址
        .rd_end_addr         (RD_END_ADDR         ), //读终止地址
        .rd_burst_len        (RD_BURST_LEN        ), //读突发长度
        .rd_en               (rd_en               ), //读FIFO读请求
        .rd_data             (rd_data             ), //读FIFO读数据
        .rd_valid            (rd_valid            ), //读FIFO有效标志,高电平代表当前处理的数据有效
        .ui_clk              (ui_clk              ), //MIG IP核输出的用户时钟, 用作AXI控制器时钟
        .ui_rst              (ui_rst              ), //MIG IP核输出的复位信号, 高电平有效
        .calib_done          (calib_done          ), //DDR3初始化完成
        
        //DDR3接口                              
        .ddr3_addr           (ddr3_addr           ),  
        .ddr3_ba             (ddr3_ba             ),
        .ddr3_cas_n          (ddr3_cas_n          ),
        .ddr3_ck_n           (ddr3_ck_n           ),
        .ddr3_ck_p           (ddr3_ck_p           ),
        .ddr3_cke            (ddr3_cke            ),
        .ddr3_ras_n          (ddr3_ras_n          ),
        .ddr3_reset_n        (ddr3_reset_n        ),
        .ddr3_we_n           (ddr3_we_n           ),
        .ddr3_dq             (ddr3_dq             ),
        .ddr3_dqs_n          (ddr3_dqs_n          ),
        .ddr3_dqs_p          (ddr3_dqs_p          ),
        .ddr3_cs_n           (ddr3_cs_n           ),
        .ddr3_dm             (ddr3_dm             ),
        .ddr3_odt            (ddr3_odt            )
    );
    
    
endmodule
ddr3_test

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: lauchinyuan
// Email: lauchinyuan@yeah.net
// Create Date: 2023/09/20 21:43:45
// Module Name: ddr_interface
// Description: DDR3顶层模块, 将MIG IP核与axi_ddr_ctrl模块封装起来
// 其中axi_ddr_ctrl模块包含AXI主机, 读FIFO、写FIFO及AXI读写控制器axi_ctrl
// 外接DDR3存储器,即可实现对DDR3存储器的FIFO式读写
//////////////////////////////////////////////////////////////////////////////////


module ddr_interface
    #(parameter FIFO_WR_WIDTH = 'd32    ,  //用户端FIFO读写位宽
                FIFO_RD_WIDTH = 'd32    ,
                AXI_WIDTH     = 'd64    ,  //AXI总线读写数据位宽
                AXI_AXSIZE    = 3'b011     //AXI总线的axi_awsize, 需要与AXI_WIDTH对应
                )
        (
        input   wire                        clk                 , //DDR3时钟, 也就是DDR3 MIG IP核参考时钟
        input   wire                        rst_n               , 
                                    
        //用户端                       
        input   wire                        wr_clk              , //写FIFO写时钟
        input   wire                        wr_rst              , //写复位
        input   wire [29:0]                 wr_beg_addr         , //写起始地址
        input   wire [29:0]                 wr_end_addr         , //写终止地址
        input   wire [7:0]                  wr_burst_len        , //写突发长度
        input   wire                        wr_en               , //写FIFO写请求
        input   wire [FIFO_WR_WIDTH-1:0]    wr_data             , //写FIFO写数据 
        input   wire                        rd_clk              , //读FIFO读时钟
        input   wire                        rd_rst              , //读复位
        input   wire                        rd_mem_enable       , //读存储器使能,防止存储器未写先读
        input   wire [29:0]                 rd_beg_addr         , //读起始地址
        input   wire [29:0]                 rd_end_addr         , //读终止地址
        input   wire [7:0]                  rd_burst_len        , //读突发长度
        input   wire                        rd_en               , //读FIFO读请求
        output  wire [FIFO_RD_WIDTH-1:0]    rd_data             , //读FIFO读数据
        output  wire                        rd_valid            , //读FIFO有效标志,高电平代表当前处理的数据有效
        output  wire                        ui_clk              , //MIG IP核输出的用户时钟, 用作AXI控制器时钟
        output  wire                        ui_rst              , //MIG IP核输出的复位信号, 高电平有效
        output  wire                        calib_done          , //DDR3初始化完成
        
        //DDR3接口                              
        output  wire [14:0] ddr3_addr           ,  
        output  wire [2:0]  ddr3_ba             ,
        output  wire        ddr3_cas_n          ,
        output  wire        ddr3_ck_n           ,
        output  wire        ddr3_ck_p           ,
        output  wire        ddr3_cke            ,
        output  wire        ddr3_ras_n          ,
        output  wire        ddr3_reset_n        ,
        output  wire        ddr3_we_n           ,
        inout   wire [31:0] ddr3_dq             ,
        inout   wire [3:0]  ddr3_dqs_n          ,
        inout   wire [3:0]  ddr3_dqs_p          ,
        output  wire        ddr3_cs_n           ,
        output  wire [3:0]  ddr3_dm             ,
        output  wire        ddr3_odt            
        
    );
    
    localparam AXI_WSTRB_W   = AXI_WIDTH >> 3   ; //axi_wstrb的位宽, AXI_WIDTH/8
    
    //AXI连线
    //AXI4写地址通道
    wire [3:0]              axi_awid      ; 
    wire [29:0]             axi_awaddr    ;
    wire [7:0]              axi_awlen     ; //突发传输长度
    wire [2:0]              axi_awsize    ; //突发传输大小(Byte)
    wire [1:0]              axi_awburst   ; //突发类型
    wire                    axi_awlock    ; 
    wire [3:0]              axi_awcache   ; 
    wire [2:0]              axi_awprot    ;
    wire [3:0]              axi_awqos     ;
    wire                    axi_awvalid   ; //写地址valid
    wire                    axi_awready   ; //从机发出的写地址ready
    
    //写数据通道
    wire [AXI_WIDTH-1:0]    axi_wdata     ; //写数据
    wire [AXI_WSTRB_W-1:0]  axi_wstrb     ; //写数据有效字节线
    wire                    axi_wlast     ; //最后一个数据标志
    wire                    axi_wvalid    ; //写数据有效标志
    wire                    axi_wready    ; //从机发出的写数据ready
                
    //写响应通道         
    wire [3:0]              axi_bid       ;
    wire [1:0]              axi_bresp     ; //响应信号,表征写传输是否成功
    wire                    axi_bvalid    ; //响应信号valid标志
    wire                    axi_bready    ; //主机响应ready信号
    
    //读地址通道
    wire [3:0]              axi_arid      ; 
    wire [29:0]             axi_araddr    ; 
    wire [7:0]              axi_arlen     ; //突发传输长度
    wire [2:0]              axi_arsize    ; //突发传输大小(Byte)
    wire [1:0]              axi_arburst   ; //突发类型
    wire                    axi_arlock    ; 
    wire [3:0]              axi_arcache   ; 
    wire [2:0]              axi_arprot    ;
    wire [3:0]              axi_arqos     ;
    wire                    axi_arvalid   ; //读地址valid
    wire                    axi_arready   ; //从机准备接收读地址
    
    //读数据通道
    wire [AXI_WIDTH-1:0]    axi_rdata     ; //读数据
    wire [1:0]              axi_rresp     ; //收到的读响应
    wire                    axi_rlast     ; //最后一个数据标志
    wire                    axi_rvalid    ; //读数据有效标志
    wire                    axi_rready    ; //主机发出的读数据ready
    
    //输入系统时钟异步复位、同步释放处理
    reg                     rst_n_d1      ;
    reg                     rst_n_sync    ;
    
    //rst_n_d1、rst_n_sync
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin  //异步复位
            rst_n_d1    <= 1'b0;
            rst_n_sync  <= 1'b0;
        end else begin   //同步释放
            rst_n_d1    <= 1'b1;
            rst_n_sync  <= rst_n_d1;
        end
    end
    
   
    
    
    // axi_ddr_ctrl模块
    axi_ddr_ctrl 
        #(.FIFO_WR_WIDTH(FIFO_WR_WIDTH),  
          .FIFO_RD_WIDTH(FIFO_RD_WIDTH),
          .AXI_WIDTH    (AXI_WIDTH    ),
          .AXI_AXSIZE   (AXI_AXSIZE   ),
          .AXI_WSTRB_W  (AXI_WSTRB_W  ) 
          
          )
          axi_ddr_ctrl_inst
         (
        .clk             (ui_clk           ), //AXI读写主机时钟
        .rst_n           (~ui_rst          ), 
                
        //用户端    
        .wr_clk          (wr_clk           ), //写FIFO写时钟
        .wr_rst          (wr_rst           ), //写复位
        .wr_beg_addr     (wr_beg_addr      ), //写起始地址
        .wr_end_addr     (wr_end_addr      ), //写终止地址
        .wr_burst_len    (wr_burst_len     ), //写突发长度
        .wr_en           (wr_en            ), //写FIFO写请求
        .wr_data         (wr_data          ), //写FIFO写数据 
        .rd_clk          (rd_clk           ), //读FIFO读时钟
        .rd_rst          (rd_rst           ), //读复位
        .rd_mem_enable   (rd_mem_enable    ), //读存储器使能,防止存储器未写先读
        .rd_beg_addr     (rd_beg_addr      ), //读起始地址
        .rd_end_addr     (rd_end_addr      ), //读终止地址
        .rd_burst_len    (rd_burst_len     ), //读突发长度
        .rd_en           (rd_en            ), //读FIFO读请求
        .rd_data         (rd_data          ), //读FIFO读数据
        .rd_valid        (rd_valid         ), //读FIFO可读标志,表示读FIFO中有数据可以对外输出
        
        //AXI总线
        //AXI4写地址通道
        .m_axi_awid      (axi_awid         ), 
        .m_axi_awaddr    (axi_awaddr       ),
        .m_axi_awlen     (axi_awlen        ), //突发传输长度
        .m_axi_awsize    (axi_awsize       ), //突发传输大小(Byte)
        .m_axi_awburst   (axi_awburst      ), //突发类型
        .m_axi_awlock    (axi_awlock       ), 
        .m_axi_awcache   (axi_awcache      ), 
        .m_axi_awprot    (axi_awprot       ),
        .m_axi_awqos     (axi_awqos        ),
        .m_axi_awvalid   (axi_awvalid      ), //写地址valid
        .m_axi_awready   (axi_awready      ), //从机发出的写地址ready
        
        //写数据通道
        .m_axi_wdata     (axi_wdata        ), //写数据
        .m_axi_wstrb     (axi_wstrb        ), //写数据有效字节线
        .m_axi_wlast     (axi_wlast        ), //最后一个数据标志
        .m_axi_wvalid    (axi_wvalid       ), //写数据有效标志
        .m_axi_wready    (axi_wready       ), //从机发出的写数据ready
        
        //写响应通道
        .m_axi_bid       (axi_bid          ),
        .m_axi_bresp     (axi_bresp        ), //响应信号,表征写传输是否成功
        .m_axi_bvalid    (axi_bvalid       ), //响应信号valid标志
        .m_axi_bready    (axi_bready       ), //主机响应ready信号
        
        //AXI4读地址通道
        .m_axi_arid      (axi_arid         ), 
        .m_axi_araddr    (axi_araddr       ),
        .m_axi_arlen     (axi_arlen        ), //突发传输长度
        .m_axi_arsize    (axi_arsize       ), //突发传输大小(Byte)
        .m_axi_arburst   (axi_arburst      ), //突发类型
        .m_axi_arlock    (axi_arlock       ), 
        .m_axi_arcache   (axi_arcache      ), 
        .m_axi_arprot    (axi_arprot       ),
        .m_axi_arqos     (axi_arqos        ),
        .m_axi_arvalid   (axi_arvalid      ), //读地址valid
        .m_axi_arready   (axi_arready      ), //从机准备接收读地址
        
        //读数据通道
        .m_axi_rdata     (axi_rdata        ), //读数据
        .m_axi_rresp     (axi_rresp        ), //收到的读响应
        .m_axi_rlast     (axi_rlast        ), //最后一个数据标志
        .m_axi_rvalid    (axi_rvalid       ), //读数据有效标志
        .m_axi_rready    (axi_rready       )  //主机发出的读数据ready
    );
    
    
    // Vivado MIG IP核
      axi_ddr3 axi_ddr3_mig_inst (
        // DDR3存储器接口
        .ddr3_addr              (ddr3_addr          ),  // output [14:0]    ddr3_addr
        .ddr3_ba                (ddr3_ba            ),  // output [2:0]     ddr3_ba
        .ddr3_cas_n             (ddr3_cas_n         ),  // output           ddr3_cas_n
        .ddr3_ck_n              (ddr3_ck_n          ),  // output [0:0]     ddr3_ck_n
        .ddr3_ck_p              (ddr3_ck_p          ),  // output [0:0]     ddr3_ck_p
        .ddr3_cke               (ddr3_cke           ),  // output [0:0]     ddr3_cke
        .ddr3_ras_n             (ddr3_ras_n         ),  // output           ddr3_ras_n
        .ddr3_reset_n           (ddr3_reset_n       ),  // output           ddr3_reset_n
        .ddr3_we_n              (ddr3_we_n          ),  // output           ddr3_we_n
        .ddr3_dq                (ddr3_dq            ),  // inout [31:0]     ddr3_dq
        .ddr3_dqs_n             (ddr3_dqs_n         ),  // inout [3:0]      ddr3_dqs_n
        .ddr3_dqs_p             (ddr3_dqs_p         ),  // inout [3:0]      ddr3_dqs_p
        .init_calib_complete    (calib_done         ),  // output           init_calib_complete
        .ddr3_cs_n              (ddr3_cs_n          ),  // output [0:0]     ddr3_cs_n
        .ddr3_dm                (ddr3_dm            ),  // output [3:0]     ddr3_dm
        .ddr3_odt               (ddr3_odt           ),  // output [0:0]     ddr3_odt
        
        // 用户接口
        .ui_clk                 (ui_clk             ),  // output           ui_clk
        .ui_clk_sync_rst        (ui_rst             ),  // output           ui_clk_sync_rst
        .mmcm_locked            (                   ),  // output           mmcm_locked
        .aresetn                (rst_n_sync         ),  // input            aresetn
        .app_sr_req             (1'b0               ),  // input            app_sr_req
        .app_ref_req            (1'b0               ),  // input            app_ref_req
        .app_zq_req             (1'b0               ),  // input            app_zq_req
        .app_sr_active          (                   ),  // output           app_sr_active
        .app_ref_ack            (                   ),  // output           app_ref_ack
        .app_zq_ack             (                   ),  // output           app_zq_ack
        
        // AXI写地址通道
        .s_axi_awid             (axi_awid           ),  // input [3:0]      s_axi_awid
        .s_axi_awaddr           (axi_awaddr         ),  // input [29:0]     s_axi_awaddr
        .s_axi_awlen            (axi_awlen          ),  // input [7:0]      s_axi_awlen
        .s_axi_awsize           (axi_awsize         ),  // input [2:0]      s_axi_awsize
        .s_axi_awburst          (axi_awburst        ),  // input [1:0]      s_axi_awburst
        .s_axi_awlock           (axi_awlock         ),  // input [0:0]      s_axi_awlock
        .s_axi_awcache          (axi_awcache        ),  // input [3:0]      s_axi_awcache
        .s_axi_awprot           (axi_awprot         ),  // input [2:0]      s_axi_awprot
        .s_axi_awqos            (axi_awqos          ),  // input [3:0]      s_axi_awqos
        .s_axi_awvalid          (axi_awvalid        ),  // input            s_axi_awvalid
        .s_axi_awready          (axi_awready        ),  // output           s_axi_awready
    
        // AXI写数据通道
        .s_axi_wdata            (axi_wdata          ),  // input [AXI_WIDTH-1:0]     s_axi_wdata
        .s_axi_wstrb            (axi_wstrb          ),  // input [AXI_WSTRB_W-1:0]   s_axi_wstrb
        .s_axi_wlast            (axi_wlast          ),  // input                     s_axi_wlast
        .s_axi_wvalid           (axi_wvalid         ),  // input                     s_axi_wvalid
        .s_axi_wready           (axi_wready         ),  // output                    s_axi_wready
                   
        // AXI写响应通道        
        .s_axi_bid              (axi_bid            ),  // output [3:0]              s_axi_bid
        .s_axi_bresp            (axi_bresp          ),  // output [1:0]              s_axi_bresp
        .s_axi_bvalid           (axi_bvalid         ),  // output                    s_axi_bvalid
        .s_axi_bready           (axi_bready         ),  // input                     s_axi_bready
                   
        // AXI读地址通道        
        .s_axi_arid             (axi_arid           ),  // input [3:0]               s_axi_arid
        .s_axi_araddr           (axi_araddr         ),  // input [29:0]              s_axi_araddr
        .s_axi_arlen            (axi_arlen          ),  // input [7:0]               s_axi_arlen
        .s_axi_arsize           (axi_arsize         ),  // input [2:0]               s_axi_arsize
        .s_axi_arburst          (axi_arburst        ),  // input [1:0]               s_axi_arburst
        .s_axi_arlock           (axi_arlock         ),  // input [0:0]               s_axi_arlock
        .s_axi_arcache          (axi_arcache        ),  // input [3:0]               s_axi_arcache
        .s_axi_arprot           (axi_arprot         ),  // input [2:0]               s_axi_arprot
        .s_axi_arqos            (axi_arqos          ),  // input [3:0]               s_axi_arqos
        .s_axi_arvalid          (axi_arvalid        ),  // input                     s_axi_arvalid
        .s_axi_arready          (axi_arready        ),  // output                    s_axi_arready
        
        // AXI读数据通道
        .s_axi_rid              (axi_rid            ),  // output [3:0]              s_axi_rid
        .s_axi_rdata            (axi_rdata          ),  // output [AXI_WIDTH-1:0]    s_axi_rdata
        .s_axi_rresp            (axi_rresp          ),  // output [1:0]              s_axi_rresp
        .s_axi_rlast            (axi_rlast          ),  // output                    s_axi_rlast
        .s_axi_rvalid           (axi_rvalid         ),  // output                    s_axi_rvalid
        .s_axi_rready           (axi_rready         ),  // input                     s_axi_rready
        
        // AXI从机系统时钟
        .sys_clk_i              (clk                ),
        // 参考时钟
        // .clk_ref_i              (clk                ),
        .sys_rst                (rst_n_sync         )   // input            sys_rst
    );
    
    
    
    
    
endmodule
ddr_interface

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: lauchinyuan
// Email: lauchinyuan@yeah.net
// Create Date: 2023/09/18 21:49:34
// Module Name: axi_ddr_ctrl
// Description: AXI接口DDR控制顶层模块,集成AXI读主机、AXI写主机、AXI控制器(包含读写FIFO)
//////////////////////////////////////////////////////////////////////////////////


module axi_ddr_ctrl
    #(parameter FIFO_WR_WIDTH = 'd32            ,  //用户端FIFO读写位宽
                FIFO_RD_WIDTH = 'd32            ,
                AXI_WIDTH     = 'd64            ,  //AXI总线读写数据位宽
                AXI_AXSIZE    = 3'b011          ,  //AXI总线的axi_axsize, 需要与AXI_WIDTH对应
                AXI_WSTRB_W   = AXI_WIDTH>>3    )   //axi_wstrb的位宽, AXI_WIDTH/8
        (
        input   wire                        clk             , //AXI读写主机时钟(ui_clk)
        input   wire                        rst_n           , 
                                
        //用户端                   
        input   wire                        wr_clk          , //写FIFO写时钟
        input   wire                        wr_rst          , //写复位
        input   wire [29:0]                 wr_beg_addr     , //写起始地址
        input   wire [29:0]                 wr_end_addr     , //写终止地址
        input   wire [7:0]                  wr_burst_len    , //写突发长度
        input   wire                        wr_en           , //写FIFO写请求
        input   wire [FIFO_WR_WIDTH-1:0]    wr_data         , //写FIFO写数据 
        input   wire                        rd_clk          , //读FIFO读时钟
        input   wire                        rd_rst          , //读复位
        input   wire                        rd_mem_enable   , //读存储器使能,防止存储器未写先读
        input   wire [29:0]                 rd_beg_addr     , //读起始地址
        input   wire [29:0]                 rd_end_addr     , //读终止地址
        input   wire [7:0]                  rd_burst_len    , //读突发长度
        input   wire                        rd_en           , //读FIFO读请求
        output  wire [FIFO_RD_WIDTH-1:0]    rd_data         , //读FIFO读数据
        output  wire                        rd_valid        , //读FIFO可读标志,表示读FIFO中有数据可以对外输出
                        
        //AXI总线             
        //AXI4写地址通道             
        input   wire [3:0]                  m_axi_awid      , 
        output  wire [29:0]                 m_axi_awaddr    ,
        output  wire [7:0]                  m_axi_awlen     , //突发传输长度
        output  wire [2:0]                  m_axi_awsize    , //突发传输大小(Byte)
        output  wire [1:0]                  m_axi_awburst   , //突发类型
        output  wire                        m_axi_awlock    , 
        output  wire [3:0]                  m_axi_awcache   , 
        output  wire [2:0]                  m_axi_awprot    ,
        output  wire [3:0]                  m_axi_awqos     ,
        output  wire                        m_axi_awvalid   , //写地址valid
        input   wire                        m_axi_awready   , //从机发出的写地址ready
                        
        //写数据通道             
        output  wire [AXI_WIDTH-1:0]        m_axi_wdata     , //写数据
        output  wire [AXI_WSTRB_W-1:0]      m_axi_wstrb     , //写数据有效字节线
        output  wire                        m_axi_wlast     , //最后一个数据标志
        output  wire                        m_axi_wvalid    , //写数据有效标志
        input   wire                        m_axi_wready    , //从机发出的写数据ready
                        
        //写响应通道             
        output  wire [3:0]                  m_axi_bid       ,
        input   wire [1:0]                  m_axi_bresp     , //响应信号,表征写传输是否成功
        input   wire                        m_axi_bvalid    , //响应信号valid标志
        output  wire                        m_axi_bready    , //主机响应ready信号
                        
        //AXI4读地址通道             
        output  wire [3:0]                  m_axi_arid      , 
        output  wire [29:0]                 m_axi_araddr    ,
        output  wire [7:0]                  m_axi_arlen     , //突发传输长度
        output  wire [2:0]                  m_axi_arsize    , //突发传输大小(Byte)
        output  wire [1:0]                  m_axi_arburst   , //突发类型
        output  wire                        m_axi_arlock    , 
        output  wire [3:0]                  m_axi_arcache   , 
        output  wire [2:0]                  m_axi_arprot    ,
        output  wire [3:0]                  m_axi_arqos     ,
        output  wire                        m_axi_arvalid   , //读地址valid
        input   wire                        m_axi_arready   , //从机准备接收读地址
                        
        //读数据通道             
        input   wire [AXI_WIDTH-1:0]        m_axi_rdata     , //读数据
        input   wire [1:0]                  m_axi_rresp     , //收到的读响应
        input   wire                        m_axi_rlast     , //最后一个数据标志
        input   wire                        m_axi_rvalid    , //读数据有效标志
        output  wire                        m_axi_rready      //主机发出的读数据ready
    );
    
    
    //连线
    //AXI控制器到AXI写主机
    wire                    axi_writing     ;
    wire                    axi_wr_ready    ;
    wire                    axi_wr_start    ;
    wire [AXI_WIDTH-1:0]    axi_wr_data     ;
    wire [29:0]             axi_wr_addr     ;
    wire [7:0]              axi_wr_len      ;
    wire                    axi_wr_done     ;
    
    //读AXI主机
    wire                    axi_reading     ;
    wire                    axi_rd_ready    ;
    wire                    axi_rd_start    ;
    wire [AXI_WIDTH-1:0]    axi_rd_data     ;
    wire [29:0]             axi_rd_addr     ;
    wire [7:0]              axi_rd_len      ;
    wire                    axi_rd_done     ;
    
    //AXI控制器
    axi_ctrl 
    #(.FIFO_WR_WIDTH(FIFO_WR_WIDTH),  //用户端FIFO读写位宽
      .FIFO_RD_WIDTH(FIFO_RD_WIDTH),
      .AXI_WIDTH    (AXI_WIDTH    )
      )
      axi_ctrl_inst
    (
        .clk             (clk             ), //AXI读写主机时钟
        .rst_n           (rst_n           ), 
 
        .wr_clk          (wr_clk          ), //写FIFO写时钟
        .wr_rst          (wr_rst          ), //写复位
        .wr_beg_addr     (wr_beg_addr     ), //写起始地址
        .wr_end_addr     (wr_end_addr     ), //写终止地址
        .wr_burst_len    (wr_burst_len    ), //写突发长度
        .wr_en           (wr_en           ), //写FIFO写请求
        .wr_data         (wr_data         ), //写FIFO写数据 
        .rd_clk          (rd_clk          ), //读FIFO读时钟
        .rd_rst          (rd_rst          ), //读复位
        .rd_mem_enable   (rd_mem_enable   ), //读存储器使能,防止存储器未写先读
        .rd_beg_addr     (rd_beg_addr     ), //读起始地址
        .rd_end_addr     (rd_end_addr     ), //读终止地址
        .rd_burst_len    (rd_burst_len    ), //读突发长度
        .rd_en           (rd_en           ), //读FIFO读请求
        .rd_data         (rd_data         ), //读FIFO读数据
        .rd_valid        (rd_valid        ), //读FIFO可读标志,表示读FIFO中有数据可以对外输出
        
        //写AXI主机
        .axi_writing     (axi_writing     ), //AXI主机写正在进行
        .axi_wr_ready    (axi_wr_ready    ), //AXI主机写准备好
        .axi_wr_start    (axi_wr_start    ), //AXI主机写请求
        .axi_wr_data     (axi_wr_data     ), //从写FIFO中读取的数据,写入AXI写主机
        .axi_wr_addr     (axi_wr_addr     ), //AXI主机写地址
        .axi_wr_len      (axi_wr_len      ), //AXI主机写突发长度
        .axi_wr_done     (axi_wr_done     ),
        
        //读AXI主机
        .axi_reading     (axi_reading     ), //AXI主机读正在进行
        .axi_rd_ready    (axi_rd_ready    ), //AXI主机读准备好
        .axi_rd_start    (axi_rd_start    ), //AXI主机读请求
        .axi_rd_data     (axi_rd_data     ), //从AXI读主机读到的数据,写入读FIFO
        .axi_rd_addr     (axi_rd_addr     ), //AXI主机读地址
        .axi_rd_len      (axi_rd_len      ), //AXI主机读突发长度   
        .axi_rd_done     (axi_rd_done     )
    );
    
    
    
    
    //AXI读主机
    axi_master_rd 
    #(  .AXI_WIDTH     (AXI_WIDTH     ),  //AXI总线读写数据位宽
        .AXI_AXSIZE    (AXI_AXSIZE    ))   //AXI总线的axi_axsize, 需要与AXI_WIDTH对应    
        axi_master_rd_inst
    (
        //用户端
        .clk              (clk              ),
        .rst_n            (rst_n            ),
        .rd_start         (axi_rd_start     ), //开始读信号
        .rd_addr          (axi_rd_addr      ), //读首地址
        .rd_data          (axi_rd_data      ), //读出的数据
        .rd_len           (axi_rd_len       ), //突发传输长度
        .rd_done          (axi_rd_done      ), //读完成标志
        .rd_ready         (axi_rd_ready     ), //准备好读标志
        .m_axi_r_handshake(axi_reading      ), //读通道成功握手
        
        //AXI4读地址通道
        .m_axi_arid       (m_axi_arid       ), 
        .m_axi_araddr     (m_axi_araddr     ),
        .m_axi_arlen      (m_axi_arlen      ), //突发传输长度
        .m_axi_arsize     (m_axi_arsize     ), //突发传输大小(Byte)
        .m_axi_arburst    (m_axi_arburst    ), //突发类型
        .m_axi_arlock     (m_axi_arlock     ), 
        .m_axi_arcache    (m_axi_arcache    ), 
        .m_axi_arprot     (m_axi_arprot     ),
        .m_axi_arqos      (m_axi_arqos      ),
        .m_axi_arvalid    (m_axi_arvalid    ), //读地址valid
        .m_axi_arready    (m_axi_arready    ), //从机准备接收读地址
                                            
        //读数据通道                        
        .m_axi_rdata      (m_axi_rdata      ), //读数据
        .m_axi_rresp      (m_axi_rresp      ), //收到的读响应
        .m_axi_rlast      (m_axi_rlast      ), //最后一个数据标志
        .m_axi_rvalid     (m_axi_rvalid     ), //读数据有效标志
        .m_axi_rready     (m_axi_rready     )  //主机发出的读数据ready
    );
    
    //AXI写主机
    axi_master_wr 
    #(.AXI_WIDTH     (AXI_WIDTH     ),  //AXI总线读写数据位宽
      .AXI_AXSIZE    (AXI_AXSIZE    ),  //AXI总线的axi_axsize, 需要与AXI_WIDTH对应
      .AXI_WSTRB_W   (AXI_WSTRB_W   ))   //axi_wstrb的位宽, AXI_WIDTH/8
    axi_master_wr_inst(
        //用户端
        .clk              (clk              ),
        .rst_n            (rst_n            ),
        .wr_start         (axi_wr_start     ), //开始写信号
        .wr_addr          (axi_wr_addr      ), //写首地址
        .wr_data          (axi_wr_data      ),
        .wr_len           (axi_wr_len       ), //突发传输长度
        .wr_done          (axi_wr_done      ), //写完成标志
        .m_axi_w_handshake(axi_writing      ), //写通道成功握手
        .wr_ready         (axi_wr_ready     ), //写准备信号,拉高时可以发起wr_start
        
        //AXI4写地址通道
        .m_axi_awid       (m_axi_awid       ), 
        .m_axi_awaddr     (m_axi_awaddr     ),
        .m_axi_awlen      (m_axi_awlen      ), //突发传输长度
        .m_axi_awsize     (m_axi_awsize     ), //突发传输大小(Byte)
        .m_axi_awburst    (m_axi_awburst    ), //突发类型
        .m_axi_awlock     (m_axi_awlock     ), 
        .m_axi_awcache    (m_axi_awcache    ), 
        .m_axi_awprot     (m_axi_awprot     ),
        .m_axi_awqos      (m_axi_awqos      ),
        .m_axi_awvalid    (m_axi_awvalid    ), //写地址valid
        .m_axi_awready    (m_axi_awready    ), //从机发出的写地址ready
                                            
        //写数据通道                        
        .m_axi_wdata      (m_axi_wdata      ), //写数据
        .m_axi_wstrb      (m_axi_wstrb      ), //写数据有效字节线
        .m_axi_wlast      (m_axi_wlast      ), //最后一个数据标志
        .m_axi_wvalid     (m_axi_wvalid     ), //写数据有效标志
        .m_axi_wready     (m_axi_wready     ), //从机发出的写数据ready
                                            
        //写响应通道                        
        .m_axi_bid        (m_axi_bid        ),
        .m_axi_bresp      (m_axi_bresp      ), //响应信号,表征写传输是否成功
        .m_axi_bvalid     (m_axi_bvalid     ), //响应信号valid标志
        .m_axi_bready     (m_axi_bready     )  //主机响应ready信号
    );
endmodule
axi_ddr_ctrl

 以上

//AXI总线
//AXI4写地址通道

  input  wire [3:0]   m_axi_awid有误,得修改成output,这里有个bug

//写响应通道
output wire [3:0] m_axi_bid 有误,得修改成input,这里有个bug

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: lauchinyuan
// Email: lauchinyuan@yeah.net
// Create Date: 2023/09/18 21:49:34
// Module Name: axi_ddr_ctrl
// Description: AXI接口DDR控制顶层模块,集成AXI读主机、AXI写主机、AXI控制器(包含读写FIFO)
//////////////////////////////////////////////////////////////////////////////////


module axi_ddr_ctrl
    #(parameter FIFO_WR_WIDTH = 'd32            ,  //用户端FIFO读写位宽
                FIFO_RD_WIDTH = 'd32            ,
                AXI_WIDTH     = 'd64            ,  //AXI总线读写数据位宽
                AXI_AXSIZE    = 3'b011          ,  //AXI总线的axi_axsize, 需要与AXI_WIDTH对应
                AXI_WSTRB_W   = AXI_WIDTH>>3    )   //axi_wstrb的位宽, AXI_WIDTH/8
        (
        input   wire                        clk             , //AXI读写主机时钟(ui_clk)
        input   wire                        rst_n           , 
                                
        //用户端                   
        input   wire                        wr_clk          , //写FIFO写时钟
        input   wire                        wr_rst          , //写复位
        input   wire [29:0]                 wr_beg_addr     , //写起始地址
        input   wire [29:0]                 wr_end_addr     , //写终止地址
        input   wire [7:0]                  wr_burst_len    , //写突发长度
        input   wire                        wr_en           , //写FIFO写请求
        input   wire [FIFO_WR_WIDTH-1:0]    wr_data         , //写FIFO写数据 
        input   wire                        rd_clk          , //读FIFO读时钟
        input   wire                        rd_rst          , //读复位
        input   wire                        rd_mem_enable   , //读存储器使能,防止存储器未写先读
        input   wire [29:0]                 rd_beg_addr     , //读起始地址
        input   wire [29:0]                 rd_end_addr     , //读终止地址
        input   wire [7:0]                  rd_burst_len    , //读突发长度
        input   wire                        rd_en           , //读FIFO读请求
        output  wire [FIFO_RD_WIDTH-1:0]    rd_data         , //读FIFO读数据
        output  wire                        rd_valid        , //读FIFO可读标志,表示读FIFO中有数据可以对外输出
                        
        //AXI总线             
        //AXI4写地址通道             
        output  wire [3:0]                  m_axi_awid      , 
        output  wire [29:0]                 m_axi_awaddr    ,
        output  wire [7:0]                  m_axi_awlen     , //突发传输长度
        output  wire [2:0]                  m_axi_awsize    , //突发传输大小(Byte)
        output  wire [1:0]                  m_axi_awburst   , //突发类型
        output  wire                        m_axi_awlock    , 
        output  wire [3:0]                  m_axi_awcache   , 
        output  wire [2:0]                  m_axi_awprot    ,
        output  wire [3:0]                  m_axi_awqos     ,
        output  wire                        m_axi_awvalid   , //写地址valid
        input   wire                        m_axi_awready   , //从机发出的写地址ready
                        
        //写数据通道             
        output  wire [AXI_WIDTH-1:0]        m_axi_wdata     , //写数据
        output  wire [AXI_WSTRB_W-1:0]      m_axi_wstrb     , //写数据有效字节线
        output  wire                        m_axi_wlast     , //最后一个数据标志
        output  wire                        m_axi_wvalid    , //写数据有效标志
        input   wire                        m_axi_wready    , //从机发出的写数据ready
                        
        //写响应通道             
        input   wire [3:0]                  m_axi_bid       ,
        input   wire [1:0]                  m_axi_bresp     , //响应信号,表征写传输是否成功
        input   wire                        m_axi_bvalid    , //响应信号valid标志
        output  wire                        m_axi_bready    , //主机响应ready信号
                        
        //AXI4读地址通道             
        output  wire [3:0]                  m_axi_arid      , 
        output  wire [29:0]                 m_axi_araddr    ,
        output  wire [7:0]                  m_axi_arlen     , //突发传输长度
        output  wire [2:0]                  m_axi_arsize    , //突发传输大小(Byte)
        output  wire [1:0]                  m_axi_arburst   , //突发类型
        output  wire                        m_axi_arlock    , 
        output  wire [3:0]                  m_axi_arcache   , 
        output  wire [2:0]                  m_axi_arprot    ,
        output  wire [3:0]                  m_axi_arqos     ,
        output  wire                        m_axi_arvalid   , //读地址valid
        input   wire                        m_axi_arready   , //从机准备接收读地址
                        
        //读数据通道             
        input   wire [AXI_WIDTH-1:0]        m_axi_rdata     , //读数据
        input   wire [1:0]                  m_axi_rresp     , //收到的读响应
        input   wire                        m_axi_rlast     , //最后一个数据标志
        input   wire                        m_axi_rvalid    , //读数据有效标志
        output  wire                        m_axi_rready      //主机发出的读数据ready
    );
    
    
    //连线
    //AXI控制器到AXI写主机
    wire                    axi_writing     ;
    wire                    axi_wr_ready    ;
    wire                    axi_wr_start    ;
    wire [AXI_WIDTH-1:0]    axi_wr_data     ;
    wire [29:0]             axi_wr_addr     ;
    wire [7:0]              axi_wr_len      ;
    wire                    axi_wr_done     ;
    
    //读AXI主机
    wire                    axi_reading     ;
    wire                    axi_rd_ready    ;
    wire                    axi_rd_start    ;
    wire [AXI_WIDTH-1:0]    axi_rd_data     ;
    wire [29:0]             axi_rd_addr     ;
    wire [7:0]              axi_rd_len      ;
    wire                    axi_rd_done     ;
    
    //AXI控制器
    axi_ctrl 
    #(.FIFO_WR_WIDTH(FIFO_WR_WIDTH),  //用户端FIFO读写位宽
      .FIFO_RD_WIDTH(FIFO_RD_WIDTH),
      .AXI_WIDTH    (AXI_WIDTH    )
      )
      axi_ctrl_inst
    (
        .clk             (clk             ), //AXI读写主机时钟
        .rst_n           (rst_n           ), 
 
        .wr_clk          (wr_clk          ), //写FIFO写时钟
        .wr_rst          (wr_rst          ), //写复位
        .wr_beg_addr     (wr_beg_addr     ), //写起始地址
        .wr_end_addr     (wr_end_addr     ), //写终止地址
        .wr_burst_len    (wr_burst_len    ), //写突发长度
        .wr_en           (wr_en           ), //写FIFO写请求
        .wr_data         (wr_data         ), //写FIFO写数据 
        .rd_clk          (rd_clk          ), //读FIFO读时钟
        .rd_rst          (rd_rst          ), //读复位
        .rd_mem_enable   (rd_mem_enable   ), //读存储器使能,防止存储器未写先读
        .rd_beg_addr     (rd_beg_addr     ), //读起始地址
        .rd_end_addr     (rd_end_addr     ), //读终止地址
        .rd_burst_len    (rd_burst_len    ), //读突发长度
        .rd_en           (rd_en           ), //读FIFO读请求
        .rd_data         (rd_data         ), //读FIFO读数据
        .rd_valid        (rd_valid        ), //读FIFO可读标志,表示读FIFO中有数据可以对外输出
        
        //写AXI主机
        .axi_writing     (axi_writing     ), //AXI主机写正在进行
        .axi_wr_ready    (axi_wr_ready    ), //AXI主机写准备好
        .axi_wr_start    (axi_wr_start    ), //AXI主机写请求
        .axi_wr_data     (axi_wr_data     ), //从写FIFO中读取的数据,写入AXI写主机
        .axi_wr_addr     (axi_wr_addr     ), //AXI主机写地址
        .axi_wr_len      (axi_wr_len      ), //AXI主机写突发长度
        .axi_wr_done     (axi_wr_done     ),
        
        //读AXI主机
        .axi_reading     (axi_reading     ), //AXI主机读正在进行
        .axi_rd_ready    (axi_rd_ready    ), //AXI主机读准备好
        .axi_rd_start    (axi_rd_start    ), //AXI主机读请求
        .axi_rd_data     (axi_rd_data     ), //从AXI读主机读到的数据,写入读FIFO
        .axi_rd_addr     (axi_rd_addr     ), //AXI主机读地址
        .axi_rd_len      (axi_rd_len      ), //AXI主机读突发长度   
        .axi_rd_done     (axi_rd_done     )
    );
    
    
    
    
    //AXI读主机
    axi_master_rd 
    #(  .AXI_WIDTH     (AXI_WIDTH     ),  //AXI总线读写数据位宽
        .AXI_AXSIZE    (AXI_AXSIZE    ))   //AXI总线的axi_axsize, 需要与AXI_WIDTH对应    
        axi_master_rd_inst
    (
        //用户端
        .clk              (clk              ),
        .rst_n            (rst_n            ),
        .rd_start         (axi_rd_start     ), //开始读信号
        .rd_addr          (axi_rd_addr      ), //读首地址
        .rd_data          (axi_rd_data      ), //读出的数据
        .rd_len           (axi_rd_len       ), //突发传输长度
        .rd_done          (axi_rd_done      ), //读完成标志
        .rd_ready         (axi_rd_ready     ), //准备好读标志
        .m_axi_r_handshake(axi_reading      ), //读通道成功握手
        
        //AXI4读地址通道
        .m_axi_arid       (m_axi_arid       ), 
        .m_axi_araddr     (m_axi_araddr     ),
        .m_axi_arlen      (m_axi_arlen      ), //突发传输长度
        .m_axi_arsize     (m_axi_arsize     ), //突发传输大小(Byte)
        .m_axi_arburst    (m_axi_arburst    ), //突发类型
        .m_axi_arlock     (m_axi_arlock     ), 
        .m_axi_arcache    (m_axi_arcache    ), 
        .m_axi_arprot     (m_axi_arprot     ),
        .m_axi_arqos      (m_axi_arqos      ),
        .m_axi_arvalid    (m_axi_arvalid    ), //读地址valid
        .m_axi_arready    (m_axi_arready    ), //从机准备接收读地址
                                            
        //读数据通道                        
        .m_axi_rdata      (m_axi_rdata      ), //读数据
        .m_axi_rresp      (m_axi_rresp      ), //收到的读响应
        .m_axi_rlast      (m_axi_rlast      ), //最后一个数据标志
        .m_axi_rvalid     (m_axi_rvalid     ), //读数据有效标志
        .m_axi_rready     (m_axi_rready     )  //主机发出的读数据ready
    );
    
    //AXI写主机
    axi_master_wr 
    #(.AXI_WIDTH     (AXI_WIDTH     ),  //AXI总线读写数据位宽
      .AXI_AXSIZE    (AXI_AXSIZE    ),  //AXI总线的axi_axsize, 需要与AXI_WIDTH对应
      .AXI_WSTRB_W   (AXI_WSTRB_W   ))   //axi_wstrb的位宽, AXI_WIDTH/8
    axi_master_wr_inst(
        //用户端
        .clk              (clk              ),
        .rst_n            (rst_n            ),
        .wr_start         (axi_wr_start     ), //开始写信号
        .wr_addr          (axi_wr_addr      ), //写首地址
        .wr_data          (axi_wr_data      ),
        .wr_len           (axi_wr_len       ), //突发传输长度
        .wr_done          (axi_wr_done      ), //写完成标志
        .m_axi_w_handshake(axi_writing      ), //写通道成功握手
        .wr_ready         (axi_wr_ready     ), //写准备信号,拉高时可以发起wr_start
        
        //AXI4写地址通道
        .m_axi_awid       (m_axi_awid       ), 
        .m_axi_awaddr     (m_axi_awaddr     ),
        .m_axi_awlen      (m_axi_awlen      ), //突发传输长度
        .m_axi_awsize     (m_axi_awsize     ), //突发传输大小(Byte)
        .m_axi_awburst    (m_axi_awburst    ), //突发类型
        .m_axi_awlock     (m_axi_awlock     ), 
        .m_axi_awcache    (m_axi_awcache    ), 
        .m_axi_awprot     (m_axi_awprot     ),
        .m_axi_awqos      (m_axi_awqos      ),
        .m_axi_awvalid    (m_axi_awvalid    ), //写地址valid
        .m_axi_awready    (m_axi_awready    ), //从机发出的写地址ready
                                            
        //写数据通道                        
        .m_axi_wdata      (m_axi_wdata      ), //写数据
        .m_axi_wstrb      (m_axi_wstrb      ), //写数据有效字节线
        .m_axi_wlast      (m_axi_wlast      ), //最后一个数据标志
        .m_axi_wvalid     (m_axi_wvalid     ), //写数据有效标志
        .m_axi_wready     (m_axi_wready     ), //从机发出的写数据ready
                                            
        //写响应通道                        
        .m_axi_bid        (m_axi_bid        ),
        .m_axi_bresp      (m_axi_bresp      ), //响应信号,表征写传输是否成功
        .m_axi_bvalid     (m_axi_bvalid     ), //响应信号valid标志
        .m_axi_bready     (m_axi_bready     )  //主机响应ready信号
    );
endmodule
axi_ddr_ctrl修改

 

image

 

image

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: lauchinyuan
// Email: lauchinyuan@yeah.net
// Create Date: 2023/09/18 13:09:46
// Module Name: axi_ctrl
// Description: AXI控制器, 依据AXI读写主机发来的读写信号, 自动产生AXI读写请求、读写地址以及读写突发长度
//////////////////////////////////////////////////////////////////////////////////

module axi_ctrl
    #(parameter FIFO_WR_WIDTH = 'd32,   //用户端FIFO读写位宽
                FIFO_RD_WIDTH = 'd32,
                AXI_WIDTH     = 'd64
    )
    (
        input   wire                        clk             , //AXI读写主机时钟
        input   wire                        rst_n           , 
                                
        //用户端                   
        input   wire                        wr_clk          , //写FIFO写时钟
        input   wire                        wr_rst          , //写复位,模块中是同步复位
        input   wire [29:0]                 wr_beg_addr     , //写起始地址
        input   wire [29:0]                 wr_end_addr     , //写终止地址
        input   wire [7:0]                  wr_burst_len    , //写突发长度
        input   wire                        wr_en           , //写FIFO写请求
        input   wire [FIFO_WR_WIDTH-1:0]    wr_data         , //写FIFO写数据 
        input   wire                        rd_clk          , //读FIFO读时钟
        input   wire                        rd_rst          , //读复位,模块中是同步复位
        input   wire                        rd_mem_enable   , //读存储器使能,防止存储器未写先读
        input   wire [29:0]                 rd_beg_addr     , //读起始地址
        input   wire [29:0]                 rd_end_addr     , //读终止地址
        input   wire [7:0]                  rd_burst_len    , //读突发长度
        input   wire                        rd_en           , //读FIFO读请求
        output  wire [FIFO_RD_WIDTH-1:0]    rd_data         , //读FIFO读数据
        output  wire                        rd_valid        , //读FIFO可读标志,表示读FIFO中有数据可以对外输出
        
        //写AXI主机
        input   wire                        axi_writing     , //AXI主机写正在进行
        input   wire                        axi_wr_ready    , //AXI主机写准备好
        output  reg                         axi_wr_start    , //AXI主机写请求
        output  wire [AXI_WIDTH-1:0]        axi_wr_data     , //从写FIFO中读取的数据,写入AXI写主机
        output  reg  [29:0]                 axi_wr_addr     , //AXI主机写地址
        output  wire [7:0]                  axi_wr_len      , //AXI主机写突发长度
        input   wire                        axi_wr_done     , //AXI主机完成一次写操作
                        
        //读AXI主机                
        input   wire                        axi_reading     , //AXI主机读正在进行
        input   wire                        axi_rd_ready    , //AXI主机读准备好
        output  reg                         axi_rd_start    , //AXI主机读请求
        input   wire [AXI_WIDTH-1:0]        axi_rd_data     , //从AXI读主机读到的数据,写入读FIFO
        output  reg  [29:0]                 axi_rd_addr     , //AXI主机读地址
        output  wire [7:0]                  axi_rd_len      , //AXI主机读突发长度 
        input   wire                        axi_rd_done       //AXI主机完成一次写操作
        
    );
    
        
    //FIFO数据数量计数器   
    wire [10:0]  cnt_rd_fifo_wrport      ;  //读FIFO写端口(对接AXI读主机)数据数量
    wire [9:0]  cnt_wr_fifo_rdport       ;  //写FIFO读端口(对接AXI写主机)数据数量    
    
    wire        rd_fifo_empty           ;  //读FIFO空标志
    wire        rd_fifo_wr_rst_busy     ;  //读FIFO正在初始化,此时先不向SDRAM发出读取请求, 否则将有数据丢失
        
/*  reg         axi_wr_start_d          ;  //axi_wr_start打一拍,用于上升沿提取
    reg         axi_rd_start_d          ;  //axi_rd_start打一拍,用于上升沿提取
    wire        axi_wr_start_raise      ;  //axi_wr_start上升沿
    wire        axi_rd_start_raise      ;  //axi_rd_start上升沿 */
    
    //真实的读写突发长度
    wire  [7:0] real_wr_len             ;  //真实的写突发长度,是wr_burst_len+1
    wire  [7:0] real_rd_len             ;  //真实的读突发长度,是rd_burst_len+1
    
    //突发地址增量, 每次进行一次连续突发传输地址的增量, 在外边计算, 方便后续复用
    wire  [29:0]burst_wr_addr_inc       ;
    wire  [29:0]burst_rd_addr_inc       ;
    
    //复位信号处理(异步复位同步释放)
    reg     rst_n_sync  ;  //同步释放处理后的rst_n
    reg     rst_n_d1    ;  //同步释放处理rst_n, 同步器第一级输出 

    //读复位同步到clk
    reg     rd_rst_sync ;  //读复位打两拍
    reg     rd_rst_d1   ;  //读复位打一拍
    

    //rst_n相对clk同步释放
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin  //异步复位
            rst_n_d1    <= 1'b0;
            rst_n_sync  <= 1'b0;
        end else begin
            rst_n_d1    <= 1'b1;
            rst_n_sync  <= rst_n_d1;
        end
    end
    
    //读复位同步释放到clk, 作为读fifo的复位输入
    always@(posedge clk or posedge rd_rst) begin
        if(rd_rst) begin
            rd_rst_d1   <= 1'b1;
            rd_rst_sync <= 1'b1;
        end else begin
            rd_rst_d1   <= 1'b0;
            rd_rst_sync <= rd_rst_d1;
        end
    end
    
       
    //真实的读写突发长度
    assign real_wr_len = wr_burst_len + 8'd1;
    assign real_rd_len = rd_burst_len + 8'd1;
    
    //突发地址增量, 右移3的
    assign burst_wr_addr_inc = real_wr_len * AXI_WIDTH >> 3;
    assign burst_rd_addr_inc = real_rd_len * AXI_WIDTH >> 3;
    
    
    //向AXI主机发出的读写突发长度
    assign axi_wr_len = wr_burst_len;
    assign axi_rd_len = rd_burst_len;
    
    
    //AXI读主机开始读标志
    //axi_rd_start
    always@(posedge clk or negedge rst_n_sync) begin
        if(~rst_n_sync) begin
            axi_rd_start <= 1'b0;
        end else if(~axi_rd_ready) begin  //axi_rd_ready低,代表AXI读主机正在进行数据读取, start信号已经被响应
            axi_rd_start <= 1'b0;
/*         end else if(rd_mem_enable && cnt_rd_fifo_wrport < real_rd_len && axi_rd_ready) begin  */
        end else if(rd_mem_enable && cnt_rd_fifo_wrport < 512 && axi_rd_ready && ~rd_fifo_wr_rst_busy) begin 
            //读FIFO中的数据存量不足, AXI读主机已经准备好, 且允许读存储器, 读FIFO可以接收数据
            axi_rd_start <= 1'b1;
        end else begin
            axi_rd_start <= axi_rd_start;
        end
    end
    
    //AXI写主机开始写标志
    //axi_wr_start
    always@(posedge clk or negedge rst_n_sync) begin
        if(~rst_n_sync) begin
            axi_wr_start <= 1'b0;
        end else if(~axi_wr_ready) begin  //axi_wr_ready低,代表AXI写主机正在进行数据发送, start信号已经被响应
            axi_wr_start <= 1'b0;
        end else if(cnt_wr_fifo_rdport > real_wr_len && axi_wr_ready) begin 
            //写FIFO中的数据存量足够, AXI写主机已经准备好, 数据不在写FIFO中久留
            axi_wr_start <= 1'b1;
        end else begin
            axi_wr_start <= axi_wr_start;
        end
    end
    
/*     //axi_wr_start打拍
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            axi_wr_start_d <= 1'b0;
        end else begin
            axi_wr_start_d <= axi_wr_start;
        end
    end */
    
/*     //axi_rd_start打拍
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            axi_rd_start_d <= 1'b0;
        end else begin
            axi_rd_start_d <= axi_rd_start;
        end
    end */
   
    
/*     //axi_wr_start上升沿提取
    assign axi_wr_start_raise = (~axi_wr_start_d) & axi_wr_start;
    
    //axi_rd_start上升沿提取
    assign axi_rd_start_raise = (~axi_rd_start_d) & axi_rd_start; */
    
/*     //rd_fifo_wr_en
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            rd_fifo_wr_en <= 1'b0;
        end else begin
            rd_fifo_wr_en <= axi_reading;
        end
    end */
    
    //AXI写地址,更新地址并判断是否可能超限
    //axi_wr_addr
    always@(posedge clk or negedge rst_n_sync) begin
        if(~rst_n_sync) begin
            axi_wr_addr <= wr_beg_addr;  //初始化为起始地址
        end else if(wr_rst) begin
            axi_wr_addr <= wr_beg_addr;
        end else if(axi_wr_done && axi_wr_addr > (wr_end_addr - {burst_wr_addr_inc[28:0], 1'b0} + 30'd1)) begin 
        //每次写完成后判断是否超限, 下一个写首地址后续的空间已经不够再进行一次突发写操作, 位拼接的作用是×2
            axi_wr_addr <= wr_beg_addr;
        end else if(axi_wr_done) begin
            axi_wr_addr <= axi_wr_addr + burst_wr_addr_inc;  //增加一个burst_len的地址
        end else begin
            axi_wr_addr <= axi_wr_addr;
        end
    end
    
    //AXI读地址
    //axi_rd_addr
    always@(posedge clk or negedge rst_n_sync) begin
        if(~rst_n_sync) begin
            axi_rd_addr <= rd_beg_addr;  //初始化为起始地址
        end else if(rd_rst) begin
            axi_rd_addr <= rd_beg_addr;  //人工读复位时
        end else if(axi_rd_done && axi_rd_addr > (rd_end_addr - {burst_rd_addr_inc[28:0], 1'b0} + 30'd1)) begin 
        //每次写完成后判断是否超限, 下一个写首地址后续的空间已经不够再进行一次突发写操作, 位拼接的作用是×2
            axi_rd_addr <= rd_beg_addr;
        end else if(axi_rd_done) begin
            axi_rd_addr <= axi_rd_addr + burst_rd_addr_inc;  //增加一个burst_len的地址
        end else begin
            axi_rd_addr <= axi_rd_addr;
        end
    end
    
/*     //AXI写突发长度
    //axi_wr_len 
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            axi_wr_len <= wr_burst_len; //axi_wr_len初始化
        end else if(wr_rst) begin
            axi_wr_len <= wr_burst_len;
        end else if(axi_wr_start_raise) begin 
            //在上升沿到来时判断写地址是否超限, 若是, 则将axi_wr_len减小, 使地址恰可达wr_end_addr
            //注意地址是按照字节寻址的,而每次burst将传输8Byte
            if((axi_wr_addr + {real_wr_len[4:0],3'b0}) > wr_end_addr) begin //超限, 位拼接的作用是×8
            //axi_wr_len设置为剩下的空间大小, 位拼接的作用是÷8, 减去1是由于AXI总线定义的burst_len = 真实burst_len - 1
                axi_wr_len <= {3'b0, wr_addr_margin[7:3]} - 8'd1; 
            end else begin
                axi_wr_len <= wr_burst_len;  //未超限,则保持标准的wr_burst_len
            end
        end else begin
            axi_wr_len <= axi_wr_len;
        end
    end */

    //AXI读突发长度
    //axi_rd_len 
/*     always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            axi_rd_len <= rd_burst_len; //axi_rd_len初始化
        end else if(rd_rst) begin
            axi_rd_len <= rd_burst_len;
        end else if(axi_rd_start_raise) begin 
            //在上升沿到来时判断写地址是否超限, 若是, 则将axi_rd_len减小, 使地址恰可达rd_end_addr
            if((axi_rd_addr + {real_rd_len[4:0],3'b0}) > rd_end_addr) begin //超限, 位拼接的作用是×8
            //设置为剩下的空间大小, 位拼接的作用是÷8, 减去1是由于AXI总线定义的burst_len = 真实burst_len - 1
                axi_rd_len <= {3'b0, rd_addr_margin[7:3]} - 8'd1; 
            end else begin
                axi_rd_len <= rd_burst_len;  //未超限,则保持标准的wr_burst_len
            end
        end else begin
            axi_rd_len <= axi_rd_len;
        end
    end    */ 

    
    //读FIFO, 从SDRAM中读出的数据先暂存于此
    //使用FIFO IP核
    rd_fifo rd_fifo_inst (
        .rst                (~rst_n_sync | rd_rst_sync  ),  //读复位时需要复位读FIFO
        .wr_clk             (clk                        ),  //写端口时钟是AXI主机时钟, 从axi_master_rd模块写入数据
        .rd_clk             (rd_clk                     ),  //读端口时钟
        .din                (axi_rd_data                ),  //从axi_master_rd模块写入数据
        .wr_en              (axi_reading                ),  //axi_master_rd正在读时,FIFO也在写入
        .rd_en              (rd_en                      ),  //读FIFO读使能
        .dout               (rd_data                    ),  //读FIFO读取的数据
        .full               (                           ),  
        .almost_full        (                           ),  
        .empty              (rd_fifo_empty              ),  
        .almost_empty       (                           ),  
        .rd_data_count      (                           ),  
        .wr_data_count      (cnt_rd_fifo_wrport         ),  //读FIFO写端口(对接AXI读主机)数据数量
        .wr_rst_busy        (rd_fifo_wr_rst_busy        ),     
        .rd_rst_busy        (                           )      
);



    //写FIFO, 待写入SDRAM的数据先暂存于此
    //使用FIFO IP核
    wr_fifo wr_fifo_inst (
        .rst                (~rst_n_sync        ),  
        .wr_clk             (wr_clk             ),  //写端口时钟
        .rd_clk             (clk                ),  //读端口时钟是AXI主机时钟, AXI写主机读取数据
        .din                (wr_data            ),  
        .wr_en              (wr_en              ),  
        .rd_en              (axi_writing        ),  //axi_master_wr正在写时,从写FIFO中不断读出数据
        .dout               (axi_wr_data        ),  //读出的数据作为AXI写主机的输入数据
        .full               (                   ),  
        .almost_full        (                   ),  
        .empty              (                   ),  
        .almost_empty       (                   ),  
        .rd_data_count      (cnt_wr_fifo_rdport ),  //写FIFO读端口(对接AXI写主机)数据数量
        .wr_data_count      (                   ),  
        .wr_rst_busy        (                   ),  
        .rd_rst_busy        (                   )   
    );

/*     //读FIFO, 从SDRAM中读出的数据先暂存于此
    //使用自行编写的异步FIFO模块
    async_fifo
    #(.RAM_DEPTH       ('d2048          ), //内部RAM存储器深度
      .RAM_ADDR_WIDTH  ('d11            ), //内部RAM读写地址宽度, 需与RAM_DEPTH匹配
      .WR_WIDTH        (AXI_WIDTH       ), //写数据位宽
      .RD_WIDTH        (FIFO_RD_WIDTH   ), //读数据位宽
      .WR_IND          ('d2             ), //单次写操作访问的ram_mem单元个数
      .RD_IND          ('d1             ), //单次读操作访问的ram_mem单元个数         
      .RAM_WIDTH       (FIFO_RD_WIDTH   ), //读端口数据位宽更小,使用读数据位宽作为RAM存储器的位宽
      .WR_CNT_WIDTH    ('d11            ), //FIFO写端口计数器的位宽
      .RD_CNT_WIDTH    ('d12            ), //FIFO读端口计数器的位宽
      .WR_L2           ('d1             ), //log2(WR_IND), 决定写地址有效数据位个数及RAM位宽
      .RD_L2           ('d0             ), //log2(RD_IND), 决定读地址有效低位
      .RAM_RD2WR       ('d1             )  //读数据位宽和写数据位宽的比, 即一次读取的RAM单元深度, RAM_RD2WR = RD_WIDTH/WR_WIDTH, 当读位宽小于等于写位宽时, 值为1     
                )
    rd_fifo_inst
    (
            //写相关
            .wr_clk          (clk                        ),  //写端口时钟是AXI主机时钟, 从axi_master_rd模块写入数据
            .wr_rst_n        (rst_n_sync & ~rd_rst_sync  ),  //读复位时需要复位读FIFO
            .wr_en           (axi_reading                ),  //axi_master_rd正在读时,FIFO也在写入
            .wr_data         (axi_rd_data                ),  //从axi_master_rd模块写入数据
            .fifo_full       (                           ),  //FIFO写满
            .wr_data_count   (cnt_rd_fifo_wrport         ),  //读FIFO写端口(对接AXI读主机)数据数量
            //读相关
            .rd_clk          (rd_clk                     ),  //读端口时钟
            .rd_rst_n        (rst_n_sync & ~rd_rst_sync  ),  //读复位时需要复位读FIFO 
            .rd_en           (rd_en                      ),  //读FIFO读使能
            .rd_data         (rd_data                    ),  //读FIFO读取的数据
            .fifo_empty      (rd_fifo_empty              ),  //FIFO读空
            .rd_data_count   (                           )   //读端口数据个数,按读端口数据位宽计算
    );
    //自定义FIFO没有复位busy信号
    assign rd_fifo_wr_rst_busy = 1'b0;
    
    //写FIFO, 待写入SDRAM的数据先暂存于此
    //使用自定义异步FIFO
    async_fifo
    #(.RAM_DEPTH       ('d2048       ), //内部RAM存储器深度
      .RAM_ADDR_WIDTH  ('d11         ), //内部RAM读写地址宽度, 需与RAM_DEPTH匹配
      .WR_WIDTH        (FIFO_WR_WIDTH), //写数据位宽
      .RD_WIDTH        (AXI_WIDTH    ), //读数据位宽
      .WR_IND          ('d1          ), //单次写操作访问的ram_mem单元个数
      .RD_IND          ('d2          ), //单次读操作访问的ram_mem单元个数         
      .RAM_WIDTH       (FIFO_WR_WIDTH), //RAM单元的位宽
      .WR_L2           ('d0          ), //log2(WR_IND), 决定写地址有效数据位个数及RAM位宽
      .RD_L2           ('d1          ), //log2(RD_IND), 决定读地址有效低位
      .WR_CNT_WIDTH    ('d12         ), //FIFO写端口计数器的位宽RAM_ADDR_WIDTH + 'd1 - WR_L2
      .RD_CNT_WIDTH    ('d11         ), //FIFO读端口计数器的位宽RAM_ADDR_WIDTH + 'd1 - RD_L2  
      .RAM_RD2WR       ('d2          )  //读数据位宽和写数据位宽的比, 即一次读取的RAM单元深度, RAM_RD2WR = RD_WIDTH/WR_WIDTH, 当读位宽小于等于写位宽时, 值为1            
    )
    wr_fifo_inst
    (
        //写相关
        .wr_clk          (wr_clk             ), //写端口时钟
        .wr_rst_n        (rst_n_sync         ),
        .wr_en           (wr_en              ),
        .wr_data         (wr_data            ),
        .fifo_full       (                   ), //FIFO写满
        .wr_data_count   (                   ), //写端口数据个数,按写端口数据位宽计算
        //读相关
        .rd_clk          (clk                ), //读端口时钟是AXI主机时钟, AXI写主机读取数据
        .rd_rst_n        (rst_n_sync         ), 
        .rd_en           (axi_writing        ), //axi_master_wr正在写时,从写FIFO中不断读出数据
        .rd_data         (axi_wr_data        ), //读出的数据作为AXI写主机的输入数据
        .fifo_empty      (                   ), //FIFO读空
        .rd_data_count   (cnt_wr_fifo_rdport )  //写FIFO读端口(对接AXI写主机)数据数量
    );     */
    
    //读FIFO可读标志,表示读FIFO中有数据可以对外输出
    assign rd_valid = ~rd_fifo_empty;
    
endmodule
axi_ctrl

 

image

 

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: lauchinyuan
// Email: lauchinyuan@yeah.net
// Create Date: 2023/09/15 16:50:47
// Module Name: axi_master_wr
// Description: AIX4接口主机写模块,包含AXI4总线Master端的写数据通道、写地址通道和写响应通道
//////////////////////////////////////////////////////////////////////////////////


module axi_master_wr
#(parameter     AXI_WIDTH     = 'd64            ,  //AXI总线读写数据位宽
                AXI_AXSIZE    = 3'b011          ,  //AXI总线的axi_axsize, 需要与AXI_WIDTH对应
                AXI_WSTRB_W   = AXI_WIDTH>>3    )  //axi_wstrb的位宽, AXI_WIDTH/8                              
(
        //用户端
        input   wire                    clk              ,
        input   wire                    rst_n            ,
        input   wire                    wr_start         , //开始写信号
        input   wire [29:0]             wr_addr          , //写首地址
        input   wire [AXI_WIDTH-1:0]    wr_data          ,
        input   wire [7:0]              wr_len           , //突发传输长度
        output  reg                     wr_done          , //写完成标志
        output  wire                    m_axi_w_handshake, //写通道成功握手
        output  wire                    wr_ready         , //写准备信号,拉高时可以发起wr_start
        
        //AXI4写地址通道
        output  wire [3:0]              m_axi_awid      , 
        output  reg  [29:0]             m_axi_awaddr    ,
        output  reg  [7:0]              m_axi_awlen     , //突发传输长度
        output  wire [2:0]              m_axi_awsize    , //突发传输大小(Byte)
        output  wire [1:0]              m_axi_awburst   , //突发类型
        output  wire                    m_axi_awlock    , 
        output  wire [3:0]              m_axi_awcache   , 
        output  wire [2:0]              m_axi_awprot    ,
        output  wire [3:0]              m_axi_awqos     ,
        output  reg                     m_axi_awvalid   , //写地址valid
        input   wire                    m_axi_awready   , //从机发出的写地址ready
        
        //写数据通道
        output  wire [AXI_WIDTH-1:0]    m_axi_wdata     , //写数据
        output  wire [AXI_WSTRB_W-1:0]  m_axi_wstrb     , //写数据有效字节线
        output  reg                     m_axi_wlast     , //最后一个数据标志
        output  reg                     m_axi_wvalid    , //写数据有效标志
        input   wire                    m_axi_wready    , //从机发出的写数据ready
        
        //写响应通道
        input   wire [3:0]              m_axi_bid       ,
        input   wire [1:0]              m_axi_bresp     , //响应信号,表征写传输是否成功
        input   wire                    m_axi_bvalid    , //响应信号valid标志
        output  reg                     m_axi_bready      //主机响应ready信号
    );
    
    //写数据相关参数定义
    parameter   M_AXI_AWID      =  4'd0         ,
                M_AXI_AWSIZE    =  AXI_AXSIZE   , 
                M_AXI_AWBURST   =  2'b10        , //突发类型, INCR(2'b01,burst length支持1-256)  WRAP(2'b10,burst length仅支持2,4,8,16)
                M_AXI_AWLOCK    =  1'b0         , //不锁定
                M_AXI_AWCACHE   =  4'b0010      , //存储器类型, 选择Normal Non-cacheable Non-bufferable
                M_AXI_AWPROT    =  3'b0         ,
                M_AXI_AWQOS     =  4'b0         ,
                M_AXI_WSTRB     =  'hff         ;
                
 
                
                
    
    
    //状态机状态定义
    parameter   IDLE    =   3'b000,  //空闲状态
                WA_WAIT =   3'b001,  //等待写地址
                WA      =   3'b010,  //写地址有效
                W_WAIT  =   3'b011,  //等待写数据
                W       =   3'b100,  //写数据有效
                B_WAIT  =   3'b101,  //等待写响应
                B       =   3'b110;  //准备接收写响应
                
    //状态机变量
    reg [2:0]   state       ;
    reg [2:0]   next_state  ;
    
    //握手成功标志
    wire        m_axi_aw_handshake;  //写地址通道握手成功
    wire        m_axi_b_handshake;   //写响应通道握手成功
    
    //中间辅助变量
    reg [7:0]   cnt_w_burst     ;    //突发次数计数器,用于辅助生成m_axi_wlast信号
    
    //握手成功标志
    assign      m_axi_aw_handshake  = m_axi_awready & m_axi_awvalid ;
    assign      m_axi_w_handshake   = m_axi_wready  & m_axi_wvalid  ;
    assign      m_axi_b_handshake   = m_axi_bready  & m_axi_bvalid  ;   
    
    
    //写参数赋值
    assign  m_axi_awid    = M_AXI_AWID      ;
    assign  m_axi_awsize  = M_AXI_AWSIZE    ;
    assign  m_axi_awburst = M_AXI_AWBURST   ;
    assign  m_axi_awlock  = M_AXI_AWLOCK    ;
    assign  m_axi_awcache = M_AXI_AWCACHE   ;
    assign  m_axi_awprot  = M_AXI_AWPROT    ;
    assign  m_axi_awqos   = M_AXI_AWQOS     ;
    assign  m_axi_wstrb   = M_AXI_WSTRB     ;
    
    //状态转移
    //state
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            state <= IDLE;
        end else begin
            state <= next_state;
        end
    end
    
    //次态
    //next_state
    always@(*) begin
        case(state) 
            IDLE: begin
                if(wr_start) begin
                    next_state = WA_WAIT;
                end else begin
                    next_state = IDLE;
                end
            end
            
            WA_WAIT: begin
                next_state = WA;
            end
            
            WA: begin
                if(m_axi_aw_handshake) begin //写地址通道握手成功
                    next_state = W_WAIT;
                end else begin
                    next_state = WA;
                end
            end
            
            W_WAIT: begin
                next_state = W;
            end
            
            W: begin
                if(m_axi_w_handshake && m_axi_wlast) begin //写数据通道握手成功, 且已经是突发传输的最后一个数据
                    next_state = B_WAIT;
                end else begin
                    next_state = W;
                end
            end
            
            B_WAIT: begin
                next_state = B;
            end
            
            B: begin
                if(m_axi_b_handshake) begin  //写响应通道握手成功
                    next_state = IDLE;
                end else begin
                    next_state = B;
                end
            end
            
            default: begin
                next_state = IDLE;
            end
        endcase
    end
    
    //写地址通道valid
    //m_axi_awvalid
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            m_axi_awvalid <= 1'b0;
        end else if(state == WA_WAIT) begin //在WA_WAIT状态的下一个时钟周期拉高m_axi_awvalid
            m_axi_awvalid <= 1'b1;
        end else if(m_axi_aw_handshake) begin //写地址通道握手成功,拉低valid信号
            m_axi_awvalid <= 1'b0;
        end else begin
            m_axi_awvalid <= m_axi_awvalid;
        end
    end
    
    //写地址通道地址、突发长度
    //m_axi_awaddr
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            m_axi_awaddr <= 30'b0;
            m_axi_awlen  <= 8'd0;
        end else if(state == WA_WAIT) begin //在WA_WAIT状态的下一个时钟周期更新地址和突发长度
            m_axi_awaddr <= wr_addr;
            m_axi_awlen  <= wr_len;
        end else begin
            m_axi_awaddr <= m_axi_awaddr;
            m_axi_awlen  <= m_axi_awlen;
        end
    end
    
    
    //突发次数计数器
    //cnt_w_burst
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            cnt_w_burst <= 8'd0;
        end else if(state == W_WAIT) begin //在W_WAIT状态的下一个时钟周期清零
            cnt_w_burst <= 8'd0;
        end else if(state == W && m_axi_w_handshake && cnt_w_burst < wr_len) begin //每握手成功一次,更新一次计数值,直到wr_len
            cnt_w_burst <= cnt_w_burst + 8'd1;
        end else begin
            cnt_w_burst <= cnt_w_burst;
        end
    end
    
    //最后一次突发标志
    //m_axi_wlast
    always@(*) begin
        if((cnt_w_burst == m_axi_awlen) && m_axi_w_handshake && (state == W)) begin //最后一个有效数据
            m_axi_wlast = 1'b1;
        end else begin
            m_axi_wlast = 1'b0;
        end
    end
    
    
    //写通道valid
    //m_axi_wvalid
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            m_axi_wvalid <= 1'b0;
        end else if(state == W_WAIT) begin
            m_axi_wvalid <= 1'b1;
        end else if(state == W && m_axi_w_handshake && m_axi_wlast) begin //写通道握手成功且是最后一个数据
            m_axi_wvalid <= 1'b0;
        end else begin
            m_axi_wvalid <= m_axi_wvalid;
        end
    end
    
    //写通道数据
    //m_axi_wdata
    assign m_axi_wdata = wr_data;
    
    //写响应通道ready
    //m_axi_bready
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            m_axi_bready <= 1'b0;
        end else if(state == B_WAIT) begin  //在B_WAIT的下一个状态拉高bready信号,准备接收从机发来的响应
            m_axi_bready <= 1'b1;
        end else if(state == B && m_axi_b_handshake) begin //响应通道握手成功后拉低
            m_axi_bready <= 1'b0;
        end else begin
            m_axi_bready <= m_axi_bready;
        end
    end
    
    //写完成标志
    //wr_done
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            wr_done <= 1'b0;
        end else if(m_axi_b_handshake && state == B) begin //在B状态下成功握手,代表一次突发传输已经完成
            wr_done <= 1'b1;
        end else begin
            wr_done <= 1'b0;
        end
    end
    
    //wr_ready
    assign wr_ready = (state == IDLE)?1'b1:1'b0;  //在IDLE状态下准备好写
        
endmodule
axi_master_wr

 

image

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: lauchinyuan
// Email: lauchinyuan@yeah.net
// Create Date: 2023/09/17 09:43:12
// Module Name: axi_master_rd 
// Description: AXI4接口的主机读模块,完成读数据通道和读地址通道的功能
//////////////////////////////////////////////////////////////////////////////////


module axi_master_rd
#(parameter     AXI_WIDTH     = 'd64    ,  //AXI总线读写数据位宽
                AXI_AXSIZE    = 3'b011   )  //AXI总线的axi_axsize, 需要与AXI_WIDTH对应
(
        //用户端
        input   wire                    clk              ,
        input   wire                    rst_n            ,
        input   wire                    rd_start         , //开始读信号
        input   wire [29:0]             rd_addr          , //读首地址
        output  wire [AXI_WIDTH-1:0]    rd_data          , //读出的数据
        input   wire [7:0]              rd_len           , //突发传输长度
        output  reg                     rd_done          , //读完成标志
        output  wire                    rd_ready         , //准备好读标志
        output  wire                    m_axi_r_handshake, //读通道成功握手
        
        //AXI4读地址通道
        output  wire [3:0]              m_axi_arid      , 
        output  reg  [29:0]             m_axi_araddr    ,
        output  reg  [7:0]              m_axi_arlen     , //突发传输长度
        output  wire [2:0]              m_axi_arsize    , //突发传输大小(Byte)
        output  wire [1:0]              m_axi_arburst   , //突发类型
        output  wire                    m_axi_arlock    , 
        output  wire [3:0]              m_axi_arcache   , 
        output  wire [2:0]              m_axi_arprot    ,
        output  wire [3:0]              m_axi_arqos     ,
        output  reg                     m_axi_arvalid   , //读地址valid
        input   wire                    m_axi_arready   , //从机准备接收读地址
        
        //读数据通道
        input   wire [AXI_WIDTH-1:0]    m_axi_rdata     , //读数据
        input   wire [1:0]              m_axi_rresp     , //收到的读响应
        input   wire                    m_axi_rlast     , //最后一个数据标志
        input   wire                    m_axi_rvalid    , //读数据有效标志
        output  reg                     m_axi_rready      //主机发出的读数据ready
    );
    
    //读数据相关参数定义
    parameter   M_AXI_ARID      =  4'd0         ,
                M_AXI_ARSIZE    =  AXI_AXSIZE   , 
                M_AXI_ARBURST   =  2'b10        , //突发类型, INCR(2'b01,burst length支持1-256)  WRAP(2'b10,burst length仅支持2,4,8,16)
                M_AXI_ARLOCK    =  1'b0         , //不锁定
                M_AXI_ARCACHE   =  4'b0010      , //存储器类型, 选择Normal Non-cacheable Non-bufferable
                M_AXI_ARPROT    =  3'b0         ,
                M_AXI_ARQOS     =  4'b0         ;   
    
    //状态机状态定义
    parameter   IDLE    =   3'b000,  //空闲状态
                RA_WAIT =   3'b001,  //等待读地址
                RA      =   3'b010,  //读地址有效
                R_WAIT  =   3'b011,  //等待读数据
                R       =   3'b100;  //读数据有效
    
    //状态机变量
    reg [2:0]   state       ;
    reg [2:0]   next_state  ;
    
    //握手成功标志
    wire        m_axi_ar_handshake;  //读地址通道握手成功
/*     reg         m_axi_r_handshake_d; //读数据通道握手成功打一拍,使其高电平与读取的数据对齐 */
    
    assign      m_axi_ar_handshake = m_axi_arready & m_axi_arvalid;
    assign      m_axi_r_handshake  = m_axi_rready & m_axi_rvalid;
    
    
    //读参数赋值
    assign  m_axi_arid    = M_AXI_ARID      ;
    assign  m_axi_arsize  = M_AXI_ARSIZE    ;
    assign  m_axi_arburst = M_AXI_ARBURST   ;
    assign  m_axi_arlock  = M_AXI_ARLOCK    ;
    assign  m_axi_arcache = M_AXI_ARCACHE   ;
    assign  m_axi_arprot  = M_AXI_ARPROT    ;
    assign  m_axi_arqos   = M_AXI_ARQOS     ;
    
    //状态转移
    //state
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            state <= IDLE;
        end else begin
            state <= next_state;
        end
    end

    //次态
    //next_state
    always@(*) begin
        case(state) 
            IDLE: begin  //准备接收读开始信号(rd_start)
                if(rd_start) begin
                    next_state = RA_WAIT; //接收到rd_start有效
                end else begin
                    next_state = IDLE;
                end
            end
            
            RA_WAIT: begin
                next_state = RA;
            end
            
            RA: begin
                if(m_axi_ar_handshake) begin //读地址通道握手成功
                    next_state = R_WAIT;
                end else begin
                    next_state = RA;
                end
            end
            
            R_WAIT: begin
                next_state = R;
            end
            
            R: begin
                if(m_axi_r_handshake && m_axi_rlast) begin  //读通道握手成功,且是最后一个突发数据
                    next_state = IDLE;
                end else begin
                    next_state = R;
                end
            end
            
            default: begin
                next_state = IDLE;
            end
        endcase
    end
    
    //读地址通道valid
    //m_axi_arvalid
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            m_axi_arvalid <= 1'b0;
        end else if(state == RA_WAIT) begin
            m_axi_arvalid <= 1'b1;
        end else if(state == RA && m_axi_ar_handshake) begin  //读地址通道握手成功
            m_axi_arvalid <= 1'b0;
        end else begin
            m_axi_arvalid <= m_axi_arvalid;
        end
    end
    
    //读地址通道地址以及突发长度
    //m_axi_arlen / m_axi_araddr
    always@(posedge clk or negedge rst_n) begin 
        if(~rst_n) begin
            m_axi_arlen <= 8'd0;
            m_axi_araddr<= 30'd0;
        end else if(state == RA_WAIT) begin //在RA_WAIT的下一个时钟周期拉高了arvalid信号, 同时更新AXI总线地址和len
            m_axi_arlen <= rd_len;
            m_axi_araddr<= rd_addr;
        end else begin
            m_axi_arlen <= m_axi_arlen;
            m_axi_araddr<= m_axi_araddr;
        end
    end
    
    //读数据通道ready
    //m_axi_rready
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            m_axi_rready <= 1'b0;
        end else if(state == R_WAIT) begin
            m_axi_rready <= 1'b1;
        end else if(state == R && m_axi_rlast && m_axi_r_handshake) begin //读数据通道握手成功,且是最后一个数据
            m_axi_rready <= 1'b0;
        end else begin
            m_axi_rready <= m_axi_rready;
        end
    end
    
    //rd_ready
    assign rd_ready = (state == IDLE)?1'b1:1'b0;  //在IDLE状态下准备好接收读请求
    
    //rd_done
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            rd_done <= 1'b0;
        end else if(state == R && m_axi_rlast && m_axi_r_handshake) begin //读数据通道握手成功,且是最后一个数据
            rd_done <= 1'b1;
        end else begin
            rd_done <= 1'b0;
        end
    end
    
/*     //m_axi_r_handshake_d
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            m_axi_r_handshake_d <= 1'b0;
        end else begin
            m_axi_r_handshake_d <= m_axi_r_handshake;
        end
    end */
    
    //rd_data 
    //读通道握手成功时,为有效数据输出
    assign rd_data = (m_axi_r_handshake)?m_axi_rdata:'d0;
    

endmodule
axi_master_rd

 

image

 

在小梅哥系列FPGA器件中,有许多开发板都配置有两片的DDR3,如ACX750、ACZ702、ACZ7015等。以ACX750开发板为例,使用的是两片型号为MT41K256M16 RE-125的DDR3存储器件。从型号我们可以推断出单片DDR拥有256M个存储颗粒,每个存储颗粒的位宽为16位。而两片DDR,则可以以并联的方式组成一个位宽为32位,存储深度为256M的存储器件。因此,在进行读写操作时,其内部数据存储类似于下图:

image

 由于是并联的,所以两片DDR地址线共享,用户在进行写操作时,需要将数据的高16位和低16位分开存放。至于单片DDR的使用,我们可以理解为屏蔽掉了其中一个DDR存储器件,在地址不变的情况下,数据位宽变为16,用户写入数据时,直接写入单片DDR中即可。那么这是单片/双片DDR的工作原理,接下来我们再来看看使用时的差异:

对DDR3的读写我们一般通过mig软核或是ZYNQ PS端的DDR控制器实现,这里我们还是以ACX750为例,由于是纯FPGA,因此使用mig实现ddr读写。在进行配置时,差异主要体现在三处:

1.数据位宽,单片DDR数据位宽为16位,两片DDR数据位宽为32位

2.AXI总线位宽,注意这里说的是AXI总线位宽,并非我们说的DDR地址线,这里mig会自动帮我们计算,当然我们也可以手动验算

image

 3.引脚分配,由于两片DDR的地址线共享,数据分开存放,所以两片DDR的dm(数据选通)、dqs(数据同步)、dq(数据总线)信号位宽为单片的两倍,而地址线(addr)位宽相同。

基于以上三点,在实际的代码设计中,就需要根据使用的是单片/双片DDR来调整dm、dqs、dq的信号位宽,以及与mig交互的AXI接口中,araddr、awaddr信号的位宽。

最后是仿真例化,ddr3的仿真模型可以通过mig的例程获取,仿真模型对应单片DDR,因此,在双片DDR的仿真中,我们需要例化两个ddr3_model,然后对dm(数据选通)、dqs(数据同步)、dq(数据总线)信号分别作控制,如下:

image

 

参考:

https://www.corecourse.cn/forum.php?mod=viewthread&tid=29677

 

Xilinx官方为我们提供了ddr3仿真的方法,可以更方便的进行程序的调试。

1、右击刚设置好的ip核

image

 

点击Open IP Example Design

2、弹出下框,路径为创建工程路径不用改,若是之前创建过仿真工程文件现在又做了修改则勾选覆盖之前工程。然后点击OK。

image

 3、等待自动创建打开仿真文件

image

 

image

 4、自动生成的测试工程文件,点击Run Simulation即可观看仿真波形。

image

 

5、这里不用运行仿真,只需要取两个我们需要的文件加入我们自己的工程目录。

按照刚才存放工程的位置找到这两个文件

image

 6、直接加入

image

 下面这两个文件就出现在这个目录下

image

 7、.vh这个文件不用管他,主要是操作.sv

双击打开.sv文件

image

 

官方已经给出了例化模型

用下面的方法将ddr3例化至仿真文件,因为使用的是两片ddr3所以需要例化两个模型,类似于真正绑定IO口的感觉。

感兴趣的可以看一下上面两个文件,就可以知道为什么必须例化两个,我写程序时仿真后ddr3一直初始化不成功就是因为没有认识到ddr3_modle.sv的真正含义。

附上官方解释。

image

 

原文链接:https://blog.csdn.net/jn20181024/article/details/130033589

 

 

单片: 

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/06/21 15:48:17
// Design Name: 
// Module Name: tb_ddr3_test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module tb_ddr3_test(

    );

reg                 clk     ;
reg                 rst_n   ;
    
wire [13:0] ddr3_addr       ;  
wire [2:0]  ddr3_ba         ;
wire        ddr3_cas_n      ;
wire        ddr3_ck_n       ;
wire        ddr3_ck_p       ;
wire        ddr3_cke        ;
wire        ddr3_ras_n      ;
wire        ddr3_reset_n    ;
wire        ddr3_we_n       ;
wire [15:0] ddr3_dq         ;
wire [1:0]  ddr3_dqs_n      ;
wire [1:0]  ddr3_dqs_p      ;
wire        ddr3_cs_n       ;
wire [1:0]  ddr3_dm         ;
wire        ddr3_odt        ;

initial                                                
begin                                                  
    clk = 1   ;              
end                                                    
always #10 clk = ~clk ; 

initial                                                
begin                                                  
    rst_n = 0   ;    
    #100
    rst_n = 1   ;          
end 
    
ddr3_test   ddr3_test_uut(
    .clk          (clk            )   ,
    .rst_n        (rst_n          )   ,

    .ddr3_addr    ( ddr3_addr )   ,
    .ddr3_ba      (   ddr3_ba   )   ,
    .ddr3_cas_n   (ddr3_cas_n)   ,
    .ddr3_ck_n    ( ddr3_ck_n )   ,
    .ddr3_ck_p    ( ddr3_ck_p )   ,
    .ddr3_cke     (  ddr3_cke  )   ,
    .ddr3_ras_n   (ddr3_ras_n   )   ,
    .ddr3_reset_n (ddr3_reset_n )   ,
    .ddr3_we_n    ( ddr3_we_n   )   ,
    .ddr3_dq      (   ddr3_dq   )   ,
    .ddr3_dqs_n   (ddr3_dqs_n   )   ,
    .ddr3_dqs_p   (ddr3_dqs_p   )   ,
    .ddr3_cs_n    ( ddr3_cs_n   )   ,
    .ddr3_dm      (   ddr3_dm   )   ,
    .ddr3_odt     (  ddr3_odt   )   

);
    
ddr3_model    ddr3_model_inst
(    
    .rst_n           (rst_n            ),    
    .ck              (ddr3_ck_p        ),    
    .ck_n            (ddr3_ck_n        ),    
    .cke             (ddr3_cke        ),    
    .cs_n            (ddr3_cs_n        ),    
    .ras_n           (ddr3_ras_n        ),    
    .cas_n           (ddr3_cas_n        ),    
    .we_n            (ddr3_we_n        ),    
    .dm_tdqs         (ddr3_dm        ),    
    .ba              (ddr3_ba        ),    
    .addr            (ddr3_addr        ),    
    .dq              (ddr3_dq        ),    
    .dqs             (ddr3_dqs_p        ),    
    .dqs_n           (ddr3_dqs_n        ),    
    .tdqs_n          (                ),            //NULL
    .odt             (ddr3_odt        )    
);    
        
endmodule
tb_ddr3_test

 

`timescale 1ns / 1ps
// Description: DDR3读写功能测试模块, 包含DDR3接口、测试数据生成模块、时钟生成模块
// 输出线输出到DDR3物理端口, 使用在线逻辑分析仪进行DDR3逻辑功能分析
module ddr3_test
#(parameter WR_BEG_ADDR     = 30'd0     ,
  parameter WR_END_ADDR     = 30'd8191  ,//30'd8191  ,
  parameter WR_BURST_LEN    = 8'd15     ,
  parameter RD_BEG_ADDR     = 30'd0     ,
  parameter RD_END_ADDR     = 30'd5184  ,//30'd2047  ,30'd8191 
  parameter RD_BURST_LEN    = 8'd15      ,//  parameter RD_BURST_LEN    = 8'd15     ,
  parameter FIFO_WR_WIDTH   = 6'd32     ,
  parameter FIFO_RD_WIDTH   = 6'd32     
  )
    (
        input   wire        clk           ,//50MHz时钟输入
        input   wire        rst_n         ,
       
        output  wire [13:0] ddr3_addr     ,  
        output  wire [2:0]  ddr3_ba       ,
        output  wire        ddr3_cas_n    ,
        output  wire        ddr3_ck_n     ,
        output  wire        ddr3_ck_p     ,
        output  wire        ddr3_cke      ,
        output  wire        ddr3_ras_n    ,
        output  wire        ddr3_reset_n  ,
        output  wire        ddr3_we_n     ,
        inout   wire [15:0] ddr3_dq       ,
        inout   wire [1:0]  ddr3_dqs_n    ,
        inout   wire [1:0]  ddr3_dqs_p    ,
        output  wire        ddr3_cs_n     ,
        output  wire [1:0]  ddr3_dm       ,
        output  wire        ddr3_odt      
        
    );
        
    //时钟模块相关连线
    wire        clk_fifo       ; //FIFO读写时钟
    wire        clk_ddr        ; //提供给DDR MIG的参考时钟
    wire        locked         ;
    wire        locked_rst_n   ;
    
    //ddr_interface相关连线
(*mark_debug="true", dont_touch="true"*)    wire                        wr_en          ; //写FIFO写请求
(*mark_debug="true", dont_touch="true"*)    wire [FIFO_WR_WIDTH-1:0]    wr_data        ; //写FIFO写数据 
(*mark_debug="true", dont_touch="true"*)    wire                        rd_mem_enable  ; //读存储器使能,防止存储器未写先读
(*mark_debug="true", dont_touch="true"*)    wire                        rd_en          ; //读FIFO读请求
(*mark_debug="true", dont_touch="true"*)    wire [FIFO_RD_WIDTH-1:0]    rd_data        ; //读FIFO读数据
(*mark_debug="true", dont_touch="true"*)    wire                        rd_valid       ; //读FIFO有效标志,高电平代表当前处理的数据有效  
(*mark_debug="true", dont_touch="true"*)    wire                        calib_done     ; //DDR3初始化完成 
    
    wire        ui_clk         ; //MIG IP核输出的用户时钟, 用作AXI控制器时钟
    wire        ui_rst         ; //MIG IP核输出的复位信号, 高电平有效
           
    //测试数据生成模块
    testdata_gen_valid 
    #(.FIFO_WR_WIDTH(FIFO_WR_WIDTH))
    testdata_gen_valid_inst
    (
        .clk             (clk_fifo        ),  //和FIFO时钟保持一致
        .rst_n           (locked_rst_n    ),
        .calib_done      (calib_done      ),  //DDR3初始化完成标志
            
        //写端口   
        .wr_data         (wr_data         ),   //向写FIFO中写入的数据
        .wr_en           (wr_en           ),   //写FIFO写使能
        
        //读端口
        .rd_en           (rd_en           ),   //读FIFO读使能
        .rd_mem_enable   (rd_mem_enable   ),   //读存储器使能, 为高时才能从DDR3 SDRAM中读取数据
        .rd_valid        (rd_valid        )    //读有效信号, 为高时代表读取的数据有效
        
    );
    
    
    
      //时钟生成模块,产生FIFO读写时钟及AXI读写主机工作时钟
      clk_gen clk_gen_inst(
        .clk_ddr    (clk_ddr    ),     
        .clk_fifo   (clk_fifo   ),   
        // Status and control signals
        .reset      (~rst_n     ), 
        .locked     (locked     ),     
        // Clock in ports
        .clk_in1    (clk        )      //50MHz时钟输入
    ); 
    
    assign locked_rst_n = rst_n & locked;
    
    
    //DDR3接口模块
    ddr_interface 
    #(.FIFO_WR_WIDTH(FIFO_WR_WIDTH),  //用户端FIFO读写位宽
      .FIFO_RD_WIDTH(FIFO_RD_WIDTH))
    ddr_interface_inst
    (
        .clk                 (clk_ddr             ), //DDR3时钟, 也就是DDR3 MIG IP核参考时钟
        .rst_n               (locked_rst_n        ), 
                    
        //用户端       
        .wr_clk              (clk_fifo            ), //写FIFO写时钟
        .wr_rst              (~locked_rst_n       ), //写复位
        .wr_beg_addr         (WR_BEG_ADDR         ), //写起始地址
        .wr_end_addr         (WR_END_ADDR         ), //写终止地址
        .wr_burst_len        (WR_BURST_LEN        ), //写突发长度
        .wr_en               (wr_en               ), //写FIFO写请求
        .wr_data             (wr_data             ), //写FIFO写数据 
        .rd_clk              (clk_fifo            ), //读FIFO读时钟
        .rd_rst              (~locked_rst_n       ), //读复位
        .rd_mem_enable       (rd_mem_enable       ), //读存储器使能,防止存储器未写先读
        .rd_beg_addr         (RD_BEG_ADDR         ), //读起始地址
        .rd_end_addr         (RD_END_ADDR         ), //读终止地址
        .rd_burst_len        (RD_BURST_LEN        ), //读突发长度
        .rd_en               (rd_en               ), //读FIFO读请求
        .rd_data             (rd_data             ), //读FIFO读数据
        .rd_valid            (rd_valid            ), //读FIFO有效标志,高电平代表当前处理的数据有效
        .ui_clk              (ui_clk              ), //MIG IP核输出的用户时钟, 用作AXI控制器时钟
        .ui_rst              (ui_rst              ), //MIG IP核输出的复位信号, 高电平有效
        .calib_done          (calib_done          ), //DDR3初始化完成
        
        //DDR3接口                              
        .ddr3_addr           (ddr3_addr           ),  
        .ddr3_ba             (ddr3_ba             ),
        .ddr3_cas_n          (ddr3_cas_n          ),
        .ddr3_ck_n           (ddr3_ck_n           ),
        .ddr3_ck_p           (ddr3_ck_p           ),
        .ddr3_cke            (ddr3_cke            ),
        .ddr3_ras_n          (ddr3_ras_n          ),
        .ddr3_reset_n        (ddr3_reset_n        ),
        .ddr3_we_n           (ddr3_we_n           ),
        .ddr3_dq             (ddr3_dq             ),
        .ddr3_dqs_n          (ddr3_dqs_n          ),
        .ddr3_dqs_p          (ddr3_dqs_p          ),
        .ddr3_cs_n           (ddr3_cs_n           ),
        .ddr3_dm             (ddr3_dm             ),
        .ddr3_odt            (ddr3_odt            )
    );
    
    
endmodule
    //进行ILA在线调试时, 使用这一段代码
    // (*mark_debug="true", dont_touch="true"*)wire                        wr_en          ; //写FIFO写请求
    // (*mark_debug="true", dont_touch="true"*)wire [FIFO_WR_WIDTH-1:0]    wr_data        ; //写FIFO写数据 
    // (*mark_debug="true", dont_touch="true"*)wire                        rd_mem_enable  ; //读存储器使能,防止存储器未写先读
    // (*mark_debug="true", dont_touch="true"*)wire                        rd_en          ; //读FIFO读请求
    // (*mark_debug="true", dont_touch="true"*)wire [FIFO_RD_WIDTH-1:0]    rd_data        ; //读FIFO读数据
    // (*mark_debug="true", dont_touch="true"*)wire                        rd_valid       ; //读FIFO有效标志,高电平代表当前处理的数据有效  
    // (*mark_debug="true", dont_touch="true"*)wire                        calib_done     ; //DDR3初始化完成    
ddr3_test

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////

// Module Name: testdata_gen_valid
// Description: 生成DDR3测试数据, 发送读写FIFO请求, 并最终验证从读FIFO中读取的数据是否与生成的数据一致
//////////////////////////////////////////////////////////////////////////////////


module testdata_gen_valid
    #(parameter FIFO_WR_WIDTH = 6'd32)  //用户端FIFO写位宽
    (
        input   wire                        clk             ,  //和FIFO时钟保持一致
        input   wire                        rst_n           ,
        input   wire                        calib_done      ,  //DDR3初始化完成标志
            
        //写端口   
        output  reg [FIFO_WR_WIDTH-1:0]     wr_data         ,   //向写FIFO中写入的数据
        output  reg                         wr_en           ,   //写FIFO写使能
                        
        //读端口               
        // output  reg                         rd_en           ,   //读FIFO读使能
        output  wire                        rd_en           ,   //读FIFO读使能
        output  reg                         rd_mem_enable   ,   //读存储器使能, 为高时才能从DDR3 SDRAM中读取数据
        input   wire                        rd_valid            //读有效信号, 为高时代表读取的数据有效
    );
//
/* (*mark_debug="true", dont_touch="true"*)reg [15:0] cnt0;
(*mark_debug="true", dont_touch="true"*)wire      add_cnt0;
(*mark_debug="true", dont_touch="true"*)wire      end_cnt0;
always@(posedge clk or negedge rst_n)begin
    if(~rst_n)begin
        cnt0<=0;
    end
    else if(add_cnt0)begin
        if(end_cnt0)
            cnt0<=0;
        else
            cnt0<=cnt0+1;
    end 
end 
assign add_cnt0 = calib_done;
assign end_cnt0 = add_cnt0 && cnt0 == 1000-1; 
//wr_en
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            wr_en <= 1'b0;
        end else if(add_cnt0 && (cnt0 <'d128)) begin 
            wr_en <= 1'b1;
        end else if(add_cnt0 && (cnt0 >='d128)) begin  
            wr_en <= 1'b0;
        end 
    end
//wr_data
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            wr_data <= 'd0;
        end else if(wr_en) begin  //每次写入FIFO的时候数据自增一
            wr_data <= cnt0;//wr_data + 'd1;
        end 
    end
//rd_mem_enable     
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            rd_mem_enable <= 1'b0;
        end else if(add_cnt0 && (cnt0 >='d128)) begin  
            rd_mem_enable <= 1'b1;
        end else if(add_cnt0 && (cnt0 <'d128)) begin 
            rd_mem_enable <= 1'b0;
        end
    
    end */    
    //wr_en
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            wr_en <= 1'b0;
        end else if(wr_data >= 16'd1299) begin //写完最后一个数据
            wr_en <= 1'b0;
        end else if(calib_done) begin  //DDR3初始化完成后, 开始向写FIFO中写数据
            wr_en <= 1'b1;
        end else begin
            wr_en <= wr_en;
        end
    end
    
    //wr_data
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            wr_data <= 'd0;
        end else if(wr_en) begin  //每次写入FIFO的时候数据自增一
            wr_data <= wr_data + 'd1;
        end else begin
            wr_data <=wr_data;
        end
    end
//
// reg [15:0] cnt0;
// wire      add_cnt0;
// wire      end_cnt0;
// always@(posedge clk or negedge rst_n)begin
    // if(~rst_n)begin
        // cnt0<=0;
    // end
    // else if(add_cnt0)begin
        // if(end_cnt0)
            // cnt0<='d21125-1;
        // else
            // cnt0<=cnt0+1;
    // end 
// end 
// assign add_cnt0 = rd_mem_enable;
// assign end_cnt0 = add_cnt0 && cnt0 == 'd21125-1;     
    //rd_mem_enable 
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            rd_mem_enable <= 1'b0;
        end else if(wr_data == 'd1300) begin  //数据已经写完, 可以确保DDR3 SDRAM中已经有数据 wr_data == 'd1300
            rd_mem_enable <= 1'b1;
        end else begin
            rd_mem_enable <= rd_mem_enable;
        end
    end
    
    //rd_en
    reg rd_en_0;
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            rd_en_0 <= 1'b0;
        end else if(rd_mem_enable && rd_valid) begin  //允许读存储器, 且读FIFO有数据, 且没有读够1000个数据
            rd_en_0 <= 1'b1;
        end else begin
            rd_en_0 <= 1'b0;
        end 
    end
    
    assign rd_en= rd_en_0 & rd_valid;//    assign rd_valid = ~rd_fifo_empty;
endmodule
testdata_gen_valid

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////

// Module Name: ddr_interface
// Description: DDR3顶层模块, 将MIG IP核与axi_ddr_ctrl模块封装起来
// 其中axi_ddr_ctrl模块包含AXI主机, 读FIFO、写FIFO及AXI读写控制器axi_ctrl
// 外接DDR3存储器,即可实现对DDR3存储器的FIFO式读写
//////////////////////////////////////////////////////////////////////////////////


module ddr_interface
    #(parameter FIFO_WR_WIDTH = 'd32    ,  //用户端FIFO读写位宽
                FIFO_RD_WIDTH = 'd32    ,
                AXI_WIDTH     = 'd64    ,  //AXI总线读写数据位宽
                AXI_AXSIZE    = 3'b011     //AXI总线的axi_awsize, 需要与AXI_WIDTH对应
                )
        (
        input   wire                        clk                 , //DDR3时钟, 也就是DDR3 MIG IP核参考时钟
        input   wire                        rst_n               , 
                                    
        //用户端                       
        input   wire                        wr_clk              , //写FIFO写时钟
        input   wire                        wr_rst              , //写复位
        // input   wire [29:0]                 wr_beg_addr         , //写起始地址
        // input   wire [29:0]                 wr_end_addr         , //写终止地址
        input   wire [27:0]                 wr_beg_addr         , //写起始地址
        input   wire [27:0]                 wr_end_addr         , //写终止地址        
        input   wire [7:0]                  wr_burst_len        , //写突发长度
        input   wire                        wr_en               , //写FIFO写请求
        input   wire [FIFO_WR_WIDTH-1:0]    wr_data             , //写FIFO写数据 
        input   wire                        rd_clk              , //读FIFO读时钟
        input   wire                        rd_rst              , //读复位
        input   wire                        rd_mem_enable       , //读存储器使能,防止存储器未写先读
        // input   wire [29:0]                 rd_beg_addr         , //读起始地址
        // input   wire [29:0]                 rd_end_addr         , //读终止地址
        input   wire [27:0]                 rd_beg_addr         , //读起始地址
        input   wire [27:0]                 rd_end_addr         , //读终止地址        
        input   wire [7:0]                  rd_burst_len        , //读突发长度
        input   wire                        rd_en               , //读FIFO读请求
        output  wire [FIFO_RD_WIDTH-1:0]    rd_data             , //读FIFO读数据
        output  wire                        rd_valid            , //读FIFO有效标志,高电平代表当前处理的数据有效
        output  wire                        ui_clk              , //MIG IP核输出的用户时钟, 用作AXI控制器时钟
        output  wire                        ui_rst              , //MIG IP核输出的复位信号, 高电平有效
        output  wire                        calib_done          , //DDR3初始化完成
        
        //DDR3接口                            
        output  wire [13:0] ddr3_addr           ,  
        output  wire [2:0]  ddr3_ba             ,
        output  wire        ddr3_cas_n          ,
        output  wire        ddr3_ck_n           ,
        output  wire        ddr3_ck_p           ,
        output  wire        ddr3_cke            ,
        output  wire        ddr3_ras_n          ,
        output  wire        ddr3_reset_n        ,
        output  wire        ddr3_we_n           ,
        inout   wire [15:0] ddr3_dq             ,
        inout   wire [1:0]  ddr3_dqs_n          ,
        inout   wire [1:0]  ddr3_dqs_p          ,
        output  wire        ddr3_cs_n           ,
        output  wire [1:0]  ddr3_dm             ,
        output  wire        ddr3_odt                    
//        
    );
    
    localparam AXI_WSTRB_W   = AXI_WIDTH >> 3   ; //axi_wstrb的位宽, AXI_WIDTH/8
    
    //AXI连线
    //AXI4写地址通道
    wire [3:0]              axi_awid      ; 
    // wire [29:0]             axi_awaddr    ;
    wire [27:0]             axi_awaddr    ;    
    wire [7:0]              axi_awlen     ; //突发传输长度
    wire [2:0]              axi_awsize    ; //突发传输大小(Byte)
    wire [1:0]              axi_awburst   ; //突发类型
    wire                    axi_awlock    ; 
    wire [3:0]              axi_awcache   ; 
    wire [2:0]              axi_awprot    ;
    wire [3:0]              axi_awqos     ;
    wire                    axi_awvalid   ; //写地址valid
    wire                    axi_awready   ; //从机发出的写地址ready
    
    //写数据通道
    wire [AXI_WIDTH-1:0]    axi_wdata     ; //写数据
    wire [AXI_WSTRB_W-1:0]  axi_wstrb     ; //写数据有效字节线
    wire                    axi_wlast     ; //最后一个数据标志
    wire                    axi_wvalid    ; //写数据有效标志
    wire                    axi_wready    ; //从机发出的写数据ready
                
    //写响应通道         
    wire [3:0]              axi_bid       ;
    wire [1:0]              axi_bresp     ; //响应信号,表征写传输是否成功
    wire                    axi_bvalid    ; //响应信号valid标志
    wire                    axi_bready    ; //主机响应ready信号
    
    //读地址通道
   wire [3:0]              axi_arid      ; 
    // wire [29:0]             axi_araddr    ; 
    wire [27:0]             axi_araddr    ;     
    wire [7:0]              axi_arlen     ; //突发传输长度
    wire [2:0]              axi_arsize    ; //突发传输大小(Byte)
    wire [1:0]              axi_arburst   ; //突发类型
    wire                    axi_arlock    ; 
    wire [3:0]              axi_arcache   ; 
    wire [2:0]              axi_arprot    ;
    wire [3:0]              axi_arqos     ;
    wire                    axi_arvalid   ; //读地址valid
    wire                    axi_arready   ; //从机准备接收读地址
    
    //读数据通道
   wire [AXI_WIDTH-1:0]    axi_rdata     ; //读数据
   wire [1:0]              axi_rresp     ; //收到的读响应
   wire                    axi_rlast     ; //最后一个数据标志
   wire                    axi_rvalid    ; //读数据有效标志
   wire                    axi_rready    ; //主机发出的读数据ready
    
    //输入系统时钟异步复位、同步释放处理
    reg                     rst_n_d1      ;
    reg                     rst_n_sync    ;
    
    //rst_n_d1、rst_n_sync
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin  //异步复位
            rst_n_d1    <= 1'b0;
            rst_n_sync  <= 1'b0;
        end else begin   //同步释放
            rst_n_d1    <= 1'b1;
            rst_n_sync  <= rst_n_d1;
        end
    end
    
   
    
    
    // axi_ddr_ctrl模块
    axi_ddr_ctrl 
        #(.FIFO_WR_WIDTH(FIFO_WR_WIDTH),  
          .FIFO_RD_WIDTH(FIFO_RD_WIDTH),
          .AXI_WIDTH    (AXI_WIDTH    ),
          .AXI_AXSIZE   (AXI_AXSIZE   ),
          .AXI_WSTRB_W  (AXI_WSTRB_W  ) 
          
          )
          axi_ddr_ctrl_inst
         (
        .clk             (ui_clk           ), //AXI读写主机时钟
        .rst_n           (~ui_rst          ), 
                
        //用户端    
        .wr_clk          (wr_clk           ), //写FIFO写时钟
        .wr_rst          (wr_rst           ), //写复位
        .wr_beg_addr     (wr_beg_addr      ), //写起始地址
        .wr_end_addr     (wr_end_addr      ), //写终止地址
        .wr_burst_len    (wr_burst_len     ), //写突发长度
        .wr_en           (wr_en            ), //写FIFO写请求
        .wr_data         (wr_data          ), //写FIFO写数据 
        .rd_clk          (rd_clk           ), //读FIFO读时钟
        .rd_rst          (rd_rst           ), //读复位
        .rd_mem_enable   (rd_mem_enable    ), //读存储器使能,防止存储器未写先读
        .rd_beg_addr     (rd_beg_addr      ), //读起始地址
        .rd_end_addr     (rd_end_addr      ), //读终止地址
        .rd_burst_len    (rd_burst_len     ), //读突发长度
        .rd_en           (rd_en            ), //读FIFO读请求
        .rd_data         (rd_data          ), //读FIFO读数据
        .rd_valid        (rd_valid         ), //读FIFO可读标志,表示读FIFO中有数据可以对外输出
        
        //AXI总线
        //AXI4写地址通道
        .m_axi_awid      (axi_awid         ), 
        .m_axi_awaddr    (axi_awaddr       ),
        .m_axi_awlen     (axi_awlen        ), //突发传输长度
        .m_axi_awsize    (axi_awsize       ), //突发传输大小(Byte)
        .m_axi_awburst   (axi_awburst      ), //突发类型
        .m_axi_awlock    (axi_awlock       ), 
        .m_axi_awcache   (axi_awcache      ), 
        .m_axi_awprot    (axi_awprot       ),
        .m_axi_awqos     (axi_awqos        ),
        .m_axi_awvalid   (axi_awvalid      ), //写地址valid
        .m_axi_awready   (axi_awready      ), //从机发出的写地址ready
        
        //写数据通道
        .m_axi_wdata     (axi_wdata        ), //写数据
        .m_axi_wstrb     (axi_wstrb        ), //写数据有效字节线
        .m_axi_wlast     (axi_wlast        ), //最后一个数据标志
        .m_axi_wvalid    (axi_wvalid       ), //写数据有效标志
        .m_axi_wready    (axi_wready       ), //从机发出的写数据ready
        
        //写响应通道
        .m_axi_bid       (axi_bid          ),
        .m_axi_bresp     (axi_bresp        ), //响应信号,表征写传输是否成功
        .m_axi_bvalid    (axi_bvalid       ), //响应信号valid标志
        .m_axi_bready    (axi_bready       ), //主机响应ready信号
        
        //AXI4读地址通道
        .m_axi_arid      (axi_arid         ), 
        .m_axi_araddr    (axi_araddr       ),
        .m_axi_arlen     (axi_arlen        ), //突发传输长度
        .m_axi_arsize    (axi_arsize       ), //突发传输大小(Byte)
        .m_axi_arburst   (axi_arburst      ), //突发类型
        .m_axi_arlock    (axi_arlock       ), 
        .m_axi_arcache   (axi_arcache      ), 
        .m_axi_arprot    (axi_arprot       ),
        .m_axi_arqos     (axi_arqos        ),
        .m_axi_arvalid   (axi_arvalid      ), //读地址valid
        .m_axi_arready   (axi_arready      ), //从机准备接收读地址
        
        //读数据通道
        .m_axi_rdata     (axi_rdata        ), //读数据
        .m_axi_rresp     (axi_rresp        ), //收到的读响应
        .m_axi_rlast     (axi_rlast        ), //最后一个数据标志
        .m_axi_rvalid    (axi_rvalid       ), //读数据有效标志
        .m_axi_rready    (axi_rready       )  //主机发出的读数据ready
    );
     
    // Vivado MIG IP核
      ddr3         ddr3_mig_inst (    
      // axi_ddr03 axi_ddr03_mig_inst (
        // DDR3存储器接口
        .ddr3_addr              (ddr3_addr          ),  // output [13:0]    ddr3_addr
        .ddr3_ba                (ddr3_ba            ),  // output [2:0]     ddr3_ba
        .ddr3_cas_n             (ddr3_cas_n         ),  // output           ddr3_cas_n
        .ddr3_ck_n              (ddr3_ck_n          ),  // output [0:0]     ddr3_ck_n
        .ddr3_ck_p              (ddr3_ck_p          ),  // output [0:0]     ddr3_ck_p
        .ddr3_cke               (ddr3_cke           ),  // output [0:0]     ddr3_cke
        .ddr3_ras_n             (ddr3_ras_n         ),  // output           ddr3_ras_n
        .ddr3_reset_n           (ddr3_reset_n       ),  // output           ddr3_reset_n
        .ddr3_we_n              (ddr3_we_n          ),  // output           ddr3_we_n
        .ddr3_dq                (ddr3_dq            ),  // inout [15:0]     ddr3_dq
        .ddr3_dqs_n             (ddr3_dqs_n         ),  // inout [1:0]      ddr3_dqs_n
        .ddr3_dqs_p             (ddr3_dqs_p         ),  // inout [1:0]      ddr3_dqs_p
        .init_calib_complete    (calib_done         ),  // output           init_calib_complete
        .ddr3_cs_n              (ddr3_cs_n          ),  // output [0:0]     ddr3_cs_n
        .ddr3_dm                (ddr3_dm            ),  // output [3:0]     ddr3_dm
        .ddr3_odt               (ddr3_odt           ),  // output [0:0]     ddr3_odt
        
        // 用户接口
        .ui_clk                 (ui_clk             ),  // output           ui_clk
        .ui_clk_sync_rst        (ui_rst             ),  // output           ui_clk_sync_rst
        .mmcm_locked            (                   ),  // output           mmcm_locked
        .aresetn                (rst_n_sync         ),  // input            aresetn
        .app_sr_req             (1'b0               ),  // input            app_sr_req
        .app_ref_req            (1'b0               ),  // input            app_ref_req
        .app_zq_req             (1'b0               ),  // input            app_zq_req
        .app_sr_active          (                   ),  // output           app_sr_active
        .app_ref_ack            (                   ),  // output           app_ref_ack
        .app_zq_ack             (                   ),  // output           app_zq_ack
        
        // AXI写地址通道
        .s_axi_awid             (axi_awid           ),  // input [3:0]      s_axi_awid
        .s_axi_awaddr           (axi_awaddr         ),  // input [27:0]     s_axi_awaddr
        .s_axi_awlen            (axi_awlen          ),  // input [7:0]      s_axi_awlen
        .s_axi_awsize           (axi_awsize         ),  // input [2:0]      s_axi_awsize
        .s_axi_awburst          (axi_awburst        ),  // input [1:0]      s_axi_awburst
        .s_axi_awlock           (axi_awlock         ),  // input [0:0]      s_axi_awlock
        .s_axi_awcache          (axi_awcache        ),  // input [3:0]      s_axi_awcache
        .s_axi_awprot           (axi_awprot         ),  // input [2:0]      s_axi_awprot
        .s_axi_awqos            (axi_awqos          ),  // input [3:0]      s_axi_awqos
        .s_axi_awvalid          (axi_awvalid        ),  // input            s_axi_awvalid
        .s_axi_awready          (axi_awready        ),  // output           s_axi_awready
    
        // AXI写数据通道
        .s_axi_wdata            (axi_wdata          ),  // input [AXI_WIDTH-1:0]     s_axi_wdata
        .s_axi_wstrb            (axi_wstrb          ),  // input [AXI_WSTRB_W-1:0]   s_axi_wstrb
        .s_axi_wlast            (axi_wlast          ),  // input                     s_axi_wlast
        .s_axi_wvalid           (axi_wvalid         ),  // input                     s_axi_wvalid
        .s_axi_wready           (axi_wready         ),  // output                    s_axi_wready
                   
        // AXI写响应通道        
        .s_axi_bid              (axi_bid            ),  // output [3:0]              s_axi_bid
        .s_axi_bresp            (axi_bresp          ),  // output [1:0]              s_axi_bresp
        .s_axi_bvalid           (axi_bvalid         ),  // output                    s_axi_bvalid
        .s_axi_bready           (axi_bready         ),  // input                     s_axi_bready
                   
        // AXI读地址通道        
        .s_axi_arid             (axi_arid           ),  // input [3:0]               s_axi_arid
        .s_axi_araddr           (axi_araddr         ),  // input [27:0]              s_axi_araddr
        .s_axi_arlen            (axi_arlen          ),  // input [7:0]               s_axi_arlen
        .s_axi_arsize           (axi_arsize         ),  // input [2:0]               s_axi_arsize
        .s_axi_arburst          (axi_arburst        ),  // input [1:0]               s_axi_arburst
        .s_axi_arlock           (axi_arlock         ),  // input [0:0]               s_axi_arlock
        .s_axi_arcache          (axi_arcache        ),  // input [3:0]               s_axi_arcache
        .s_axi_arprot           (axi_arprot         ),  // input [2:0]               s_axi_arprot
        .s_axi_arqos            (axi_arqos          ),  // input [3:0]               s_axi_arqos
        .s_axi_arvalid          (axi_arvalid        ),  // input                     s_axi_arvalid
        .s_axi_arready          (axi_arready        ),  // output                    s_axi_arready
        
        // AXI读数据通道
        .s_axi_rid              (axi_rid            ),  // output [3:0]              s_axi_rid
        .s_axi_rdata            (axi_rdata          ),  // output [AXI_WIDTH-1:0]    s_axi_rdata
        .s_axi_rresp            (axi_rresp          ),  // output [1:0]              s_axi_rresp
        .s_axi_rlast            (axi_rlast          ),  // output                    s_axi_rlast
        .s_axi_rvalid           (axi_rvalid         ),  // output                    s_axi_rvalid
        .s_axi_rready           (axi_rready         ),  // input                     s_axi_rready
        
        // AXI从机系统时钟
        .sys_clk_i              (clk                ),
        // 参考时钟
        // .clk_ref_i              (clk                ),
        .sys_rst                (rst_n_sync         )   // input            sys_rst
    );
// 


endmodule
/* //
  ddr3 u_ddr3 (
    // Memory interface ports
    .ddr3_addr                      (ddr3_addr),  // output [13:0]        ddr3_addr
    .ddr3_ba                        (ddr3_ba),  // output [2:0]        ddr3_ba
    .ddr3_cas_n                     (ddr3_cas_n),  // output            ddr3_cas_n
    .ddr3_ck_n                      (ddr3_ck_n),  // output [0:0]        ddr3_ck_n
    .ddr3_ck_p                      (ddr3_ck_p),  // output [0:0]        ddr3_ck_p
    .ddr3_cke                       (ddr3_cke),  // output [0:0]        ddr3_cke
    .ddr3_ras_n                     (ddr3_ras_n),  // output            ddr3_ras_n
    .ddr3_reset_n                   (ddr3_reset_n),  // output            ddr3_reset_n
    .ddr3_we_n                      (ddr3_we_n),  // output            ddr3_we_n
    .ddr3_dq                        (ddr3_dq),  // inout [15:0]        ddr3_dq
    .ddr3_dqs_n                     (ddr3_dqs_n),  // inout [1:0]        ddr3_dqs_n
    .ddr3_dqs_p                     (ddr3_dqs_p),  // inout [1:0]        ddr3_dqs_p
    .init_calib_complete            (init_calib_complete),  // output            init_calib_complete
    .ddr3_cs_n                      (ddr3_cs_n),  // output [0:0]        ddr3_cs_n
    .ddr3_dm                        (ddr3_dm),  // output [1:0]        ddr3_dm
    .ddr3_odt                       (ddr3_odt),  // output [0:0]        ddr3_odt
    // Application interface ports
    .ui_clk                         (ui_clk),  // output            ui_clk
    .ui_clk_sync_rst                (ui_clk_sync_rst),  // output            ui_clk_sync_rst
    .mmcm_locked                    (mmcm_locked),  // output            mmcm_locked
    .aresetn                        (aresetn),  // input            aresetn
    .app_sr_req                     (app_sr_req),  // input            app_sr_req
    .app_ref_req                    (app_ref_req),  // input            app_ref_req
    .app_zq_req                     (app_zq_req),  // input            app_zq_req
    .app_sr_active                  (app_sr_active),  // output            app_sr_active
    .app_ref_ack                    (app_ref_ack),  // output            app_ref_ack
    .app_zq_ack                     (app_zq_ack),  // output            app_zq_ack
    // Slave Interface Write Address Ports
    .s_axi_awid                     (s_axi_awid),  // input [3:0]            s_axi_awid
    .s_axi_awaddr                   (s_axi_awaddr),  // input [27:0]            s_axi_awaddr
    .s_axi_awlen                    (s_axi_awlen),  // input [7:0]            s_axi_awlen
    .s_axi_awsize                   (s_axi_awsize),  // input [2:0]            s_axi_awsize
    .s_axi_awburst                  (s_axi_awburst),  // input [1:0]            s_axi_awburst
    .s_axi_awlock                   (s_axi_awlock),  // input [0:0]            s_axi_awlock
    .s_axi_awcache                  (s_axi_awcache),  // input [3:0]            s_axi_awcache
    .s_axi_awprot                   (s_axi_awprot),  // input [2:0]            s_axi_awprot
    .s_axi_awqos                    (s_axi_awqos),  // input [3:0]            s_axi_awqos
    .s_axi_awvalid                  (s_axi_awvalid),  // input            s_axi_awvalid
    .s_axi_awready                  (s_axi_awready),  // output            s_axi_awready
    // Slave Interface Write Data Ports
    .s_axi_wdata                    (s_axi_wdata),  // input [63:0]            s_axi_wdata
    .s_axi_wstrb                    (s_axi_wstrb),  // input [7:0]            s_axi_wstrb
    .s_axi_wlast                    (s_axi_wlast),  // input            s_axi_wlast
    .s_axi_wvalid                   (s_axi_wvalid),  // input            s_axi_wvalid
    .s_axi_wready                   (s_axi_wready),  // output            s_axi_wready
    // Slave Interface Write Response Ports
    .s_axi_bid                      (s_axi_bid),  // output [3:0]            s_axi_bid
    .s_axi_bresp                    (s_axi_bresp),  // output [1:0]            s_axi_bresp
    .s_axi_bvalid                   (s_axi_bvalid),  // output            s_axi_bvalid
    .s_axi_bready                   (s_axi_bready),  // input            s_axi_bready
    // Slave Interface Read Address Ports
    .s_axi_arid                     (s_axi_arid),  // input [3:0]            s_axi_arid
    .s_axi_araddr                   (s_axi_araddr),  // input [27:0]            s_axi_araddr
    .s_axi_arlen                    (s_axi_arlen),  // input [7:0]            s_axi_arlen
    .s_axi_arsize                   (s_axi_arsize),  // input [2:0]            s_axi_arsize
    .s_axi_arburst                  (s_axi_arburst),  // input [1:0]            s_axi_arburst
    .s_axi_arlock                   (s_axi_arlock),  // input [0:0]            s_axi_arlock
    .s_axi_arcache                  (s_axi_arcache),  // input [3:0]            s_axi_arcache
    .s_axi_arprot                   (s_axi_arprot),  // input [2:0]            s_axi_arprot
    .s_axi_arqos                    (s_axi_arqos),  // input [3:0]            s_axi_arqos
    .s_axi_arvalid                  (s_axi_arvalid),  // input            s_axi_arvalid
    .s_axi_arready                  (s_axi_arready),  // output            s_axi_arready
    // Slave Interface Read Data Ports
    .s_axi_rid                      (s_axi_rid),  // output [3:0]            s_axi_rid
    .s_axi_rdata                    (s_axi_rdata),  // output [63:0]            s_axi_rdata
    .s_axi_rresp                    (s_axi_rresp),  // output [1:0]            s_axi_rresp
    .s_axi_rlast                    (s_axi_rlast),  // output            s_axi_rlast
    .s_axi_rvalid                   (s_axi_rvalid),  // output            s_axi_rvalid
    .s_axi_rready                   (s_axi_rready),  // input            s_axi_rready
    // System Clock Ports
    .sys_clk_i                      (sys_clk_i   ),
    .sys_rst                        (sys_rst    ) // input sys_rst
    ); */
ddr_interface

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////

// Module Name: axi_ddr_ctrl
// Description: AXI接口DDR控制顶层模块,集成AXI读主机、AXI写主机、AXI控制器(包含读写FIFO)
//////////////////////////////////////////////////////////////////////////////////


module axi_ddr_ctrl
    #(parameter FIFO_WR_WIDTH = 'd32            ,  //用户端FIFO读写位宽
                FIFO_RD_WIDTH = 'd32            ,
                AXI_WIDTH     = 'd64            ,  //AXI总线读写数据位宽
                AXI_AXSIZE    = 3'b011          ,  //AXI总线的axi_axsize, 需要与AXI_WIDTH对应
                AXI_WSTRB_W   = AXI_WIDTH>>3    )   //axi_wstrb的位宽, AXI_WIDTH/8
        (
        input   wire                        clk             , //AXI读写主机时钟(ui_clk)
        input   wire                        rst_n           , 
                                
        //用户端                   
        input   wire                        wr_clk          , //写FIFO写时钟
        input   wire                        wr_rst          , //写复位
        // input   wire [29:0]                 wr_beg_addr     , //写起始地址
        // input   wire [29:0]                 wr_end_addr     , //写终止地址
        input   wire [27:0]                 wr_beg_addr     , //写起始地址
        input   wire [27:0]                 wr_end_addr     , //写终止地址        
        input   wire [7:0]                  wr_burst_len    , //写突发长度
        input   wire                        wr_en           , //写FIFO写请求
        input   wire [FIFO_WR_WIDTH-1:0]    wr_data         , //写FIFO写数据 
        input   wire                        rd_clk          , //读FIFO读时钟
        input   wire                        rd_rst          , //读复位
        input   wire                        rd_mem_enable   , //读存储器使能,防止存储器未写先读
        // input   wire [29:0]                 rd_beg_addr     , //读起始地址
        // input   wire [29:0]                 rd_end_addr     , //读终止地址
        input   wire [27:0]                 rd_beg_addr     , //读起始地址
        input   wire [27:0]                 rd_end_addr     , //读终止地址        
        input   wire [7:0]                  rd_burst_len    , //读突发长度
        input   wire                        rd_en           , //读FIFO读请求
        output  wire [FIFO_RD_WIDTH-1:0]    rd_data         , //读FIFO读数据
        output  wire                        rd_valid        , //读FIFO可读标志,表示读FIFO中有数据可以对外输出
                        
        //AXI总线             
        //AXI4写地址通道             
        input   wire [3:0]                  m_axi_awid      , 
        // output  wire [29:0]                 m_axi_awaddr    ,
        output  wire [27:0]                 m_axi_awaddr    ,        
        output  wire [7:0]                  m_axi_awlen     , //突发传输长度
        output  wire [2:0]                  m_axi_awsize    , //突发传输大小(Byte)
        output  wire [1:0]                  m_axi_awburst   , //突发类型
        output  wire                        m_axi_awlock    , 
        output  wire [3:0]                  m_axi_awcache   , 
        output  wire [2:0]                  m_axi_awprot    ,
        output  wire [3:0]                  m_axi_awqos     ,
        output  wire                        m_axi_awvalid   , //写地址valid
        input   wire                        m_axi_awready   , //从机发出的写地址ready
                        
        //写数据通道             
        output  wire [AXI_WIDTH-1:0]        m_axi_wdata     , //写数据
        output  wire [AXI_WSTRB_W-1:0]      m_axi_wstrb     , //写数据有效字节线
        output  wire                        m_axi_wlast     , //最后一个数据标志
        output  wire                        m_axi_wvalid    , //写数据有效标志
        input   wire                        m_axi_wready    , //从机发出的写数据ready
                        
        //写响应通道             
        output  wire [3:0]                  m_axi_bid       ,
        input   wire [1:0]                  m_axi_bresp     , //响应信号,表征写传输是否成功
        input   wire                        m_axi_bvalid    , //响应信号valid标志
        output  wire                        m_axi_bready    , //主机响应ready信号
                        
        //AXI4读地址通道             
        output  wire [3:0]                  m_axi_arid      , 
        // output  wire [29:0]                 m_axi_araddr    ,
        output  wire [27:0]                 m_axi_araddr    ,        
        output  wire [7:0]                  m_axi_arlen     , //突发传输长度
        output  wire [2:0]                  m_axi_arsize    , //突发传输大小(Byte)
        output  wire [1:0]                  m_axi_arburst   , //突发类型
        output  wire                        m_axi_arlock    , 
        output  wire [3:0]                  m_axi_arcache   , 
        output  wire [2:0]                  m_axi_arprot    ,
        output  wire [3:0]                  m_axi_arqos     ,
        output  wire                        m_axi_arvalid   , //读地址valid
        input   wire                        m_axi_arready   , //从机准备接收读地址
                        
        //读数据通道             
        input   wire [AXI_WIDTH-1:0]        m_axi_rdata     , //读数据
        input   wire [1:0]                  m_axi_rresp     , //收到的读响应
        input   wire                        m_axi_rlast     , //最后一个数据标志
        input   wire                        m_axi_rvalid    , //读数据有效标志
        output  wire                        m_axi_rready      //主机发出的读数据ready
    );
    
    
    //连线
    //AXI控制器到AXI写主机
    wire                    axi_writing     ;
    wire                    axi_wr_ready    ;
    wire                    axi_wr_start    ;
    wire [AXI_WIDTH-1:0]    axi_wr_data     ;
    // wire [29:0]             axi_wr_addr     ;
   wire [27:0]             axi_wr_addr     ;    
   wire [7:0]              axi_wr_len      ;
   wire                    axi_wr_done     ;
    
    //读AXI主机
   wire                    axi_reading     ;
   wire                    axi_rd_ready    ;
   wire                    axi_rd_start    ;
   wire [AXI_WIDTH-1:0]    axi_rd_data     ;
    // wire [29:0]             axi_rd_addr     ;
   wire [27:0]             axi_rd_addr     ;    
   wire [7:0]              axi_rd_len      ;
   wire                    axi_rd_done     ;
    
    //AXI控制器
    axi_ctrl 
    #(.FIFO_WR_WIDTH(FIFO_WR_WIDTH),  //用户端FIFO读写位宽
      .FIFO_RD_WIDTH(FIFO_RD_WIDTH),
      .AXI_WIDTH    (AXI_WIDTH    )
      )
      axi_ctrl_inst
    (
        .clk             (clk             ), //AXI读写主机时钟
        .rst_n           (rst_n           ), 
 
        .wr_clk          (wr_clk          ), //写FIFO写时钟
        .wr_rst          (wr_rst          ), //写复位
        .wr_beg_addr     (wr_beg_addr     ), //写起始地址
        .wr_end_addr     (wr_end_addr     ), //写终止地址
        .wr_burst_len    (wr_burst_len    ), //写突发长度
        .wr_en           (wr_en           ), //写FIFO写请求
        .wr_data         (wr_data         ), //写FIFO写数据 
        .rd_clk          (rd_clk          ), //读FIFO读时钟
        .rd_rst          (rd_rst          ), //读复位
        .rd_mem_enable   (rd_mem_enable   ), //读存储器使能,防止存储器未写先读
        .rd_beg_addr     (rd_beg_addr     ), //读起始地址
        .rd_end_addr     (rd_end_addr     ), //读终止地址
        .rd_burst_len    (rd_burst_len    ), //读突发长度
        .rd_en           (rd_en           ), //读FIFO读请求
        .rd_data         (rd_data         ), //读FIFO读数据
        .rd_valid        (rd_valid        ), //读FIFO可读标志,表示读FIFO中有数据可以对外输出
        
        //写AXI主机
        .axi_writing     (axi_writing     ), //AXI主机写正在进行
        .axi_wr_ready    (axi_wr_ready    ), //AXI主机写准备好
        .axi_wr_start    (axi_wr_start    ), //AXI主机写请求
        .axi_wr_data     (axi_wr_data     ), //从写FIFO中读取的数据,写入AXI写主机
        .axi_wr_addr     (axi_wr_addr     ), //AXI主机写地址
        .axi_wr_len      (axi_wr_len      ), //AXI主机写突发长度
        .axi_wr_done     (axi_wr_done     ),
        
        //读AXI主机
        .axi_reading     (axi_reading     ), //AXI主机读正在进行
        .axi_rd_ready    (axi_rd_ready    ), //AXI主机读准备好
        .axi_rd_start    (axi_rd_start    ), //AXI主机读请求
        .axi_rd_data     (axi_rd_data     ), //从AXI读主机读到的数据,写入读FIFO
        .axi_rd_addr     (axi_rd_addr     ), //AXI主机读地址
        .axi_rd_len      (axi_rd_len      ), //AXI主机读突发长度   
        .axi_rd_done     (axi_rd_done     )
    );
    
    
    
    
    //AXI读主机
    axi_master_rd 
    #(  .AXI_WIDTH     (AXI_WIDTH     ),  //AXI总线读写数据位宽
        .AXI_AXSIZE    (AXI_AXSIZE    ))   //AXI总线的axi_axsize, 需要与AXI_WIDTH对应    
        axi_master_rd_inst
    (
        //用户端
        .clk              (clk              ),
        .rst_n            (rst_n            ),
        .rd_start         (axi_rd_start     ), //开始读信号
        .rd_addr          (axi_rd_addr      ), //读首地址
        .rd_data          (axi_rd_data      ), //读出的数据
        .rd_len           (axi_rd_len       ), //突发传输长度
        .rd_done          (axi_rd_done      ), //读完成标志
        .rd_ready         (axi_rd_ready     ), //准备好读标志
        .m_axi_r_handshake(axi_reading      ), //读通道成功握手
        
        //AXI4读地址通道
        .m_axi_arid       (m_axi_arid       ), 
        .m_axi_araddr     (m_axi_araddr     ),
        .m_axi_arlen      (m_axi_arlen      ), //突发传输长度
        .m_axi_arsize     (m_axi_arsize     ), //突发传输大小(Byte)
        .m_axi_arburst    (m_axi_arburst    ), //突发类型
        .m_axi_arlock     (m_axi_arlock     ), 
        .m_axi_arcache    (m_axi_arcache    ), 
        .m_axi_arprot     (m_axi_arprot     ),
        .m_axi_arqos      (m_axi_arqos      ),
        .m_axi_arvalid    (m_axi_arvalid    ), //读地址valid
        .m_axi_arready    (m_axi_arready    ), //从机准备接收读地址
                                            
        //读数据通道                        
        .m_axi_rdata      (m_axi_rdata      ), //读数据
        .m_axi_rresp      (m_axi_rresp      ), //收到的读响应
        .m_axi_rlast      (m_axi_rlast      ), //最后一个数据标志
        .m_axi_rvalid     (m_axi_rvalid     ), //读数据有效标志
        .m_axi_rready     (m_axi_rready     )  //主机发出的读数据ready
    );
    
    //AXI写主机
    axi_master_wr 
    #(.AXI_WIDTH     (AXI_WIDTH     ),  //AXI总线读写数据位宽
      .AXI_AXSIZE    (AXI_AXSIZE    ),  //AXI总线的axi_axsize, 需要与AXI_WIDTH对应
      .AXI_WSTRB_W   (AXI_WSTRB_W   ))   //axi_wstrb的位宽, AXI_WIDTH/8
    axi_master_wr_inst(
        //用户端
        .clk              (clk              ),
        .rst_n            (rst_n            ),
        .wr_start         (axi_wr_start     ), //开始写信号
        .wr_addr          (axi_wr_addr      ), //写首地址
        .wr_data          (axi_wr_data      ),
        .wr_len           (axi_wr_len       ), //突发传输长度
        .wr_done          (axi_wr_done      ), //写完成标志
        .m_axi_w_handshake(axi_writing      ), //写通道成功握手
        .wr_ready         (axi_wr_ready     ), //写准备信号,拉高时可以发起wr_start
        
        //AXI4写地址通道
        .m_axi_awid       (m_axi_awid       ), 
        .m_axi_awaddr     (m_axi_awaddr     ),
        .m_axi_awlen      (m_axi_awlen      ), //突发传输长度
        .m_axi_awsize     (m_axi_awsize     ), //突发传输大小(Byte)
        .m_axi_awburst    (m_axi_awburst    ), //突发类型
        .m_axi_awlock     (m_axi_awlock     ), 
        .m_axi_awcache    (m_axi_awcache    ), 
        .m_axi_awprot     (m_axi_awprot     ),
        .m_axi_awqos      (m_axi_awqos      ),
        .m_axi_awvalid    (m_axi_awvalid    ), //写地址valid
        .m_axi_awready    (m_axi_awready    ), //从机发出的写地址ready
                                            
        //写数据通道                        
        .m_axi_wdata      (m_axi_wdata      ), //写数据
        .m_axi_wstrb      (m_axi_wstrb      ), //写数据有效字节线
        .m_axi_wlast      (m_axi_wlast      ), //最后一个数据标志
        .m_axi_wvalid     (m_axi_wvalid     ), //写数据有效标志
        .m_axi_wready     (m_axi_wready     ), //从机发出的写数据ready
                                            
        //写响应通道                        
        .m_axi_bid        (m_axi_bid        ),
        .m_axi_bresp      (m_axi_bresp      ), //响应信号,表征写传输是否成功
        .m_axi_bvalid     (m_axi_bvalid     ), //响应信号valid标志
        .m_axi_bready     (m_axi_bready     )  //主机响应ready信号
    );
endmodule
axi_ddr_ctrl

 以上

//写响应通道
output wire [3:0] m_axi_bid 有误,得修改成input,这里有个bug

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////

// Module Name: axi_ctrl
// Description: AXI控制器, 依据AXI读写主机发来的读写信号, 自动产生AXI读写请求、读写地址以及读写突发长度
//////////////////////////////////////////////////////////////////////////////////

module axi_ctrl
    #(parameter FIFO_WR_WIDTH = 'd32,   //用户端FIFO读写位宽
                FIFO_RD_WIDTH = 'd32,
                AXI_WIDTH     = 'd64
    )
    (
        input   wire                        clk             , //AXI读写主机时钟
        input   wire                        rst_n           , 
                                
        //用户端                   
        input   wire                        wr_clk          , //写FIFO写时钟
        input   wire                        wr_rst          , //写复位,模块中是同步复位
        input   wire [27:0]                 wr_beg_addr     , //写起始地址
        input   wire [27:0]                 wr_end_addr     , //写终止地址
        
        input   wire [7:0]                  wr_burst_len    , //写突发长度
        input   wire                        wr_en           , //写FIFO写请求
        input   wire [FIFO_WR_WIDTH-1:0]    wr_data         , //写FIFO写数据 
        input   wire                        rd_clk          , //读FIFO读时钟
        input   wire                        rd_rst          , //读复位,模块中是同步复位
        input   wire                        rd_mem_enable   , //读存储器使能,防止存储器未写先读
        input   wire [27:0]                 rd_beg_addr     , //读起始地址
        input   wire [27:0]                 rd_end_addr     , //读终止地址
        
        input   wire [7:0]                  rd_burst_len    , //读突发长度
        input   wire                        rd_en           , //读FIFO读请求
        output  wire [FIFO_RD_WIDTH-1:0]    rd_data         , //读FIFO读数据
        output  wire                        rd_valid        , //读FIFO可读标志,表示读FIFO中有数据可以对外输出
        
        //写AXI主机
        input   wire                        axi_writing     , //AXI主机写正在进行
        input   wire                        axi_wr_ready    , //AXI主机写准备好
        output  reg                         axi_wr_start    , //AXI主机写请求
        output  wire [AXI_WIDTH-1:0]        axi_wr_data     , //从写FIFO中读取的数据,写入AXI写主机
        output  reg  [27:0]                 axi_wr_addr     , //AXI主机写地址        
        output  wire [7:0]                  axi_wr_len      , //AXI主机写突发长度
        input   wire                        axi_wr_done     , //AXI主机完成一次写操作
                        
        //读AXI主机                
        input   wire                        axi_reading     , //AXI主机读正在进行
        input   wire                        axi_rd_ready    , //AXI主机读准备好
        output  reg                         axi_rd_start    , //AXI主机读请求
        input   wire [AXI_WIDTH-1:0]        axi_rd_data     , //从AXI读主机读到的数据,写入读FIFO
        output  reg  [27:0]                 axi_rd_addr     , //AXI主机读地址        
        output  wire [7:0]                  axi_rd_len      , //AXI主机读突发长度 
        input   wire                        axi_rd_done       //AXI主机完成一次写操作
        
    );
//            
    //FIFO数据数量计数器   
   wire [10:0]  cnt_rd_fifo_wrport      ;  //读FIFO写端口(对接AXI读主机)数据数量
   wire [9:0]  cnt_wr_fifo_rdport      ;  //写FIFO读端口(对接AXI写主机)数据数量    

   wire        rd_fifo_empty           ;  //读FIFO空标志
   wire        rd_fifo_wr_rst_busy     ;  //读FIFO正在初始化,此时先不向SDRAM发出读取请求, 否则将有数据丢失
            
    //真实的读写突发长度
   wire  [7:0] real_wr_len             ;  //真实的写突发长度,是wr_burst_len+1
  wire  [7:0] real_rd_len             ;  //真实的读突发长度,是rd_burst_len+1
    
    //突发地址增量, 每次进行一次连续突发传输地址的增量, 在外边计算, 方便后续复用
    wire  [27:0]burst_wr_addr_inc       ;
    wire  [27:0]burst_rd_addr_inc       ;    

    //复位信号处理(异步复位同步释放)
    reg     rst_n_sync  ;  //同步释放处理后的rst_n
    reg     rst_n_d1    ;  //同步释放处理rst_n, 同步器第一级输出 

    //读复位同步到clk
    reg     rd_rst_sync ;  //读复位打两拍
    reg     rd_rst_d1   ;  //读复位打一拍
    

    //rst_n相对clk同步释放
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin  //异步复位
            rst_n_d1    <= 1'b0;
            rst_n_sync  <= 1'b0;
        end else begin
            rst_n_d1    <= 1'b1;
            rst_n_sync  <= rst_n_d1;
        end
    end
    
    //读复位同步释放到clk, 作为读fifo的复位输入
    always@(posedge clk or posedge rd_rst) begin
        if(rd_rst) begin
            rd_rst_d1   <= 1'b1;
            rd_rst_sync <= 1'b1;
        end else begin
            rd_rst_d1   <= 1'b0;
            rd_rst_sync <= rd_rst_d1;
        end
    end
    
       
    //真实的读写突发长度
    assign real_wr_len = wr_burst_len + 8'd1;
    assign real_rd_len = rd_burst_len + 8'd1;
    
    //突发地址增量, 右移3的
    assign burst_wr_addr_inc = real_wr_len * AXI_WIDTH >> 3;
    assign burst_rd_addr_inc = real_rd_len * AXI_WIDTH >> 3;
    
    
    //向AXI主机发出的读写突发长度
    assign axi_wr_len = wr_burst_len;
    assign axi_rd_len = rd_burst_len;
    
//
reg [15:0] cnt0;
wire      add_cnt0;
wire      end_cnt0;
always@(posedge clk or negedge rst_n)begin
    if(~rst_n)begin
        cnt0<=0;
    end
    else if(add_cnt0)begin
        if(end_cnt0)
            cnt0<='d21125-1;
        else
            cnt0<=cnt0+1;
    end 
end 
assign add_cnt0 = rd_mem_enable;
assign end_cnt0 = add_cnt0 && cnt0 == 'd21125-1; 
//    
    //AXI读主机开始读标志
    //axi_rd_start
    always@(posedge clk or negedge rst_n_sync) begin
        if(~rst_n_sync) begin
            axi_rd_start <= 1'b0;
        end else if(~axi_rd_ready) begin  //axi_rd_ready低,代表AXI读主机正在进行数据读取, start信号已经被响应
            axi_rd_start <= 1'b0;
        // end else if(rd_mem_enable && cnt_rd_fifo_wrport < 512 && axi_rd_ready && ~rd_fifo_wr_rst_busy) begin 
        end else if(rd_mem_enable && cnt_rd_fifo_wrport < 512 && axi_rd_ready && ~rd_fifo_wr_rst_busy&& ~end_cnt0) begin         
           //读FIFO中的数据存量不足, AXI读主机已经准备好, 且允许读存储器, 读FIFO可以接收数据
            axi_rd_start <= 1'b1;
        end else begin
            axi_rd_start <= axi_rd_start;
        end
    end
    
    //AXI写主机开始写标志
    //axi_wr_start
    always@(posedge clk or negedge rst_n_sync) begin
        if(~rst_n_sync) begin
            axi_wr_start <= 1'b0;
        end else if(~axi_wr_ready) begin  //axi_wr_ready低,代表AXI写主机正在进行数据发送, start信号已经被响应
            axi_wr_start <= 1'b0;
        end else if(cnt_wr_fifo_rdport > real_wr_len && axi_wr_ready) begin 
            //写FIFO中的数据存量足够, AXI写主机已经准备好, 数据不在写FIFO中久留
            axi_wr_start <= 1'b1;
        end else begin
            axi_wr_start <= axi_wr_start;
        end
    end
    
    //AXI写地址,更新地址并判断是否可能超限
    //axi_wr_addr
    always@(posedge clk or negedge rst_n_sync) begin
        if(~rst_n_sync) begin
            axi_wr_addr <= wr_beg_addr;  //初始化为起始地址
        end else if(wr_rst) begin
            axi_wr_addr <= wr_beg_addr;
        // end else if(axi_wr_done && axi_wr_addr > (wr_end_addr - {burst_wr_addr_inc[28:0], 1'b0} + 30'd1)) begin 
        end else if(axi_wr_done && axi_wr_addr > (wr_end_addr - {burst_wr_addr_inc[26:0], 1'b0} + 30'd1)) begin         
        //每次写完成后判断是否超限, 下一个写首地址后续的空间已经不够再进行一次突发写操作, 位拼接的作用是×2
            axi_wr_addr <= wr_beg_addr;
        end else if(axi_wr_done) begin
            axi_wr_addr <= axi_wr_addr + burst_wr_addr_inc;  //增加一个burst_len的地址
        end else begin
            axi_wr_addr <= axi_wr_addr;
        end
    end
    
    //AXI读地址
    //axi_rd_addr
    always@(posedge clk or negedge rst_n_sync) begin
        if(~rst_n_sync) begin
            axi_rd_addr <= rd_beg_addr;  //初始化为起始地址
        end else if(rd_rst) begin
            axi_rd_addr <= rd_beg_addr;  //人工读复位时
        // end else if(axi_rd_done && axi_rd_addr > (rd_end_addr - {burst_rd_addr_inc[28:0], 1'b0} + 30'd1)) begin 
        end else if(axi_rd_done && axi_rd_addr > (rd_end_addr - {burst_rd_addr_inc[26:0], 1'b0} + 30'd1)) begin         
        //每次写完成后判断是否超限, 下一个写首地址后续的空间已经不够再进行一次突发写操作, 位拼接的作用是×2
            axi_rd_addr <= rd_beg_addr;
        end else if(axi_rd_done) begin
            axi_rd_addr <= axi_rd_addr + burst_rd_addr_inc;  //增加一个burst_len的地址
        end else begin
            axi_rd_addr <= axi_rd_addr;
        end
    end
   
    //读FIFO, 从SDRAM中读出的数据先暂存于此
    //使用FIFO IP核
    rd_fifo rd_fifo_inst (
        .rst                (~rst_n_sync | rd_rst_sync  ),  //读复位时需要复位读FIFO
        .wr_clk             (clk                        ),  //写端口时钟是AXI主机时钟, 从axi_master_rd模块写入数据
        .rd_clk             (rd_clk                     ),  //读端口时钟
        .din                (axi_rd_data                ),  //从axi_master_rd模块写入数据
        .wr_en              (axi_reading                ),  //axi_master_rd正在读时,FIFO也在写入
        .rd_en              (rd_en                      ),  //读FIFO读使能     //.rd_en  (rd_en  ),
        .dout               (rd_data                    ),  //读FIFO读取的数据
        .full               (                           ),  
        .almost_full        (                           ),  
        .empty              (rd_fifo_empty              ),  
        .almost_empty       (                           ),  
        .rd_data_count      (                           ),  
        .wr_data_count      (cnt_rd_fifo_wrport         ),  //读FIFO写端口(对接AXI读主机)数据数量
        .wr_rst_busy        (rd_fifo_wr_rst_busy        ),     
        .rd_rst_busy        (                           )      
);

    //写FIFO, 待写入SDRAM的数据先暂存于此
    //使用FIFO IP核
    wr_fifo wr_fifo_inst (
        .rst                (~rst_n_sync        ),  
        .wr_clk             (wr_clk             ),  //写端口时钟
        .rd_clk             (clk                ),  //读端口时钟是AXI主机时钟, AXI写主机读取数据
        .din                (wr_data            ),  
        .wr_en              (wr_en              ),  
        .rd_en              (axi_writing        ),  //axi_master_wr正在写时,从写FIFO中不断读出数据
        .dout               (axi_wr_data        ),  //读出的数据作为AXI写主机的输入数据
        .full               (                   ),  
        .almost_full        (                   ),  
        .empty              (                   ),  
        .almost_empty       (                   ),  
        .rd_data_count      (cnt_wr_fifo_rdport ),  //写FIFO读端口(对接AXI写主机)数据数量
        .wr_data_count      (                   ),  
        .wr_rst_busy        (                   ),  
        .rd_rst_busy        (                   )   
    );

    assign rd_valid = ~rd_fifo_empty;
    
endmodule

/*  reg         axi_wr_start_d          ;  //axi_wr_start打一拍,用于上升沿提取
    reg         axi_rd_start_d          ;  //axi_rd_start打一拍,用于上升沿提取
    wire        axi_wr_start_raise      ;  //axi_wr_start上升沿
    wire        axi_rd_start_raise      ;  //axi_rd_start上升沿 */

/*     //axi_wr_start打拍
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            axi_wr_start_d <= 1'b0;
        end else begin
            axi_wr_start_d <= axi_wr_start;
        end
    end */
    
/*     //axi_rd_start打拍
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            axi_rd_start_d <= 1'b0;
        end else begin
            axi_rd_start_d <= axi_rd_start;
        end
    end */
   
    
/*     //axi_wr_start上升沿提取
    assign axi_wr_start_raise = (~axi_wr_start_d) & axi_wr_start;
    
    //axi_rd_start上升沿提取
    assign axi_rd_start_raise = (~axi_rd_start_d) & axi_rd_start; */
    
/*     //rd_fifo_wr_en
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            rd_fifo_wr_en <= 1'b0;
        end else begin
            rd_fifo_wr_en <= axi_reading;
        end
    end */

/*     //AXI写突发长度
    //axi_wr_len 
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            axi_wr_len <= wr_burst_len; //axi_wr_len初始化
        end else if(wr_rst) begin
            axi_wr_len <= wr_burst_len;
        end else if(axi_wr_start_raise) begin 
            //在上升沿到来时判断写地址是否超限, 若是, 则将axi_wr_len减小, 使地址恰可达wr_end_addr
            //注意地址是按照字节寻址的,而每次burst将传输8Byte
            if((axi_wr_addr + {real_wr_len[4:0],3'b0}) > wr_end_addr) begin //超限, 位拼接的作用是×8
            //axi_wr_len设置为剩下的空间大小, 位拼接的作用是÷8, 减去1是由于AXI总线定义的burst_len = 真实burst_len - 1
                axi_wr_len <= {3'b0, wr_addr_margin[7:3]} - 8'd1; 
            end else begin
                axi_wr_len <= wr_burst_len;  //未超限,则保持标准的wr_burst_len
            end
        end else begin
            axi_wr_len <= axi_wr_len;
        end
    end */

    //AXI读突发长度
    //axi_rd_len 
/*     always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            axi_rd_len <= rd_burst_len; //axi_rd_len初始化
        end else if(rd_rst) begin
            axi_rd_len <= rd_burst_len;
        end else if(axi_rd_start_raise) begin 
            //在上升沿到来时判断写地址是否超限, 若是, 则将axi_rd_len减小, 使地址恰可达rd_end_addr
            if((axi_rd_addr + {real_rd_len[4:0],3'b0}) > rd_end_addr) begin //超限, 位拼接的作用是×8
            //设置为剩下的空间大小, 位拼接的作用是÷8, 减去1是由于AXI总线定义的burst_len = 真实burst_len - 1
                axi_rd_len <= {3'b0, rd_addr_margin[7:3]} - 8'd1; 
            end else begin
                axi_rd_len <= rd_burst_len;  //未超限,则保持标准的wr_burst_len
            end
        end else begin
            axi_rd_len <= axi_rd_len;
        end
    end    */ 


/*     //读FIFO, 从SDRAM中读出的数据先暂存于此
    //使用自行编写的异步FIFO模块
    async_fifo
    #(.RAM_DEPTH       ('d2048          ), //内部RAM存储器深度
      .RAM_ADDR_WIDTH  ('d11            ), //内部RAM读写地址宽度, 需与RAM_DEPTH匹配
      .WR_WIDTH        (AXI_WIDTH       ), //写数据位宽
      .RD_WIDTH        (FIFO_RD_WIDTH   ), //读数据位宽
      .WR_IND          ('d2             ), //单次写操作访问的ram_mem单元个数
      .RD_IND          ('d1             ), //单次读操作访问的ram_mem单元个数         
      .RAM_WIDTH       (FIFO_RD_WIDTH   ), //读端口数据位宽更小,使用读数据位宽作为RAM存储器的位宽
      .WR_CNT_WIDTH    ('d11            ), //FIFO写端口计数器的位宽
      .RD_CNT_WIDTH    ('d12            ), //FIFO读端口计数器的位宽
      .WR_L2           ('d1             ), //log2(WR_IND), 决定写地址有效数据位个数及RAM位宽
      .RD_L2           ('d0             ), //log2(RD_IND), 决定读地址有效低位
      .RAM_RD2WR       ('d1             )  //读数据位宽和写数据位宽的比, 即一次读取的RAM单元深度, RAM_RD2WR = RD_WIDTH/WR_WIDTH, 当读位宽小于等于写位宽时, 值为1     
                )
    rd_fifo_inst
    (
            //写相关
            .wr_clk          (clk                        ),  //写端口时钟是AXI主机时钟, 从axi_master_rd模块写入数据
            .wr_rst_n        (rst_n_sync & ~rd_rst_sync  ),  //读复位时需要复位读FIFO
            .wr_en           (axi_reading                ),  //axi_master_rd正在读时,FIFO也在写入
            .wr_data         (axi_rd_data                ),  //从axi_master_rd模块写入数据
            .fifo_full       (                           ),  //FIFO写满
            .wr_data_count   (cnt_rd_fifo_wrport         ),  //读FIFO写端口(对接AXI读主机)数据数量
            //读相关
            .rd_clk          (rd_clk                     ),  //读端口时钟
            .rd_rst_n        (rst_n_sync & ~rd_rst_sync  ),  //读复位时需要复位读FIFO 
            .rd_en           (rd_en                      ),  //读FIFO读使能
            .rd_data         (rd_data                    ),  //读FIFO读取的数据
            .fifo_empty      (rd_fifo_empty              ),  //FIFO读空
            .rd_data_count   (                           )   //读端口数据个数,按读端口数据位宽计算
    );
    //自定义FIFO没有复位busy信号
    assign rd_fifo_wr_rst_busy = 1'b0;
    
    //写FIFO, 待写入SDRAM的数据先暂存于此
    //使用自定义异步FIFO
    async_fifo
    #(.RAM_DEPTH       ('d2048       ), //内部RAM存储器深度
      .RAM_ADDR_WIDTH  ('d11         ), //内部RAM读写地址宽度, 需与RAM_DEPTH匹配
      .WR_WIDTH        (FIFO_WR_WIDTH), //写数据位宽
      .RD_WIDTH        (AXI_WIDTH    ), //读数据位宽
      .WR_IND          ('d1          ), //单次写操作访问的ram_mem单元个数
      .RD_IND          ('d2          ), //单次读操作访问的ram_mem单元个数         
      .RAM_WIDTH       (FIFO_WR_WIDTH), //RAM单元的位宽
      .WR_L2           ('d0          ), //log2(WR_IND), 决定写地址有效数据位个数及RAM位宽
      .RD_L2           ('d1          ), //log2(RD_IND), 决定读地址有效低位
      .WR_CNT_WIDTH    ('d12         ), //FIFO写端口计数器的位宽RAM_ADDR_WIDTH + 'd1 - WR_L2
      .RD_CNT_WIDTH    ('d11         ), //FIFO读端口计数器的位宽RAM_ADDR_WIDTH + 'd1 - RD_L2  
      .RAM_RD2WR       ('d2          )  //读数据位宽和写数据位宽的比, 即一次读取的RAM单元深度, RAM_RD2WR = RD_WIDTH/WR_WIDTH, 当读位宽小于等于写位宽时, 值为1            
    )
    wr_fifo_inst
    (
        //写相关
        .wr_clk          (wr_clk             ), //写端口时钟
        .wr_rst_n        (rst_n_sync         ),
        .wr_en           (wr_en              ),
        .wr_data         (wr_data            ),
        .fifo_full       (                   ), //FIFO写满
        .wr_data_count   (                   ), //写端口数据个数,按写端口数据位宽计算
        //读相关
        .rd_clk          (clk                ), //读端口时钟是AXI主机时钟, AXI写主机读取数据
        .rd_rst_n        (rst_n_sync         ), 
        .rd_en           (axi_writing        ), //axi_master_wr正在写时,从写FIFO中不断读出数据
        .rd_data         (axi_wr_data        ), //读出的数据作为AXI写主机的输入数据
        .fifo_empty      (                   ), //FIFO读空
        .rd_data_count   (cnt_wr_fifo_rdport )  //写FIFO读端口(对接AXI写主机)数据数量
    );     */
    
    //读FIFO可读标志,表示读FIFO中有数据可以对外输出
    
    
    
    // ila_0 ila_0_uut (
    // .clk(clk), // input wire clk

    // .probe0(axi_writing  ), // input wire [0:0]  probe0  
    // .probe1(axi_wr_ready ), // input wire [0:0]  probe1 
    // .probe2(axi_wr_start ), // input wire [0:0]  probe2 
    // .probe3(axi_wr_data  ), // input wire [63:0]  probe3 
    // .probe4(axi_wr_addr ), // input wire [27:0]  probe4 
    // .probe5(axi_wr_len  ), // input wire [7:0]  probe5 
    // .probe6(axi_wr_done ), // input wire [0:0]  probe6 
    // .probe7 (axi_reading  ), // input wire [0:0]  probe7 
    // .probe8 (axi_rd_ready ), // input wire [0:0]  probe8 
    // .probe9 (axi_rd_start ), // input wire [0:0]  probe9 
    // .probe10(axi_rd_data  ), // input wire [63:0]  probe10 
    // .probe11(axi_rd_addr ), // input wire [27:0]  probe11 
    // .probe12(axi_rd_len  ), // input wire [7:0]  probe12 
    // .probe13(axi_rd_done ) // input wire [0:0]  probe13
// );
axi_ctrl

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////

// Module Name: axi_master_wr
// Description: AIX4接口主机写模块,包含AXI4总线Master端的写数据通道、写地址通道和写响应通道
//////////////////////////////////////////////////////////////////////////////////

// (*mark_debug="true", dont_touch="true"*)
module axi_master_wr
#(parameter     AXI_WIDTH     = 'd64            ,  //AXI总线读写数据位宽
                AXI_AXSIZE    = 3'b011          ,  //AXI总线的axi_axsize, 需要与AXI_WIDTH对应
                AXI_WSTRB_W   = AXI_WIDTH>>3    )  //axi_wstrb的位宽, AXI_WIDTH/8                              
(
        //用户端
        input   wire                    clk              ,
        input   wire                    rst_n            ,
        input   wire                    wr_start         , //开始写信号
        // input   wire [29:0]             wr_addr          , //写首地址
        input   wire [27:0]             wr_addr          , //写首地址        
        input   wire [AXI_WIDTH-1:0]    wr_data          ,
        input   wire [7:0]              wr_len           , //突发传输长度
        output  reg                     wr_done          , //写完成标志
        output  wire                    m_axi_w_handshake, //写通道成功握手
        output  wire                    wr_ready         , //写准备信号,拉高时可以发起wr_start
        
        //AXI4写地址通道
        output  wire [3:0]              m_axi_awid      , 
        // output  reg  [29:0]             m_axi_awaddr    ,
        output  reg  [27:0]             m_axi_awaddr    ,        
        output  reg  [7:0]              m_axi_awlen     , //突发传输长度
        output  wire [2:0]              m_axi_awsize    , //突发传输大小(Byte)
        output  wire [1:0]              m_axi_awburst   , //突发类型
        output  wire                    m_axi_awlock    , 
        output  wire [3:0]              m_axi_awcache   , 
        output  wire [2:0]              m_axi_awprot    ,
        output  wire [3:0]              m_axi_awqos     ,
        output  reg                     m_axi_awvalid   , //写地址valid
        input   wire                    m_axi_awready   , //从机发出的写地址ready
        
        //写数据通道
        output  wire [AXI_WIDTH-1:0]    m_axi_wdata     , //写数据
        output  wire [AXI_WSTRB_W-1:0]  m_axi_wstrb     , //写数据有效字节线
        output  reg                     m_axi_wlast     , //最后一个数据标志
        output  reg                     m_axi_wvalid    , //写数据有效标志
        input   wire                    m_axi_wready    , //从机发出的写数据ready
        
        //写响应通道
        input   wire [3:0]              m_axi_bid       ,
        input   wire [1:0]              m_axi_bresp     , //响应信号,表征写传输是否成功
        input   wire                    m_axi_bvalid    , //响应信号valid标志
        output  reg                     m_axi_bready      //主机响应ready信号
    );
    
    //写数据相关参数定义
    parameter   M_AXI_AWID      =  4'd0         ,
                M_AXI_AWSIZE    =  AXI_AXSIZE   , 
                M_AXI_AWBURST   =  2'b10        , //突发类型, INCR
                M_AXI_AWLOCK    =  1'b0         , //不锁定
                M_AXI_AWCACHE   =  4'b0010      , //存储器类型, 选择Normal Non-cacheable Non-bufferable
                M_AXI_AWPROT    =  3'b0         ,
                M_AXI_AWQOS     =  4'b0         ,
                M_AXI_WSTRB     =  'hff         ;
                
 
                
                
    
    
    //状态机状态定义
    parameter   IDLE    =   3'b000,  //空闲状态
                WA_WAIT =   3'b001,  //等待写地址
                WA      =   3'b010,  //写地址有效
                W_WAIT  =   3'b011,  //等待写数据
                W       =   3'b100,  //写数据有效
                B_WAIT  =   3'b101,  //等待写响应
                B       =   3'b110;  //准备接收写响应
                
    //状态机变量
   reg [2:0]   state       ;
   reg [2:0]   next_state  ;
    
    //握手成功标志
   wire        m_axi_aw_handshake;  //写地址通道握手成功
   wire        m_axi_b_handshake;   //写响应通道握手成功
    
    //中间辅助变量
  reg [7:0]   cnt_w_burst     ;    //突发次数计数器,用于辅助生成m_axi_wlast信号
    
    //握手成功标志
    assign      m_axi_aw_handshake  = m_axi_awready & m_axi_awvalid ;
    assign      m_axi_w_handshake   = m_axi_wready  & m_axi_wvalid  ;
    assign      m_axi_b_handshake   = m_axi_bready  & m_axi_bvalid  ;   
    
    
    //写参数赋值
    assign  m_axi_awid    = M_AXI_AWID      ;
    assign  m_axi_awsize  = M_AXI_AWSIZE    ;
    assign  m_axi_awburst = M_AXI_AWBURST   ;
    assign  m_axi_awlock  = M_AXI_AWLOCK    ;
    assign  m_axi_awcache = M_AXI_AWCACHE   ;
    assign  m_axi_awprot  = M_AXI_AWPROT    ;
    assign  m_axi_awqos   = M_AXI_AWQOS     ;
    assign  m_axi_wstrb   = M_AXI_WSTRB     ;
    
    //状态转移
    //state
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            state <= IDLE;
        end else begin
            state <= next_state;
        end
    end
    
    //次态
    //next_state
    always@(*) begin
        case(state) 
            IDLE: begin
                if(wr_start) begin
                    next_state = WA_WAIT;
                end else begin
                    next_state = IDLE;
                end
            end
            
            WA_WAIT: begin
                next_state = WA;
            end
            
            WA: begin
                if(m_axi_aw_handshake) begin //写地址通道握手成功
                    next_state = W_WAIT;
                end else begin
                    next_state = WA;
                end
            end
            
            W_WAIT: begin
                next_state = W;
            end
            
            W: begin
                if(m_axi_w_handshake && m_axi_wlast) begin //写数据通道握手成功, 且已经是突发传输的最后一个数据
                    next_state = B_WAIT;
                end else begin
                    next_state = W;
                end
            end
            
            B_WAIT: begin
                next_state = B;
            end
            
            B: begin
                if(m_axi_b_handshake) begin  //写响应通道握手成功
                    next_state = IDLE;
                end else begin
                    next_state = B;
                end
            end
            
            default: begin
                next_state = IDLE;
            end
        endcase
    end
    
    //写地址通道valid
    //m_axi_awvalid
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            m_axi_awvalid <= 1'b0;
        end else if(state == WA_WAIT) begin //在WA_WAIT状态的下一个时钟周期拉高m_axi_awvalid
            m_axi_awvalid <= 1'b1;
        end else if(m_axi_aw_handshake) begin //写地址通道握手成功,拉低valid信号
            m_axi_awvalid <= 1'b0;
        end else begin
            m_axi_awvalid <= m_axi_awvalid;
        end
    end
    
    //写地址通道地址、突发长度
    //m_axi_awaddr
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            m_axi_awaddr <= 30'b0;
            m_axi_awlen  <= 8'd0;
        end else if(state == WA_WAIT) begin //在WA_WAIT状态的下一个时钟周期更新地址和突发长度
            m_axi_awaddr <= wr_addr;
            m_axi_awlen  <= wr_len;
        end else begin
            m_axi_awaddr <= m_axi_awaddr;
            m_axi_awlen  <= m_axi_awlen;
        end
    end
    
    
    //突发次数计数器
    //cnt_w_burst
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            cnt_w_burst <= 8'd0;
        end else if(state == W_WAIT) begin //在W_WAIT状态的下一个时钟周期清零
            cnt_w_burst <= 8'd0;
        end else if(state == W && m_axi_w_handshake && cnt_w_burst < wr_len) begin //每握手成功一次,更新一次计数值,直到wr_len
            cnt_w_burst <= cnt_w_burst + 8'd1;
        end else begin
            cnt_w_burst <= cnt_w_burst;
        end
    end
    
    //最后一次突发标志
    //m_axi_wlast
    always@(*) begin
        if((cnt_w_burst == m_axi_awlen) && m_axi_w_handshake && (state == W)) begin //最后一个有效数据
            m_axi_wlast = 1'b1;
        end else begin
            m_axi_wlast = 1'b0;
        end
    end
    
    
    //写通道valid
    //m_axi_wvalid
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            m_axi_wvalid <= 1'b0;
        end else if(state == W_WAIT) begin
            m_axi_wvalid <= 1'b1;
        end else if(state == W && m_axi_w_handshake && m_axi_wlast) begin //写通道握手成功且是最后一个数据
            m_axi_wvalid <= 1'b0;
        end else begin
            m_axi_wvalid <= m_axi_wvalid;
        end
    end
    
    //写通道数据
    //m_axi_wdata
    assign m_axi_wdata = wr_data;
    
    //写响应通道ready
    //m_axi_bready
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            m_axi_bready <= 1'b0;
        end else if(state == B_WAIT) begin  //在B_WAIT的下一个状态拉高bready信号,准备接收从机发来的响应
            m_axi_bready <= 1'b1;
        end else if(state == B && m_axi_b_handshake) begin //响应通道握手成功后拉低
            m_axi_bready <= 1'b0;
        end else begin
            m_axi_bready <= m_axi_bready;
        end
    end
    
    //写完成标志
    //wr_done
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            wr_done <= 1'b0;
        end else if(m_axi_b_handshake && state == B) begin //在B状态下成功握手,代表一次突发传输已经完成
            wr_done <= 1'b1;
        end else begin
            wr_done <= 1'b0;
        end
    end
    
    //wr_ready
    assign wr_ready = (state == IDLE)?1'b1:1'b0;  //在IDLE状态下准备好写
        
endmodule
axi_master_wr

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////

// Module Name: axi_master_rd 
// Description: AXI4接口的主机读模块,完成读数据通道和读地址通道的功能
//////////////////////////////////////////////////////////////////////////////////


module axi_master_rd
#(parameter     AXI_WIDTH     = 'd64    ,  //AXI总线读写数据位宽
                AXI_AXSIZE    = 3'b011   )  //AXI总线的axi_axsize, 需要与AXI_WIDTH对应
(
        //用户端
        input   wire                    clk              ,
        input   wire                    rst_n            ,
        input   wire                    rd_start         , //开始读信号
        input   wire [27:0]             rd_addr          , //读首地址        
        output  wire [AXI_WIDTH-1:0]    rd_data          , //读出的数据
        input   wire [7:0]              rd_len           , //突发传输长度
        output  reg                     rd_done          , //读完成标志
        output  wire                    rd_ready         , //准备好读标志
        output  wire                    m_axi_r_handshake, //读通道成功握手
        
        //AXI4读地址通道
        output  wire [3:0]              m_axi_arid      , 
        output  reg  [27:0]             m_axi_araddr    ,        
        output  reg  [7:0]              m_axi_arlen     , //突发传输长度
        output  wire [2:0]              m_axi_arsize    , //突发传输大小(Byte)
        output  wire [1:0]              m_axi_arburst   , //突发类型
        output  wire                    m_axi_arlock    , 
        output  wire [3:0]              m_axi_arcache   , 
        output  wire [2:0]              m_axi_arprot    ,
        output  wire [3:0]              m_axi_arqos     ,
        output  reg                     m_axi_arvalid   , //读地址valid
        input   wire                    m_axi_arready   , //从机准备接收读地址
        
        //读数据通道
        input   wire [AXI_WIDTH-1:0]    m_axi_rdata     , //读数据
        input   wire [1:0]              m_axi_rresp     , //收到的读响应
        input   wire                    m_axi_rlast     , //最后一个数据标志
        input   wire                    m_axi_rvalid    , //读数据有效标志
        output  reg                     m_axi_rready      //主机发出的读数据ready
    );
    
    //读数据相关参数定义
    parameter   M_AXI_ARID      =  4'd0         ,
                M_AXI_ARSIZE    =  AXI_AXSIZE   , 
                M_AXI_ARBURST   =  2'b10        , //突发类型, INCR
                M_AXI_ARLOCK    =  1'b0         , //不锁定
                M_AXI_ARCACHE   =  4'b0010      , //存储器类型, 选择Normal Non-cacheable Non-bufferable
                M_AXI_ARPROT    =  3'b0         ,
                M_AXI_ARQOS     =  4'b0         ;   
    
    //状态机状态定义
    parameter   IDLE    =   3'b000,  //空闲状态
                RA_WAIT =   3'b001,  //等待读地址
                RA      =   3'b010,  //读地址有效
                R_WAIT  =   3'b011,  //等待读数据
                R       =   3'b100;  //读数据有效
    
    //状态机变量
reg [2:0]   state       ;
reg [2:0]   next_state  ;
    
    //握手成功标志
wire        m_axi_ar_handshake;  //读地址通道握手成功
    
    assign      m_axi_ar_handshake = m_axi_arready & m_axi_arvalid;
    assign      m_axi_r_handshake  = m_axi_rready & m_axi_rvalid;
    
    
    //读参数赋值
    assign  m_axi_arid    = M_AXI_ARID      ;
    assign  m_axi_arsize  = M_AXI_ARSIZE    ;
    assign  m_axi_arburst = M_AXI_ARBURST   ;
    assign  m_axi_arlock  = M_AXI_ARLOCK    ;
    assign  m_axi_arcache = M_AXI_ARCACHE   ;
    assign  m_axi_arprot  = M_AXI_ARPROT    ;
    assign  m_axi_arqos   = M_AXI_ARQOS     ;
    
    //状态转移
    //state
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            state <= IDLE;
        end else begin
            state <= next_state;
        end
    end

    //次态
    //next_state
    always@(*) begin
        case(state) 
            IDLE: begin  //准备接收读开始信号(rd_start)
                if(rd_start) begin
                    next_state = RA_WAIT; //接收到rd_start有效
                end else begin
                    next_state = IDLE;
                end
            end
            
            RA_WAIT: begin
                next_state = RA;
            end
            
            RA: begin
                if(m_axi_ar_handshake) begin //读地址通道握手成功
                    next_state = R_WAIT;
                end else begin
                    next_state = RA;
                end
            end
            
            R_WAIT: begin
                next_state = R;
            end
            
            R: begin
                if(m_axi_r_handshake && m_axi_rlast) begin  //读通道握手成功,且是最后一个突发数据
                    next_state = IDLE;
                end else begin
                    next_state = R;
                end
            end
            
            default: begin
                next_state = IDLE;
            end
        endcase
    end
    
    //读地址通道valid
    //m_axi_arvalid
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            m_axi_arvalid <= 1'b0;
        end else if(state == RA_WAIT) begin
            m_axi_arvalid <= 1'b1;
        end else if(state == RA && m_axi_ar_handshake) begin  //写地址通道握手成功
            m_axi_arvalid <= 1'b0;
        end else begin
            m_axi_arvalid <= m_axi_arvalid;
        end
    end
    
    //读地址通道地址以及突发长度
    //m_axi_arlen / m_axi_araddr
    always@(posedge clk or negedge rst_n) begin 
        if(~rst_n) begin
            m_axi_arlen <= 8'd0;
            m_axi_araddr<= 30'd0;
        end else if(state == RA_WAIT) begin //在RA_WAIT的下一个时钟周期拉高了arvalid信号, 同时更新AXI总线地址和len
            m_axi_arlen <= rd_len;
            m_axi_araddr<= rd_addr;
        end else begin
            m_axi_arlen <= m_axi_arlen;
            m_axi_araddr<= m_axi_araddr;
        end
    end
    
    //读数据通道ready
    //m_axi_rready
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            m_axi_rready <= 1'b0;
        end else if(state == R_WAIT) begin
            m_axi_rready <= 1'b1;
        end else if(state == R && m_axi_rlast && m_axi_r_handshake) begin //读数据通道握手成功,且是最后一个数据
            m_axi_rready <= 1'b0;
        end else begin
            m_axi_rready <= m_axi_rready;
        end
    end
    
    //rd_ready
    assign rd_ready = (state == IDLE)?1'b1:1'b0;  //在IDLE状态下准备好接收读请求
    
    //rd_done
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            rd_done <= 1'b0;
        end else if(state == R && m_axi_rlast && m_axi_r_handshake) begin //读数据通道握手成功,且是最后一个数据
            rd_done <= 1'b1;
        end else begin
            rd_done <= 1'b0;
        end
    end
       
    //rd_data 
    //读通道握手成功时,为有效数据输出
    assign rd_data = (m_axi_r_handshake)?m_axi_rdata:'d0;
    

endmodule
axi_master_rd

 

参考:

https://github.com/taylorrrrrrrr/FPGA_DDR3_Ctrl/blob/master/rtl/ddr3_test.v

posted on 2025-08-24 10:13  taylorrrrrrrrrr  阅读(28)  评论(0)    收藏  举报