DDR3(MIG核配置官方demoFPGA代码实现及仿真)

news/2024/11/17 10:38:31/

  由于直接对 DDR3 进行控制很复杂,因此一般使用 MIG IP 来实现,同时为了更简单地使用 MIG IP,我们采用 AXI4 总线协议进行控制。下面首先介绍 MIG IP 的配置,然后看看官方 demo (里面包含一个仿真要用到的 DDR3 模型)及其仿真结果,最后进行我们自己的控制代码实现。

MIG IP 生成

  在 IP Catalog 里搜索 MIG,如下

在这里插入图片描述

第一步里,勾选 AXI4 Interface 选项,使用 AXI4 接口

在这里插入图片描述

下一步是选择 FPGA 型号,读者自行选择自己的 FPGA 型号;下一步是选择控制器类型,我们直接选择 DDR3 SDRAM;这几步很简单,就不放图了。再下一步,Controller Options,这里要重点介绍下

在这里插入图片描述

首先配置 DDR3 的工作时钟,这个时钟也就是 DDR3_CLK_P/N,下一个 PHY to Controller Clock Ratio 是 FPGA 与 MIG 间通信使用的时钟(ui_clk)与 DDR3 时钟的比值,笔者使用 200MHz,因此这里设置为 2:1;Memory Type 需读者按照自己的 DDR 型号进行选择;Data Width 是 DDR3 用到的数据位宽,比如笔者用到 4 片 DDR,每片位宽 16bit,菊花链连接,因此这里需要设为 64。

  下一步,这里的 Data Width 是 FPGA 与 MIG 通信用到的数据位宽,为方便起见,我使用了与 DDR 数据同位宽;下一个是设置读写优先级的,TDM 是读写同级,也可修改为读/写优先、循环读写等。

在这里插入图片描述

  下一步,Input Clock Period 是设置 sys_clk_i 的频率,MIG IP 会使用这个时钟生成 DDR3_CK 信号以及供用户使用的 ui_clk,所有关于 MIG 的用户操作均应在 ui_clk 下进行;最下面的 Memory Address Mapping Selection 是 MIG 与 DDR 进行读写通信时的地址写入顺序。

在这里插入图片描述

下一步,System Clock 设为 No Buffer,因为我们用到的 sys_clk_i 是从 FPGA 内部提供的,如果是从外部引脚提供,则需要修改这里(有单引脚时钟,也有差分时钟信号);参考时钟直接使用 sys_clk_i;System Reset Polarity 设置 sys_rst 的极性,这里我设为低电平有效。

在这里插入图片描述

下一步是设置引脚阻抗;再下一步,勾选 Fixed Pin Out;再下一步,这里配置 DDR3 的引脚,可以手动配置也可以 read XDC 来配置,然后 Validate 一下,如果通过了,就可以下一步了(不 validate 那个 next 无法点击)。

在这里插入图片描述

  下一步,由于这三个信号我均做为 FPGA 内部信号,因此都 No connect

在这里插入图片描述

再之后就是 summary 啥的,一路 next 到底就行。

  • 注意事项

  在使用 MIG IP 时,mmcm_locked 信号指示是否稳定给出 ui_clk,为高表示给出了稳定的 ui_clk;init_calib_complete 信号表示会否完成 DDR3 的初始化,为高表示完成初始化,在这之后才可以进行 DDR3 的读写。

  注意 MIG IP 的 app_sr_req、app_ref_req、app_zq_req 要置零,否则无法完成 DDR 初始化,init_calib_complete 将无法拉高。

  此外,MIG IP 有三个 reset 信号,分别是 sys_rst、ui_clk_sync_rst 和 aresetn 。ui_clk_sync_rst 是同步于 ui_clk 的 sys_rst,高电平有效;但 MIG 并不会因为 sys_rst 而 reset,而是通过 aresetn 进行 reset 的,且 aresetn 应当同步于 ui_clk。因此应当如下书写三者的关系

always @(posedge ui_clk) beginaresetn				<= ~ui_clk_sync_rst;
end

官方 demo

  在生成的 MIG IP 上右击,Open IP Example Design,会新建一个名为 mig_7series_0_ex.xpr 的工程,打开工程,可以看到一个顶层文件 example_top.v 和一个仿真文件 sim_tb_top.v

在这里插入图片描述

可以直接运行仿真,结果如下

在这里插入图片描述

