MIG IP核介绍

在Xilinx系列的FPGA中,为了方便用户对DDR进行读写,官方提供了用于访问DDR的IP核MIG,全称为Memory Interface Generator,具体可参考赛灵思官方文档参考手册:ug586(7 Series Devices Memory Interface Solutions v4.1)。下图是MIG IP核的架构,从图中可以看出,MIG主要有面向用户的端口和面向DDR的端口,用户通过使用MIG能够通过用户端口的信号,来完成对DDR SDRAM的访问,达到简化操作的目的。

在本文中,我们仅关注某些面向用户的端口,即以下端口:
clk,rst
app_addr,app_cmd,app_en,app_rdy
app_wdf_wren,app_wdf_end,app_wdf_rdy,app_wdf_data
app_rd_data,app_rd_data_valid
其中,第一行信号为全局的时钟和复位信号,第二行信号为命令通道信号,用于发出读写命令,第三行信号为写数据通道信号,最后一行信号为读数据通道信号。

命令通道


如上图所示,app_cmd用于指定是何命令,3’b000为写命令,而3’b001为读命令,app_addr为相应的读写地址,命令只会在app_en和app_rdy同时为高时,才会被接受。

读数据通道

如上图所示,读数据的时序比较简单,当读命令发出后,过若干时钟周期,app_rd_data_valid信号便会拉高,此时对应的app_rd_data就是读出的数据。

写数据通道


上图是一张MIG控制器的写时序图和官方对这几种写操作的解释,通过官方文档的介绍我们可以知道写入的数据可以在写命令给出之前,之时或者之后给出,但是在写命令之后给出的写数据不能超过两个时钟周期。在写命令之前给出写数据则没有这些限制。之所以能过这样操作,是因为在IP核内部有写入数据的FIFO能够对数据实现缓冲。
在本文中,我们采用1这种方式的数据写入

DDR3 MIG实验

在本实验中,我们实现了一个接口转换:将MIG用户侧的app_*接口信号转化为AXI4接口信号,以供用户更方便的进行调用。
转化的代码如下:

