平台:ise14.7,modelsim 10.4
芯片:XC1A100T
关于ddr3的mig的学习。使用xilinx官方提供的IP核。
官方资料下载地址:
ug586_7Series_MIS.pdf • 查看器 • 文档门户 (xilinx.com)
7 Series FPGAs Memory Interface Solutions v1.7
项目工程地址
(306条消息) ddr-test.zip-嵌入式文档类资源-CSDN文库
关于ddr3的学习
DDR3属于SDRAM。
同步动态随机存取存储器,同步是指 Memory工作需要同步时钟,内部的命令的发送与数据的传输都以它为基准;
动态是指存储阵列需要不断的刷新来保证数据不丢失;
随机是指数据不是线性依次存储,而是自由指定地址进行数据读写,DDR,DDR2以及DDR3就属于SDRAM的一类。
内存芯片的内存芯片内部的核心时钟基本上是保持一致的,都是100MHz 到 200MHz(某些厂商生产的超频内存除外)。
DDR就是 double data rate ,在时钟上升沿下降沿同时传输数据,
芯片内部数据数据传输速度的提升则是通过Prefetch 技术实现的。
Prefetch:DDR3采样8bit预取技术。一次从存储单元预取8-bit的数据,在I/O端口处上下沿触发传输,预取8bit也就需要4个时钟周期,所以DDR3的I/O时钟频率是内部核心频率的四倍,由于是上下沿都在传输数据,所以实际有效的数据传输频率达到了核心频率的八倍。所以,对于200mhz核心频率的ddr3-1600其IO时钟频率为800MHZ左右,有效的数据传输频率为1600mhz。
DDR1、DDR2 和 DDR3 存储器的电压分别为 2.5、1.8 和 1.5V,因此与采用 3.3V 的正常SDRAM 芯片组相比,它们在电源管理中产生的热量更少,效率更高。
DDR的核心频率,一般为100mhz和200mhz,对于DDR3-1600,核心频率就是200mhz(DDR芯片内部进行逻辑处理的时钟频率)
时钟频率,是指DDR芯片io管脚CK和CK#上的时钟信号的频率。DDR3的时钟频率是核心频率的4倍。对于DDR3-1600,时钟频率就是800mhz(工作频率)
数据传输速率,DDR内存在IO时钟的上下边沿都传输数据,所以数据传输频率是时钟频率的2倍。
传输速率,也叫做传输频率或者等效频率,等效频率在数值上与传输速率相等。
对于DDR3-1600,数据传输速率就是1600MT/s
一般我们以数据速率来表述DDR的速率。关系如下表:
工作频率=等效频率/2。因为DDR是利用时钟的上升沿与下降沿均传输数据,所以DDR芯片的工作频率(时钟引脚的频率)为等效频率(传输频率)的一半。 |
核心频率=等效频率/DDR的预存数。对于DDR来说。预存数为2;对于DDR2来说,预存数为4;对于DDR3来说,预存数为8。 |
寻址:DDR3寻址流程是先指定Bank地址,再指定行地址,然后指列地址最终的确寻址单元。可以想象成一个Excel表格,每新建一个表格就是一个bank,每个表格有行和列对应ddr3的行地址和列地址。
容量计算:ddr3芯片的容量计算。加入单个ddr3拥有行地址线(ROW)14根,列地址线(Column)10根,bank数量为8个,数据位宽为(DQ7-DQ0)。
容量计算公式为:
那假如我们需要一个容量为1GB的内存条,则需要用到8个这样的DDR3内存芯片。每个芯片包含8根数据线(DQ7-DQ0)数据总位宽为64bit,这样正好用了一个RANK。
关于更多的ddr芯片测接口和ddr硬件原理可以参考ddr芯片手册。例如我们这里使用这一款。
MT41J128M16HA-125可以直接去官网下载他的代码。
接下来看看xilinx关于ddr的IP mig这部分。为了简化ddr的控制流程,xilinx 设计mig IP来帮助我们控制ddr芯片。
配置界面
点击user Guide可以下载mig IP手册。里面的内容非常重要。
这里有基本保持默认,mig支持AXI模式,在此模式下数据的传输更加简单。
兼容的FPGA型号。
选择ddr3 sdram。
时钟频率400MHZ,输入核心频率则为100mhz。芯片数据位宽为16位,时钟倍频后上下沿都传输数据,时钟关系为4:1,即用户数据位宽位16*4*2=128bit。
选择ddr3输入时钟为200mhz。
选择系统时钟是单端输入还是差分输入,选择参考时钟为系统时钟。
这一页默认就好。
选择做仿真使用默认管脚。
不上板子,系统默认不分配。
选择下面这个的话,就需要你分配一下管脚。一般从ucf自动导入看看合适不。
默认位置就好。
你的设置总结。
一路next后来到这里。生成ip。
打开仿真工程,sim_tb_top
E:\code1\FPGAzero_bace\Artix7\ddr3_tb\ipcore_dir\ddr3\example_design\sim添加sim文件夹下面的所有类容到工程。
E:\code1\FPGAzero_bace\Artix7\ddr3_tb\ipcore_dir\ddr3\example_design\rtl添加example_top.v和traffic_gen文件下所有的.v文件。
文件添加成功后效果如下。
在整个工程中。example_top是对ddr3的IP核的例化,traffic_gen_top是产生了一些内部的测试数据。在测试过程中我们可以使用自己的代码替换traffic_gen_top模块。来测试自己产生的数据。
在仿真设置中设置使用xilinx的仿真库。
设置仿真库文件。运行仿真。
可以见到成功拉高初始化成功信号。
感兴趣的朋友可以去看看traffic_gen_top里面的代码。下面我门使用自己的代码将ddr3的IP核控制起来,首先分析一下ddr3的接口。
这个是xilinx文档上关于IP核的描述。左侧是IP提供给我们的用户侧接口。右侧是IP控制ddr3芯片的引脚,这里我们主要注意用户侧这边的接口。
信号名字 |
信号功能 |
clk |
用户时钟 |
rst |
复位高有效 |
init_calib_complete |
DDR命令初始化完成 |
app_rdy |
MIG数据接收准备好 |
app_wdf_rdy |
MIG数据接收准备好 |
app_rd_data_end |
高表示,突发读当前时钟最后一个数据 |
app_rd_data_valid |
读数据有效 |
app_rd_data[127:0] |
用户读数据 |
app_en |
MIG IP发送命令使能 |
app_wdf_wren |
用户写数据使能 |
app_wdf_end |
突发写当前时钟最后一个数据 |
error |
错误信号 |
app_cmd[2:0] |
MIG IP核操作命令,读或者写 |
app_addr[27:0] |
DDR3地址 |
app_wdf_mask[15:0] |
数据掩码 |
app_wdf_data[127:0] |
用户写数据 |
ddr3的写命令操作。
ddr3的写数据操作。
ddr3的写数据有三种情况。
写数据与写命令同一个周期。
写数据先与写命令一个周期。
写数据落后于写命令两个周期,最大两个周期。
写入过程:检查app_wdf_rdy信号为高,用户拉高app_wdf_wren给到数据。
ddr3的读数据过程。
读过程给到读命令和读数据后,等待app_rd_data_valid有效即表示读数据有效。
设计一个简单的控制器,此部分代代码仿照黑金开发板的代码。产生了几个接口,读写请求,读写地址,读写数据,读写长度。通过该接口接入外部fifo设计一个缓存空间。
//.v
// ------------------------------------------------------
// Author : i_huyi
// Last modified: 2021-01-04 09:02
// Email : [email protected]
// blog : https://www.cnblogs.com/yizifeizi/
// Filename : data_burst.v
// Description :
// ------------------------------------------------------
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 10:19:18 12/31/2020
// Design Name:
// Module Name: data_burst
// Project Name:
// Target Devices:
// Tool versions:
// Description: 把外部的burst读请求和写请求转化成DDR3ip的用户接口的所需的信号
// 和时序。
// DDR burst读流程:
// 当程序在IDLE状态接收到读请求(rd_burst_req为高)时,会向DDR3 IP用户接口发送
// 第一个数据读命令(读命令,地址,命令有效)信号。并会进入MEM_READ状态,在
// MEM_READ状态里,如果判断DDR3 IP的用户接口空闲的话,会发送剩余的数据读命令
// (地址增加),发送完成转到MEM_READ_WAIT状态。另外在这个MEM_READ状态里,还
// 需要判断DDR3IP从DDR3里读出来的数据是否有效统计读出的数据是否为读burst长度。
// 在MEM_READ_WAIT状态里读取burst长度的DDR3的数据,数据全部读出完成后进入
// READ_END状态,在返回IDLE状态。
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module data_burst
#(
parameter MEM_DATA_BITS = 128,
parameter ADDR_BITS = 28
)
(
//input rst, /*复位*/
//input mem_clk, /*接口时钟*/
input rd_burst_req, /*读请求*/
input wr_burst_req, /*写请求*/
input[9:0] rd_burst_len, /*读数据长度*/
input[9:0] wr_burst_len, /*写数据长度*/
input[ADDR_BITS - 1:0] rd_burst_addr, /*读首地址*/
input[ADDR_BITS - 1:0] wr_burst_addr, /*写首地址*/
output rd_burst_data_valid,/*读出数据有效*/
output wr_burst_data_req, /*写数据信号,请求用户提前准备好写入ddr3的数据,提前一个周期产生*/
output[MEM_DATA_BITS - 1:0] rd_burst_data, /*读出的数据*/
input[MEM_DATA_BITS - 1:0] wr_burst_data, /*写入的数据*/
output rd_burst_finish, /*读完成*/
output wr_burst_finish, /*写完成*/
output burst_finish, /*读或写完成*/
input clk,//用户时钟
input rst,//复位高有效
input init_calib_complete,//DDR命令初始化完成
input app_rdy,//MIG命令接收准备好标志
input app_wdf_rdy,//MIG数据接收准备好
input app_rd_data_end,//高表示,突发读当前时钟最后一个数据
input app_rd_data_valid,//读数据有效
input [127:0] app_rd_data,//用户读数据
output app_en,//MIG IP发送命令使能
output app_wdf_wren,//用户写数据使能
output app_wdf_end,//突发写当前时钟最后一个数据
output error,//错误信号
output [2:0] app_cmd,//MIG IP核操作命令,读或者写
output [27:0] app_addr,//DDR3地址
output [15:0] app_wdf_mask,//数据掩码
output [127:0] app_wdf_data );//用户写数据
//------------------------------------
//assign define
//------------------------------------
assign app_wdf_mask = {MEM_DATA_BITS/8{1'b0}};//掩码置0
//------------------------------------
//localparam define
//------------------------------------
localparam IDLE = 3'd0;
localparam MEM_READ = 3'd1;
localparam MEM_READ_WAIT = 3'd2;
localparam MEM_WRITE = 3'd3;
localparam MEM_WRITE_WAIT = 3'd4;
localparam READ_END = 3'd5;
localparam WRITE_END = 3'd6;
localparam MEM_WRITE_FIRST_READ = 3'd7;
//------------------------------------
//register define
//------------------------------------
reg[2:0] state;
reg[9:0] rd_addr_cnt;
reg[9:0] rd_data_cnt;
reg[9:0] wr_addr_cnt;//多少个写命令被发出
reg[9:0] wr_data_cnt;//多少个数据被发送
reg[2:0] app_cmd_r;//cmd register
reg[ADDR_BITS-1:0] app_addr_r;//command address register
reg app_en_r;
reg app_wdf_end_r;
reg app_wdf_wren_r;//写使能寄存器
//------------------------------------
//assign define
//------------------------------------
assign app_cmd = app_cmd_r;
assign app_addr = app_addr_r;
assign app_en = app_en_r;
assign app_wdf_end = app_wdf_end_r;
assign app_wdf_data = wr_burst_data;
assign app_wdf_wren = app_wdf_wren_r & app_wdf_rdy;//写使能和写有效同时有效
assign rd_burst_finish = (state == READ_END);
assign wr_burst_finish = (state == WRITE_END);
assign burst_finish = rd_burst_finish | wr_burst_finish;//读或者写完成
//读数据
assign rd_burst_data = app_rd_data;
assign rd_burst_data_valid = app_rd_data_valid;
assign wr_burst_data_req = (state == MEM_WRITE) & app_wdf_rdy ;//写状态写和有效时,写数据信号有效
//----------------------------------
//----------------------------------
always@(posedge clk or posedge rst)
begin
if(rst)
begin
app_wdf_wren_r <= 1'b0;
end
else if(app_wdf_rdy)
app_wdf_wren_r <= wr_burst_data_req;//写请求到写有效
end
always@(posedge clk or posedge rst)
begin
if(rst)
begin
state <= IDLE;
app_cmd_r <= 3'b000;
app_addr_r <= 0;
app_en_r <= 1'b0;
rd_addr_cnt <= 0;
rd_data_cnt <= 0;
wr_addr_cnt <= 0;
wr_data_cnt <= 0;
app_wdf_end_r <= 1'b0;
end
else if(init_calib_complete === 1'b1)
begin
case(state)
IDLE:
begin
if(rd_burst_req)//读请求有效
begin
state <= MEM_READ;
app_cmd_r <= 3'b001;
app_addr_r <= {rd_burst_addr,3'd0};
app_en_r <= 1'b1;
end
else if(wr_burst_req)//写请求
begin
state <= MEM_WRITE;
app_cmd_r <= 3'b000;
app_addr_r <= {wr_burst_addr,3'd0};
app_en_r <= 1'b1;
wr_addr_cnt <= 0;//写地址计数器从0开始
app_wdf_end_r <= 1'b1;
wr_data_cnt <= 0;//写数据计数器从0开始
end
end
MEM_READ://读
begin
if(app_rdy)//命令有效写地址,当到达读数据的长度的时候停止读
begin
app_addr_r <= app_addr_r +8;
if(rd_addr_cnt == rd_burst_len -1)
begin
state <= MEM_READ_WAIT;
rd_addr_cnt <= 0;
app_en_r <= 1'b0;
end
else
rd_addr_cnt <= rd_addr_cnt +1;
end
if(app_rd_data_valid)//数据有效就读输入的长度那么多个数据
begin
if(rd_data_cnt == rd_burst_len -1)
begin
rd_data_cnt <= 0;
state <= READ_END;
end
else
begin
rd_data_cnt <= rd_data_cnt +1;
end
end
end
MEM_READ_WAIT://在读状态,读命令传输完毕,但是读出来的数据会延迟输出,所以,进入读等待状态,等待读数据计数器计时完毕,完结读状态。
begin
if(app_rd_data_valid)
begin
if(rd_data_cnt == rd_burst_len -1)
begin
rd_data_cnt <= 0;
state <= READ_END;
end
else
begin
rd_data_cnt <= rd_data_cnt +1;
end
end
end
MEM_WRITE_FIRST_READ:
begin
app_en_r <= 1'b1;
state <= MEM_WRITE;
wr_data_cnt <= 0;
end
MEM_WRITE:
begin
if(app_rdy)
begin
app_addr_r <= app_addr_r +8;
if(wr_addr_cnt == wr_burst_len -1)
begin
app_wdf_end_r <= 1'b0;
app_en_r <= 1'b0;
end
else
begin
wr_addr_cnt <= wr_addr_cnt +1;
end
end
if(wr_burst_data_req)//实际app_wdf_rdy为真,写的数据会是被缓存在fifo中,当写命令有效时会依次传入,为什么不让app_wdf_rdy和app_rdy同时有效呢?他们不是同时为高的。
begin
if(wr_data_cnt == wr_burst_len -1)
begin
state <= MEM_WRITE_WAIT;
end
else
begin
wr_data_cnt <= wr_data_cnt +1;
end
end
end
READ_END:
state <= IDLE;
MEM_WRITE_WAIT://写的数据都写入进去了。但是写命令还没写进去完毕,等待写命令写完毕,结束写状态。
begin
if(app_rdy)
begin
app_addr_r <= app_addr_r + 'b1000;
if(wr_addr_cnt == wr_burst_len -1)
begin
app_wdf_end_r <= 1'b0;
app_en_r <= 1'b0;
if(app_wdf_rdy)
state <= WRITE_END;
end
else
begin
wr_addr_cnt <= wr_addr_cnt +1;
end
end
else if(~app_en_r & app_wdf_rdy)
state <= WRITE_END;
end
WRITE_END:
state <= IDLE;
default:
state <= IDLE;
endcase
end
end
endmodule
设计一个fifo缓存空间。此部分代码为一个自动产生数据的模块。将自动产生的数据写入fifo,等待数据个数达到时,写入ddr3。等待写入完成后,在从ddr3内部读出写入长度的数据。
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 10:49:53 01/18/2021
// Design Name:
// Module Name: ddr3_control
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module ddr3_control#(
parameter WR_FIFO_LEN = 8'd100,
parameter RD_FIFO_LEN = 6'd1,
parameter U_DLY = 1 )
(
//input ddr clk
input clk ,//ddr用户侧时钟
input rst ,
//input tempture clk
input wire I_clk ,//通道侧数据时钟
input wire I_rst_n ,
//input pci clk
inout wire lb_CLK ,//pci clk
//input data and vaild
//input reg[31:0] data_out ,//从通道发出来的数据
//input reg data_valid ,//通道发出的数据有效
//input rd_fifo signal
input wire rd_ddr3_rd_en,//读ddr侧rd_fifo里面的数据
output wire[31:0] rd_ddr3_rd_data,//rd_fifo读出数据
//wr_fifo cnt
output wire[5:0] wr_ddr3_rd_count,
output wire[7:0] wr_ddr3_wr_count,
//rd_fifo cnt
output wire[6:0] rd_ddr3_rd_count,
output wire[5:0] rd_ddr3_wr_count,
//input ddr signal
input wire init_calib_complete,
//ddr_brust signal
output reg rd_burst_req, /*读请求*/
output reg wr_burst_req, /*写请求*/
output reg[9:0] rd_burst_len, /*读数据长度*/
output reg[9:0] wr_burst_len, /*写数据长度*/
output reg[27:0] rd_burst_addr, /*读首地址*/
output reg[27:0] wr_burst_addr, /*写首地址*/
//写入ddr的数据
input wr_burst_data_req,
output[127:0] wr_burst_data,
//从ddr读出来的数据
input rd_burst_data_valid,
input [127:0] rd_burst_data,
//out 写ddr fifo准备好信号
output reg wr_ddr_fifo_ready,
//ddr读写完成信号
input rd_burst_finish,
input wr_burst_finish,
inout burst_finish
);
//----------------------------------------
//wire define
//-----------------------------------------
wire fifo_rst;
//wr_ddr3_fifo data
reg [31:0] wr_ddr3_fifo_din;
reg wr_ddr3_fifo_wr_en;
reg [31:0] wr_ddr3_fifo_din_buffer;
reg wr_ddr3_fifo_wr_en_buffer;
//-----------------------------------------
//reg define
//-----------------------------------------
reg cnt_interrupt;
//-----------------------------------------
reg [7:0] wr_cnt;//写入ddr的数据个数计数器
reg [7:0] rd_cnt;//读出ddr的数据个数计数器
//
reg [2:0] state;
//-----------------------------------------
//assign define
//-----------------------------------------
assign fifo_rst = ~I_rst_n;
//assign wr_ddr3_fifo_din=(data_valid==1)? data_out : 0;
//assign wr_ddr3_fifo_wr_en =data_valid;
//------------------------------------
//localparam define
//------------------------------------
localparam IDLE = 3'd0;
localparam MEM_WRITE = 3'd1;
localparam MEM_WRITE_WAIT = 3'd2;
localparam MEM_READ = 3'd3;
//-----------------------------------------
//-----------------------------------------
//
//产生写使能
always@(posedge I_clk or posedge rst)
begin
if(rst)
begin
wr_ddr3_fifo_wr_en_buffer<= 1'b0;
wr_ddr3_fifo_din_buffer <= 32'd0;
end
else if(init_calib_complete == 1'b1 && wr_ddr_fifo_ready == 1'b1)
//else if(wr_ddr_fifo_ready== 1'b1)
begin
wr_ddr3_fifo_wr_en_buffer<= 1'b1;
wr_ddr3_fifo_din_buffer <= wr_ddr3_fifo_din_buffer +1'b1;
end
else
begin
wr_ddr3_fifo_wr_en_buffer<= 1'b0;
wr_ddr3_fifo_din_buffer <= 32'b0;
end
end
always @(posedge I_clk or posedge rst)
begin
if(rst)
begin
wr_ddr3_fifo_wr_en<= 1'b0;
wr_ddr3_fifo_din <= 32'd0;
end
else
begin
wr_ddr3_fifo_wr_en <= wr_ddr3_fifo_wr_en_buffer;
wr_ddr3_fifo_din <= wr_ddr3_fifo_din_buffer;
end
end
//产生读使能
reg rd_en;
always@(posedge lb_CLK or posedge rst)
begin
if(fifo_rst)
rd_en<=1'b0;
else if(rd_ddr3_wr_count >=0)
rd_en <= 1'b1;
end
//
//产生读写请求模块
always@(posedge clk or posedge rst)
begin
if(rst)
begin
state <= IDLE;
wr_burst_req <= 1'b0;
rd_burst_req <= 1'b0;
rd_burst_len <= 10'd0;
wr_burst_len <= 10'd0;
rd_burst_addr<= 0;
wr_burst_addr<= 0;
end
else
begin
case(state)
IDLE:
begin
state <= MEM_WRITE_WAIT;
end
MEM_WRITE_WAIT:
begin
if(wr_ddr3_wr_count >= 8'd50)
begin
state <= MEM_WRITE;
wr_burst_req <= 1'b1;
rd_burst_req <= 1'b0;
//wr_burst_len <= 10'd25;
wr_burst_len <= {4'b0,wr_ddr3_rd_count};
end
end
MEM_WRITE:
begin
if(wr_burst_finish)
begin
state <= MEM_READ;
wr_burst_req <= 1'b0;
rd_burst_req <= 1'b1;
rd_burst_len <= wr_burst_len;
rd_burst_addr <= wr_burst_addr;
end
end
MEM_READ:
begin
if(rd_burst_finish)
begin
state <= IDLE;
wr_burst_req <= 1'b0;
rd_burst_req <= 1'b0;
//wr_burst_len <= 10'd25;
rd_burst_len <= 10'd0;
wr_burst_len <= 10'd0;
wr_burst_addr <= wr_burst_addr + {18'b0,rd_burst_len};
end
end
default:
state <= IDLE;
endcase
end
end
//产生ddr写入fifo 准备好信号
always @(posedge clk or posedge rst )
begin
if(rst)
begin
wr_ddr_fifo_ready <= 1'b0;
end
else if(state == MEM_WRITE_WAIT || state == MEM_WRITE || state == MEM_READ)
begin
wr_ddr_fifo_ready <= 1'b1;
end
else
wr_ddr_fifo_ready <= 1'b0;
end
//对写入ddr的数据个数计数。
always @(posedge clk or posedge rst)
begin
if(rst)
wr_cnt <= 8'd0;
else if(state == MEM_WRITE)
begin
if(wr_burst_data_req)
begin
wr_cnt <= wr_cnt +8'd1;
end
else if(wr_burst_finish)
wr_cnt <= 8'd0;
end
else
wr_cnt <= 8'd0;
end
//对读出ddr的数据个数计数
always@(posedge clk or posedge rst )
begin
if(rst)
begin
rd_cnt <= 8'd0;
end
else if(state == MEM_READ)
begin
if(rd_burst_data_valid)
begin
rd_cnt <= rd_cnt +8'd1;
end
else if (rd_burst_finish)
rd_cnt <= 8'd0;
end
else
rd_cnt <= 8'd0;
end
//wr_ddr3_fifo
wr_ddr3_fifo u_wr_ddr3_fifo (
.rst (rst), // input rst
.wr_clk (I_clk), // input wr_clk
.rd_clk (clk), // input rd_clk
.din (wr_ddr3_fifo_din), // input [31 : 0] din
.wr_en (wr_ddr3_fifo_wr_en), // input wr_en
.rd_en (wr_burst_data_req), // input rd_en
.dout (wr_burst_data), // output [127 : 0] dout
.full (full), // output full
.empty (empty), // output empty
.rd_data_count (wr_ddr3_rd_count), // output [5 : 0] rd_data_count
.wr_data_count (wr_ddr3_wr_count) // output [7 : 0] wr_data_count
);
//rd_ddr3_fifo
rd_ddr3_fifo u_rd_ddr3_fifo (
.rst (rst), // input rst
.wr_clk (clk), // input wr_clk
.rd_clk (lb_CLK), // input rd_clk
.din (rd_burst_data), // input [127 : 0] din
.wr_en (rd_burst_data_valid), // input wr_en
.rd_en (rd_ddr3_rd_en), // input rd_en
.dout (rd_ddr3_rd_data), // output [31 : 0] dout
.full (), // output full
.empty (), // output empty
.rd_data_count (rd_ddr3_rd_count), // output [6 : 0] rd_data_count
.wr_data_count (rd_ddr3_wr_count) // output [5 : 0] wr_data_count
);
/*
//wr_ddr3_fifo的读使能
always @(posedge clk or posedge rst)
begin
if(rst)
fifo_rd_en <= 1'b0;
else if(init_calib_complete)
begin
if(cnt_interrupt)
begin
fifo_rd_en <= 1'b0;
end
else
fifo_rd_en <= 1'b1;
end
else
fifo_rd_en <= 1'b0;
end
//利用wr_ddr3_fifo的计数器产生使能中断信号,wr_ddr3_ffio写入100个数据,就产生
//计数器中断信号,等待wr_ddr3_fifo读取数据计数器小于1个结束中断。
always @(posedge clk or posedge rst)
begin
if(rst)
begin
cnt_interrupt <= 1'b0;
end
else if(wr_ddr3_wr_count >= WR_FIFO_LEN)
cnt_interrupt <= 1'b1;
else if(wr_ddr3_rd_count <= RD_FIFO_LEN)
cnt_interrupt <= 1'b0;
else
;
end
*/
/*
//产生ddr控制器读写需求模块,此模式为写入ddr完成自己开启读取模式。
always @(posedge clk or posedge rst )
begin
if(rst)
begin
rd_burst_req <= 1'd0;
wr_burst_req <= 1'd0;
end
else if(wr_ddr3_wr_count >= WR_FIFO_LEN)
wr_burst_req <= 1'd1;
else if(wr_burst_finish)
begin
wr_burst_req <= 1'd0;
rd_burst_req <= 1'd1;
end
else if(rd_burst_finish)
rd_burst_req <= 1'd0;
else
begin
wr_burst_req <= 1'd0;
rd_burst_req <= 1'd0;
end
end
*/
endmodule
最后启动后的效果如下。
状态机到达状态后启动写入ddr3。数据为0,1,2...
状态机到达后启动读出ddr3。读出的数据为0,1,2...
此部分的代码仅仅完成对ddr3的IP的简单控制。代码里面也做了详细的注释。
ddr3的部分就结束了。