原创 SDRAM 控制器 基本版 V2.3

2012-9-10 11:29 1333 8 9 分类: FPGA/CPLD

看看V1版实在太凌乱,现在对代码风格进行革新,共有两个小版本 V2.2两段式+同步输出+独热编码  V2.3两段式+同步输出。。这里有一些我自己的思想:1.两段式状态机也可以做到同步输出;2.延时定时模块;3.状态重复操作的处理。关于突发操作部分仍在努力中,敬请大家期待,点评,并给出建议。希望共同进步,有附件源码

/**
  ******************************************************************************
  * @file    sdram_v2_3.v
  * @author  西殿源
  * @version V2.3
  * @date    09/08/2012 最后修改
  * @brief   SDRAM控制器
  * @info 1. 本版本实现SDRAM最基本功能
2. 将bank1和bank0 接到地址总线最底两位,地址线错两位接到地址总线的高位
3. 顺序寻址,避开页错失的情况,tRCD + CL
4. 不考虑突发读写
5. 不考虑页直接命中的情况
6. 状态机两段式+同步输出
7. 砍掉POWER_ON,
  ******************************************************************************
  */

module sdram_v2_3(
//-------------------时钟复位-------------------------------------//
input clk,
input rst_n,
//-------------------片内端口-------------------------------------//
input[23:0] addr_in, //内部输入地址总线
input wr, //内部写内存信号,低电平有效,脉宽一个clk周期即可
input rd, //内部读内存信号,低电平有效,脉宽一个clk周期即可
output reg wr_ok, //写SDRAM,=1标志数据已写入SDRAM,脉宽一个clk周期
output reg rd_ok, //读SDRAM,=1标志数据已送到总线上,脉宽一个clk周期
//-------------------片外端口-------------------------------------//
output reg cs_ro, //SDRAM片选,寄存器输出
output reg cke_ro, //SDRAM时钟使能
output reg[12:0] addr_ro, //SDRAM地址总线
output reg[1:0] bank_ro, //SDRAM块片选
output reg ras_ro, //SDRAM行激活
output reg cas_ro, //SDRAM列激活
output reg we_ro, //SDRAM写使能
output reg[1:0] dqm_ro //SDRAM Mask

);


parameter YES = 1'b1;
parameter NO = 1'b0;
parameter HI = 1'b1;
parameter LO = 1'b0;

parameter MODEL_SET = 5'd0; //模式寄存器设置
parameter AUTO_FREH = 5'd1; //自动刷新
parameter SELF_ENT = 5'd2; //进入自刷新,就是刷新操作不在依靠clk
parameter SELF_EXT = 5'd3; //推出自刷新,就是刷新操作不在依靠clk
parameter ROW_ACTV = 5'd4; //行激活,行地址
parameter COLUM_RD = 5'd5; //列激活,列地址
parameter COLUM_WR = 5'd6; //列激活,写数据
parameter BST_STOP = 5'd7; //突发停
parameter PRE_CHAG_A = 5'd8; //所有bank预充电
parameter PRE_CHAG_S = 5'd9; //选中bank预充电
parameter SSPD_ENT = 5'd10; //进入挂起
parameter SSPD_EXT = 5'd11; //退出挂起
parameter POWR_ENT = 5'd12; //进入
parameter POWR_EXT = 5'd13; //退出
parameter DQM = 5'd14; //数据掩码
parameter NOP_OPTN = 5'd15; //空操作
parameter WR_OK = 5'd16; //写入成功
parameter RD_OK = 5'd17; //读出成功
parameter POWER_ON = 5'd18; //上电初始化
parameter CHK_BEGN = 5'd19; //上电初始化

reg wr_ok_temp; //=1写数据成功,用于组合逻辑,
reg rd_ok_temp; //=1读数据成功,用于组合逻辑,
reg cs_temp; //SDRAM片选,用于组合逻辑,
reg cke_temp; //SDRAM时钟使能,用于组合逻辑,
reg[12:0] addr_temp; //SDRAM地址,用于组合逻辑,
reg[1:0] bank_temp; //SDRAM块选,用于组合逻辑,
reg ras_temp; //SDRAM行激活,用于组合逻辑,
reg cas_temp; //SDRAM列激活,用于组合逻辑,
reg we_temp; //SDRAMD读写信号,用于组合逻辑,
reg[1:0] dqm_temp; //SDRAM Mask

reg chk_en; //=1时,处于检测模式,=0时处于状态跳转模式;用于时序逻辑
reg chk_en_temp; //作为chk_en的赋值,用于组合逻辑