`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/01/03 10:38:32
// Design Name:
// Module Name: mig2axi4
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module mig2axi4(
//AXI4接口
//全局信号
input logic ACLK,
input logic ARESETn,
//读地址通道
input logic [31:0] ARADDR,
input logic [7:0] ARLEN,
input logic [2:0] ARSIZE,               //2^7=128
input logic [1:0] ARBURST,
input logic [2:0] ARPROT,
input logic ARVALID,
output logic ARREADY,
//读数据通道
output logic RVALID,
output logic [127:0] RDATA,
output logic [1:0] RRESP,
output logic RLAST,
input logic RREADY,
//写地址通道
input logic [31:0] AWADDR,
input logic [7:0] AWLEN,
input logic [2:0] AWSIZE,
input logic [1:0] AWBURST,
input logic [2:0] AWPROT,
input logic AWVALID,
output logic AWREADY,
//写数据通道
input logic [127:0]WDATA,
input logic [15:0] WSTRB,
input logic WLAST,
input logic WVALID,
output logic WREADY,
//写应答通道
output logic [1:0] BRESP,
output logic BVALID,
input logic BREADY,
//MIG侧接口
input  logic ui_clk,
input  logic ui_clk_sync_rst,
input  logic init_calib_complete,
input  logic app_rdy,
input  logic app_wdf_rdy,
input  logic app_rd_data_valid,
input  logic [127:0]   app_rd_data,
output logic [27:0]    app_addr,
output logic app_en,
output logic app_wdf_wren,
output logic app_wdf_end,
output logic [2:0]     app_cmd,               //3'b000为写数据,3'b001为读数据
output logic [127:0]   app_wdf_data);logic [31:0] rd_base_addr;                       //地址每次递增128/16=8
logic [8:0]  rd_len;
logic [31:0] wr_base_addr;
logic [8:0] wr_len;
logic [127:0] rd_buffer [0:255];                  //读数据缓存
logic [31:0] rd_cnt;                              //数据缓存中数据个数
logic [31:0] rd_cmd_cnt;                          //读命令个数
logic [31:0] wr_cnt;
logic [31:0] send_cnt;                            //数据发送个数
typedef enum bit [7:0] { IDLE,READ,WRITE
} State;
State cur_state,next_state;
//cur_state
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)cur_state<=IDLE;
elsecur_state<=next_state;
//next_state
always_comb
begincase(cur_state)IDLE:if(ARVALID)next_state=READ;else if(AWVALID)next_state=WRITE;elsenext_state=IDLE;WRITE:if(BVALID&&BREADY&&BRESP==2'b00)next_state=IDLE;elsenext_state=WRITE;READ:if(RVALID&&RREADY&&RLAST)          //最后一个数据读取完成next_state=IDLE;elsenext_state=READ;default:next_state=IDLE;endcase
end
/********************************************************读数据***************************************************/
//ARREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)ARREADY<=0;
else if(ARVALID&&~ARREADY)ARREADY<=1;
else if(ARREADY&&ARVALID)                       //读地址通道握手完成ARREADY<=0;
//rd_base_addr
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)rd_base_addr<=0;
else if(ARVALID&&ARREADY)rd_base_addr<=ARADDR;
//rd_len
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)rd_len<=0;
else if(ARVALID&&ARREADY)rd_len<=ARLEN+1;
//app_cmd
always_comb
if(cur_state==WRITE)app_cmd=3'b000;
else if(cur_state==READ)app_cmd=3'b001;
elseapp_cmd=3'b000;
//app_en
always_comb
case(cur_state)IDLE:app_en=0;READ:if(rd_cmd_cnt<rd_len&&app_rdy)                 //app_rdy为高且读命令次数还未到rd_lenapp_en=1;elseapp_en=0;WRITE:if(app_rdy&&app_wdf_rdy&&WVALID)               //DDR准备好接受数据,并且WDATA有效时,拉高app_en                 app_en=1;elseapp_en=0;default:app_en=0;
endcase
//app_addr
always_ff@(posedge ACLK)
if(ARVALID&&ARREADY)app_addr<=ARADDR;
else if(AWVALID&&AWREADY)app_addr<=AWADDR;
else if(app_en&&app_rdy)                               //写数据成功或者读命令发送成功app_addr<=app_addr+8;
//rd_cmd_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)rd_cmd_cnt<=0;
else if(cur_state==READ&&app_en&&app_rdy)      //发出一次读命令rd_cmd_cnt<=rd_cmd_cnt+1;
else if(cur_state==IDLE)rd_cmd_cnt<=0;
//rd_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)rd_cnt<=0;
else if(app_rd_data_valid)rd_cnt<=rd_cnt+1;
else if(cur_state==IDLE)rd_cnt<=0;
//rd_buffer
always_ff@(posedge ACLK)
if(app_rd_data_valid)rd_buffer[rd_cnt]<=app_rd_data;                                                //数据缓存
//send_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)send_cnt<=0;
else if(ARVALID&&ARREADY)send_cnt<=0;
else if(rd_cnt==rd_len&&RVALID&&RREADY)                                         //数据缓存完毕send_cnt<=send_cnt+1;
else if(cur_state==IDLE)send_cnt<=0;
//RVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)RVALID<=0;
else if(rd_cnt==rd_len&&RVALID&&RREADY&&RLAST)                    //之后send_cnt==rd_len                        RVALID<=0;
else if(rd_cnt==rd_len&&send_cnt<rd_len)                          RVALID<=1;
//RDATA
always_combRDATA=rd_buffer[send_cnt];
//RLAST
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)RLAST<=0;
else if(send_cnt==rd_len-2&&RVALID&&RREADY)                        //倒数第二个数据发送完成,拉高RLAST,表明下一个数据是最后一个数据RLAST<=1;
else if(send_cnt==rd_len-1&&RVALID&&RREADY&&RLAST)                 //最后一个数据发送完成,拉低RLASTRLAST<=0;
/***************************************************************************写数据*******************************************************************/
//awready
always_ff @(posedge ACLK)
begin    if(~ARESETn)AWREADY<=0;else if(AWVALID&&~AWREADY)AWREADY<=1;else if(AWVALID&&AWREADY)                //写地址通道握手完成AWREADY<=0;
end
//wr_len
always_ff@(posedge ACLK)
if(AWVALID&&AWREADY)wr_len<=AWLEN+1;
//wr_base_addr
always_ff@(posedge ACLK)
if(AWVALID&&AWREADY)wr_base_addr<=AWADDR;
//app_wdf_wren                                   若app_rdy和app_wdf_rdy以及WVALID均为高,则拉高app_wdf_wren和wready         (WVALID为高说明数据有效,app_rdy和app_wdf_rdy为高说明DDR可写入数据)
always_comb
if(cur_state==WRITE&&app_rdy&&app_wdf_rdy&&WVALID)app_wdf_wren=1;
elseapp_wdf_wren=0;
//wready
assign WREADY=app_wdf_wren;
//app_wdf_end
assign app_wdf_end=app_wdf_wren;
//app_wdf_data
assign app_wdf_data=WDATA;
//BRESP
assign BRESP=2'b00;         //OK
//BVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)BVALID<=0;
else if(WVALID&&WREADY&&WLAST)            //最后一个数据写入完成后拉高BVALIDBVALID<=1;
else if(BVALID&&BREADY&&BRESP==2'b00)     //写响应通道握手完成BVALID<=0;
//BID
endmodule

我们通过MIG IP提供的DDR3仿真模型进行仿真,如下图所示,只需添加ddr3_model.svddr3_model_parameters.vh文件至仿真平台即可。


下面的代码用于产生AXI4测试信号:
axi4_master.sv

`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/01/03 12:56:25
// Design Name:
// Module Name: axi4_master
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module axi4_master(
input logic ACLK,
input logic ARESETn,
//读地址通道
output logic [31:0] ARADDR,
output logic [7:0] ARLEN,
output logic ARVALID,
input logic ARREADY,
//读数据通道
input logic [127:0] RDATA,
input logic [1:0] RRESP,
input logic RLAST,
input logic RVALID,
output logic RREADY,
//写地址通道
output logic [31:0] AWADDR,
output logic [7:0] AWLEN,
output logic AWVALID,
input logic AWREADY,
//写数据通道
output logic [127:0] WDATA,
output logic [15:0] WSTRB,
output logic WLAST,
output logic WVALID,
input logic WREADY,
//写应答通道
input logic [1:0] BRESP,
input logic BVALID,
output logic BREADY,
//初始化完成信号
input  logic init_calib_complete  );
parameter WRITE_BASE_ADDR = 256;
parameter READ_BASE_ADDR = 256;
parameter TEST_LEN = 32-1;
logic init_calib_complete_d1;
logic start;
logic [31:0] wr_cnt;
logic [31:0] rd_cnt;
//start
assign start=init_calib_complete&(~init_calib_complete_d1);
//init_calib_complete_d1
always_ff@(posedge ACLK)init_calib_complete_d1<=init_calib_complete;
//写16个数据
//AWADDR
assign AWADDR=WRITE_BASE_ADDR;
//AWLEN
assign AWLEN=TEST_LEN;
//AWVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)AWVALID<=0;
else if(start)AWVALID<=1;
else if(AWVALID&&AWREADY)AWVALID<=0;
//WDATA
always_combWDATA=wr_cnt;
//WSTRB
assign WSTRB=16'hffff;
//WLAST
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)WLAST<=0;
else if(WVALID&&WREADY&&wr_cnt==TEST_LEN+1-2)            //倒数第二个数据写入完成WLAST<=1;
else if(WVALID&&WREADY&&WLAST)                         //最后一个数据传输完成WLAST<=0;
//WVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)WVALID<=0;
else if(AWVALID&&AWREADY)WVALID<=1;
else if(WVALID&&WREADY&&WLAST)WVALID<=0;
//BREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)BREADY<=0;
else if(AWVALID&&AWREADY)BREADY<=1;
else if(BVALID&&BREADY&&BRESP==2'b00)BREADY<=0;
//wr_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)wr_cnt<=0;
else if(start)wr_cnt<=0;
else if(WVALID&&WREADY)wr_cnt<=wr_cnt+1;
//读16个数据
//ARADDR
assign ARADDR=READ_BASE_ADDR;
//ARLEN
assign  ARLEN=TEST_LEN;
//ARVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)ARVALID<=0;
else if(BVALID&&BREADY)ARVALID<=1;
else if(ARVALID&&ARREADY)ARVALID<=0;
//rready
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)RREADY<=0;
else if(ARVALID&&ARREADY)RREADY<=1;
else if(RVALID&&RREADY&&RLAST)RREADY<=0;endmodule

