当前位置:   article > 正文

Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(一)_ad9238以太网

ad9238以太网

 Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(前导)

Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(二)

Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(三)


  四、AXI转FIFO接口模块设计

1.AXI接口知识

AXI协议是基于 burst的传输,并且定义了以下 5 个独立的传输通道:

  • 读地址通道(Read Address Channel, AR)
  • 读数据通道(Read Data Channel, R)
  • 写地址通道(Write Address Channel, AW)
  • 写数据通道(Write Data Channel, W)
  • 写响应通道(Write Response Channel, B)

  • 这 5 条独立的通道都包含一个双路的 VALD、 READY 握手机制。信息源通过 VALID 信号来指示通道中的数据和控制信息什么时候有效。目地源用READY 信号来表示何时准备好接收数据。传输地址信息和数据都是在 VALID和 READY 同时为高时有效。
  • 读数据和写数据通道都包括一个 LAST 信号,用来指明一个事物传输的最后一个数据
  • 读/写事务都有自己的地址通道,地址通道携带着传输事务所必需的地址和控制信息
  • 读数据通道传送着从设备到主机的读数据和读响应信息。读响应信息指明读事务的完成状态
  • 写数据通路传送着主机向从设备的写数据。写响应通道提供了设备响应写事务的一种方式。在每一次突发式写会产生一个完成信号

写事务时序

读事务时序

AXI 协议支持乱序传输。每一个通过接口的事务有一个 IDtag。协议要求相同 ID tag 的事务必须有序完成,而不同 ID tag 可以乱序完成


1.1写地址通道信号

1.2写数据通道信号

1.3写响应通道信号

1.4读地址通道信号

1.5读数据通道信号

2.ZynqAXI接口

红绿蓝三种颜色的箭头代表了几种不同位宽的 AXI 总线。 红色线条框是 PL 端访问 DDR控制器的路径,其中, High Performamce AXI 32/64b Slave Ports 便是我们所说的HP 接口, 该接口为 AXI 接口,通常用于大量数据的高速传输。

PS 端通过硬件电路实现 AXI 总线,而 PL 端则需要用户通过逻辑资源搭建 AXI 总线

3.AXI转换模块设计(fifo_axi4_adapter)

目的:为了解决上下游模块常常处于不同时钟域的问题。

fifo_axi4_adapter 负责FIFO接口到AXI4接口的转换,FIFO中的数据可以通过该模块写入PS端,PS端的数据也可以由该模块接收写入FIFO。通过这种方式,用户只需要操作FIFO,就能实现PL端数据对PS端DDR的读写。

wr_ddr3_fifo rd_ddr3_fifo 为上文中我们提到的读写 FIFO,用于存储读写数据,同时解决时钟域等问题。fifo2axi4 为 AXI4 接口转换模块,负责fifo 与 axi4 接口间的转换, 将写侧 FIFO 里的数据读出然后存储在 DDR 存储器以及将 DDR 存储器读出的数据存放到读侧 FIFO 缓存。

3.1接口转换模块设计(fifo2axi4)

写流程:主机向写地址通道写入地址和控制信息→写数据通道突发写入数据→收到设备的写数据响应。

读流程:主机向读地址通道写入地址和控制信息→ 收到设备的读数据响应和读的数据。