reg[15:0] dly_cnt; //延时次数装载寄存器,例如某操作延时2个clk再操作,可以赋以2
reg[15:0] dly_cnt_temp; //作为dly_cnt的赋值,用于组合逻辑
reg[15:0] dly_cnt1; //延时计数器,时序逻辑,用于延时always块

reg dly_en; //=1时使能延时定时器,与dly_cnt配合使用,有效宽度为一个clk周期
reg dly_en_temp; //作为dly_en的赋值,用于组合逻辑
reg dly_en1; //延时计数使能,与dly_cnt1配合使用,
reg dly_ok; //延时到时,=1,脉宽为一个clk周期


// reg[4:0] stat_temp;
reg stat_cnt_en; //状态重复执行使能,用于时序逻辑
reg stat_cnt_en_temp; //状态重复执行使能,用于组合逻辑,作为stat_cnt_en的赋值
reg[3:0] stat_cnt; //状态重复次数计数器
// reg[4:0] nxt_stat_clk; //??ò???×′ì?£???±eóú??ò???2ù×÷ ,ó?óúê±Dò???-
reg[4:0] nxt_stat; //下一个状态,组合逻辑状态
reg[4:0] nxt_opt; //下一个操作,例如无论读写,在行选通之后要紧随列的读选通或写选通,将此值付给nxt_stat
reg[4:0] cur_stat; //当前状态,时序逻辑
// reg[15:0] nop_cnt; //??2ù×÷??êy

reg[23:0] addr_r; //地址锁存,

reg init_en;

always @(posedge clk,negedge rst_n) begin
if(!rst_n) begin
addr_r <= 0;

wr_ok <= NO;
rd_ok <= NO;

{cs_ro,cke_ro,ras_ro,cas_ro,we_ro} <= 5'b00000;
addr_ro <= 0;
bank_ro <= 0;
dqm_ro <= 0;

init_en <= NO;

dly_cnt <= 10; //上电后稳定200us 定位10000;
dly_en <= YES;
stat_cnt_en <= NO;
chk_en <= NO;

cur_stat <= PRE_CHAG_A;
nxt_opt <= PRE_CHAG_A;

end
else if(chk_en) begin //chk_en=1时,每个clk上升沿检测读写请求位
case({wr,rd})
2'b01 : begin
addr_r <= addr_in; //锁存地址
cur_stat <= ROW_ACTV; //跳转到行激活状态
nxt_opt <= COLUM_WR; //行激活状态完毕后跳转到列写激活状态
chk_en <= NO; //关闭读写检测,切入状态跳转模式。下一个clk就切入
init_en <= YES; //触发状态跳转,就在下一个clk
end
2'b10 : begin
addr_r <= addr_in; //锁存地址
cur_stat <= ROW_ACTV; //跳转到行激活状态
nxt_opt <= COLUM_RD; //行激活状态完毕后跳转到列读激活状态
chk_en <= NO; //关闭读写检测,切入状态跳转模式。下一个clk就切入
init_en <= YES;
end
default : ;
endcase
end
else begin //chk_en=0,状态跳转模式
if((init_en == YES)||(dly_ok == YES)) begin //,或延时时间到执行状态跳转
init_en <= NO; //进来后关掉init_en,保证下一次状态跳转是在延时到

cur_stat <= nxt_stat; //状态切换

wr_ok <= wr_ok_temp; //同步输出
rd_ok <= rd_ok_temp; //同步输出

{cs_ro,cke_ro,ras_ro,cas_ro,we_ro} <= {cs_temp,cke_temp,ras_temp,cas_temp,we_temp};
addr_ro <= addr_temp; //同步输出
bank_ro <= bank_temp; //同步输出
dqm_ro <= dqm_temp; //同步输出

stat_cnt_en <= stat_cnt_en_temp; //同步输出
dly_en <= dly_en_temp; //同步输出
dly_cnt <= dly_cnt_temp; //同步输出
chk_en <= chk_en_temp; //同步输出
end
else begin //不满足(init_en == YES)||(dly_ok == YES),执行空操作
{cs_ro,cke_ro,ras_ro,cas_ro,we_ro} <= 5'b01111; //空操作
wr_ok <= NO; //清除写成功标志,保证wr_ro脉宽为一个clk周期
rd_ok <= NO;
dly_en <= NO; //清除写成功标志,保证dly_en脉宽为一个clk周期
end

end
end



always @(cur_stat,stat_cnt) begin
case(cur_stat)

PRE_CHAG_A : begin //预充电
{cs_temp,cke_temp,ras_temp,cas_temp,we_temp} = 5'b01010; //预充电
addr_temp = 13'b0010000000000; //A[10]=1
bank_temp = 0; //
dqm_temp = 0; //