整个工程的顶层文件top.sv为:

`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/01/03 14:22:32
// Design Name:
// Module Name: top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module top(
input              sys_clk,         //ϵͳʱ��
input              sys_rst_n,       //��λ,����Ч
// DDR3
inout [15:0]       ddr3_dq,         //DDR3 ����
inout [1:0]        ddr3_dqs_n,      //DDR3 dqs��
inout [1:0]        ddr3_dqs_p,      //DDR3 dqs��
output [13:0]      ddr3_addr,       //DDR3 ��ַ
output [2:0]       ddr3_ba,         //DDR3 banck ѡ��
output             ddr3_ras_n,      //DDR3 ��ѡ��
output             ddr3_cas_n,      //DDR3 ��ѡ��
output             ddr3_we_n,       //DDR3 ��дѡ��
output             ddr3_reset_n,    //DDR3 ��λ
output [0:0]       ddr3_ck_p,       //DDR3 ʱ����
output [0:0]       ddr3_ck_n,       //DDR3 ʱ�Ӹ�
output [0:0]       ddr3_cke,        //DDR3 ʱ��ʹ��
output [0:0]       ddr3_cs_n,       //DDR3 Ƭѡ
output [1:0]       ddr3_dm,         //DDR3_dm
output [0:0]       ddr3_odt         //DDR3_odt);//axi接口
logic ACLK;
logic ARESETn;
//读地址通道
logic [31:0] ARADDR;
logic [7:0] ARLEN;
logic ARVALID;
logic ARREADY;
//读数据通道
logic [127:0] RDATA;
logic [1:0] RRESP;
logic RLAST;
logic RVALID;
logic RREADY;
//写地址通道
logic [31:0] AWADDR;
logic [7:0] AWLEN;
logic AWVALID;
logic AWREADY;
//写数据通道
logic [127:0] WDATA;
logic [15:0] WSTRB;
logic WLAST;
logic WVALID;
logic WREADY;
//写应答通道
logic [1:0] BRESP;
logic BVALID;
logic BREADY;
//mig接口
logic app_rdy;
logic app_wdf_rdy;
logic app_rd_data_valid;
logic [127:0] app_rd_data;
logic [27:0] app_addr;
logic app_en;
logic app_wdf_wren;
logic app_wdf_end;
logic [2:0] app_cmd;               //3'b000为写数据,3'b001为读数据
logic [127:0] app_wdf_data;
logic init_calib_complete;
//
logic clk_200;
logic ui_clk;
logic ui_clk_sync_rst;
logic locked;
//
assign ACLK=ui_clk;
assign ARESETn=~ui_clk_sync_rst;
//ddr侧信号
// logic ddr3_addr                      (ddr3_addr),   // output [14:0] ddr3_addr
// logic ddr3_ba                        (ddr3_ba),     // output [2:0]  ddr3_ba
// logic ddr3_cas_n                     (ddr3_cas_n),  // output        ddr3_cas_n
// logic ddr3_ck_n                      (ddr3_ck_n),   // output [0:0]  ddr3_ck_n
// logic ddr3_ck_p                      (ddr3_ck_p),   // output [0:0]  ddr3_ck_p
// logic ddr3_cke                       (ddr3_cke),    // output [0:0]  ddr3_cke
// logic ddr3_ras_n                     (ddr3_ras_n),  // output        ddr3_ras_n
// logic ddr3_reset_n                   (ddr3_reset_n),// output        ddr3_reset_n
// logic ddr3_we_n                      (ddr3_we_n),   // output        ddr3_we_n
// logic ddr3_dq                        (ddr3_dq),     // inout [31:0]  ddr3_dq
// logic ddr3_dqs_n                     (ddr3_dqs_n),  // inout [3:0]   ddr3_dqs_n
// logic ddr3_dqs_p                     (ddr3_dqs_p),  // inout [3:0]   ddr3_dqs_p
// logic ddr3_cs_n                      (ddr3_cs_n),   // output [0:0]  ddr3_cs_n
// logic ddr3_dm                        (ddr3_dm),     // output [3:0]  ddr3_dm
// logic ddr3_odt                       (ddr3_odt),    // output [0:0]  ddr3_odt//模块例化
axi4_master U1(
.ACLK(ACLK),
.ARESETn(ARESETn),
//读地址通道
.ARADDR(ARADDR),
.ARLEN(ARLEN),
.ARVALID(ARVALID),
.ARREADY(ARREADY),
//读数据通道
.RVALID(RVALID),
.RDATA(RDATA),
.RRESP(RRESP),
.RLAST(RLAST),
.RREADY(RREADY),
//写地址通道
.AWADDR(AWADDR),
.AWLEN(AWLEN),
.AWVALID(AWVALID),
.AWREADY(AWREADY),
//写数据通道
.WDATA(WDATA),
.WSTRB(WSTRB),
.WLAST(WLAST),
.WVALID(WVALID),
.WREADY(WREADY),
//写应答通道
.BRESP(BRESP),
.BVALID(BVALID),
.BREADY(BREADY),
//初始化完成信号
.init_calib_complete(init_calib_complete)  );mig2axi4 U2(
//AXI4接口
//全局信号
.ACLK(ACLK),
.ARESETn(ARESETn),
//读地址通道
.ARADDR(ARADDR),
.ARLEN(ARLEN),
.ARSIZE(),               //2^7=128
.ARBURST(),
.ARPROT(),
.ARVALID(ARVALID),
.ARREADY(ARREADY),
//读数据通道
.RVALID(RVALID),
.RDATA(RDATA),
.RRESP(RRESP),
.RLAST(RLAST),
.RREADY(RREADY),
//写地址通道
.AWADDR(AWADDR),
.AWLEN(AWLEN),
.AWSIZE(),
.AWBURST(),
.AWPROT(),
.AWVALID(AWVALID),
.AWREADY(AWREADY),
//写数据通道
.WDATA(WDATA),
.WSTRB(WSTRB),
.WLAST(WLAST),
.WVALID(WVALID),
.WREADY(WREADY),
//写应答通道
.BRESP(BRESP),
.BVALID(BVALID),
.BREADY(BREADY),
//MIG侧接口
.ui_clk(ui_clk),
.ui_clk_sync_rst(ui_clk_sync_rst),
.init_calib_complete(init_calib_complete),
.app_rdy(app_rdy),
.app_wdf_rdy(app_wdf_rdy),
.app_rd_data_valid(app_rd_data_valid),
.app_rd_data(app_rd_data),
.app_addr(app_addr),
.app_en(app_en),
.app_wdf_wren(app_wdf_wren),
.app_wdf_end(app_wdf_end),
.app_cmd(app_cmd),               //3'b000为写数据,3'b001为读数据
.app_wdf_data(app_wdf_data));mig_7series_0 u_mig_7series_0 (// Memory interface ports.ddr3_addr                      (ddr3_addr),   // output [14:0]    ddr3_addr.ddr3_ba                        (ddr3_ba),     // output [2:0] ddr3_ba.ddr3_cas_n                     (ddr3_cas_n),  // output     ddr3_cas_n.ddr3_ck_n                      (ddr3_ck_n),   // output [0:0]    ddr3_ck_n.ddr3_ck_p                      (ddr3_ck_p),   // output [0:0] ddr3_ck_p.ddr3_cke                       (ddr3_cke),    // output [0:0] ddr3_cke.ddr3_ras_n                     (ddr3_ras_n),  // output        ddr3_ras_n.ddr3_reset_n                   (ddr3_reset_n),// output      ddr3_reset_n.ddr3_we_n                      (ddr3_we_n),   // output        ddr3_we_n.ddr3_dq                        (ddr3_dq),     // inout [31:0] ddr3_dq.ddr3_dqs_n                     (ddr3_dqs_n),  // inout [3:0]    ddr3_dqs_n.ddr3_dqs_p                     (ddr3_dqs_p),  // inout [3:0] ddr3_dqs_p.init_calib_complete            (init_calib_complete), // init_calib_complete.ddr3_cs_n                      (ddr3_cs_n),   // output [0:0]   ddr3_cs_n.ddr3_dm                        (ddr3_dm),     // output [3:0] ddr3_dm.ddr3_odt                       (ddr3_odt),    // output [0:0]   ddr3_odt// Application interface ports.app_addr                       (app_addr),    // input [28:0]    app_addr.app_cmd                        (app_cmd),     // input [2:0]   app_cmd.app_en                         (app_en),      // input          app_en.app_wdf_data                   (app_wdf_data),// input [255:0] app_wdf_data.app_wdf_end                    (app_wdf_end), // input         app_wdf_end.app_wdf_wren                   (app_wdf_wren),// input            app_wdf_wren.app_rd_data                    (app_rd_data), // output [255:0]app_rd_data.app_rd_data_end                (app_rd_data_end),  // output        app_rd_data_end.app_rd_data_valid              (app_rd_data_valid),  // output      app_rd_data_valid.app_rdy                        (app_rdy),     // output       app_rdy.app_wdf_rdy                    (app_wdf_rdy), // output     app_wdf_rdy.app_sr_req                     (1'b0),            // input         app_sr_req.app_ref_req                    (1'b0),            // input          app_ref_req.app_zq_req                     (1'b0),            // input         app_zq_req.app_sr_active                  (app_sr_active),// output     app_sr_active.app_ref_ack                    (app_ref_ack),  // output      app_ref_ack.app_zq_ack                     (app_zq_ack),   // output        app_zq_ack.ui_clk                         (ui_clk),       // output     ui_clk.ui_clk_sync_rst                (ui_clk_sync_rst), // output       ui_clk_sync_rst.app_wdf_mask                   (31'b0),        // input [31:0]    app_wdf_mask// System Clock Ports.sys_clk_i                      (clk_200),// Reference Clock Ports.clk_ref_i                      (clk_200),.sys_rst                        (sys_rst_n)     // input         sys_rst);//PLLģ��
clk_wiz_0 u_clk_wiz_0(// Clock out ports.clk_out1(clk_200),     // output clk_out1// Status and control signals.reset(1'b0),           // input resetn.locked(locked),        // output locked// Clock in ports.clk_in1(sys_clk));        endmodule

测试平台文件编写如下,只需例化top模块和ddr3仿真模型模块即可:
test_tb.sv

`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2021/12/29 20:23:18
// Design Name:
// Module Name: test_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module test_tb();
parameter T=20;//
logic led;
logic sys_clk;
logic sys_rst_n;
//
wire   [13:0]       ddr3_addr;wire   [2:0]      ddr3_ba;wire            ddr3_cas_n;wire   [0:0]     ddr3_ck_n;wire   [0:0]      ddr3_ck_p;wire   [0:0]      ddr3_cke;wire           ddr3_ras_n;wire             ddr3_reset_n;wire           ddr3_we_n;wire  [15:0]      ddr3_dq;wire  [1:0]     ddr3_dqs_n;wire  [1:0]      ddr3_dqs_p;wire   [0:0]     ddr3_cs_n;wire   [1:0]      ddr3_dm;wire   [0:0]        ddr3_odt;
//sys_clk
initial beginsys_clk=0;forever begin#(T/2) sys_clk=~sys_clk;end
end
//sys_rst_n
initial beginsys_rst_n=0;#(10*T)sys_rst_n=1;
end//
// ddr3_rw_top U(
//    .sys_clk(sys_clk),         //
//    .sys_rst_n(sys_rst_n),       //
//     // DDR3
//    .ddr3_dq(ddr3_dq),         //
//    .ddr3_dqs_n(ddr3_dqs_n),      //
//    .ddr3_dqs_p(ddr3_dqs_p),      //
//    .ddr3_addr(ddr3_addr),       //
//    .ddr3_ba(ddr3_ba),         //
//    .ddr3_ras_n(ddr3_ras_n),      //
//    .ddr3_cas_n(ddr3_cas_n),      //
//    .ddr3_we_n(ddr3_we_n),       //
//    .ddr3_reset_n(ddr3_reset_n),    //
//    .ddr3_ck_p(ddr3_ck_p),       //
//    .ddr3_ck_n(ddr3_ck_n),       //
//    .ddr3_cke(ddr3_cke),        //
//    .ddr3_cs_n(ddr3_cs_n),       //
//    .ddr3_dm(ddr3_dm),         //
//    .ddr3_odt(ddr3_odt),        //
//    .led(led)              //
//     );
top U(
.sys_clk(sys_clk),         //ϵͳʱ��
.sys_rst_n(sys_rst_n),       //��λ,����Ч
// DDR3
.ddr3_dq(ddr3_dq),         //DDR3 ����
.ddr3_dqs_n(ddr3_dqs_n),      //DDR3 dqs��
.ddr3_dqs_p(ddr3_dqs_p),      //DDR3 dqs��
.ddr3_addr(ddr3_addr),       //DDR3 ��ַ
.ddr3_ba(ddr3_ba),         //DDR3 banck ѡ��
.ddr3_ras_n(ddr3_ras_n),      //DDR3 ��ѡ��
.ddr3_cas_n(ddr3_cas_n),      //DDR3 ��ѡ��
.ddr3_we_n(ddr3_we_n),       //DDR3 ��дѡ��
.ddr3_reset_n(ddr3_reset_n),    //DDR3 ��λ
.ddr3_ck_p(ddr3_ck_p),       //DDR3 ʱ����
.ddr3_ck_n(ddr3_ck_n),       //DDR3 ʱ�Ӹ�
.ddr3_cke(ddr3_cke),        //DDR3 ʱ��ʹ��
.ddr3_cs_n(ddr3_cs_n),       //DDR3 Ƭѡ
.ddr3_dm(ddr3_dm),         //DDR3_dm
.ddr3_odt(ddr3_odt)         //DDR3_odt
);ddr3_model V
(.rst_n   (ddr3_reset_n),.ck      (ddr3_ck_p),.ck_n    (ddr3_ck_n),.cke     (ddr3_cke),.cs_n    (ddr3_cs_n),.ras_n   (ddr3_ras_n),.cas_n   (ddr3_cas_n),.we_n    (ddr3_we_n),.dm_tdqs (ddr3_dm),.ba      (ddr3_ba),.addr    (ddr3_addr),.dq      (ddr3_dq),.dqs     (ddr3_dqs_p),.dqs_n   (ddr3_dqs_n),.tdqs_n  (),.odt     (ddr3_odt));endmodule