在工程文件夹下, ./imports 文件夹中,有两个文件,ddr3_model.sv 和 ddr3_model_parameters.vh,前者是 ddr3 的模型,引用了后边这个 parameter 文件,parameter 文件里是关于 ddr3 模型的参数配置,在 ddr3_model 中修改 `define 值,可以配置 ddr3_model 的各类参数。后面仿真我们自己写的控制代码就要用到这个 DDR3 模型文件。

自己的FPGA实现

  MIG IP 用到 AXI 总线协议,因此建议读者首先对该总线协议进行初步了解,具体可见我之前的文章。这里也推荐一个知乎大佬写的 AXI 协议介绍,链接在此。

  其余不多说,代码如下,该模块自动完成从 W_FIFO 向 DDR 的写入,以及从 DDR 读数据到 R_FIFO,用户只需要读写两个 FIFO 即可

/* * file			: DDR3_top.v* author		: 今朝无言* Lab			: WHU-EIS-LMSWE* date			: 2023-04-21* version		: v1.0* description	: DDR3控制模块*/
module DDR3_top(
input				clk_200M,
input				rst_n,
output				rst_busy,//--------------------ddr3------------------------
inout		[63:0]	ddr3_dq,				//DQ,4片 x16 DDR的数据线output		[14:0]	ddr3_addr,				//Address
output		[2:0]	ddr3_ba,				//Bank Addressinout		[7:0]	ddr3_dqs_p,				//DQ Select,0,2,4,6分别为四片DDR的DQSL(Lower Byte),
inout		[7:0]	ddr3_dqs_n,				//1,3,5,7分别为四片DDR的DQSU(Upper Byte)
//Output with read data. Edge-aligned with read data.
//Input with write data. Center-aligned to write data.output		[0:0]	ddr3_ck_p,				//4片DR3共用ck、cke、odt、cs信号,故[0:0]
output		[0:0]	ddr3_ck_n,
//differential clock inputs. All control and address input signals are sampled 
//on the crossing of the positive edge of CK and the negative edge of CK#output		[7:0]	ddr3_dm,				//Input Data Mask,0,2,4,6为DML,1,3,5,7为DMU
output		[0:0]	ddr3_cke,				//Clock Enable
output		[0:0]	ddr3_cs_n,				//Chip Select
output				ddr3_ras_n,				//Row Address Enable
output				ddr3_cas_n,				//Column Address Enable
output				ddr3_we_n,				//Write Enable
output		[0:0]	ddr3_odt,				//On-die termination enable
output				ddr3_reset_n,//-------------FPGA FIFO Control-------------------
input				wr_en,					//高电平有效
input		[63:0]	wrdat,
output				full,					//fifo_w fullinput				rd_en,					//高电平有效
output		[63:0]	rddat,
output				empty					//fifo_r empty
);
//本方案采用4片 MT41K256M16TW-107 芯片,每片 256M * 16bit = 512MB 容量
//8个Bank,故 BA 为 3 位;行地址用到全部的 15 根地址线,列地址用到 log2(256M/2^15/2^3)=10 根地址线parameter	AXI_ID		= 4'h00;	//读写事务ID
parameter	DATA_NUM	= 32;		//一次突发传输的数据个数,1~256localparam	AXI_LEN		= DATA_NUM - 1'b1;
localparam	FIFO_LEN	= 1024;		//w_fifo、r_fifo的长度//----------------------------------state define-----------------------------------------
localparam	S_IDLE		= 8'h01;	//等待初始化
localparam	S_ARB		= 8'h02;	//判决接下来进行WR还是RD
localparam	S_WR_ADDR	= 8'h04;	//写地址
localparam	S_WR_DATA	= 8'h08;	//写数据
localparam	S_WR_RESP	= 8'h10;	//写回复
localparam	S_RD_ADDR	= 8'h20;	//读地址
localparam	S_RD_DATA	= 8'h40;	//读数据
localparam	S_RD_RESP	= 8'h80;	//读回复//---------------------------------------------------------------------------------------
reg		[7:0]	state		= S_IDLE;
reg		[7:0]	next_state	= S_IDLE;
//尽管 AXI 的读、写可以独立,然而 DDR 读写是分时复用,因此这里的读写也必须分时进行//FIFO
wire			w_fifo_full;
wire			w_fifo_empty;
wire			r_fifo_full;
wire			r_fifo_empty;reg				w_fifo_rden		= 1'b0;
reg				r_fifo_wren		= 1'b0;wire			fifo_rst;wire	[9:0]	w_fifo_rddat_cnt;
wire	[9:0]	r_fifo_wrdat_cnt;wire			w_fifo_wr_rst_busy;
wire			w_fifo_rd_rst_busy;
wire			r_fifo_wr_rst_busy;
wire			r_fifo_rd_rst_busy;wire			w_fifo_rst_busy;
wire			r_fifo_rst_busy;//Application interface ports
wire			ui_clk;					//MIG输出的时钟,一切关于mig的操作均应在此时钟域下进行
wire			ui_clk_sync_rst;		//mig输出的rst信号,同步于ui_clk,高电平有效
wire			mmcm_locked;
reg				aresetn;
wire			init_calib_complete;	//指示MIG是否完成初始化wire			app_sr_req;
wire			app_ref_req;
wire			app_zq_req;
wire			app_sr_active;
wire			app_ref_ack;
wire			app_zq_ack;//Slave Interface Write Address Ports
wire	[3:0]	s_axi_awid;
reg		[30:0]	s_axi_awaddr;			//4*512MB=2GB,对应 2^31 Byte,故 AXI 地址线位宽为 31
wire	[7:0]	s_axi_awlen;
wire	[2:0]	s_axi_awsize;
wire	[1:0]	s_axi_awburst;
wire	[0:0]	s_axi_awlock;
wire	[3:0]	s_axi_awcache;
wire	[2:0]	s_axi_awprot;
wire	[3:0]	s_axi_awqos;
reg				s_axi_awvalid;
wire			s_axi_awready;//Slave Interface Write Data Ports
wire	[63:0]	s_axi_wdata;
wire	[7:0]	s_axi_wstrb;
reg				s_axi_wlast;
reg				s_axi_wvalid;
wire			s_axi_wready;//Slave Interface Write Response Ports
wire	[3:0]	s_axi_bid;
wire	[1:0]	s_axi_bresp;
wire			s_axi_bvalid;
reg				s_axi_bready;//Slave Interface Read Address Ports
wire	[3:0]	s_axi_arid;
reg		[30:0]	s_axi_araddr;
wire	[7:0]	s_axi_arlen;
wire	[2:0]	s_axi_arsize;
wire	[1:0]	s_axi_arburst;
wire	[0:0]	s_axi_arlock;
wire	[3:0]	s_axi_arcache;
wire	[2:0]	s_axi_arprot;
wire	[3:0]	s_axi_arqos;
reg				s_axi_arvalid;
wire			s_axi_arready;//Slave Interface Read Data Ports
wire	[3:0]	s_axi_rid;
wire	[63:0]	s_axi_rdata;
wire	[1:0]	s_axi_rresp;
wire			s_axi_rlast;
wire			s_axi_rvalid;
reg				s_axi_rready;//ddr3读写请求
reg				wr_ddr3_req;
reg				rd_ddr3_req;//突发读写的已传输数据计数
reg		[8:0]	data_cnt;//------------------------------------write FIFO------------------------------------------
//异步FIFO    采用 First Word Fall Through 模式    1024*64
fifo_generator_DDR_W fifo_w(.rst			(fifo_rst),.wr_clk			(clk_200M),.rd_clk			(ui_clk),.din			(wrdat),.wr_en			(wr_en),.rd_en			(w_fifo_rden),.dout			(s_axi_wdata),.full			(w_fifo_full),.empty			(w_fifo_empty),.rd_data_count	(w_fifo_rddat_cnt),		//仿真显示,w_fifo_rddat_cnt 和 r_fifo_wrdat_cnt 计数不可信,...IP 在做什么!!!.wr_data_count	(),.wr_rst_busy	(w_fifo_wr_rst_busy),.rd_rst_busy	(w_fifo_rd_rst_busy)
);//------------------------------------read FIFO-------------------------------------------
//异步FIFO
fifo_generator_DDR_R fifo_r(.rst			(fifo_rst),.wr_clk			(ui_clk),.rd_clk			(clk_200M),.din			(s_axi_rdata),.wr_en			(r_fifo_wren),.rd_en			(rd_en),.dout			(rddat),.full			(r_fifo_full),.empty			(r_fifo_empty),.rd_data_count	(),.wr_data_count	(r_fifo_wrdat_cnt),.wr_rst_busy	(r_fifo_wr_rst_busy),.rd_rst_busy	(r_fifo_rd_rst_busy)
);//----------------------------------MIG IP, AXI4-----------------------------------------
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 [63:0]		ddr3_dq.ddr3_dqs_n				(ddr3_dqs_n),			// inout [7:0]		ddr3_dqs_n.ddr3_dqs_p				(ddr3_dqs_p),			// inout [7:0]		ddr3_dqs_p.ddr3_cs_n				(ddr3_cs_n), 			// output [0:0]		ddr3_cs_n.ddr3_dm				(ddr3_dm),  			// output [7:0]		ddr3_dm.ddr3_odt				(ddr3_odt),  			// output [0:0]		ddr3_odt// Application interface ports.ui_clk					(ui_clk),				// output			ui_clk.ui_clk_sync_rst		(ui_clk_sync_rst),		// output			ui_clk_sync_rst.mmcm_locked			(mmcm_locked),			// output			mmcm_locked.aresetn				(aresetn),				// input			aresetn.init_calib_complete	(init_calib_complete),	// output			init_calib_complete.app_sr_req				(app_sr_req),			// input			app_sr_req.app_ref_req			(app_ref_req),			// input			app_ref_req.app_zq_req				(app_zq_req),			// 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// Slave Interface Write Address Ports.s_axi_awid				(s_axi_awid),			// input [3:0]		s_axi_awid.s_axi_awaddr			(s_axi_awaddr),			// input [30:0]		s_axi_awaddr.s_axi_awlen			(s_axi_awlen),			// input [7:0]		s_axi_awlen.s_axi_awsize			(s_axi_awsize),			// input [2:0]		s_axi_awsize.s_axi_awburst			(s_axi_awburst),		// input [1:0]		s_axi_awburst.s_axi_awlock			(s_axi_awlock),			// input [0:0]		s_axi_awlock.s_axi_awcache			(s_axi_awcache),		// input [3:0]		s_axi_awcache.s_axi_awprot			(s_axi_awprot),			// input [2:0]		s_axi_awprot.s_axi_awqos			(s_axi_awqos),			// input [3:0]		s_axi_awqos.s_axi_awvalid			(s_axi_awvalid),		// input			s_axi_awvalid.s_axi_awready			(s_axi_awready),		// output			s_axi_awready// Slave Interface Write Data Ports.s_axi_wdata			(s_axi_wdata),			// input [63:0]		s_axi_wdata.s_axi_wstrb			(s_axi_wstrb),			// input [7:0]		s_axi_wstrb.s_axi_wlast			(s_axi_wlast),			// input			s_axi_wlast.s_axi_wvalid			(s_axi_wvalid),			// input			s_axi_wvalid.s_axi_wready			(s_axi_wready),			// output			s_axi_wready// Slave Interface Write Response Ports.s_axi_bid				(s_axi_bid),			// output [3:0]		s_axi_bid.s_axi_bresp			(s_axi_bresp),			// output [1:0]		s_axi_bresp.s_axi_bvalid			(s_axi_bvalid),			// output			s_axi_bvalid.s_axi_bready			(s_axi_bready),			// input			s_axi_bready// Slave Interface Read Address Ports.s_axi_arid				(s_axi_arid),			// input [3:0]		s_axi_arid.s_axi_araddr			(s_axi_araddr),			// input [30:0]		s_axi_araddr.s_axi_arlen			(s_axi_arlen),			// input [7:0]		s_axi_arlen.s_axi_arsize			(s_axi_arsize),			// input [2:0]		s_axi_arsize.s_axi_arburst			(s_axi_arburst),		// input [1:0]		s_axi_arburst.s_axi_arlock			(s_axi_arlock),			// input [0:0]		s_axi_arlock.s_axi_arcache			(s_axi_arcache),		// input [3:0]		s_axi_arcache.s_axi_arprot			(s_axi_arprot),			// input [2:0]		s_axi_arprot.s_axi_arqos			(s_axi_arqos),			// input [3:0]		s_axi_arqos.s_axi_arvalid			(s_axi_arvalid),		// input			s_axi_arvalid.s_axi_arready			(s_axi_arready),		// output			s_axi_arready// Slave Interface Read Data Ports.s_axi_rid				(s_axi_rid),			// output [3:0]		s_axi_rid.s_axi_rdata			(s_axi_rdata),			// output [63:0]	s_axi_rdata.s_axi_rresp			(s_axi_rresp),			// output [1:0]		s_axi_rresp.s_axi_rlast			(s_axi_rlast),			// output			s_axi_rlast.s_axi_rvalid			(s_axi_rvalid),			// output			s_axi_rvalid.s_axi_rready			(s_axi_rready),			// input			s_axi_rready// System Clock Ports.sys_clk_i				(clk_200M),				// input sys_clk_i 200M.sys_rst				(rst_n)					// input sys_rst
);//---------------------------------------FSM----------------------------------------------
always @(posedge ui_clk or posedge ui_clk_sync_rst) beginif(ui_clk_sync_rst) beginstate <= S_IDLE;endelse beginstate <= next_state;end
endalways @(*) begincase(state)S_IDLE: beginif(mmcm_locked && init_calib_complete) beginnext_state	<= S_ARB;endelse beginnext_state	<= S_IDLE;endendS_ARB: beginif(wr_ddr3_req) beginnext_state	<= S_WR_ADDR;endelse if(rd_ddr3_req && (s_axi_araddr != s_axi_awaddr)) begin	//DDR3不空,才可读取next_state	<= S_RD_ADDR;endelse beginnext_state	<= S_ARB;endendS_WR_ADDR: beginif(s_axi_awvalid && s_axi_awready) beginnext_state	<= S_WR_DATA;endelse beginnext_state	<= S_WR_ADDR;endendS_WR_DATA: beginif(data_cnt >= DATA_NUM) beginnext_state	<= S_WR_RESP;endelse beginnext_state	<= S_WR_DATA;endendS_WR_RESP: beginif(s_axi_bvalid && s_axi_bready) beginnext_state	<= S_ARB;endelse beginnext_state	<= S_WR_RESP;endendS_RD_ADDR: beginif(s_axi_arvalid && s_axi_arready) beginnext_state	<= S_RD_DATA;endelse beginnext_state	<= S_RD_ADDR;endendS_RD_DATA: beginif(data_cnt >= DATA_NUM) begin	//m_axi_rready && m_axi_rvalid && m_axi_rlastnext_state	<= S_RD_RESP;endelse beginnext_state	<= S_RD_DATA;endendS_RD_RESP: beginnext_state	<= S_ARB;enddefault: beginnext_state	<= S_IDLE;endendcase
end//-------------------------------------Control--------------------------------------------
assign	s_axi_awid		= AXI_ID;
assign	s_axi_arid		= AXI_ID;assign	s_axi_awlen		= AXI_LEN;
assign	s_axi_arlen		= AXI_LEN;assign	s_axi_awsize	= 3'd3;		//每个数据的大小为2^awsize = 2^3 = 8Bytes = 64bit
assign	s_axi_awburst	= 2'b01;	//突发传输模式为INCR,地址一直增加,递增的值为(2^Burst_size)
assign	s_axi_awlock	= 1'b0; 	//正常传输,非独占传输
assign	s_axi_awcache	= 4'b0000;	//指明了总线中的存储类型
assign	s_axi_awprot	= 3'b000;	//指明访问是否被允许的信号
assign	s_axi_awqos		= 4'b0000;
assign	s_axi_wstrb		= 8'hff;	//写字节通道选通assign	s_axi_arsize	= 3'd3;
assign	s_axi_arburst	= 2'b01;	//突发传输模式为INCR
assign	s_axi_arlock	= 1'b0;
assign	s_axi_arcache	= 4'b0000;
assign	s_axi_arprot	= 3'b000;
assign	s_axi_arqos		= 4'b0000;assign	full			= w_fifo_full;
assign	empty			= r_fifo_empty;always @(posedge ui_clk) beginaresetn				<= ~ui_clk_sync_rst;
endassign	fifo_rst		= ~mmcm_locked;
//fifo的rst必须同时存在rd_clk和wr_clk,否则将初始化失败,一直处在rst_busy阶段assign	app_sr_req		= 1'b0;		//此三者要置零,否则 refresh DDR
assign	app_ref_req		= 1'b0;
assign	app_zq_req		= 1'b0;assign	w_fifo_rst_busy	= w_fifo_wr_rst_busy | w_fifo_rd_rst_busy;
assign	r_fifo_rst_busy	= r_fifo_wr_rst_busy | r_fifo_rd_rst_busy;assign	rst_busy		= w_fifo_rst_busy | r_fifo_rst_busy | (~init_calib_complete);//-----------s_axi_awvalid--------------
always @(*) begincase(state)S_WR_ADDR: begins_axi_awvalid	<= 1'b1;enddefault: begins_axi_awvalid	<= 1'b0;endendcase
end//-----------s_axi_wvalid---------------
always @(*) begincase(state)S_WR_DATA: beginif(~w_fifo_empty && data_cnt < DATA_NUM) begins_axi_wvalid	<= 1'b1;endelse begins_axi_wvalid	<= 1'b0;endenddefault: begins_axi_wvalid	<= 1'b0;endendcase
end//-----------s_axi_wlast---------------
always @(*) begincase(state)S_WR_DATA: beginif(data_cnt == DATA_NUM - 1) begins_axi_wlast	<= 1'b1;endelse begins_axi_wlast	<= 1'b0;endenddefault: begins_axi_wlast	<= 1'b0;endendcase
end//-----------s_axi_bready---------------
always @(*) begincase(state)S_WR_RESP: begins_axi_bready	<= 1'b1;enddefault: begins_axi_bready	<= 1'b0;endendcase
end//-----------s_axi_arvalid--------------
always @(*) begincase(state)S_RD_ADDR: begins_axi_arvalid	<= 1'b1;enddefault: begins_axi_arvalid	<= 1'b0;endendcase
end//-----------s_axi_rready---------------
always @(*) begincase(state)S_RD_DATA: beginif(~r_fifo_full && data_cnt < DATA_NUM) begins_axi_rready	<= 1'b1;endelse begins_axi_rready	<= 1'b0;endendS_RD_RESP: begins_axi_rready	<= 1'b1;enddefault: begins_axi_rready	<= 1'b0;endendcase
end//------------w_fifo_rden---------------
always @(*) begincase(state)S_WR_DATA: beginw_fifo_rden		<= s_axi_wvalid & s_axi_wready;enddefault: beginw_fifo_rden		<= 1'b0;endendcase
end//------------r_fifo_wren---------------
always @(*) begincase(state)S_RD_DATA: beginr_fifo_wren		<= s_axi_rready & s_axi_rvalid;enddefault: beginr_fifo_wren		<= 1'b0;endendcase
end//-------------data_cnt-----------------
always @(posedge ui_clk) begincase(state)S_IDLE, S_ARB: begindata_cnt	<= 9'd0;endS_WR_DATA: beginif(s_axi_wvalid && s_axi_wready) begindata_cnt	<= data_cnt + 1'b1;endelse begindata_cnt	<= data_cnt;endendS_RD_DATA: beginif(s_axi_rvalid && s_axi_rready) begindata_cnt	<= data_cnt + 1'b1;endelse begindata_cnt	<= data_cnt;endenddefault: begindata_cnt	<= data_cnt;endendcase
end//------------s_axi_awaddr--------------
always @(posedge ui_clk) begincase(state)S_IDLE: begins_axi_awaddr	<= 31'd0;endS_WR_RESP: beginif(s_axi_bvalid && s_axi_bready) begins_axi_awaddr	<= s_axi_awaddr + DATA_NUM * 8;		//s_axi_awaddr为字节地址,每次写NUM个64bit数据end														//超出最大范围后自动回到0else begins_axi_awaddr	<= s_axi_awaddr;endenddefault: begins_axi_awaddr	<= s_axi_awaddr;endendcase
end//------------s_axi_araddr--------------
always @(posedge ui_clk) begincase(state)S_IDLE: begins_axi_araddr	<= 31'd0;endS_RD_RESP: beginif(s_axi_rvalid && s_axi_rready) begins_axi_araddr	<= s_axi_araddr + DATA_NUM * 8;endelse begins_axi_awaddr	<= s_axi_awaddr;endenddefault: begins_axi_araddr	<= s_axi_araddr;endendcase
end//------------wr_ddr3_req---------------
always @(posedge ui_clk) begincase(state)S_ARB: beginif(w_fifo_rddat_cnt >= DATA_NUM) beginwr_ddr3_req		<= 1'b1;			//w_FIFO中数据足够一次突发传输,发起写请求endelse beginwr_ddr3_req		<= 1'b0;endenddefault: beginwr_ddr3_req		<= 1'b0;endendcase
end//------------rd_ddr3_req---------------
always @(posedge ui_clk) begincase(state)S_ARB: beginif((FIFO_LEN - r_fifo_wrdat_cnt) > DATA_NUM) beginrd_ddr3_req		<= 1'b1;			//r_FIFO中空闲位置足够一次突发传输,发起读请求endelse beginrd_ddr3_req		<= 1'b0;endenddefault: beginrd_ddr3_req		<= 1'b0;endendcase
endendmodule

testbench 如下

`timescale 100ps/100psmodule DDR3_tb();reg		clk_200M	= 1'b1;
always #25 beginclk_200M	<= ~clk_200M;
endreg					rst_n;
wire				rst_busy;//--------------------ddr3------------------------
wire		[63:0]	ddr3_dq;			//DQ,4片 x16 DDR的数据线wire		[14:0]	ddr3_addr;			//Address
wire		[2:0]	ddr3_ba;			//Bank Addresswire		[7:0]	ddr3_dqs_p;			//DQ Select,0,2,4,6分别为四片DDR的DQSL(Lower Byte),
wire		[7:0]	ddr3_dqs_n;			//1,3,5,7分别为四片DDR的DQSU(Upper Byte)
//Output with read data. Edge-aligned with read data.
//Input with write data. Center-aligned to write data.wire		[0:0]	ddr3_ck_p;			//4片DR3共用ck、cke、odt、cs信号,故[0:0]
wire		[0:0]	ddr3_ck_n;
//differential clock inputs. All control and address input signals are sampled 
//on the crossing of the positive edge of CK and the negative edge of CK#wire		[7:0]	ddr3_dm;			//Input Data Mask,0,2,4,6为DML,1,3,5,7为DMU
wire		[0:0]	ddr3_cke;			//Clock Enable
wire		[0:0]	ddr3_cs_n;			//Chip Select
wire				ddr3_ras_n;			//Row Address Enable
wire				ddr3_cas_n;			//Column Address Enable
wire				ddr3_we_n;			//Write Enable
wire		[0:0]	ddr3_odt;			//On-die termination enable
wire				ddr3_reset_n;//-------------FPGA FIFO Control-------------------
reg					wr_en;				//高电平有效
reg			[63:0]	wrdat	= 64'd0;
wire				full;				//fifo_w fullreg					rd_en;				//高电平有效
wire		[63:0]	rddat;
wire				empty;				//fifo_r empty//--------------------DDR3 Control-----------------------------------
DDR3_top DDR3_top_inst(.clk_200M				(clk_200M),.rst_n					(rst_n),.rst_busy				(rst_busy),//--------------------ddr3------------------------.ddr3_dq				(ddr3_dq),.ddr3_addr				(ddr3_addr),.ddr3_ba				(ddr3_ba),.ddr3_dqs_p				(ddr3_dqs_p),.ddr3_dqs_n				(ddr3_dqs_n),.ddr3_ck_p				(ddr3_ck_p),.ddr3_ck_n				(ddr3_ck_n),.ddr3_dm				(ddr3_dm),.ddr3_cke				(ddr3_cke),.ddr3_cs_n				(ddr3_cs_n),.ddr3_ras_n				(ddr3_ras_n),.ddr3_cas_n				(ddr3_cas_n),.ddr3_we_n				(ddr3_we_n),.ddr3_odt				(ddr3_odt),.ddr3_reset_n			(ddr3_reset_n),//-------------FPGA FIFO Control-------------------.wr_en					(wr_en),.wrdat					(wrdat),.full					(full),.rd_en					(rd_en),.rddat					(rddat),.empty					(empty)
);//--------------------DDR3 Model-----------------------------------
ddr3_model ddr3_b1 (.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[1:0]),.ba			(ddr3_ba),.addr		(ddr3_addr),.dq			(ddr3_dq[15:0]),.dqs		(ddr3_dqs_p[1:0]),.dqs_n		(ddr3_dqs_n[1:0]),.tdqs_n		(),.odt		(ddr3_odt)
);ddr3_model ddr3_b2 (.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[3:2]),.ba			(ddr3_ba),.addr		(ddr3_addr),.dq			(ddr3_dq[31:16]),.dqs		(ddr3_dqs_p[3:2]),.dqs_n		(ddr3_dqs_n[3:2]),.tdqs_n		(),.odt		(ddr3_odt)
);ddr3_model ddr3_b3 (.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[5:4]),.ba			(ddr3_ba),.addr		(ddr3_addr),.dq			(ddr3_dq[47:32]),.dqs		(ddr3_dqs_p[5:4]),.dqs_n		(ddr3_dqs_n[5:4]),.tdqs_n		(),.odt		(ddr3_odt)
);ddr3_model ddr3_b4 (.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[7:6]),.ba			(ddr3_ba),.addr		(ddr3_addr),.dq			(ddr3_dq[63:48]),.dqs		(ddr3_dqs_p[7:6]),.dqs_n		(ddr3_dqs_n[7:6]),.tdqs_n		(),.odt		(ddr3_odt)
);//--------------------wrdat, rddat-----------------------------------
always @(posedge clk_200M) beginif(wr_en) beginwrdat	<= wrdat + 1'b1;endelse beginwrdat	<= wrdat;end
end//-----------------------tb----------------------------------------
initial beginwr_en	<= 1'b0;rd_en	<= 1'b0;rst_n	<= 1'b1;#100;rst_n	<= 1'b0;#100;rst_n	<= 1'b1;wait(~rst_busy);#200;fork begin: w_rwrite(16);#100;write(16);#100;write(16);#100;// #10000;read(16);#100;write(16);#100;read(64);#2000;disable shut_down;$stop;endbegin: shut_down#100000;disable w_r;$stop;endjoin
endtask write;input	[7:0]	num;integer 		i;beginfor(i=0; i<num; i=i) beginwait(clk_200M);if(~full) beginwr_en	<= 1'b1;i		<= i+1;endelse beginwr_en	<= 1'b0;endwait(~clk_200M);endwait(clk_200M);wr_en	<= 1'b0;end
endtasktask read;input	[7:0]	num;integer			i;beginfor(i=0; i<num; i=i) beginwait(clk_200M);if(~empty) beginrd_en	<= 1'b1;i		<= i+1;endelse beginrd_en	<= 1'b0;endwait(~clk_200M);endwait(clk_200M);rd_en	<= 1'b0;end
endtaskendmodule

