一、自动刷新
自动刷新由控制器对SDRAM正常操作,需要时钟信号,时序图
自动刷新步骤:
上电即开始–预充电–A10拉高选择all bank–等待tRP后,自动刷新命令–等待tRFc后,第二次自动刷新命令–等待tRFc,自动刷新结束,空操作命令
///自动刷新操作任务,采用线性序列机方法
localparam ref_PRE_TIME = 1'b1, //预充电时刻
ref_REF1_TIME = REF_PRE + 1, //第一次自动刷新时刻,充电时刻加REF_PRE(tRP选通潜伏期)
ref_REF2_TIME = REF_PRE + REF_REF + 1, //第二次自动刷新时刻,每次刷新后等待tRFc
ref_END = REF_PRE + REF_REF *2; //自动刷新结束时刻
//自动刷新过程时间计数器
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
ref_cnt <= 16'd0;
else if(ref_cnt == ref_END)
ref_cnt <= 16'd0;
else if(ref_req || ref_cnt>1'b0)
ref_cnt <= ref_cnt +16'd1;
else
ref_cnt <= ref_cnt;
end
//一次刷新操作完成标志位ref_opt_done
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
ref_opt_done <= 1'b0;
else if(ref_cnt ==ref_END)
ref_opt_done <= 1'b1;
else
ref_opt_done <= 1'b0;
end
//一次突发写操作过程状态标识信号。ref_req刷新操作时,ref_opt_done拉高,自动刷新操作完成后拉低
reg ref_opt;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
ref_opt <= 1'b0;
else if(ref_req ==1'b1)
ref_opt <= 1'b1;
else if(ref_opt_done == 1'b1)
ref_opt <= 1'b0;
else
ref_opt <= ref_opt;
end
//自动刷新操作,线性序列机,根据时序图,是在下降沿后发生改变,上升沿时正好能读取到
task auto_ref;
begin
case(ref_cnt)
ref_PRE_TIME:begin
command <= C_PRE; //预充电
sa[10] <= 1'b1; //SDRAM地址总线A0-A10,其中的A10拉高选择all bank
end
ref_REF1_TIME:begin
command <= C_AREF; //自动刷新
end
ref_REF2_TIME:begin
command <= C_AREF; //自动刷新
end
ref_END:begin //结束,空操作命令
FF <= 1'b1; //标记寄存器,拉高
command <= C_NOP;
end
default:
command <= C_NOP;
endcase
end
endtask
二、不带自动预充电写操作
时序图:
写操作步骤:
上电–激活行时刻,写操作开始立刻激活命令,激活行、bank–激活后tRCD,写命令,激活列、bank–写命令后经突发长度SC_BL写数据、写数据完成到预充电时间间隔后预充电–预充电后tRP后结束,写操作结束时刻
//
//一次突发写操作任务,线性序列机方法
localparam
wr_ACT_TIME = 1'b1; //激活行时刻,写操作开始立刻激活
wr_WRITE_TIME = SC_RCD +1, //写命令时刻,激活到读命令或写命令延时tRCD后写命令
wr_PRE_TIME = SC_RCD + SC_BL + WR_PRE + 1, //预充电时刻,写命令后经突发长度SC_BL写数据、写数据完成到预充电时间间隔后预充电
wr_END_TIME = SC_RCD + SC_BL + WR_PRE +REF_PRE;//写操作结束时刻,预充电后tRP后结束
//一次突发写操作过程时间计数器
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
wr_cnt <= 16'd0;
else if(wr_cnt == wr_END_TIME)
wr_cnt <= 16'd0;
else if(wr_req || wr_cnt>1'b0) //写操作请求或读书开始后读数
wr_cnt <= wr_cnt + 16'd1;
else
wr_cnt <= 16'd0;
end
//一次写操作过程完成标志位
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
wr_opt_done <= 1'b0;
else if(wr_cnt == wr_END_TIME)
wr_opt_done <= 1'b1;
else
wr_opt_done <= 1'b0;
end
//一次突发写操作过程状态标识信号wr_opt,写操作时拉高,写完拉低
reg wr_opt;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
wr_opt <= 1'b0;
else if(wr_req == 1'b1)
wr_opt <= 1'b1;
else if(wr_opt_done == 1'b1)
wr_opt <= 1'b0;
else
wr_opt <= wr_opt;
end
//写数据操作,数据写入(改变)时刻有效区间,激活到读命令或写命令延时tRCD后到突发长度8这一段时序数据写入
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
wr_data_vaild <= 1'b0;
else if((wr_cnt > SC_RCD)&& (wr_cnt <= SC_RCD + SC_BL))
wr_data_vaild <= 1'b1;
else
wr_data_vaild <= 1'b0;
end
//一次突发写操作数据写完成标志位,写完拉高
assign wdata_done = (wr_cnt == SC_RCD+SC_BL+1)?1'b1:1'b0;
//一次突发写操作任务,类似线性序列机方法
task write_data;
begin
case(wr_cnt)
wr_ACT_TIME:begin //激活行时刻
command <= C_ACT; //激活命令
sa <= raddr_r; //激活行,SDRAM地址总线读写行地址寄存器
ba <= baddr_r; //激活bank,SDRAMBank地址读写bank地址寄存器
end
wr_WRITE_TIME:begin //写命令时刻
command <= C_WR; //写命令
sa <= {1'b0,caddr_r[8:0]}; //激活列,读写列地址寄存器A0-A9
ba <= baddr_r;
end
wr_PRE_TIME:begin //预充电时刻
command <= C_PRE; //预充电命令
sa[10] <= 1'b1; //所有bank
end
wr_END_TIME:begin //写操作结束时刻
command <= C_NOP; //空命令
FF <= 1'b1; 标记寄存器拉高
end
default:
command <= C_NOP;
endcase
end
endtask
//一次突发读操作任务,线性序列机方法
localparam
rd_ACT_TIME = 1'b1, //激活行时刻
rd_READ_TIME = SC_RCD+1, //读命令时刻
rd_PRE_TIME = SC_RCD+SC_BL+1, //预充电时刻
rd_END_TIME = SC_RCD+SC_CL+SC_BL;//读操作结束时刻
//一次突发读操作过程时间计数器
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rd_cnt <= 16'd0;
else if(rd_cnt == rd_END_TIME)
rd_cnt <= 16'd0;
else if(rd_req ||rd_cnt>1'b0)
rd_cnt <= rd_cnt + 16'd1;
else
rd_cnt <= 16'd0;
end
//一次突发读操作过程完成标志位
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rd_opt_done <= 1'b0;
else if(rd_cnt == rd_END_TIME)
rd_opt_done <= 1'b1;
else
rd_opt_done <= 1'b0;
end
//一次突发读操作过程状态标识信号
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rd_opt <= 1'b0;
else if(rd_req == 1'b1)
rd_opt <= 1'b1;
else if(rd_opt_done == 1'b1)
rd_opt <= 1'b0;
else
rd_opt <= rd_opt;
end
//一次突发读操作过程中数据读完标志位
assign rdata_done = (rd_cnt == rd_END_TIME)?1'b1:1'b0;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rd_data_vaild <= 1'b0;
else if((rd_cnt > SC_RCD+SC_CL)
&&(rd_cnt <= SC_RCD+SC_CL+SC_BL))
rd_data_vaild <= 1'b1;
else
rd_data_vaild <= 1'b0;
end
//读数据
assign rd_data = dq;
//一次突发读操作任务,类似线性序列机方法
task read_data;
begin
case(rd_cnt)
rd_ACT_TIME:begin //激活命令
Command <= C_ACT;
Sa <= raddr_r;
Ba <= baddr_r;
end
rd_READ_TIME:begin //读命令
Command <= C_RD;
Sa <= {1'b0,caddr_r[8:0]};
Ba <= baddr_r;
end
rd_PRE_TIME:begin
Command <= C_PRE; //预充电
Sa[10] <= 1'b1;
end
rd_END_TIME:begin
FF <= 1'b1;
Command <= C_NOP;
end
default:
Command <= C_NOP;
endcase
end
endtask
三、不带自动预充电读操作
与写操作类似