OpenCores

DDR2 :: Overview

Project maintainers

Details

Name: ddr
Created: Dec 5, 2017
Updated: Dec 6, 2017
SVN: No files checked in
Bugs: reported / solved

★ Star 0 you like it: star it!

Other project properties

Category: Memory core
Language: Verilog
Development status: Planning
Additional info: none
WishBone compliant: No
WishBone version: n/a
License: LGPL

Description

Please write a description of the project here. It is used as a MetaTag (search engines looks at this).

ddr-test

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 else
state end

//////循环产生DDR Burst读,Burst写状态///////////
always@(*)
begin
case(state)
IDLE:
next_state MEM_WRITE: //写入数据到DDR2
if(wr_burst_finish)
next_state else
next_state MEM_READ: //读出数据从DDR2
if(rd_burst_finish)
next_state else
next_state default:
next_state 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 else if(state == MEM_READ && next_state == MEM_WRITE) //一次Burst读写完成
wr_burst_addr else
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 wr_burst_len wr_cnt end
else if(wr_burst_data_req) //写入burst数据请求
begin
wr_burst_req wr_burst_len wr_cnt end
else
begin
wr_burst_req wr_burst_len wr_cnt end
end

//产生burst读请求信号
always@(posedge phy_clk)
begin
if(next_state == MEM_READ && state != MEM_READ)
begin
rd_burst_req rd_burst_len rd_cnt end
else if(rd_burst_data_valid) //检测到data_valid信号,burst读请求变0
begin
rd_burst_req rd_burst_len rd_cnt end
else
begin
rd_burst_req rd_burst_len 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

ddr2 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 else if(state == IDLE || ~local_init_done)
cnt_timer else
cnt_timer end

/*DDR读等待计数器, 在本程序没有用到*/
always@(posedge mem_clk or negedge rst_n)
begin
if(~rst_n)
ddr_reset_timer else if(state == MEM_READ_WAIT)
ddr_reset_timer else
ddr_reset_timer ddr_rst_n_reg end
assign ddr_rst_n = ddr_rst_n_reg;

/*状态锁存*/
always@(posedge mem_clk or negedge rst_n)
begin
if(~rst_n)
state else if(~local_init_done )
state else
state end

/*burst读写处理程序*/
always@(*)
begin
case(state)
IDLE:
begin
if(rd_burst_req && rd_burst_len != 10'd0) /*接收到burst读请求*/
next_state else if(wr_burst_req && wr_burst_len != 10'd0) /*接收到burst写请求*/
next_state else
next_state end
MEM_READ: /*burst读命令*/
begin
if( (rd_addr_cnt + burst_size >= length) && local_read_req && local_ready) /*判断burst读请求的有效的长度*/
next_state else
next_state end
MEM_READ_WAIT: /*等待burst数据读完成*/
begin
if(rd_data_cnt == length - 10'd1 && local_rdata_valid) /*判断读出的有效数据长度*/
next_state else
next_state end
MEM_WRITE_FIRST: /*第一次写状态, 用于准备写入的数据*/
next_state MEM_WRITE_BURST_BEGIN: /*产生burst begin信号*/
begin
if(local_ready && wr_remain_len == 10'd1) /*如果写的剩余数据长度为1, Burst写结束*/
next_state else if(burst_remain == 1 && local_ready) /*一次local burst写完成, 重新回到burst begin */
next_state else if(local_ready)
next_state else
next_state end
MEM_WRITE:
begin
if(wr_remain_len == 10'd1 && local_ready) /*如果写的剩余数据长度为1, Burst写结束*/
next_state else if(burst_remain == 1 && local_ready) /*一次local burst写完成,重新回到burst begin */
next_state else
next_state end
default:
next_state 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 else
last_wr_burst_data_req else
last_wr_burst_data_req end

/*计算外部burst写的剩余数据长度*/
always@(posedge mem_clk)
begin
case(state)
IDLE:
if(wr_burst_req)
wr_remain_len else
wr_remain_len MEM_WRITE_BURST_BEGIN:
if(local_ready)
wr_remain_len else
wr_remain_len MEM_WRITE:
if(local_ready)
wr_remain_len else
wr_remain_len default:
wr_remain_len endcase
end

/*计算一次local burst的剩余数*/
always@(posedge mem_clk)
begin
if(next_state == MEM_WRITE_BURST_BEGIN)
burst_remain else if( ((state == MEM_WRITE_BURST_BEGIN) || (state == MEM_WRITE)) && local_ready) /*一次数据写入有效*/
burst_remain else
burst_remain end

/*计算local size, 需要判断剩余的数据是否大于burst_size*/
always@(posedge mem_clk)
begin
if(state == IDLE && rd_burst_req)
local_size = burst_size) ? burst_size : rd_burst_len ;
else if(state == IDLE && wr_burst_req)
local_size = 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 else
local_size 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 else
local_size else if(state == MEM_READ && local_ready )
local_size length) ? 1 : burst_size;
else
local_size end

/*计算地址local_address*/
always@(posedge mem_clk)
begin
case(state)
IDLE:
begin
if(rd_burst_req) /*读burst请求有效*/
begin
local_address rd_addr_cnt end
else if(wr_burst_req) /*读burst请求有效*/
begin
local_address rd_addr_cnt end
else
begin
local_address rd_addr_cnt end
end
MEM_READ:
begin
if(local_ready)
begin
local_address rd_addr_cnt end
else
begin
local_address rd_addr_cnt end
end
MEM_WRITE_BURST_BEGIN:
begin
if(local_ready && (next_state == MEM_WRITE_BURST_BEGIN))
begin
local_address end
else
begin
local_address end
end
MEM_WRITE:
begin
if(local_ready && (next_state == MEM_WRITE_BURST_BEGIN))
begin
local_address end
else
begin
local_address end
end
default:
begin
local_address rd_addr_cnt end
endcase
end

/*burst读长度*/
always@(posedge mem_clk)
begin
if(state == IDLE && rd_burst_req)
length else
length end

/*统计读数据counter*/
always@(posedge mem_clk)
begin
if(state == MEM_READ || state == MEM_READ_WAIT)
if(local_rdata_valid)
rd_data_cnt else
rd_data_cnt else
rd_data_cnt 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

© copyright 1999-2017 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.