FPGA_DDR3_Ctrl/rtl /ddr3_test.v
突发写时序#
写数据时序图如下。

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

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 相连接。

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] );
`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
///////////////////////// //例化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 ) );
`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
`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
`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总线
//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


`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

`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

`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

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

由于是并联的,所以两片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会自动帮我们计算,当然我们也可以手动验算

3.引脚分配,由于两片DDR的地址线共享,数据分开存放,所以两片DDR的dm(数据选通)、dqs(数据同步)、dq(数据总线)信号位宽为单片的两倍,而地址线(addr)位宽相同。
基于以上三点,在实际的代码设计中,就需要根据使用的是单片/双片DDR来调整dm、dqs、dq的信号位宽,以及与mig交互的AXI接口中,araddr、awaddr信号的位宽。
最后是仿真例化,ddr3的仿真模型可以通过mig的例程获取,仿真模型对应单片DDR,因此,在双片DDR的仿真中,我们需要例化两个ddr3_model,然后对dm(数据选通)、dqs(数据同步)、dq(数据总线)信号分别作控制,如下:

参考:
https://www.corecourse.cn/forum.php?mod=viewthread&tid=29677
Xilinx官方为我们提供了ddr3仿真的方法,可以更方便的进行程序的调试。
1、右击刚设置好的ip核

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

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


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

5、这里不用运行仿真,只需要取两个我们需要的文件加入我们自己的工程目录。
按照刚才存放工程的位置找到这两个文件

6、直接加入

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

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

官方已经给出了例化模型
用下面的方法将ddr3例化至仿真文件,因为使用的是两片ddr3所以需要例化两个模型,类似于真正绑定IO口的感觉。
感兴趣的可以看一下上面两个文件,就可以知道为什么必须例化两个,我写程序时仿真后ddr3一直初始化不成功就是因为没有认识到ddr3_modle.sv的真正含义。
附上官方解释。

原文链接: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
`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初始化完成
`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
`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 ); */
`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
以上
//写响应通道
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 // );
`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
`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
参考:
https://github.com/taylorrrrrrrr/FPGA_DDR3_Ctrl/blob/master/rtl/ddr3_test.v
posted on 2025-08-24 10:13 taylorrrrrrrrrr 阅读(28) 评论(0) 收藏 举报
浙公网安备 33010602011771号