下图是整个工程的RTL视图,它很好的揭示了上述代码之间的关系:

结果分析

AXI4写数据波形图

可以看到,当app_rdy、app_wdf_rdy(表明ddr已经准备好接收数据)以及WVALID信号(表示要写的数据已经有效)同时为高时,app_en、app_wdf_wren、WREADY信号均被拉高,开始写入一个数据。

AXI4读数据波形图

写命令


如图所示,app_cmd为3’b001,app_en,app_rdy均为高,表示该读命令已被接受,而app_addr为要读的数据的地址。

读数据


如图所示,MIG将读取的数据先存入缓存中,然后再将缓存中的数据通过AXI4的读数据通道发送给主机。(通过使用FIFO可以进一步增大读数据的效率)

DDR3 MIG IP核仿真与学习相关推荐

  1. Xilinx DDR3 —— MIG IP核的读写仿真(APP接口)

    在上一篇中Xilinx DDR3 -- MIG IP核的配置(APP接口),已经观看了Xilinx官方提供的MIG IP核读写例程仿真波形,本着学习的目的,本篇开始自己编写MIG IP核读写程序,用于 ...

  2. FPGA中DDR3 MIG ip核使用说明

    此篇是我在学习中做的归纳与总结,其中如果存在版权或知识错误请直接联系我,欢迎留言. PS:本着知识共享的原则,此篇博客可以随意转载,但请标明出处! 目录 1.DDR3工作原理 简介: DDR基础操作步 ...

  3. XIlinx MIG 控制DDR3 SO-DIMM内存条(三):MIG IP核仿真与调试过程

    之前写这个系列的时候忘记上传了,刚好五一补一下. 文章目录 1 MIG IP核的接口 1.1 AXI4 slave 接口 1.2 Upsizing 1.3 User Interface 1.3.1 C ...

  4. Xilinx DDR3 —— MIG IP核的原理(APP接口)

    DDR3 SDRAM(Double-Data-Rate Three Synchronous Dynamic Random Access Memory)是 DDR SDRAM的第三代产品,DDR SDR ...

  5. Xilinx vivado DDR3 MIG IP核中系统时钟、参考时钟解释及各个时钟的功能详解

    注:在使用xilinx的MIG 核时,会有许多关于时钟的配置,时间长了容易混淆,特意记录一下为以后快速回忆,如有错误请留言指正. 0.先贴出来DDR3的时钟树,这个图展示了参考时钟设置的强制规定. 1 ...

  6. DDR3 MIG IP核解决方案

    信号 方向 描述 app_addr [ADDR_WIDTH - 1:0] 输入 该输入指示当前请求的地址. app_cmd [2:0] 输入 该输入选择当前请求的命令. app_en 输入 这是app ...

  7. XIlinx MIG 控制DDR3 SO-DIMM内存条(二):MIG IP核学习

    目录 1 简介 2 IP核自定义 2.1 设置IP核参数 2.1.1 Pin Compatible FPGAs 2.1.2 Memory Selection 2.1.3 Controller Opti ...

  8. 快速上手Xilinx DDR3 IP核(2)----MIG IP核的官方例程与读写测试模块(Native接口)

    写在前面 接上一篇文章(配置MIG IP过程): 快速上手Xilinx DDR3 IP核(1)----MIG IP核的介绍及配置(Native接口) DDR3系列文章: 快速上手Xilinx DDR3 ...

  9. 基于Vivado MIG IP核的DDR3读写实验(top_rom_ddr/ddr_top)

    一.前言 关于Vivado MIG IP核详细配置可以参考我之前的文章:基于Vivado MIG IP核的DDR3控制器(DDR3_CONTROL) 关于MIG IP核的用户端的接口时序可以参考这篇文 ...

  10. Xilinx FPGA平台DDR3设计保姆式教程(3)MIG IP核使用教程及DDR读写时序

    干货来了,用DDR搬砖,只需要会用IP就好,Xilinx官方YYDS! ---------------------------------------------------------------- ...

