DDR4系列之ECC功能(六)

一、 概述

在之前我们讲到使用两个ddr4内存实现数据的流水操作的功能特性和适用情况,本章节将工程示例模块列出,并给出模块接口说明和示例代码。

二、 示例流程框架

三、 test_ddr4_0模块说明

模块功能描述:

test_ddr4_0模块作用是产生读写ddr0的命令,

写命令:

写命令需要产生wr_start、awaddr_in、awlen_in、wdata_in。每当写突发完成一次,就产生一拍wr_start,并且需要计算awaddr_in的值,awlen_in保持255的值,每次突发256个数据。Wdata_in根据wready和wvalid的握手,Wdata_in生成递增数。共产生100次写突发。

读命令:

为了使读出的数据有效,使用写地址计数减去读地址计数,地址计数不小于'h4000时,可以请求读ddr4,每次固定读取'd256长度。读地址为araddr_cnt。

示例代码:

reg [31:0] clk_cnt;

reg wr_end_flag;

reg send_valid;

reg [7:0] wr_end_flag_cnt;

assign fifo_wr_en = rd_en;

assign fifo_wr_data = rd_data;

always @(posedge clk ) begin

if (rst) begin

clk_cnt <= 0;

end

else if (clk_cnt == 'h1000) begin

clk_cnt <= clk_cnt;

end

else if (clk_cnt <= ('h1000-1)) begin

clk_cnt <= clk_cnt + 1;

end

end

always @(posedge clk ) begin

if (rst) begin

wr_start <= 0;

end

else if (send_valid && wr_end_flag ) begin

wr_start <= 1;

end

else if (clk_cnt == ('h1000-1)) begin

wr_start <= 1;

end

else begin

wr_start <= 0;

end

end

always @(posedge clk ) begin

if (rst) begin

awaddr_in <= 0;

end

else if (send_valid && wr_end_flag) begin

awaddr_in <= awaddr_cnt;

end

else if (clk_cnt == ('h1000-1)) begin

awaddr_in <= 'h0;

end

end

always @(posedge clk ) begin

if (rst) begin

awlen_in <= 0;

end

else if (send_valid && wr_end_flag) begin

awlen_in <= 'd255;

end

else if (clk_cnt == ('h1000-1)) begin

awlen_in <= 'd255;

end

end

always @(posedge clk ) begin

if (rst) begin

wdata_in <= 'h0;

end

else if (wready && wvalid) begin

wdata_in <= wdata_in + 'd1;

//wdata_in <= {512{1'b1}};

end

end

reg wr_busy_r;

always @(posedge clk ) begin

wr_busy_r <= wr_busy;

end

always @(posedge clk ) begin

if (rst) begin

wr_end_flag <= 0;

end

else if (wr_busy_r == 1 && wr_busy == 0) begin

wr_end_flag <= 1;

end

else begin

wr_end_flag <= 0;

end

end

always @(posedge clk ) begin

if (rst) begin

send_valid <= 0;

end

else if (wr_end_flag_cnt == 'd99 && wr_busy_r == 1 && wr_busy == 0) begin

send_valid <= 0;

end

else if (clk_cnt == ('h1000-1)) begin

send_valid <= 1;

end

end

always @(posedge clk ) begin

if (rst) begin

wr_end_flag_cnt <= 0;

end

else if (send_valid && wr_end_flag_cnt == 'd99 && wr_end_flag) begin

wr_end_flag_cnt <= 0;

end

else if (send_valid && wr_end_flag) begin

wr_end_flag_cnt <= wr_end_flag_cnt + 1;

end

end

//rd

reg [32:0] able_rd_addrcnt;

always @(posedge clk ) begin

if (rst) begin

able_rd_addrcnt <= 0;

end

else begin

able_rd_addrcnt <= awaddr_cnt - araddr_cnt;

end

end

always @(posedge clk ) begin

if (rst) begin

rd_start <= 0;

end

else if (rd_start == 0 && rd_busy == 0 && able_rd_addrcnt>='h4000 && fifo_alfull == 0) begin

rd_start <= 1;

end

else begin

rd_start <= 0;

end

end

always @(posedge clk ) begin

if (rst) begin

araddr_in <= 0;

end

else if (rd_start == 0 && rd_busy == 0 && able_rd_addrcnt>='h4000 && fifo_alfull == 0) begin

araddr_in <= araddr_cnt;

end

end

always @(posedge clk ) begin

if (rst) begin

arlen_in <= 0;

end

else if (rd_start == 0 && rd_busy == 0 && able_rd_addrcnt>='h4000 && fifo_alfull == 0) begin

arlen_in <= 'd255;

end

end

四、 flow_ctrl模块说明

flow_ctrl模块的作用是对数据做一个缓存。使用fifo将数据缓存。并给出可以读写数据的标志。因为每次读写的长度固定为256。所以当fifo中至少有256个数据后才能将数据读出写给ddr4。当fifo至少有256个空闲深度才能将数据从ddr4读出放到fifo中。

模块代码:

module flow_ctrl(

input wire clk,

input wire rst,

复制代码
output 		reg 				fifo_alfull,
output 		wire 				fifo_alempty, 				
input 			wire 				fifo_wr_en,
input 			wire 	[511:0] 		fifo_wr_data,

input 			wire 				fifo_rd_en,
output 		wire 	[511:0] 		fifo_rd_data
);

wire [10:0] data_count;

fifo_data_512x1024 fifo_data_512x1024 (

.clk (clk), // input wire clk

.din (fifo_wr_data), // input wire [511 : 0] din

.wr_en (fifo_wr_en), // input wire wr_en

.rd_en (fifo_rd_en), // input wire rd_en

.dout (fifo_rd_data), // output wire [511 : 0] dout

.full (full), // output wire full

.almost_full (almost_full), // output wire almost_full

.empty (empty), // output wire empty

.almost_empty (almost_empty), // output wire almost_empty

.data_count (data_count) // output wire [10 : 0] data_count

);

always @(posedge clk ) begin

if (rst) begin

fifo_alfull <= 0;

end

else if (data_count >= 'd768) begin

fifo_alfull <= 1;

end

else begin

fifo_alfull <= 0;

end

end

assign fifo_alempty = (data_count < 'd256) ? 1 :0;

endmodule

五、 test_ddr4_72width_1模块说明

模块功能描述:

test_ddr4_0模块作用是产生读写ddr0的命令,

写命令:

写命令需要产生wr_start、awaddr_in、awlen_in、wdata_in。每当写突发完成一次,就产生一拍wr_start,并且需要计算awaddr_in的值,awlen_in保持255的值,每次突发256个数据。Wdata_in根据wready和wvalid的握手,Wdata_in生成递增数。共产生100次写突发。

读命令:

为了使读出的数据有效,使用写地址计数减去读地址计数,地址计数不小于'h4000时,可以请求读ddr4,每次固定读取'd256长度。读地址为araddr_cnt。

示例代码:

reg [31:0] clk_cnt;

reg wr_end_flag;

reg send_valid;

reg [7:0] wr_end_flag_cnt;

assign fifo_wr_en = rd_en;

assign fifo_wr_data = rd_data;

always @(posedge clk ) begin

if (rst) begin

clk_cnt <= 0;

end

else if (clk_cnt == 'h1000) begin

clk_cnt <= clk_cnt;

end

else if (clk_cnt <= ('h1000-1)) begin

clk_cnt <= clk_cnt + 1;

end

end

always @(posedge clk ) begin

if (rst) begin

wr_start <= 0;

end

else if (send_valid && wr_end_flag ) begin

wr_start <= 1;

end

else if (clk_cnt == ('h1000-1)) begin

wr_start <= 1;

end

else begin

wr_start <= 0;

end

end

always @(posedge clk ) begin

if (rst) begin

awaddr_in <= 0;

end

else if (send_valid && wr_end_flag) begin

awaddr_in <= awaddr_cnt;

end

else if (clk_cnt == ('h1000-1)) begin

awaddr_in <= 'h0;

end

end

always @(posedge clk ) begin

if (rst) begin

awlen_in <= 0;

end

else if (send_valid && wr_end_flag) begin

awlen_in <= 'd255;

end

else if (clk_cnt == ('h1000-1)) begin

awlen_in <= 'd255;

end

end

always @(posedge clk ) begin

if (rst) begin

wdata_in <= 'h0;

end

else if (wready && wvalid) begin

wdata_in <= wdata_in + 'd1;

//wdata_in <= {512{1'b1}};

end

end

reg wr_busy_r;

always @(posedge clk ) begin

wr_busy_r <= wr_busy;

end

always @(posedge clk ) begin

if (rst) begin

wr_end_flag <= 0;

end

else if (wr_busy_r == 1 && wr_busy == 0) begin

wr_end_flag <= 1;

end

else begin

wr_end_flag <= 0;

end

end

always @(posedge clk ) begin

if (rst) begin

send_valid <= 0;

end

else if (wr_end_flag_cnt == 'd99 && wr_busy_r == 1 && wr_busy == 0) begin

send_valid <= 0;

end

else if (clk_cnt == ('h1000-1)) begin

send_valid <= 1;

end

end

always @(posedge clk ) begin

if (rst) begin

wr_end_flag_cnt <= 0;

end

else if (send_valid && wr_end_flag_cnt == 'd99 && wr_end_flag) begin

wr_end_flag_cnt <= 0;

end

else if (send_valid && wr_end_flag) begin

wr_end_flag_cnt <= wr_end_flag_cnt + 1;

end

end

//rd

reg [32:0] able_rd_addrcnt;

always @(posedge clk ) begin

if (rst) begin

able_rd_addrcnt <= 0;

end

else begin

able_rd_addrcnt <= awaddr_cnt - araddr_cnt;

end

end

always @(posedge clk ) begin

if (rst) begin

rd_start <= 0;

end

else if (rd_start == 0 && rd_busy == 0 && able_rd_addrcnt>='h4000 && fifo_alfull == 0) begin

rd_start <= 1;

end

else begin

rd_start <= 0;

end

end

always @(posedge clk ) begin

if (rst) begin

araddr_in <= 0;

end

else if (rd_start == 0 && rd_busy == 0 && able_rd_addrcnt>='h4000 && fifo_alfull == 0) begin

araddr_in <= araddr_cnt;

end

end

always @(posedge clk ) begin

if (rst) begin

arlen_in <= 0;

end

else if (rd_start == 0 && rd_busy == 0 && able_rd_addrcnt>='h4000 && fifo_alfull == 0) begin

arlen_in <= 'd255;

end

end

四、 flow_ctrl模块说明

flow_ctrl模块的作用是对数据做一个缓存。使用fifo将数据缓存。并给出可以读写数据的标志。因为每次读写的长度固定为256。所以当fifo中至少有256个数据后才能将数据读出写给ddr4。当fifo至少有256个空闲深度才能将数据从ddr4读出放到fifo中。

模块代码:

module flow_ctrl(

input wire clk,

input wire rst,

复制代码
output 		reg 				fifo_alfull,
output 		wire 				fifo_alempty, 				
input 			wire 				fifo_wr_en,
input 			wire 	[511:0] 		fifo_wr_data,

input 			wire 				fifo_rd_en,
output 		wire 	[511:0] 		fifo_rd_data
);

wire [10:0] data_count;

fifo_data_512x1024 fifo_data_512x1024 (

.clk (clk), // input wire clk

.din (fifo_wr_data), // input wire [511 : 0] din

.wr_en (fifo_wr_en), // input wire wr_en

.rd_en (fifo_rd_en), // input wire rd_en

.dout (fifo_rd_data), // output wire [511 : 0] dout

.full (full), // output wire full

.almost_full (almost_full), // output wire almost_full

.empty (empty), // output wire empty

.almost_empty (almost_empty), // output wire almost_empty

.data_count (data_count) // output wire [10 : 0] data_count

);

always @(posedge clk ) begin

if (rst) begin

fifo_alfull <= 0;

end

else if (data_count >= 'd768) begin

fifo_alfull <= 1;

end

else begin

fifo_alfull <= 0;

end

end

assign fifo_alempty = (data_count < 'd256) ? 1 :0;

endmodule

五、 test_ddr4_72width_1模块说明


模块功能:

此模块用来对ddr1产生读写命令。

1、写命令:

当fifo不空时,产生写ddr1命令,写ddr1突发长度为256,awlen_in的值为'd255。写突发地址(awaddr_in)根据写地址计数(wr_start)给出下一次写突发的起始地址(awaddr_in)。

写ddr数据为fifo的读数据,wready与wvalid握手作为fifo读使能。

2、读命令:

使用写地址计数-读地址计数。当差值大于等于'h4000时,可以产生ddr1的读命令,突发长度为256,将ddr1的读地址计数作为ddr1的读地址。

模块代码示例:

always @(posedge clk ) begin

if (rst) begin

wr_start <= 0;

end

else if (wr_busy == 0 && wr_start ==0 && fifo_alempty == 0) begin

wr_start <= 1;

end

else begin

wr_start <= 0;

end

end

always @(posedge clk ) begin

if (rst) begin

awaddr_in <= 0;

end

else if (wr_busy == 0 && wr_start ==0 && fifo_alempty == 0) begin

awaddr_in <= awaddr_cnt;

end

end

always @(posedge clk ) begin

if (rst) begin

awlen_in <= 0;

end

else if (wr_busy == 0 && wr_start ==0 && fifo_alempty == 0) begin

awlen_in <= 'd255;

end

end

assign fifo_rd_en = wready & wvalid;

assign wdata_in = fifo_rd_data;

reg wr_busy_r;

always @(posedge clk ) begin

wr_busy_r <= wr_busy;

end

reg [32:0] able_rd_addrcnt;

always @(posedge clk ) begin

if (rst) begin

able_rd_addrcnt <= 0;

end

else begin

able_rd_addrcnt <= awaddr_cnt - araddr_cnt;

end

end

always @(posedge clk ) begin

if (rst) begin

rd_start <= 0;

end

else if (rd_start == 0 && rd_busy == 0 && able_rd_addrcnt>='h4000 ) begin

rd_start <= 1;

end

else begin

rd_start <= 0;

end

end

always @(posedge clk ) begin

if (rst) begin

araddr_in <= 0;

end

else if (rd_start == 0 && rd_busy == 0 && able_rd_addrcnt>='h4000 ) begin

araddr_in <= araddr_cnt;

end

end

always @(posedge clk ) begin

if (rst) begin

arlen_in <= 0;

end

else if (rd_start == 0 && rd_busy == 0 && able_rd_addrcnt>='h4000 ) begin

arlen_in <= 'd255;

end

end

六、 章节概括

这一章讲述了ddr流水的两个控制ddr4的命令模块。通过将数据写入ddr0,从ddr0读出数据缓存到fifo,再从fifo取出数据写进ddr1,最后再从ddr1中读出数据。从而实现双ddr的流水控制。后面章节来进行仿真说明。

本文章由威三学社出品

对课程感兴趣可以私信联系

相关推荐
FPGA_无线通信1 小时前
OFDM FFT 时频域转换
fpga开发
XINVRY-FPGA3 小时前
EP4CE30F23I7N Altera Cyclone IV E SRAM FPGA
嵌入式硬件·fpga开发·云计算·硬件工程·信息与通信·信号处理·fpga
156082072194 小时前
FPGA(采用RGMII接口)逻辑实现千兆网TCP/IP协议栈调试记录
网络协议·tcp/ip·fpga开发
9527华安4 小时前
FPGA纯verilog实现JESD204B协议,基于AD9250数据接收,提供3套工程源码和技术支持
fpga开发·jesd204b·ad9250
FPGA_无线通信5 小时前
OFDM 精频偏补偿
算法·fpga开发
我爱C编程6 小时前
【仿真测试】基于FPGA的完整16QAM软解调链路实现,含频偏锁定,帧同步,定时点,Viterbi译码,信道,误码统计
fpga开发·16qam·软解调·帧同步·维特比译码·频偏估计·定时点提取
高速上的乌龟7 小时前
Lattice LFCPNX-100 Fpga开发+源码:基于spi协议的flash驱动控制
fpga开发
ehiway8 小时前
中科亿海微SoM模组——FPGA高速信号采集解决方案
fpga开发
tiantianuser15 小时前
RDMA设计13:融合以太网协议栈设计2
fpga开发·rdma·高速传输·cmac·roce v2
XINVRY-FPGA20 小时前
XC3S1000-4FGG320I Xilinx AMD Spartan-3 SRAM-based FPGA
嵌入式硬件·机器学习·计算机视觉·fpga开发·硬件工程·dsp开发·fpga