stat_cnt_en_temp = NO; //本状态 不 需要重复执行

wr_ok_temp = NO; //
rd_ok_temp = NO; //

chk_en_temp = NO; //

dly_cnt_temp = 2; //延时2个clk周期再跳转到下一个操作状态
dly_en_temp = YES; //时钟到来时更新到dly_en,dly_en=1 启
//动定时计数器,随后的一个clk使dly_en=0

nxt_stat = AUTO_FREH; //
end

AUTO_FREH : begin //自动刷新
{cs_temp,cke_temp,ras_temp,cas_temp,we_temp} = 5'b01001; //8???¢D??ü?ú
addr_temp = 0; //
bank_temp = 0; //
dqm_temp = 0; //

stat_cnt_en_temp = YES; //本状态 需要 重复执行

wr_ok_temp = NO;
rd_ok_temp = NO;

chk_en_temp = NO;

dly_cnt_temp = 9; //延时9个clk周期再跳转到下一个操作状态
dly_en_temp = YES; //时钟到来时更新到dly_en,dly_en=1 启
//动定时计数器,随后的一个clk使dly_en=0

if(stat_cnt == 7) nxt_stat = MODEL_SET;
else nxt_stat = AUTO_FREH;

end

MODEL_SET : begin //模式寄存器设置
{cs_temp,cke_temp,ras_temp,cas_temp,we_temp} = 5'b01000; //模式寄存器设置
addr_temp = {
3'b000,
1'b1,
2'b00,
3'b010,
1'b0,
3'b000
};
bank_temp = 0; //
dqm_temp = 0; //

stat_cnt_en_temp = NO; //本状态 不 需要重复执行

wr_ok_temp = NO; //
rd_ok_temp = NO; //

chk_en_temp = NO;

dly_cnt_temp = 2; //延时2个clk周期再跳转到下一个操作状态
dly_en_temp = YES; //时钟到来时更新到dly_en,dly_en=1 启
//动定时计数器,随后的一个clk使dly_en=0

nxt_stat = CHK_BEGN;
end

ROW_ACTV : begin
{cs_temp,cke_temp,ras_temp,cas_temp,we_temp} = 5'b01011; //行激活
addr_temp = addr_r[23:11];
bank_temp = addr_r[1:0]; //模块内部的地址总线最地两位接到bank上
dqm_temp = 0; //

stat_cnt_en_temp = NO; //本状态 不 需要重复执行

wr_ok_temp = NO;
rd_ok_temp = NO;

chk_en_temp = NO;

dly_cnt_temp = 2; //延时2个clk周期再跳转到下一个操作状态
dly_en_temp = YES; //时钟到来时更新到dly_en,dly_en=1 启
//动定时计数器,随后的一个clk使dly_en=0

nxt_stat = nxt_opt;
end