根据时序进行状态机设计:

  1. //写信号状态机
  2. always@(posedge clk or posedge reset)
  3. begin
  4. if(reset)
  5. curr_wr_state <= S_IDLE;
  6. else
  7. curr_wr_state <= next_wr_state;
  8. end
  9. always@(*)
  10. begin
  11. case(curr_wr_state)
  12. S_IDLE:
  13. begin
  14. if(wr_ddr3_req == 1'b1)
  15. next_wr_state = S_WR_ADDR;
  16. else
  17. next_wr_state = S_IDLE;
  18. end
  19. S_WR_ADDR:
  20. begin
  21. if(m_axi_awready && m_axi_awvalid)
  22. next_wr_state = S_WR_DATA;
  23. else
  24. next_wr_state = S_WR_ADDR;
  25. end
  26. S_WR_DATA:
  27. begin
  28. if(m_axi_wready && m_axi_wvalid && m_axi_wlast)
  29. next_wr_state = S_WR_RESP;
  30. else
  31. next_wr_state = S_WR_DATA;
  32. end
  33. S_WR_RESP:
  34. begin
  35. if(m_axi_bready && m_axi_bvalid && (m_axi_bresp == 2'b00) &&(m_axi_bid == AXI_ID[AXI_ID_WIDTH-1:0]))
  36. next_wr_state = S_IDLE;
  37. else
  38. next_wr_state = S_WR_RESP;
  39. end
  40. endcase
  41. end
  42. //awaddr信号
  43. always@(posedge clk or posedge reset)
  44. begin
  45. if(reset)
  46. m_axi_awaddr <= WR_AXI_BYTE_ADDR_BEGIN;
  47. else if(wr_addr_clr || axi_awaddr_clr)
  48. m_axi_awaddr <= WR_AXI_BYTE_ADDR_BEGIN;
  49. else if(m_axi_awaddr >= WR_AXI_BYTE_ADDR_END)
  50. m_axi_awaddr <= WR_AXI_BYTE_ADDR_BEGIN;
  51. else if((curr_wr_state == S_WR_RESP) && m_axi_bready && m_axi_bvalid && (m_axi_bresp == 2'b00) && (m_axi_bid == AXI_ID[AXI_ID_WIDTH-1:0]))
  52. //每次地址增加量应该是突发写数据个数*每个数据的字节数
  53. m_axi_awaddr <= m_axi_awaddr + ((m_axi_awlen + 1'b1)*(AXI_DATA_WIDTH/8));
  54. else
  55. m_axi_awaddr <= m_axi_awaddr;
  56. end
  57. //awvalid信号
  58. always@(posedge clk or posedge reset)
  59. begin
  60. if(reset)
  61. m_axi_awvalid <= 1'b0;
  62. else if((curr_wr_state == S_WR_ADDR) && m_axi_awready && m_axi_awvalid)
  63. m_axi_awvalid <= 1'b0;
  64. else if(curr_wr_state == S_WR_ADDR)
  65. m_axi_awvalid <= 1'b1;
  66. else
  67. m_axi_awvalid <= m_axi_awvalid;
  68. end
  69. //wvalid信号
  70. always@(posedge clk or posedge reset)
  71. begin
  72. if(reset)
  73. m_axi_wvalid <= 1'b0;
  74. else if((curr_wr_state == S_WR_DATA) && m_axi_wready && m_axi_wvalid && m_axi_wlast)
  75. m_axi_wvalid <= 1'b0;
  76. else if(curr_wr_state == S_WR_DATA)
  77. m_axi_wvalid <= 1'b1;
  78. else
  79. m_axi_wvalid <= m_axi_wvalid;
  80. end
  81. //传输计数
  82. always@(posedge clk or posedge reset)
  83. begin
  84. if(reset)
  85. wr_data_cnt <= 1'b0;
  86. else if(curr_wr_state == S_IDLE)
  87. wr_data_cnt <= 1'b0;
  88. else if(curr_wr_state == S_WR_DATA && m_axi_wready && m_axi_wvalid)
  89. wr_data_cnt <= wr_data_cnt + 1'b1;
  90. else
  91. wr_data_cnt <= wr_data_cnt;
  92. end
  93. //wlast信号:
  94. always@(posedge clk or posedge reset)
  95. begin
  96. if(reset)
  97. m_axi_wlast <= 1'b0;
  98. else if(curr_wr_state == S_WR_DATA && m_axi_wready && m_axi_wvalid && m_axi_wlast)
  99. m_axi_wlast <= 1'b0;
  100. else if(curr_wr_state == S_WR_DATA && m_axi_awlen == 8'd0)
  101. //数据个数为1
  102. m_axi_wlast <= 1'b1;
  103. else if(curr_wr_state == S_WR_DATA && m_axi_wready && m_axi_wvalid && (wr_data_cnt == m_axi_awlen -1'b1))
  104. //传输完倒数第二个数
  105. m_axi_wlast <= 1'b1;
  106. else
  107. m_axi_wlast <= m_axi_wlast;
  108. end

根据时序进行状态机设计:

  1. //读状态机
  2. always@(posedge clk or posedge reset)
  3. begin
  4. if(reset)
  5. curr_rd_state <= S_IDLE;
  6. else
  7. curr_rd_state <= next_rd_state;
  8. end
  9. always@(*)
  10. begin
  11. case(curr_rd_state)
  12. S_IDLE:
  13. begin
  14. if(rd_ddr3_req == 1'b1)
  15. next_rd_state = S_RD_ADDR;
  16. else
  17. next_rd_state = S_IDLE;
  18. end
  19. S_RD_ADDR:
  20. begin
  21. if(m_axi_arready && m_axi_arvalid)
  22. next_rd_state = S_RD_RESP;
  23. else
  24. next_rd_state = S_RD_ADDR;
  25. end
  26. S_RD_RESP:
  27. begin
  28. if(m_axi_rready && m_axi_rvalid && m_axi_rlast && (m_axi_rresp == 2'b00)&& (m_axi_rid == AXI_ID[AXI_ID_WIDTH-1:0]))
  29. next_rd_state = S_IDLE;
  30. else
  31. next_rd_state = S_RD_RESP;
  32. end
  33. endcase
  34. end
  35. //araddr
  36. always@(posedge clk or posedge reset)
  37. begin
  38. if(reset)
  39. m_axi_araddr <= RD_AXI_BYTE_ADDR_BEGIN;
  40. else if(rd_addr_clr || axi_araddr_clr)
  41. m_axi_araddr <= RD_AXI_BYTE_ADDR_BEGIN;
  42. else if(m_axi_araddr >= RD_AXI_BYTE_ADDR_END)
  43. m_axi_araddr <= RD_AXI_BYTE_ADDR_BEGIN;
  44. else if((curr_rd_state == S_RD_RESP) && m_axi_rready && m_axi_rvalid && m_axi_rlast && (m_axi_rresp == 2'b00) && (m_axi_rid == AXI_ID[AXI_ID_WIDTH-1:0]))
  45. m_axi_araddr <= m_axi_araddr + ((m_axi_arlen + 1'b1)*(AXI_DATA_WIDTH/8));
  46. else
  47. m_axi_araddr <= m_axi_araddr;
  48. end
  49. //m_axi_arvalid
  50. always@(posedge clk or posedge reset)
  51. begin
  52. if(reset)
  53. m_axi_arvalid <= 1'b0;
  54. else if((curr_rd_state == S_RD_ADDR) && m_axi_arready && m_axi_arvalid)
  55. m_axi_arvalid <= 1'b0;
  56. else if(curr_rd_state == S_RD_ADDR)
  57. m_axi_arvalid <= 1'b1;
  58. else
  59. m_axi_arvalid <= m_axi_arvalid;
  60. end

其他信号定义:

  1. assign m_axi_awid = AXI_ID[AXI_ID_WIDTH-1:0];
  2. assign m_axi_awsize = DATA_SIZE;
  3. assign m_axi_awburst = 2'b01;
  4. assign m_axi_awlock = 1'b0;
  5. assign m_axi_awcache = 4'b0000;
  6. assign m_axi_awprot = 3'b000;
  7. assign m_axi_awqos = 4'b0000;
  8. assign m_axi_awregion= 4'b0000;
  9. assign m_axi_awlen = AXI_BURST_LEN[7:0];
  10. assign m_axi_wstrb = 16'hffff;
  11. assign m_axi_wdata = wr_fifo_rddata;
  12. assign m_axi_bready = 1'b1;
  13. assign m_axi_arid = AXI_ID[AXI_ID_WIDTH-1:0];
  14. assign m_axi_arsize = DATA_SIZE;
  15. assign m_axi_arburst = 2'b01;
  16. assign m_axi_arlock = 1'b0;
  17. assign m_axi_arcache = 4'b0000;
  18. assign m_axi_arprot = 3'b000;
  19. assign m_axi_arqos = 4'b0000;
  20. assign m_axi_arregion= 4'b0000;
  21. assign m_axi_arlen = AXI_BURST_LEN[7:0];
  22. assign m_axi_rready = ~rd_fifo_alfull;
  23. assign wr_fifo_rdreq = (~axi_awaddr_clr) && m_axi_wvalid && m_axi_wready;
  24. assign rd_fifo_wrreq = (~axi_araddr_clr) && m_axi_rvalid && m_axi_rready;
  25. assign rd_fifo_wrdata = m_axi_rdata;
  26. assign wr_req_cnt_thresh = (m_axi_awlen == 'd0)? 1'b1 : (AXI_BURST_LEN[7:0]+1'b1-2'd2);//计数比实际数量少 2
  27. assign rd_req_cnt_thresh = AXI_BURST_LEN[7:0];
  28. assign wr_ddr3_req = (wr_fifo_rst_busy == 1'b0) && (wr_fifo_rd_cnt >= wr_req_cnt_thresh) ? 1'b1:1'b0;
  29. assign rd_ddr3_req = (rd_fifo_rst_busy == 1'b0) && (rd_fifo_wr_cnt <= rd_req_cnt_thresh) ? 1'b1:1'b0;

3.2FIFO IP创建(wr_ddr3_fifo、rd_ddr3_fifo)

wr_ddr3_fifo: 

设置写FIFO接口类型,写入和读出的时钟不一致, 所以这里需要创建一个独立时钟 FIFO。

设置写FIFO端口

rd_ddr3_fifo:

设置读FIFO接口类型,写入和读出的时钟不一致, 所以这里需要创建一个独立时钟 FIFO。

设置读 FIFO 端口

设置读FIFO数据计数

 3.3 封装接口转换模块

  1. module fifo_axi4_adapter #(
  2. parameter FIFO_DW = 16 ,
  3. parameter WR_AXI_BYTE_ADDR_BEGIN = 0 ,
  4. parameter WR_AXI_BYTE_ADDR_END = 1023 ,
  5. parameter RD_AXI_BYTE_ADDR_BEGIN = 0 ,
  6. parameter RD_AXI_BYTE_ADDR_END = 1023 ,
  7. parameter AXI_DATA_WIDTH = 128 ,
  8. parameter AXI_ADDR_WIDTH = 29 ,
  9. parameter AXI_ID_WIDTH = 4 ,
  10. parameter AXI_ID = 4'b0000,
  11. parameter AXI_BURST_LEN = 8'd31 //burst length = 32
  12. )
  13. (
  14. // clock reset
  15. input clk ,
  16. input reset ,
  17. // wr_fifo wr Interface
  18. input wrfifo_clr ,
  19. input wrfifo_clk ,
  20. input wrfifo_wren ,
  21. input [FIFO_DW-1:0] wrfifo_din ,
  22. output wrfifo_full ,
  23. output [15:0] wrfifo_wr_cnt ,
  24. // rd_fifo rd Interface
  25. input rdfifo_clr ,
  26. input rdfifo_clk ,
  27. input rdfifo_rden ,
  28. output [FIFO_DW-1:0] rdfifo_dout ,
  29. output rdfifo_empty ,
  30. output [15:0] rdfifo_rd_cnt ,
  31. // Master Interface Write Address Ports
  32. output [AXI_ID_WIDTH-1:0] m_axi_awid ,
  33. output [AXI_ADDR_WIDTH-1:0] m_axi_awaddr ,
  34. output [7:0] m_axi_awlen ,
  35. output [2:0] m_axi_awsize ,
  36. output [1:0] m_axi_awburst ,
  37. output [0:0] m_axi_awlock ,
  38. output [3:0] m_axi_awcache ,
  39. output [2:0] m_axi_awprot ,
  40. output [3:0] m_axi_awqos ,
  41. output [3:0] m_axi_awregion,
  42. output m_axi_awvalid ,
  43. input m_axi_awready ,
  44. // Master Interface Write Data Ports
  45. output [AXI_DATA_WIDTH-1:0] m_axi_wdata ,
  46. output [AXI_DATA_WIDTH/8-1:0] m_axi_wstrb ,
  47. output m_axi_wlast ,
  48. output m_axi_wvalid ,
  49. input m_axi_wready ,
  50. // Master Interface Write Response Ports
  51. input [AXI_ID_WIDTH-1:0] m_axi_bid ,
  52. input [1:0] m_axi_bresp ,
  53. input m_axi_bvalid ,
  54. output m_axi_bready ,
  55. // Master Interface Read Address Ports
  56. output [AXI_ID_WIDTH-1:0] m_axi_arid ,
  57. output [AXI_ADDR_WIDTH-1:0] m_axi_araddr ,
  58. output [7:0] m_axi_arlen ,
  59. output [2:0] m_axi_arsize ,
  60. output [1:0] m_axi_arburst ,
  61. output [0:0] m_axi_arlock ,
  62. output [3:0] m_axi_arcache ,
  63. output [2:0] m_axi_arprot ,
  64. output [3:0] m_axi_arqos ,
  65. output [3:0] m_axi_arregion,
  66. output m_axi_arvalid ,
  67. input m_axi_arready ,
  68. // Master Interface Read Data Ports
  69. input [AXI_ID_WIDTH-1:0] m_axi_rid ,
  70. input [AXI_DATA_WIDTH-1:0] m_axi_rdata ,
  71. input [1:0] m_axi_rresp ,
  72. input m_axi_rlast ,
  73. input m_axi_rvalid ,
  74. output m_axi_rready
  75. );
  76. wire wrfifo_rden;
  77. wire [AXI_DATA_WIDTH-1:0] wrfifo_dout;
  78. wire [5 : 0] wrfifo_rd_cnt;
  79. wire wrfifo_empty;
  80. wire wrfifo_wr_rst_busy;
  81. wire wrfifo_rd_rst_busy;
  82. wire rdfifo_wren;
  83. wire [AXI_DATA_WIDTH-1:0] rdfifo_din;
  84. wire [5 : 0] rdfifo_wr_cnt;
  85. wire rdfifo_full;
  86. wire rdfifo_wr_rst_busy;
  87. wire rdfifo_rd_rst_busy;
  88. reg wrfifo_clr_sync_clk;
  89. reg wr_addr_clr;
  90. reg rdfifo_clr_sync_clk;
  91. reg rd_addr_clr;
  92. wr_ddr3_fifo wr_ddr3_fifo
  93. (
  94. .rst (wrfifo_clr ),
  95. .wr_clk (wrfifo_clk ),
  96. .rd_clk (clk ),
  97. .din (wrfifo_din ),
  98. .wr_en (wrfifo_wren ),
  99. .rd_en (wrfifo_rden ),
  100. .dout (wrfifo_dout ),
  101. .full (wrfifo_full ),
  102. .empty (wrfifo_empty ),
  103. .rd_data_count (wrfifo_rd_cnt ),
  104. .wr_data_count (wrfifo_wr_cnt ),
  105. .wr_rst_busy (wrfifo_wr_rst_busy ),
  106. .rd_rst_busy (wrfifo_rd_rst_busy )
  107. );
  108. rd_ddr3_fifo rd_ddr3_fifo
  109. (
  110. .rst (rdfifo_clr ),
  111. .wr_clk (clk ),
  112. .rd_clk (rdfifo_clk ),
  113. .din (rdfifo_din ),
  114. .wr_en (rdfifo_wren ),
  115. .rd_en (rdfifo_rden ),
  116. .dout (rdfifo_dout ),
  117. .full (rdfifo_full ),
  118. .empty (rdfifo_empty ),
  119. .rd_data_count (rdfifo_rd_cnt ),
  120. .wr_data_count (rdfifo_wr_cnt ),
  121. .wr_rst_busy (rdfifo_wr_rst_busy ),
  122. .rd_rst_busy (rdfifo_rd_rst_busy )
  123. );
  124. always@(posedge clk)
  125. begin
  126. wrfifo_clr_sync_clk <= wrfifo_clr;
  127. wr_addr_clr <= wrfifo_clr_sync_clk;
  128. end
  129. always@(posedge clk)
  130. begin
  131. rdfifo_clr_sync_clk <= rdfifo_clr;
  132. rd_addr_clr <= rdfifo_clr_sync_clk;
  133. end
  134. fifo2axi4
  135. #(
  136. .WR_AXI_BYTE_ADDR_BEGIN (WR_AXI_BYTE_ADDR_BEGIN ),
  137. .WR_AXI_BYTE_ADDR_END (WR_AXI_BYTE_ADDR_END ),
  138. .RD_AXI_BYTE_ADDR_BEGIN (RD_AXI_BYTE_ADDR_BEGIN ),
  139. .RD_AXI_BYTE_ADDR_END (RD_AXI_BYTE_ADDR_END ),
  140. .AXI_DATA_WIDTH (AXI_DATA_WIDTH ),
  141. .AXI_ADDR_WIDTH (AXI_ADDR_WIDTH ),
  142. .AXI_ID_WIDTH (AXI_ID_WIDTH ),
  143. .AXI_ID (AXI_ID ),
  144. .AXI_BURST_LEN (AXI_BURST_LEN )//burst length = 32
  145. )fifo2axi4_inst
  146. (
  147. //clock reset
  148. .clk (clk ),
  149. .reset (reset ),
  150. //FIFO Interface ports
  151. .wr_addr_clr (wr_addr_clr ), //1:clear, sync clk
  152. .wr_fifo_rdreq (wrfifo_rden ),
  153. .wr_fifo_rddata (wrfifo_dout ),
  154. .wr_fifo_empty (wrfifo_empty ),
  155. .wr_fifo_rd_cnt (wrfifo_rd_cnt ),
  156. .wr_fifo_rst_busy (wrfifo_rd_rst_busy ),
  157. .rd_addr_clr (rd_addr_clr ), //1:clear, sync clk
  158. .rd_fifo_wrreq (rdfifo_wren ),
  159. .rd_fifo_wrdata (rdfifo_din ),
  160. .rd_fifo_alfull (rdfifo_full ),
  161. .rd_fifo_wr_cnt (rdfifo_wr_cnt ),
  162. .rd_fifo_rst_busy (rdfifo_wr_rst_busy ),
  163. // Slave Interface Write Address Ports
  164. .m_axi_awid (m_axi_awid ),
  165. .m_axi_awaddr (m_axi_awaddr ),
  166. .m_axi_awlen (m_axi_awlen ),
  167. .m_axi_awsize (m_axi_awsize ),
  168. .m_axi_awburst (m_axi_awburst ),
  169. .m_axi_awlock (m_axi_awlock ),
  170. .m_axi_awcache (m_axi_awcache ),
  171. .m_axi_awprot (m_axi_awprot ),
  172. .m_axi_awqos (m_axi_awqos ),
  173. .m_axi_awregion (m_axi_awregion ),
  174. .m_axi_awvalid (m_axi_awvalid ),
  175. .m_axi_awready (m_axi_awready ),
  176. // Slave Interface Write Data Ports
  177. .m_axi_wdata (m_axi_wdata ),
  178. .m_axi_wstrb (m_axi_wstrb ),
  179. .m_axi_wlast (m_axi_wlast ),
  180. .m_axi_wvalid (m_axi_wvalid ),
  181. .m_axi_wready (m_axi_wready ),
  182. // Slave Interface Write Response Ports
  183. .m_axi_bid (m_axi_bid ),
  184. .m_axi_bresp (m_axi_bresp ),
  185. .m_axi_bvalid (m_axi_bvalid ),
  186. .m_axi_bready (m_axi_bready ),
  187. // Slave Interface Read Address Ports
  188. .m_axi_arid (m_axi_arid ),
  189. .m_axi_araddr (m_axi_araddr ),
  190. .m_axi_arlen (m_axi_arlen ),
  191. .m_axi_arsize (m_axi_arsize ),
  192. .m_axi_arburst (m_axi_arburst ),
  193. .m_axi_arlock (m_axi_arlock ),
  194. .m_axi_arcache (m_axi_arcache ),
  195. .m_axi_arprot (m_axi_arprot ),
  196. .m_axi_arqos (m_axi_arqos ),
  197. .m_axi_arregion (m_axi_arregion ),
  198. .m_axi_arvalid (m_axi_arvalid ),
  199. .m_axi_arready (m_axi_arready ),
  200. // Slave Interface Read Data Ports
  201. .m_axi_rid (m_axi_rid ),
  202. .m_axi_rdata (m_axi_rdata ),
  203. .m_axi_rresp (m_axi_rresp ),
  204. .m_axi_rlast (m_axi_rlast ),
  205. .m_axi_rvalid (m_axi_rvalid ),
  206. .m_axi_rready (m_axi_rready )
  207. );
  208. endmodule

4.AXI 接口转换模块仿真

1.仿真设计结构

2.DDR控制器(MIG IP)创建

1、配置MIG IP

DDR3存储器驱动的时钟周期(Clock Period)设置为2500ps(即400MHz),这个时钟是用于 FPGA 输出给到 DDR 存储器时钟管脚的时钟。注意这里根据实际情况是有设置区间范围的,并非可以设置任意值,这里的区间范围为 2500~3300ps(即 300~400MHz)。


TMD(Time DivisionMultiplexing),该设置读写优先级相同,读写交替进行。



仿真选New Design,上板测试选Fixed Pin Out。


在 Vivado 的 Source 窗口中,出现了新配置生成的 IP 核文件mig_7series_0(mig_7series_0.xci)。

在上面窗口的 IP Sources 一栏,可以找到 IP 例化模板文件(mig_7series_0.veo)。

3.产生时钟和复位、数据产生和数据读取的激励

DDR控制器时钟200MHz(T=5ns,每2.5ns翻转一次)

wr_ddr3_fifo、rd_ddr3_fifo时钟100MHz(T=10ns,每5ns翻转一次)

fifo_axi4_adapter模块时钟使用DDR控制器输出的供用户侧使用的ui_clk。

仿真的时间单位1ns,精度100ps。具体可以看一下Verilog(未完待续)里面的编译指令timescale部分。每2.5ns翻转一次,它的最低精度就是0.1ns=100ps,时间单位就是1ns。

`timescale 1ns/100ps
  1. initial sys_clk_i = 1'b1;
  2. always #2.5 sys_clk_i = ~sys_clk_i;
  3. initial wrfifo_clk = 1'b1;
  4. always #2.5 wrfifo_clk = ~wrfifo_clk;
  5. initial rdfifo_clk = 1'b1;
  6. always #2.5 rdfifo_clk = ~rdfifo_clk;

数据产生和读取的激励设计上将其封装成任务 task 形式,方便调用。

  1. //向 wr_ddr3_fifo 中写入以起始数据 data_begin 开始递增的wr_data_cnt 个数据。
  2. task wr_data;
  3. input [15:0]data_begin;
  4. input [15:0]wr_data_cnt;
  5. begin
  6. wrfifo_wren = 1'b0;
  7. wrfifo_din = data_begin;
  8. @(posedge wrfifo_clk);
  9. #1 wrfifo_wren = 1'b1;
  10. repeat(wr_data_cnt)
  11. begin
  12. @(posedge wrfifo_clk);
  13. wrfifo_din = wrfifo_din + 1'b1;
  14. end
  15. #1 wrfifo_wren = 1'b0;
  16. end
  17. endtask
  18. //向 rd_ddr3_fifo 中读出个 rd_data_cnt 数据
  19. task rd_data;
  20. input [15:0]data_begin;
  21. input [15:0]rd_data_cnt;
  22. begin
  23. rdfifo_rden = 1'b0;
  24. expect_rd_data = data_begin;
  25. @(posedge rdfifo_clk);
  26. #1 rdfifo_rden = 1'b1;
  27. repeat(rd_data_cnt)
  28. begin
  29. @(posedge rdfifo_clk);
  30. if(rdfifo_dout != expect_rd_data)
  31. begin
  32. $display("SIM is failed");
  33. $finish;
  34. end
  35. expect_rd_data = expect_rd_data + 1'b1;
  36. end
  37. #1 rdfifo_rden = 1'b0;
  38. end
  39. endtask

  1. /*
  2. 先产生 DDR 控制器的复位以及 FIFO 的复位。
  3. 等 DDR 控制器内部锁相环锁定后,延时 200ns 后对 FIFO 解复位。
  4. 等待 DDR 初始化校准完成后,延时 200n 往 wr_ddr3_fifo 写入 1024 个数据,
  5. 数据写完后,对rd_ddr3_fifo 进行复位,清空里面的缓存,
  6. 等 FIFO 复位结束一段时间后,等待rd_ddr3_fifo 非空后开始对 rd_ddr3_fifo 进行读取数据,
  7. 读取 1024 个数据。整个仿真结束后打印“SIM is successfully”信息
  8. */
  9. initial begin
  10. sys_rst = 1'b0;
  11. aresetn = 1'b0;
  12. expect_rd_data = 16'd0;
  13. wrfifo_clr = 1'b1;
  14. wrfifo_wren = 1'b0;
  15. wrfifo_din = 16'd0;
  16. rdfifo_clr = 1'b1;
  17. rdfifo_rden = 1'b0;
  18. #201;
  19. sys_rst = 1'b1;
  20. aresetn = 1'b1;
  21. @(posedge mmcm_locked);
  22. #200;
  23. wrfifo_clr = 1'b0;
  24. rdfifo_clr = 1'b0;
  25. @(posedge init_calib_complete);
  26. #200;
  27. wr_data(SIM_DATA_BEGIN,SIM_DATA_CNT);
  28. #2000;
  29. rdfifo_clr = 1'b1;
  30. #20;
  31. rdfifo_clr = 1'b0;
  32. #2000;
  33. wait(rdfifo_empty == 1'b0)
  34. rd_data(SIM_DATA_BEGIN,SIM_DATA_CNT);
  35. #5000;
  36. $display("SIM is successfully");
  37. $stop;
  38. end

4.运行仿真

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/480768
推荐阅读
相关标签
  

闽ICP备14008679号