最新文章

  1. c - 字符串的拼接.
  2. 爬过这 6 个坡,你就能对 Linux 操作系统了如指掌
  3. Python回顾与整理1:Python基础
  4. 《Cracking the Coding Interview》——第18章:难题——题目3
  5. 《看聊天记录都学不会C语言?太菜了吧》(15)你学了一节课的函数我5分钟搞定了,还很熟
  6. spring解析配置文件(三)
  7. [bash] 打包某目录(可以是绝对路径)下的指定扩展名的文件
  8. 图形学 射线相交算法_计算机图形学中的阴极射线管(CRT)
  9. 03Oracle Database 物理结构,逻辑结构
  10. java两种不同单例模式_关于Java里的两种单例模式
  11. linux桌面版本安装MSDM,Parallel_s desktop怎么安装linux系统
  12. Emacs学习笔记(二)
  13. 误差分析(python)
  14. vue引入字体文件踩坑
  15. 马尔科夫模型系列文章(二)——隐马尔科夫模型
  16. MYMPS蚂蚁分类信息系统源码,5.9E多城市全开源版本
  17. tex 表格内容换行_如何让latex表格中一个单元格的文字换行
  18. arduino 操纵杆_使用Arduino Leonardo开发板制作操纵杆游戏控制器
  19. 精益求精, ePub 电子书制作手记
  20. Translation[VERTEBRA-FOCUSED LANDMARK DETECTION FOR SCOLIOSIS ASSESSMENT]——2021.6.18

热门文章

  1. 逆向脱壳附加数据处理
  2. velocity 语法简记
  3. RISC-V_GD32VF103-开发环境搭建和使用
  4. php+分割文本文件,python实现:将文本文件分割成多个小文本文件(php也可实现)...
  5. 使用STL标准模板库实现的个人通讯录
  6. win11游戏窗口化如何设置 windows11游戏窗口化的设置方法
  7. 如何做一个淘宝客(前期为自己省钱)
  8. Wireshark抓包获取QQ好友IP
  9. DNF私服商业服搭建教程
  10. dnf服务器地址修改,修改dnf单机服务器地址