XILINX关于DDR3的IP学习

编程入门 行业动态 更新时间:2024-10-24 22:24:35

<a href=https://www.elefans.com/category/jswz/34/1767552.html style=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的一类。

  1. 基本原理

内存芯片的内存芯片内部的核心时钟基本上是保持一致的,都是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。

  1. 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。

  1. 寻址和容量计算

寻址:DDR3寻址流程是先指定Bank地址,再指定行地址,然后指列地址最终的确寻址单元。可以想象成一个Excel表格,每新建一个表格就是一个bank,每个表格有行和列对应ddr3的行地址和列地址。

容量计算:ddr3芯片的容量计算。加入单个ddr3拥有行地址线(ROW)14根,列地址线(Column)10根,bank数量为8个,数据位宽为(DQ7-DQ0)。

容量计算公式为:

那假如我们需要一个容量为1GB的内存条,则需要用到8个这样的DDR3内存芯片。每个芯片包含8根数据线(DQ7-DQ0)数据总位宽为64bit,这样正好用了一个RANK。

  1. DDR3的数据传输操作和内部状态

关于更多的ddr芯片测接口和ddr硬件原理可以参考ddr芯片手册。例如我们这里使用这一款。

MT41J128M16HA-125可以直接去官网下载他的代码。

  1. xlinx的mig IP的使用

接下来看看xilinx关于ddr的IP mig这部分。为了简化ddr的控制流程,xilinx 设计mig IP来帮助我们控制ddr芯片。

  1. IP的建立与仿真

配置界面

点击user Guide可以下载mig IP手册。里面的内容非常重要。

这里有基本保持默认,mig支持AXI模式,在此模式下数据的传输更加简单。

兼容的FPGA型号。

选择ddr3 sdram。

时钟频率400MHZ,输入核心频率则为100mhz。芯片数据位宽为16位,时钟倍频后上下沿都传输数据,时钟关系为4:1,即用户数据位宽位16*4*2=128bit。

选择ddr3输入时钟为200mhz。

选择系统时钟是单端输入还是差分输入,选择参考时钟为系统时钟。

这一页默认就好。

选择做仿真使用默认管脚。

不上板子,系统默认不分配。

选择下面这个的话,就需要你分配一下管脚。一般从ucf自动导入看看合适不。

默认位置就好。

你的设置总结。

一路next后来到这里。生成ip。

  1. 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的仿真库。

设置仿真库文件。运行仿真。

可以见到成功拉高初始化成功信号。

  1. 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的写数据有三种情况。

  1. 写数据与写命令同一个周期。

  1. 写数据先与写命令一个周期。

  1. 写数据落后于写命令两个周期,最大两个周期。

写入过程:检查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
  1. xlinx的mig IP的控制接口仿真

最后启动后的效果如下。

状态机到达状态后启动写入ddr3。数据为0,1,2...

状态机到达后启动读出ddr3。读出的数据为0,1,2...

此部分的代码仅仅完成对ddr3的IP的简单控制。代码里面也做了详细的注释。

ddr3的部分就结束了。

更多推荐

XILINX关于DDR3的IP学习

本文发布于:2024-02-08 13:43:51,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1674164.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:XILINX   IP

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!