COLUM_WR : begin
{cs_temp,cke_temp,ras_temp,cas_temp,we_temp} = 5'b01100; //列写激活
addr_temp = {4'b0010,addr_r[10:2]}; //A[10]=1 列地址
bank_temp = addr_r[1:0]; //模块内部的地址总线最地两位接到bank上
dqm_temp = 0; //

stat_cnt_en_temp = NO; //本状态 不 需要重复执行

wr_ok_temp = NO; //
rd_ok_temp = NO; //

chk_en_temp = NO;

dly_cnt_temp = 2; //延时2个clk周期再跳转到下一个操作状态
dly_en_temp = YES; //时钟到来时更新到dly_en,dly_en=1 启
//动定时计数器,随后的一个clk使dly_en=0

nxt_stat = WR_OK;
end

WR_OK : begin
{cs_temp,cke_temp,ras_temp,cas_temp,we_temp} = 5'b01111; //发出置位写成功标志
addr_temp = 0; //
bank_temp = 0; //
dqm_temp = 0; //

stat_cnt_en_temp = NO; //本状态 不 需要重复执行

wr_ok_temp = YES; //时钟到来时就更新到wr_ok,置位写成功,随后的clk再清除wr_ok。
rd_ok_temp = NO;

chk_en_temp = NO;

dly_cnt_temp = 2; //延时2个clk周期再跳转到下一个操作状态
dly_en_temp = YES; //时钟到来时更新到dly_en,dly_en=1 启
//动定时计数器,随后的一个clk使dly_en=0

nxt_stat = CHK_BEGN;
end

COLUM_RD : begin
{cs_temp,cke_temp,ras_temp,cas_temp,we_temp} = 5'b01101; //列读激活
addr_temp = {4'b0010,addr_r[10:2]}; //A[10]=1 列地址
bank_temp = addr_r[1:0]; //模块内部的地址总线最地两位接到bank上
dqm_temp = 0; //

stat_cnt_en_temp = NO; //本状态 不 需要重复执行

wr_ok_temp = NO;
rd_ok_temp = NO;

chk_en_temp = NO;

dly_cnt_temp = 2; //延时2个clk周期再跳转到下一个操作状态
dly_en_temp = YES; //时钟到来时更新到dly_en,dly_en=1 启
//动定时计数器,随后的一个clk使dly_en=0

nxt_stat = RD_OK;
end

RD_OK : begin
{cs_temp,cke_temp,ras_temp,cas_temp,we_temp} = 5'b01111; //置位读成功,标志数据已放到数据总线
addr_temp = 0; //
bank_temp = 0; //
dqm_temp = 0; //

stat_cnt_en_temp = NO; //本状态 不 需要重复执行

wr_ok_temp = NO;
rd_ok_temp = YES; //时钟到来时就更新到rd_ok,置位写成功,随后的clk再清除rd_ok。

chk_en_temp = NO;

dly_cnt_temp = 2; //延时2个clk周期再跳转到下一个操作状态
dly_en_temp = YES; //时钟到来时更新到dly_en,dly_en=1 启
//动定时计数器,随后的一个clk使dly_en=0

nxt_stat = CHK_BEGN;
end

CHK_BEGN : begin
{cs_temp,cke_temp,ras_temp,cas_temp,we_temp} = 5'b01111; //退出转换模式,开启读写请求检测模式
addr_temp = 0; //
bank_temp = 0; //
dqm_temp = 0; //

stat_cnt_en_temp = NO; //本状态 不 需要重复执行

wr_ok_temp = NO;
rd_ok_temp = NO;

chk_en_temp = YES; //时钟到来时更新到chk_en,准备转到读写请求检测模式

dly_cnt_temp = 2; //延时2个clk周期再跳转到下一个操作状态
dly_en_temp = NO; //这个打开或关闭都可以

nxt_stat = CHK_BEGN;
end

endcase
end


//操作重复次数计数器
always @(posedge clk,negedge rst_n) begin
if(!rst_n) begin
stat_cnt <= 0;
end
else if(stat_cnt_en == YES) begin
if(dly_cnt1 == 1) begin
stat_cnt <= stat_cnt + 1;
end
else ;
end
else stat_cnt <= 0;
end



//定时延时计数器
always @(posedge clk,negedge rst_n) begin
if(!rst_n) begin
dly_en1 <= NO;
dly_ok <= NO;
dly_cnt1 <= 0;
end
else if(dly_en == YES) begin
if((dly_cnt - 2)==0) begin
dly_ok <= YES;
dly_en1 <= NO;
end
else begin
dly_cnt1 <= dly_cnt - 3; //参数修正
dly_en1 <= YES;
end
end
else if(dly_en1 == YES) begin
if(dly_cnt1 == 0) begin
dly_en1 <= NO;
dly_ok <= YES;
end
else begin
dly_cnt1 <= dly_cnt1 - 1;
end
end
else dly_ok <= NO; //??2ù×÷
end//always

endmodule 
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
 

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

363732023_340721035 2012-10-9 13:49

很好
相关推荐阅读
用户1629256 2012-09-10 21:37
[Craftor原创]精通ModelSim脚本(1)
[Craftor原创]精通ModelSim脚本(1) ModelSim之强大是毋庸置疑的。而ModelSim脚本语言的强大,也同样让人佩服得五体投地。在此文中,Craftor将一...
用户1629256 2012-09-10 11:06
调用modelsim 不用每次都编译库文件 转载 谢谢观赏
Quartus II调用modelsim无缝仿真   本篇文章为转载,写的不错,最近在学modelsim仿真,网上的教程很乱,把自己认为不错的整理贴出来,后面有机会会写个详细...
用户1629256 2012-09-04 11:17
SDRAM控制器,V1版,最基本功能,仍在升级中。。。。
  以上是上电200us后,对SDRAM的初始化时序图:左数第一条黄线是对所有bank预充电,第二条到第三条黄线是8个刷新周期,第四条黄线是模式寄存器设置。 以上是对SDRAM...
用户1629256 2012-08-09 10:13
评论:@阿松的博客 博客中提到的“让低端FPGA也能跑nios”
强悍...
用户1629256 2012-08-05 20:02
基于ISSI-IS61LV25616编写的fifo控制器(请热心网友大胆斧正,不吝赐教,重谢)
/**  ******************************************************************************  * @file     fi...
EE直播间
更多
我要评论
1
8
关闭 站长推荐上一条 /3 下一条