仿真结果如下

在这里插入图片描述

放大 FIFO 读写部分的结果如下

在这里插入图片描述


http://www.ppmy.cn/news/560865.html

相关文章

vivado生成mig_Vivado 2015.1 MIG生成DDR4控制器例化问题求助!(急)

回复 1# 固执的寻觅 那是因为DDR中RAM需要的bmm elf文件没有吃进去,你可以参考example_top implement之后的impl_1目录下的脚本example_top.tcl.例如: add_files -quiet /vivado_prj/ddr3_0_example.srcs/sources_1/ip/ddr3_0/ddr3_0.dcp set_property netlist_only true [ge…

【DDR3 控制器设计】(1)MIG IP 核的详解与配置

写在前面 本系列为 DDR3 控制器设计总结,此系列包含 DDR3 控制器相关设计:认识 MIG、初始化、读写操作、FIFO 接口等。通过此系列的学习可以加深对 DDR3 读写时序的理解以及 FIFO 接口设计等,附上汇总博客直达链接。 【DDR3 控制器设计】系列博客汇总篇(附直达链接) 目录 …

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

之前写这个系列的时候忘记上传了&#xff0c;刚好五一补一下。 文章目录 1 MIG IP核的接口1.1 AXI4 slave 接口1.2 Upsizing1.3 User Interface1.3.1 Command Path1.3.2 Write Path1.3.3 Read Path 1.4 Native interface1.5 Physical Layer Interface 2 仿真2.1 模块结构2.2 mi…

