一、IP核生成不成功可能原因
1、打开 Quartus II 软件时,请右键选择以管理员方式运行,切记,否则可能导致 IP 生成不成功。
 2、创建工程时不要将工程创建在和 Quartus II 安装目录相同的盘符下,否则可能导致生产 IP 失败。
 3、如果在生产 IP 界面长时间卡住,无法生成 IP,请关闭掉 Windows 系统的自动更新和防火墙后重新尝试。
二、modelsim仿真时出错可能原因
IP 请直接创建在 Quartus 的工程根目录下,不要再创建子文件夹,否则仿真的时候会报错。提示找不到文件,实际是因为文件太多,IP 中有些文件路径包含时候处理不好导致的,属于 IP 核设计的小 bug。
三、信号分析
1. 功能
循环写入255个数后再读出。再在接下来的地址写入、读出。
2. 关于代码中突发长度的几个信号区别
rd/wr_burst_len=255 ,用户需要读写的数据量;
burst_size=2 (=burst_length) ,访问DDR2一次连续访问的数据量,即提供一次地址,能连续读 burst_size长度的数据,然后下次的地址+ burst_size;
length初始值=rd/wr_burst_len,用于状态的判断。
ip核信号:
local_address:将访问SDRAM的地址作为输入,无论是读还是写。因此需要在各种状态下,对local_address进行赋值。
3. 程序状态示意图

四、代码
1. IP核封装
/*本模块完成对ddr2 IP的包装,方便后续模块使用,也方便程序的移植,如果更换平台,更新这个文件即可
*/
module mem_burst_v2
#(
	parameter MEM_DATA_BITS = 32,
	parameter ADDR_BITS = 24,
	parameter LOCAL_SIZE_BITS = 3
)
(
	input rst_n,                                 /*复位*/
	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,                    /*写数据信号*/
	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,                         /*读或写完成*/
	
	///
	/*以下是altera ddr2 IP的接口,可参考altera相关文档*/
	input local_init_done,
	output ddr_rst_n,
	input local_ready,
	output  local_burstbegin,
	output[MEM_DATA_BITS - 1:0] local_wdata,
	input local_rdata_valid,
	input[MEM_DATA_BITS - 1:0] local_rdata,
	output  local_write_req,
	output  local_read_req,
	output reg[23:0] local_address,
	output[MEM_DATA_BITS/8 - 1:0] local_be,
	output reg[LOCAL_SIZE_BITS - 1:0] local_size
);
parameter IDLE = 3'd0;
parameter MEM_READ = 3'd1;
parameter MEM_READ_WAIT = 3'd2;
parameter MEM_WRITE  = 3'd3;
parameter MEM_WRITE_BURST_BEGIN = 3'd4;
parameter MEM_WRITE_FIRST = 3'd5;
parameter burst_size = 10'd2;             
reg[2:0] state = 3'd0;
reg[2:0] next_state = 3'd0;	
reg[9:0] rd_addr_cnt = 10'd0;
reg[9:0] rd_data_cnt = 10'd0;
reg[9:0] length = 10'd0;
reg[11:0] cnt_timer = 12'd0;
reg[11:0] ddr_reset_timer = 12'd0;
reg ddr_rst_n_reg = 1'b1;
reg [LOCAL_SIZE_BITS - 1:0] burst_remain;
reg last_wr_burst_data_req;
reg[9:0] wr_remain_len;
/*写入数据请求信号*/
assign wr_burst_data_req = (state == MEM_WRITE_FIRST ) || (((state == MEM_WRITE_BURST_BEGIN) ||  (state == MEM_WRITE)) && local_ready && ~last_wr_burst_data_req);
assign burst_finish = rd_burst_finish | wr_burst_finish;
/*local写请求信号*/
assign local_write_req = ((state == MEM_WRITE_BURST_BEGIN) ||  (state == MEM_WRITE));
/*初始化计时器, 在本程序没有用到*/
always@(posedge mem_clk or negedge rst_n)
begin
	if(~rst_n)
		cnt_timer <= 12'd0;
	else if(state == IDLE || ~local_init_done)
		cnt_timer <= 12'd0;
	else
		cnt_timer <= cnt_timer + 12'd1;
