XILINX关于DDR3的IP学习"/>
XILINX关于DDR3的IP学习
平台:ise14.7,modelsim 10.4
芯片:XC1A100T
关于ddr3的mig的学习。使用xilinx官方提供的IP核。
官方资料下载地址:
ug586_7Series_MIS.pdf • 查看器 • 文档门户 (xilinx)
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。
DDR3技术细节
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。
DDR3的数据传输操作和内部状态
关于更多的ddr芯片测接口和ddr硬件原理可以参考ddr芯片手册。例如我们这里使用这一款。
MT41J128M16HA-125可以直接去官网下载他的代码。
xlinx的mig IP的使用
接下来看看xilinx关于ddr的IP mig这部分。为了简化ddr的控制流程,xilinx 设计mig IP来帮助我们控制ddr芯片。
IP的建立与仿真
配置界面
点击user Guide可以下载mig IP手册。里面的内容非常重要。
这里有基本保持默认,mig支持AXI模式,在此模式下数据的传输更加简单。
兼容的FPGA型号。
选择ddr3 sdram。
时钟频率400MHZ,输入核心频率则为100mhz。芯片数据位宽为16位,时钟倍频后上下沿都传输数据,时钟关系为4:1,即用户数据位宽位16*4*2=128bit。
选择ddr3输入时钟为200mhz。
选择系统时钟是单端输入还是差分输入,选择参考时钟为系统时钟。
这一页默认就好。
选择做仿真使用默认管脚。
不上板子,系统默认不分配。
选择下面这个的话,就需要你分配一下管脚。一般从ucf自动导入看看合适不。
默认位置就好。
你的设置总结。
一路next后来到这里。生成ip。
xlinx的mig 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的仿真库。
设置仿真库文件。运行仿真。
可以见到成功拉高初始化成功信号。
xlinx的mig IP的接口控制
感兴趣的朋友可以去看看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 : i_huyi@qq
// blog : /
// 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)
beginif(rst)beginapp_wdf_wren_r <= 1'b0;endelse if(app_wdf_rdy)app_wdf_wren_r <= wr_burst_data_req;//写请求到写有效
endalways@(posedge clk or posedge rst)
beginif(rst)beginstate <= 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;endelse if(init_calib_complete === 1'b1)begincase(state)IDLE:beginif(rd_burst_req)//读请求有效beginstate <= MEM_READ;app_cmd_r <= 3'b001;app_addr_r <= {rd_burst_addr,3'd0};app_en_r <= 1'b1;endelse if(wr_burst_req)//写请求beginstate <= 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开始endendMEM_READ://读beginif(app_rdy)//命令有效写地址,当到达读数据的长度的时候停止读beginapp_addr_r <= app_addr_r +8;if(rd_addr_cnt == rd_burst_len -1)beginstate <= MEM_READ_WAIT;rd_addr_cnt <= 0;app_en_r <= 1'b0;endelserd_addr_cnt <= rd_addr_cnt +1;endif(app_rd_data_valid)//数据有效就读输入的长度那么多个数据beginif(rd_data_cnt == rd_burst_len -1)beginrd_data_cnt <= 0;state <= READ_END;endelsebeginrd_data_cnt <= rd_data_cnt +1;endendendMEM_READ_WAIT://在读状态,读命令传输完毕,但是读出来的数据会延迟输出,所以,进入读等待状态,等待读数据计数器计时完毕,完结读状态。beginif(app_rd_data_valid)beginif(rd_data_cnt == rd_burst_len -1)beginrd_data_cnt <= 0;state <= READ_END;endelsebeginrd_data_cnt <= rd_data_cnt +1;endendendMEM_WRITE_FIRST_READ:beginapp_en_r <= 1'b1;state <= MEM_WRITE;wr_data_cnt <= 0;endMEM_WRITE:beginif(app_rdy)beginapp_addr_r <= app_addr_r +8;if(wr_addr_cnt == wr_burst_len -1)beginapp_wdf_end_r <= 1'b0;app_en_r <= 1'b0;endelsebeginwr_addr_cnt <= wr_addr_cnt +1;endendif(wr_burst_data_req)//实际app_wdf_rdy为真,写的数据会是被缓存在fifo中,当写命令有效时会依次传入,为什么不让app_wdf_rdy和app_rdy同时有效呢?他们不是同时为高的。beginif(wr_data_cnt == wr_burst_len -1)beginstate <= MEM_WRITE_WAIT;endelsebeginwr_data_cnt <= wr_data_cnt +1;endendendREAD_END:state <= IDLE;MEM_WRITE_WAIT://写的数据都写入进去了。但是写命令还没写进去完毕,等待写命令写完毕,结束写状态。beginif(app_rdy)beginapp_addr_r <= app_addr_r + 'b1000;if(wr_addr_cnt == wr_burst_len -1)beginapp_wdf_end_r <= 1'b0;app_en_r <= 1'b0;if(app_wdf_rdy)state <= WRITE_END;endelsebeginwr_addr_cnt <= wr_addr_cnt +1;endendelse if(~app_en_r & app_wdf_rdy)state <= WRITE_END;endWRITE_END:state <= IDLE;default:state <= IDLE;endcaseend
endendmodule
设计一个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)
beginif(rst)beginwr_ddr3_fifo_wr_en_buffer<= 1'b0;wr_ddr3_fifo_din_buffer <= 32'd0;endelse if(init_calib_complete == 1'b1 && wr_ddr_fifo_ready == 1'b1)//else if(wr_ddr_fifo_ready== 1'b1)beginwr_ddr3_fifo_wr_en_buffer<= 1'b1;wr_ddr3_fifo_din_buffer <= wr_ddr3_fifo_din_buffer +1'b1;endelsebeginwr_ddr3_fifo_wr_en_buffer<= 1'b0;wr_ddr3_fifo_din_buffer <= 32'b0;end
end
always @(posedge I_clk or posedge rst)
beginif(rst)beginwr_ddr3_fifo_wr_en<= 1'b0;wr_ddr3_fifo_din <= 32'd0;endelsebeginwr_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)
beginif(fifo_rst)rd_en<=1'b0;else if(rd_ddr3_wr_count >=0)rd_en <= 1'b1;
end//
//产生读写请求模块
always@(posedge clk or posedge rst)
beginif(rst)beginstate <= 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;endelsebegincase(state)IDLE:beginstate <= MEM_WRITE_WAIT;endMEM_WRITE_WAIT:beginif(wr_ddr3_wr_count >= 8'd50)beginstate <= 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};endendMEM_WRITE:beginif(wr_burst_finish)beginstate <= MEM_READ;wr_burst_req <= 1'b0;rd_burst_req <= 1'b1;rd_burst_len <= wr_burst_len;rd_burst_addr <= wr_burst_addr;endendMEM_READ:beginif(rd_burst_finish)beginstate <= 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};endenddefault:state <= IDLE;endcaseend
end
//产生ddr写入fifo 准备好信号
always @(posedge clk or posedge rst )
beginif(rst)beginwr_ddr_fifo_ready <= 1'b0;endelse if(state == MEM_WRITE_WAIT || state == MEM_WRITE || state == MEM_READ)beginwr_ddr_fifo_ready <= 1'b1;endelsewr_ddr_fifo_ready <= 1'b0;end//对写入ddr的数据个数计数。
always @(posedge clk or posedge rst)
beginif(rst)wr_cnt <= 8'd0;else if(state == MEM_WRITE)beginif(wr_burst_data_req)beginwr_cnt <= wr_cnt +8'd1;endelse if(wr_burst_finish)wr_cnt <= 8'd0;endelsewr_cnt <= 8'd0;
end
//对读出ddr的数据个数计数
always@(posedge clk or posedge rst )
beginif(rst)beginrd_cnt <= 8'd0;endelse if(state == MEM_READ)beginif(rd_burst_data_valid)beginrd_cnt <= rd_cnt +8'd1;endelse if (rd_burst_finish)rd_cnt <= 8'd0;endelserd_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)
beginif(rst)fifo_rd_en <= 1'b0;else if(init_calib_complete)beginif(cnt_interrupt)beginfifo_rd_en <= 1'b0;endelsefifo_rd_en <= 1'b1;endelsefifo_rd_en <= 1'b0;
end//利用wr_ddr3_fifo的计数器产生使能中断信号,wr_ddr3_ffio写入100个数据,就产生
//计数器中断信号,等待wr_ddr3_fifo读取数据计数器小于1个结束中断。
always @(posedge clk or posedge rst)
beginif(rst)begincnt_interrupt <= 1'b0;endelse 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 )
beginif(rst)beginrd_burst_req <= 1'd0;wr_burst_req <= 1'd0;endelse if(wr_ddr3_wr_count >= WR_FIFO_LEN)wr_burst_req <= 1'd1;else if(wr_burst_finish)beginwr_burst_req <= 1'd0;rd_burst_req <= 1'd1;endelse if(rd_burst_finish)rd_burst_req <= 1'd0;else beginwr_burst_req <= 1'd0;rd_burst_req <= 1'd0;end
end
*/endmodule
xlinx的mig IP的控制接口仿真
最后启动后的效果如下。
状态机到达状态后启动写入ddr3。数据为0,1,2...
状态机到达后启动读出ddr3。读出的数据为0,1,2...
此部分的代码仅仅完成对ddr3的IP的简单控制。代码里面也做了详细的注释。
ddr3的部分就结束了。
更多推荐
XILINX关于DDR3的IP学习
发布评论