Modelsim实现对Vivado中的MIG ddr3的仿真

原文地址&#xff1a;https://www.cnblogs.com/sepeng/p/6525366.html Vivado中的MIG已经集成了modelsim仿真环境&#xff0c;是不是所有IP 都有这个福利呢&#xff0c;不知道哦&#xff0c;没空去验证。 第一步&#xff1a;使用vivado中的MIG IP生成一堆东西 &#xff0c;这个…

FPGA_MIG驱动DDR3

FPGA_MIG驱动DDR3 说明&#xff1a; FPGA: zynq(7z100)。 DDR3:MT41K256M16TW-107&#xff1a;内存大小为512MB&#xff0c;数据接口为16bit。。 环境&#xff1a;Vivado2018.2。 IP核&#xff1a;Memory Interface Generator(MIG 7 Series)。 参考手册&#xff1a;ug586(7 Ser…

DDR原理及MIG IP核使用记录

DDR原理及MIG IP核使用记录 资料参考 一、DDRDDR SDRAM介绍DDR存储机制 二、MIG ip核1、DDR的ddr_ck与用户的ui_clk2、给MIG ip核的输入时钟与参考时钟 3、ip核使用步骤记录 资料参考 1、Xilinx FPGA平台DDR3设计保姆式教程&#xff08;汇总篇&#xff09;——看这一篇就够了这…

DDR3 MIG IP核仿真与学习

MIG IP核介绍 在Xilinx系列的FPGA中&#xff0c;为了方便用户对DDR进行读写&#xff0c;官方提供了用于访问DDR的IP核MIG&#xff0c;全称为Memory Interface Generator&#xff0c;具体可参考赛灵思官方文档参考手册&#xff1a;ug586(7 Series Devices Memory Interface Sol…

vivado生成mig_Xilinx-在Zynq上用MIG扩展内存(2)-Vivado篇

硬件平台:ZC706开发板 软件工具:Vivado 2013.2 Step 1: 创建工程 启动Vivado 2013.2,创建一个新的工程zc706_mig。选中Create project subdirectory。 选择RTL Project 一路Next,在Default Part页面选择ZC706开发板。 Step 2: 配置Zynq 在左面的Flow Navigator窗口,单击Cre…