module SDRAM(
input clk,
input rst_n,
input wr_rp,
input rd_rp,
input[23:0] addr_i,
input[15:0] wdata,
output reg wr_ack,
output reg rd_ack,
output reg[15:0] rdata,
output reg rdata_vld,
output reg cke,
output reg cs,
output reg ras,
output reg cas,
output reg we,
output reg[1:0] dqm,
output reg[11:0] addr_o,
output reg[1:0] bank,
inout[15:0] dq,
output debug
);
reg[15:0] wdata_ff0;
reg[15:0] wdata_ff1;
reg[15:0] wdata_ff2;
reg[15:0] wdata_ff3;
reg[3:0] cmd;
reg read_flag_ff0;
reg read_flag_ff1;
reg read_flag_ff2;
reg[3:0] state_c;
reg[3:0] state_n;
reg init_flag;
reg resh_flag;
reg rd_flag;
reg rd_hty;
reg[1:0] resh_cnt;
reg[14:0] cnt;
reg[14:0] x;
reg[10:0] cnt1;
reg[23:0] addr_i_ff0;
//state_c
parameter INIT_NOP =4’b0001; //1
parameter PRECHARGE =4’b0010; //2
parameter REFRESH =4’b0011; //3
parameter MODE =4’b0100; //4
parameter IDLE =4’b0101; //5
parameter ACTIVE =4’b0110; //6
parameter WRITE =4’b0111; //7
parameter READ =4’b1000; //8
//cmd
parameter NOP_CMD =4’b0111; //7H
parameter PRECHARGE_CMD =4’b0010; //2H
parameter REFRESH_CMD =4’b0001; //1H
parameter MODE_CMD =4’b0000; //0H
parameter ACTIVE_CMD =4’b0011; //3H
parameter WRITE_CMD =4’b0100; //4H
parameter READ_CMD =4’b0101; //5H
parameter T_200US =15’d20000;
parameter TRP =14’d4;
parameter TRC =14’d7;
parameter TMRD =14’d2;
parameter TRCD =14’d3;
parameter T_256 =14’d256;
parameter MODE_VALUE =12’b000000110111;
//A11 A10 A9 A8 A7 A6 A5 A4 A3 A2 A1 A0
// 0 0 0 0 0 0 1 1 0 1 1 1
//————————— ————– — —————
//突发读/写 潜伏期=3 顺序 全页
parameter ALL_BANK =12’b001000000000;
always@(posedge clk or negedge rst_n)begin
if(rst_n==1’b0)begin
state_c<=INIT_NOP;
end
else begin
state_c<=state_n;
end
end
always@(*)begin
case(state_c)
INIT_NOP:begin
if(ini2pre_start)begin
state_n =PRECHARGE;
end
else begin
state_n =state_c;
end
end
PRECHARGE:begin
if(pre2ref_start)begin
state_n =REFRESH;
end
else if(pre2idl_start)begin
state_n =IDLE;
end
else begin
state_n =state_c;
end
end
REFRESH:begin
if(ref2ref_start)begin
state_n =REFRESH;
end
else if(ref2mod_start)begin
state_n =MODE;
end
else if(ref2idl_start)begin
state_n =IDLE;
end
else begin
state_n =state_c;
end
end
MODE:begin
if(mod2idl_start)begin
state_n =IDLE;
end
else begin
state_n =state_c;
end
end
IDLE:begin
if(idl2ref_start)begin
state_n =REFRESH;
end
else if(idl2act_start)begin
state_n =ACTIVE;
end
else begin
state_n =state_c;
end
end
ACTIVE:begin
if(act2wrt_start)begin
state_n =WRITE;
end
else if(act2red_start)begin
state_n =READ;
end
else begin
state_n =state_c;
end
end
WRITE:begin
if(wrt2pre_start)begin
state_n =PRECHARGE;
end
else begin
state_n=state_c;
end
end
READ:begin
if(red2pre_start)begin
state_n =PRECHARGE;
end
else begin
state_n =state_c;
end
end
default:begin
state_n =INIT_NOP;
end
endcase
end
assign ini2pre_start =state_c ==INIT_NOP &&end_cnt;
assign wrt2pre_start =state_c ==WRITE &&end_cnt;
assign red2pre_start =state_c ==READ &&end_cnt;
assign pre2ref_start =state_c ==PRECHARGE &&end_cnt &&init_flag;
assign pre2idl_start =state_c ==PRECHARGE &&end_cnt &&init_flag==0;
assign ref2ref_start =state_c ==REFRESH &&end_cnt &&resh_cnt==0 &&init_flag;
assign ref2mod_start =state_c ==REFRESH &&end_cnt &&resh_cnt==1 &&init_flag;
assign ref2idl_start =state_c ==REFRESH &&end_cnt &&init_flag==0;
assign mod2idl_start =state_c ==MODE &&end_cnt;
(* keep *)wire idl2act_start;
assign idl2act_start =state_c ==IDLE &&resh_flag==0 &&(rd_req || wr_req);
assign idl2ref_start =state_c ==IDLE &&(resh_flag || end_cnt1);
assign act2wrt_start =state_c ==ACTIVE &&end_cnt &&rd_flag==0;
assign act2red_start =state_c ==ACTIVE &&end_cnt &&rd_flag==1;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
cnt<=0;
end
else if(add_cnt)begin
if(end_cnt)begin
cnt<=0;
end
else begin
cnt<=cnt+1'b1;
end
end
end
assign add_cnt =state_c!=IDLE;
assign end_cnt =add_cnt&&cnt==x-1;
always @(*)begin
if(state_c ==INIT_NOP)begin
x =T_200US;
end
else if(state_c==PRECHARGE)begin
x =TRP;
end
else if(state_c==REFRESH)begin
x =TRC;
end
else if(state_c ==MODE)begin
x =TMRD;
end
else if(state_c ==ACTIVE)begin
x =TRCD;
end
else if(state_c ==WRITE || state_c ==READ)begin
x =T_256;
end
else begin
x =0;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
cnt1 <=0;
end
else if(add_cnt1)begin
if(end_cnt1)begin
cnt1<=0;
end
else begin
cnt1<=cnt1 +1'b1;
end
end
end
assign add_cnt1 =init_flag==1'b0;
assign end_cnt1 =add_cnt1 &&cnt1==781-1;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
resh_flag<=1'b0;
end
else if(end_cnt1)begin
resh_flag<=1'b1;
end
else if(state_c == REFRESH)begin
resh_flag<=1'b0;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
init_flag<=1;
end
else if(mod2idl_start)begin
init_flag<=0;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
resh_cnt<=0;
end
else if(add_resh_cnt)begin
if(end_resh_cnt)begin
resh_cnt<=0;
end
else begin
resh_cnt<=resh_cnt +1'b1;
end
end
end
assign add_resh_cnt =init_flag &&state_c ==REFRESH &&end_cnt;
assign end_resh_cnt =add_resh_cnt &&resh_cnt ==2-1;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
rd_hty<=1'b0;
end
else if(pre2idl_start)begin
rd_hty<=rd_flag;
end
end
reg wr_hold;
reg rd_hold;
always @(posedge clk or negedge rst_n)begin
if (!rst_n)begin
wr_hold<=1'b0;
end
else begin
if (wr_rp)begin
wr_hold<=1'b1;
end
else if (state_c==WRITE)begin
wr_hold<=1'b0;
end
end
end
always @(posedge clk or negedge rst_n)begin
if (!rst_n)begin
rd_hold<=1'b0;
end
else begin
if (rd_rp)begin
rd_hold<=1'b1;
end
else if (state_c==READ)begin
rd_hold<=1'b0;
end
end
end
(* keep *) wire write_sel;
(* keep *) wire read_sel;
assign wr_req = wr_rp || wr_hold;
assign rd_req = rd_rp || rd_hold;
assign write_sel =idl2act_start &&((rd_hty==1'b0 &&rd_req==1'b0)||rd_hty==1'b1) &&wr_req;
assign read_sel =idl2act_start &&((rd_hty==1'b1 &&wr_req==1'b0)||rd_hty==1'b0) &&rd_req;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
rd_flag<=1'b0;
end
else if(write_sel)begin
rd_flag<=1'b0;
end
else if(read_sel)begin
rd_flag<=1'b1;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
addr_i_ff0<=0;
end
else begin
addr_i_ff0<=addr_i;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
bank <=2'b00;
end
else if(idl2act_start)begin
bank<=addr_i[23:22];
end
else if(act2wrt_start ||act2red_start)begin
bank<=addr_i_ff0[23:22];
end
else begin
bank<=2'b00;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
addr_o<=0;
end
else if(ref2mod_start)begin
addr_o<=MODE_VALUE;
end
else if(ini2pre_start ||wrt2pre_start ||red2pre_start)begin
addr_o<=ALL_BANK;
end
else if(idl2act_start)begin
addr_o<=addr_i[21:10];
end
else if(act2wrt_start ||act2red_start)begin
addr_o<={addr_i_ff0[9:0]};
end
else begin
addr_o<=0;
end
end
always @(*)begin
rd_ack=read_sel;
end
assign read_flag =state_c==READ;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
read_flag_ff0<=1'b0;
read_flag_ff1<=1'b0;
read_flag_ff2<=1'b0;
end
else begin
read_flag_ff0 <=read_flag;
read_flag_ff1 <=read_flag_ff0;
read_flag_ff2 <=read_flag_ff1;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
rdata<=0;
end
else if(read_flag_ff2)begin
rdata<=dq;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
rdata_vld<=0;
end
else if(read_flag_ff2)begin
rdata_vld<=1;
end
else if(pre2idl_start &&rd_flag)begin
rdata_vld<=0;
end
end
always @(*)begin
wr_ack =write_sel;
end
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
wdata_ff0<=0;
wdata_ff1<=0;
wdata_ff2<=0;
wdata_ff3<=0;
end
else begin
wdata_ff0<=wdata;
wdata_ff1<=wdata_ff0;
wdata_ff2<=wdata_ff1;
wdata_ff3<=wdata_ff2;
end
end
(* keep *) wire dq_en;
assign dq_en =state_c ==WRITE;
assign dq =dq_en?wdata_ff3:16'hzzzz;
/*
(* preserve *) reg dq_en_debug;
always @(posedge clk) dq_en_debug <= dq_en;
*/
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
cke<=0;
end
else begin
cke<=1;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
cmd<=NOP_CMD;
end
else if(ini2pre_start ||wrt2pre_start ||red2pre_start)begin
cmd<=PRECHARGE_CMD;
end
else if(pre2ref_start ||ref2ref_start ||idl2ref_start)begin
cmd<=REFRESH_CMD;
end
else if(ref2mod_start)begin
cmd<=MODE_CMD;
end
else if(act2wrt_start)begin
cmd<=WRITE_CMD;
end
else if(act2red_start)begin
cmd<=READ_CMD;
end
else if(idl2act_start)begin
cmd<=ACTIVE_CMD;
end
else begin
cmd<=NOP_CMD;
end
end
always @(*)begin
{cs,ras,cas,we}=cmd;
end
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
dqm<=2'b00;
end
else if(dqm_en)begin
dqm<=2'b11;
end
else begin
dqm<=2'b00;
end
end
assign dqm_en =state_c==init_flag;
endmodule