end
/*DDR读等待计数器, 在本程序没有用到*/
always@(posedge mem_clk or negedge rst_n)
begin
	if(~rst_n)
		ddr_reset_timer <= 12'd0;
	else if(state == MEM_READ_WAIT)
		ddr_reset_timer <= ddr_reset_timer + 12'd1;
	else
		ddr_reset_timer <= 12'd0;	
	ddr_rst_n_reg <= (ddr_reset_timer !=12'd200);
end
assign ddr_rst_n = ddr_rst_n_reg;
/*状态锁存*/
always@(posedge	mem_clk or negedge rst_n)
	begin
		if(~rst_n)
			state <= IDLE;
		else if(~local_init_done ) //IP核的初始化结束信号
			state <= IDLE;
		else
			state <= next_state;
	end
	
/*burst读写处理程序*/	
always@(*)
	begin
		case(state)
			IDLE:
				begin
					if(rd_burst_req && rd_burst_len != 10'd0)         /*接收到burst读请求*/
						next_state <= MEM_READ;      /*状态转为发burst读命令*/
					else if(wr_burst_req && wr_burst_len != 10'd0)    /*接收到burst写请求*/
						next_state <= MEM_WRITE_FIRST;    /*状态转为第一次写*/
					else
						next_state <= IDLE;
				end
			MEM_READ:                         /*burst读命令*/
				begin
					if( (rd_addr_cnt + burst_size >= length) && local_read_req && local_ready) /*判断burst读请求的有效的长度*/
						next_state <= MEM_READ_WAIT;
					else
						next_state <= MEM_READ;
				end
			MEM_READ_WAIT:                   /*等待burst数据读完成*/
				begin 
					if(rd_data_cnt == length - 10'd1 && local_rdata_valid)     /*判断读出的有效数据长度*/
						next_state <= IDLE;
					else
						next_state <= MEM_READ_WAIT;
				end
			MEM_WRITE_FIRST:                /*第一次写状态, 用于准备写入的数据*/
				next_state <= MEM_WRITE_BURST_BEGIN;
			MEM_WRITE_BURST_BEGIN:         /*产生burst begin信号*/                      
				begin
					if(local_ready && wr_remain_len == 10'd1)     /*如果写的剩余数据长度为1, Burst写结束*/
						next_state <= IDLE;
					else if(burst_remain == 1 && local_ready)     /*一次local burst写完成, 重新回到burst begin */   
						next_state <= MEM_WRITE_BURST_BEGIN;
					else if(local_ready)
						next_state <= MEM_WRITE;    /*burst begin完成, 转到数据写入*/    
					else
						next_state <= MEM_WRITE_BURST_BEGIN;
				end
			MEM_WRITE:                   
				begin
					if(wr_remain_len == 10'd1 && local_ready)     /*如果写的剩余数据长度为1, Burst写结束*/
						next_state <= IDLE;
					else if(burst_remain == 1 && local_ready)     /*一次local burst写完成,重新回到burst begin */   
						next_state <= MEM_WRITE_BURST_BEGIN;
					else 
						next_state <= MEM_WRITE;
				end
			default:
				next_state <= IDLE;
		endcase
	end
	
	assign local_burstbegin = ((state == MEM_WRITE_BURST_BEGIN) ||  (state == MEM_READ)); /*产生local burst begin信号*/
/*计算最后一个burst数据写请求信号*/
always@(posedge	mem_clk)
	begin
		if(state == MEM_WRITE_BURST_BEGIN || state == MEM_WRITE)
			if(wr_remain_len == 10'd2 && local_ready)
				last_wr_burst_data_req <= 1'b1;
			else
				last_wr_burst_data_req <= last_wr_burst_data_req;
		else
			last_wr_burst_data_req <= 1'b0;
	end
	
/*计算外部burst写的剩余数据长度*/
always@(posedge	mem_clk)
	begin
		case(state)
			IDLE:
				if(wr_burst_req)
					wr_remain_len <= wr_burst_len;  /*wr_remain_len赋初值*/
				else
					wr_remain_len <= wr_remain_len;
			MEM_WRITE_BURST_BEGIN:      
				if(local_ready)
					wr_remain_len <= wr_remain_len - 10'd1;
				else
					wr_remain_len <= wr_remain_len;
			MEM_WRITE:
				if(local_ready)
					wr_remain_len <= wr_remain_len - 10'd1;
				else
					wr_remain_len <= wr_remain_len;
			default:
				wr_remain_len <= wr_remain_len;
		endcase
	end
/*计算一次local burst的剩余数*/	
always@(posedge	mem_clk)
	begin
		if(next_state == MEM_WRITE_BURST_BEGIN)
			burst_remain <= burst_size;        /*burst size is 2*/
		else if( ((state == MEM_WRITE_BURST_BEGIN) || (state == MEM_WRITE)) && local_ready)      /*一次数据写入有效*/
			burst_remain <= burst_remain - 1;
		else
			burst_remain <= burst_remain;
	end	
	
/*计算local size, 需要判断剩余的数据是否大于burst_size*/	
always@(posedge	mem_clk)
	begin
		if(state == IDLE && rd_burst_req)
			local_size <= (rd_burst_len >= burst_size) ?  burst_size : rd_burst_len ;
		else if(state == IDLE && wr_burst_req)
			local_size <= (wr_burst_len >= burst_size) ?  burst_size : wr_burst_len;
		else if(state == MEM_WRITE && (next_state == MEM_WRITE_BURST_BEGIN))
			if((wr_remain_len - 1) > burst_size)  /*判断剩余写数据长度是否大于burst_size*/
				local_size <= burst_size;
			else
				local_size <= wr_remain_len - 1;
		else if(state == MEM_WRITE_BURST_BEGIN && (next_state == MEM_WRITE_BURST_BEGIN) && local_ready)
			if((wr_remain_len - 1) > burst_size)  /*判断剩余写数据长度是否大于burst_size*/
				local_size <= burst_size;
			else
				local_size <= wr_remain_len - 1;
		else if(state == MEM_READ && local_ready )
			local_size <= (rd_addr_cnt + burst_size > length) ? 1 : burst_size; 
		else
			local_size <= local_size;
	end
/*计算地址local_address*/
always@(posedge	mem_clk)
	begin
		case(state)
			IDLE:
				begin
					if(rd_burst_req)     /*读burst请求有效*/
						begin
							local_address <= rd_burst_addr;
							rd_addr_cnt <= 10'd0;
						end
					else if(wr_burst_req) /*读burst请求有效*/
						begin
							local_address <= wr_burst_addr;
							rd_addr_cnt <= 10'd0;
						end
					else
						begin
							local_address <= local_address;
							rd_addr_cnt <= 10'd0;
						end
				end
			MEM_READ:
				begin
					if(local_ready)
						begin
							local_address <= local_address + {14'd0,burst_size};   /*Bust读,地址加burst_size*/
							rd_addr_cnt <= rd_addr_cnt + burst_size;
						end
					else
						begin
							local_address <= local_address;
							rd_addr_cnt <= rd_addr_cnt;
						end		
				end
			MEM_WRITE_BURST_BEGIN:
				begin
					if(local_ready && (next_state == MEM_WRITE_BURST_BEGIN))
						begin
							local_address <= local_address + {14'd0,burst_size};  /*Bust begin写,地址加burst_size*/
						end
					else
						begin
							local_address <= local_address;
						end	
				end	
			MEM_WRITE: 
				begin
					if(local_ready && (next_state == MEM_WRITE_BURST_BEGIN))    
						begin
							local_address <= local_address + {14'd0,burst_size};   /*Bust 写,地址加burst_size*/
						end
					else
						begin
							local_address <= local_address;
						end	
				end
			default:
				begin
					local_address <= local_address;
					rd_addr_cnt <= 10'd0;
				end
		endcase
	end
	
/*burst读长度*/	
always@(posedge	mem_clk)
	begin
		if(state == IDLE && rd_burst_req)
			length <= rd_burst_len;
		else
			length <= length; 
	end
	
/*统计读数据counter*/
always@(posedge	mem_clk)
	begin
		if(state == MEM_READ || state == MEM_READ_WAIT)
			if(local_rdata_valid)
				rd_data_cnt <= rd_data_cnt + 10'd1;
			else
				rd_data_cnt <= rd_data_cnt;
		else
			rd_data_cnt <= 10'd0;
	end
/*输出信号赋值*/
assign rd_burst_data_valid = local_rdata_valid;
assign rd_burst_data = local_rdata;
assign local_wdata = wr_burst_data;
assign local_read_req = (state == MEM_READ);
assign rd_burst_finish = (state == MEM_READ_WAIT) && (next_state == IDLE);
assign wr_burst_finish = (local_ready && wr_remain_len == 10'd1);
assign local_be = {MEM_DATA_BITS/8{1'b1}};
endmodule 2. 顶层模块
module ddr_test(
	input  wire  source_clk,        //输入系统时钟50Mhz
	input rst_n,
	output err,                     //led1, 灯亮DDR读写正常, 灯灭DDR读写出错
   output  [ 14: 0] mem_addr,
   output  [  2: 0] mem_ba,
   output           mem_cas_n,
   output  [  0: 0] mem_cke,
   inout   [  0: 0] mem_clk,
   inout   [  0: 0] mem_clk_n,
   output  [  0: 0] mem_cs_n,
   output  [  1: 0] mem_dm,
   inout   [ 15: 0] mem_dq,
   inout   [  1: 0] mem_dqs,
   output  [  0: 0] mem_odt,
   output           mem_ras_n,
   output           mem_we_n  
);
parameter DATA_WIDTH = 32;           //总线数据宽度
parameter ADDR_WIDTH = 25;           //总线地址宽度
parameter IDLE = 3'd0;
parameter MEM_READ = 3'd1;
parameter MEM_WRITE  = 3'd2; 
reg[2:0] state;
reg[2:0] next_state;
//状态锁存///
always@(posedge	phy_clk)
	begin
		if(~local_init_done)          //等待初始化成功
			state <= IDLE;
		else	
			state <= next_state;
	end
	
//循环产生DDR Burst读,Burst写状态///
always@(*)
	begin 
		case(state)
			IDLE:
				next_state <= MEM_WRITE;  
			MEM_WRITE:                    //写入数据到DDR2
				if(wr_burst_finish)          
					next_state <= MEM_READ;
				else
					next_state <= MEM_WRITE;
			MEM_READ:                    //读出数据从DDR2
				if(rd_burst_finish)
					next_state <= MEM_WRITE;
				else
					next_state <= MEM_READ;
			default:
				next_state <= IDLE;
		endcase
end
reg  [ADDR_WIDTH - 1:0] wr_burst_addr;
wire [ADDR_WIDTH - 1:0] rd_burst_addr;
wire    wr_burst_data_req;
wire    rd_burst_data_valid;
reg  [9:0] wr_burst_len;
reg  [9:0] rd_burst_len;
reg     wr_burst_req;
reg     rd_burst_req;
reg  [9:0] wr_cnt;
reg  [9:0] rd_cnt;
wire [DATA_WIDTH - 1:0] wr_burst_data;
wire [DATA_WIDTH - 1:0] rd_burst_data;
//DDR的读写地址和DDR测试数据//
always@(posedge phy_clk)
	begin
		if(state == IDLE && next_state == MEM_WRITE)
			wr_burst_addr <= {ADDR_WIDTH{1'b0}};     //地址清零
		else if(state == MEM_READ && next_state == MEM_WRITE)                //一次Burst读写完成
			wr_burst_addr <= wr_burst_addr + {{(ADDR_WIDTH-8){1'b0}},8'd255}; //地址加burst长度255         
		else
			wr_burst_addr <= wr_burst_addr;           //锁存地址
	end
assign rd_burst_addr = wr_burst_addr;     
assign wr_burst_data = {(DATA_WIDTH/8){wr_cnt[7:0]}};     //写入DDR的数据
//产生burst写请求信号
always@(posedge phy_clk)
	begin
		if(next_state == MEM_WRITE && state != MEM_WRITE)
			begin
				wr_burst_req <= 1'b1;      //产生ddr burst写请求       
				wr_burst_len <= 10'd255;
				wr_cnt <= 10'd0;
			end
		else if(wr_burst_data_req)       //写入burst数据请求 
			begin
				wr_burst_req <= 1'b0;
				wr_burst_len <= 10'd255;
				wr_cnt <= wr_cnt + 10'd1;  //测试数据(每字节)加1
			end
		else
			begin
				wr_burst_req <= wr_burst_req;
				wr_burst_len <= 10'd255;
				wr_cnt <= wr_cnt;
			end
	end
//产生burst读请求信号	
always@(posedge phy_clk)
	begin
		if(next_state == MEM_READ && state != MEM_READ)
			begin
				rd_burst_req <= 1'b1;      //产生ddr burst读请求  
				rd_burst_len <= 10'd255;
				rd_cnt <= 10'd1;
			end
		else if(rd_burst_data_valid)     //检测到data_valid信号,burst读请求变0
			begin
				rd_burst_req <= 1'b0;
				rd_burst_len <= 10'd255;
				rd_cnt <= rd_cnt + 10'd1;
			end
		else
			begin
				rd_burst_req <= rd_burst_req;
				rd_burst_len <= 10'd255;
				rd_cnt <= rd_cnt;
			end
	end
	
assign err = rd_burst_data_valid &(rd_burst_data != {(DATA_WIDTH/8){rd_cnt[7:0]}});       //检查DDR读出的数据是否正确
wire	[ADDR_WIDTH - 1:0]	local_address;   
wire		local_write_req;
wire		local_read_req;
wire	[DATA_WIDTH - 1:0]	local_wdata;
wire	[DATA_WIDTH/8 - 1:0]	local_be;   
wire	[2:0]	local_size;
wire		local_ready;
wire	[DATA_WIDTH - 1:0]	local_rdata;
wire		local_rdata_valid;
wire		local_wdata_req;
wire		local_init_done;
wire		phy_clk;
wire		aux_full_rate_clk;
wire		aux_half_rate_clk;
wire     rd_burst_finish;
wire     wr_burst_finish;
//实例化mem_burst_v2
mem_burst_v2
#(
	.MEM_DATA_BITS(DATA_WIDTH)
)
mem_burst_m0(
	.rst_n(rst_n),
	.mem_clk(phy_clk),
	.rd_burst_req(rd_burst_req),
	.wr_burst_req(wr_burst_req),
	.rd_burst_len(rd_burst_len),
	.wr_burst_len(wr_burst_len),
	.rd_burst_addr(rd_burst_addr),
	.wr_burst_addr(wr_burst_addr),
	.rd_burst_data_valid(rd_burst_data_valid),
	.wr_burst_data_req(wr_burst_data_req),
	.rd_burst_data(rd_burst_data),
	.wr_burst_data(wr_burst_data),
	.rd_burst_finish(rd_burst_finish),
	.wr_burst_finish(wr_burst_finish),
	///
	.local_init_done(local_init_done),
	.local_ready(local_ready),
	.local_burstbegin(local_burstbegin),
	.local_wdata(local_wdata),
	.local_rdata_valid(local_rdata_valid),
	.local_rdata(local_rdata),
	.local_write_req(local_write_req),
	.local_read_req(local_read_req),
	.local_address(local_address),
	.local_be(local_be),
	.local_size(local_size)
);
//实例化ddr2.v
ddr2 ddr_m0(
	.local_address(local_address),
	.local_write_req(local_write_req),
	.local_read_req(local_read_req),
	.local_wdata(local_wdata),
	.local_be(local_be),
	.local_size(local_size),
	.global_reset_n(rst_n),
	//.local_refresh_req(1'b0), 
	//.local_self_rfsh_req(1'b0),
	.pll_ref_clk(source_clk),
	.soft_reset_n(1'b1),
	.local_ready(local_ready),
	.local_rdata(local_rdata),
	.local_rdata_valid(local_rdata_valid),
	.reset_request_n(),
	.mem_cs_n(mem_cs_n),
	.mem_cke(mem_cke),
	.mem_addr(mem_addr),
	.mem_ba(mem_ba),
	.mem_ras_n(mem_ras_n),
	.mem_cas_n(mem_cas_n),
	.mem_we_n(mem_we_n),
	.mem_dm(mem_dm),
	.local_refresh_ack(),
	.local_burstbegin(local_burstbegin),
	.local_init_done(local_init_done),
	.reset_phy_clk_n(),
	.phy_clk(phy_clk),
	.aux_full_rate_clk(),
	.aux_half_rate_clk(),
	.mem_clk(mem_clk),
	.mem_clk_n(mem_clk_n),
	.mem_dq(mem_dq),
	.mem_dqs(mem_dqs),
	.mem_odt(mem_odt)
	);
	
endmodule 
3. 测试代码
五、波形分析
1. 写过程分析
如下图所示,只有当 local_ready 为高和 local_write_req 信号都为高时,写入的数据才是有效的数据,如果 local_ready 信号为低,local_write_req 和数据需要一直保持,等待local_ready 信号为高才行。 DDR2 的 burst _length 为 2, 所以地址信号 local_address 是每写入 2 个数据就加 2, local_burstbegin 信号为第一个数据写的时候为高,第二个数据写的时候为低。

2. 读过程分析
        只有当 local_ready 为高和 local_read_req 信号都为高时,burst 读才是有
 效的,如果 local_ready 信号为低,local_ read _req 和地址 local_address 需要一直保持,等待 local_ready 信号为高才行。local_read_req 信号请求为高等待一段时间后,local_rddata_valid 信号会变高,才会有有效的读的数据输出。如下面第一张图所示,地址发出后,数据在第二张图片才发出。





















