SDRAM 控制器设计基本完结

article/2025/10/26 8:38:38

项目可以拓展的地方:
1、接口为AXI
2、接口为AXI与AXI DMA 交互
2、优化读写时序,使得SDRAM输出效率最大;

总结:
项目不足:没有进行效率的优化,无地址映射,无外接交互接口,功能单一;
注意:读写模块和自刷新模块的跳转时候数据的输出与输入是否有效进入FIFO中(建议把FIFO中的数据看一遍,不能只看物理模型的端口数据),
总体框图:
在这里插入图片描述
实现功能:读写256个数据
步骤:
1、给写入信号,FIFO中数据满256后进行一次读操作,
2、读信号,当读FIFO中能够储存数据大于256个就进行读,这里其实有个BUG:就是当我写模块没有进行数据写入时,也会进行数据的读取,这里其实可以给写模块一个计数器,写一次加一,读模块读一次减一,这个计数器在同一个时钟域下工作;
3:读FIFO的输出信号有个ready信号,为高时告诉主机我FIFO里存储了256个数据,这时可以发出中断,或者标志寄存器置1;

写操作:
在这里插入图片描述
读操作:
在这里插入图片描述
测试我只放我认为重要的图片

测试:
读FIFO;216us的时候读FIFO数据不连续,是sdram进入自刷新模式,注意输出数据的处理怎样才能保持连续;
在这里插入图片描述

在这里插入图片描述
最后说说自己的测试点:
1、连续写,写读写读,写读同时写;

翻啊翻,啊卧槽啊,又出现bug了,受不了了
写的时候自刷新144-147没写进去,看看读是不是为0就知道了;
在这里插入图片描述
果然出现BUG了
在这里插入图片描述
解决它:
原因:写状态的时候,进入自刷新之前需要进入ARBIT状态,如黄线这时state还写状态,发出写使能,只需要修改下写使能代码即可;
bug图:
在这里插入图片描述
代码修改前:
在这里插入图片描述
修改后:
在这里插入图片描述

正确图:
在这里插入图片描述

在这里插入图片描述

上代码:

`timescale 1ns/1nsmodule tb_sdram_top();
reg sclk;
reg s_rstn;
reg rd_trig;wire sdram_clk;
wire sdram_cke;
wire sdram_cs_n;
wire sdram_cas_n;
wire sdram_ras_n;
wire sdram_we_n;
wire [1:0] sdram_bank;
wire [11:0] sdram_addr;
wire [1:0] sdram_dqm;
wire [15:0] sdram_dq;
//reg wr_trig;reg wfifo_wr_clk;
reg wfifo_wr_en;
reg [15:0] wfifo_wr_data;reg rfifo_rd_clk;
reg rfifo_rd_en;wire [15:0] rfifo_rd_data;
wire rd_ready;initial beginsclk<=1;wfifo_wr_clk=1;rfifo_rd_clk=1;s_rstn<=0;#100;s_rstn<=1;
end
always #10 sclk=~sclk;always #15 wfifo_wr_clk=~wfifo_wr_clk;always #15 rfifo_rd_clk=~rfifo_rd_clk;initial begin//wr_trig=0;wfifo_wr_data=0;wfifo_wr_en=0;rfifo_rd_en=0;//#(10026*20)#(10040*20) wfifo_wr_en=1;#(30*300) wfifo_wr_en=0;rfifo_rd_en=1;#(30*300) wfifo_wr_en=1;rfifo_rd_en=0;//#(300*300) wfifo_wr_en=0;
endalways @(posedge wfifo_wr_clk)if(wfifo_wr_en)wfifo_wr_data<=wfifo_wr_data+1'b1;
initial beginend
/*
initial beginrd_trig=0;#(12363*20) rd_trig=1;#(10*20) rd_trig=0;end
*/sdram_top sdram_top_inst1(.sclk             (sclk),.s_rstn           (s_rstn),.sdram_clk        (sdram_clk          ),.sdram_cke        (sdram_cke          ),.sdram_cs_n       (sdram_cs_n         ),.sdram_cas_n      (sdram_cas_n        ),.sdram_ras_n      (sdram_ras_n        ),.sdram_we_n       (sdram_we_n         ),.sdram_bank       (sdram_bank         ),.sdram_addr       (sdram_addr         ),.sdram_dqm        (sdram_dqm          ),.sdram_dq         (sdram_dq           ),.wfifo_wr_clk(wfifo_wr_clk),.wfifo_wr_en(wfifo_wr_en),.wfifo_wr_data(wfifo_wr_data),.rfifo_rd_clk(rfifo_rd_clk),.rfifo_rd_en(rfifo_rd_en),.rfifo_rd_data(rfifo_rd_data),.rd_ready(rd_ready));sdram_model_plus sdram_model_plus_inst(.Dq(sdram_dq),.Addr(sdram_addr),.Ba(sdram_bank), .Clk(sdram_clk), .Cke(sdram_cke          ), .Cs_n(sdram_cs_n         ), .Ras_n(sdram_ras_n        ), .Cas_n(sdram_cas_n        ), .We_n(sdram_we_n         ), .Dqm(sdram_dqm          ),.Debug(1'b1)
);endmodule
module sdram_top(input sclk,input s_rstn,//sdram_interfaceoutput wire sdram_clk,output wire sdram_cke,output wire sdram_cs_n,output wire sdram_cas_n,output wire sdram_ras_n,output wire sdram_we_n,output reg [1:0] sdram_bank,output reg [11:0] sdram_addr,output wire [1:0] sdram_dqm,inout  reg [15:0] sdram_dq,input wfifo_wr_clk,input wfifo_wr_en,input [15:0] wfifo_wr_data,input rfifo_rd_clk,input rfifo_rd_en,output wire [15:0] rfifo_rd_data,output wire rd_ready);localparam NOP=4'b0111;localparam IDLE=5'b0_0001;
localparam ARBIT=5'b0_0010;
localparam AREF=5'b0_0100;
localparam WRITEDATA=5'b0_1000;
localparam READDATA=5'b1_0000;zhoong cai shua xin mo kuai
reg [4:0] state,next_state;
wire ref_req;
reg ref_en; 
wire flag_aref_end;
wire [3:0] ref_cmd;
wire [11:0] ref_addr;wire flag_init_end;
wire [3:0] init_cmd;
wire [12:0] init_addr;wire [3:0] write_cmd;
wire [11:0] wr_addr;
wire [1:0] wr_bank_addr;
wire [15:0]wr_data;wire write_req;
wire write_end;
reg wr_en;assign sdram_dqm=2'b00;
assign sdram_clk=~sclk;
assign sdram_cke=1;//read
reg rd_en;
wire rd_req;
wire rd_end;
//reg aref_req;wire [3:0] rd_cmd;
wire [11:0] rd_addr;
wire [1:0] rd_bank_addr;
wire [15:0] rd_data;wire wr_trig;
wire rd_trig;
wire [15:0] rfifo_wr_data;
wire [15:0] wfifo_rd_data;reg write_end_r2,write_end_r1;//ZHONGCAI
always@(posedge sclk or negedge s_rstn) beginif(~s_rstn)state<=IDLE;elsestate<=next_state;
endalways @(*) begincase (state) IDLE:beginif(flag_init_end)next_state=ARBIT;elsenext_state=IDLE;endARBIT:beginif(ref_req)next_state=AREF;else if (write_req) beginnext_state=WRITEDATA;endelse if(rd_req) beginnext_state=READDATA;endelsenext_state=ARBIT;endAREF:beginif(flag_aref_end)next_state=ARBIT;elsenext_state=AREF;endWRITEDATA:begin//back_write_r=0;if(write_end_r2)next_state=ARBIT;else beginnext_state=WRITEDATA;endendREADDATA:beginif(rd_end)next_state=ARBIT;else next_state=READDATA;enddefault:next_state=IDLE;endcase
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn){write_end_r2,write_end_r1}<='b0;else begin{write_end_r2,write_end_r1}<={write_end_r1,write_end};endend//assign {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n}= (state==IDLE)?init_cmd:ref_addr;
//assign {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n}= init_cmd;
//assign sdram_addr=(state==IDLE)?init_addr:ref_addr;
//assign sdram_addr=init_addr;
reg sdram_cs_n_r,sdram_ras_n_r,sdram_cas_n_r,sdram_we_n_r;
reg sdram_dq_en;
reg [15:0]sdram_dq1;always @(*) begincase (state) IDLE:begin{sdram_cs_n_r,sdram_ras_n_r,sdram_cas_n_r,sdram_we_n_r}= init_cmd;sdram_addr=init_addr;endARBIT:beginsdram_addr      =      12'd0;{sdram_cs_n_r,sdram_ras_n_r,sdram_cas_n_r,sdram_we_n_r}= NOP;		endAREF:begin{sdram_cs_n_r,sdram_ras_n_r,sdram_cas_n_r,sdram_we_n_r}= ref_cmd;sdram_addr=ref_addr;endWRITEDATA:begin{sdram_cs_n_r,sdram_ras_n_r,sdram_cas_n_r,sdram_we_n_r}= write_cmd;sdram_addr=wr_addr[11:0];sdram_bank=rd_bank_addr;sdram_dq1=wr_data;endREADDATA:begin{sdram_cs_n_r,sdram_ras_n_r,sdram_cas_n_r,sdram_we_n_r}= rd_cmd;sdram_addr=rd_addr;sdram_bank=rd_bank_addr;enddefault:begin	endendcase
end
assign sdram_dq=(state==WRITEDATA)?sdram_dq1:'hzzzz;//assign rd_data=(state==READDATA || state==IDLE)?sdram_dq:'b0;
assign rd_data=sdram_dq;
assign {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n}={sdram_cs_n_r,sdram_ras_n_r,sdram_cas_n_r,sdram_we_n_r};always @(posedge sclk or negedge s_rstn) beginif(~s_rstn)ref_en<='b0;else if(state ==AREF)ref_en<='b1;else ref_en<='b0;
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn)wr_en<='b0;else if(state==WRITEDATA && write_end)wr_en<='b0;else if(state==WRITEDATA && next_state==WRITEDATA)wr_en<='b1;elsewr_en<='b0;
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn)rd_en<='b0;else if(state==READDATA && ref_req && rd_end)beginrd_en<='b0;endelse if(state==READDATA)beginrd_en<='b1;endelse beginrd_en<='b0;end
endsdram_init sdram_init_inst(
.sclk(sclk),
.s_rstn(s_rstn),
.cmd_reg(init_cmd),
.sdram_addr(init_addr),
.flag_init_end(flag_init_end)
);sdram_aref sdram_aref_inst(.sclk(sclk),.s_rstn(s_rstn),.ref_en(ref_en),.ref_req(ref_req),.flag_aref_end(flag_aref_end),.aref_cmd(ref_cmd),.sdram_addr(ref_addr),.flag_init_end(flag_init_end)
);sdram_write sdram_write_inst(.sclk(sclk),.s_rstn(s_rstn),.wr_trig(wr_trig),.wr_en(wr_en),.write_req(write_req),.write_end(write_end),.aref_req(ref_req),.write_cmd(write_cmd),.wr_addr(wr_addr[11:0]),.bank_addr(wr_bank_addr),.wr_data(wr_data),.wfifo_rd_data(wfifo_rd_data),.wfifo_rd_en(wfifo_rd_en)
);sdram_read sdram_read_inst(.sclk(sclk),.s_rstn(s_rstn),.rd_trig(rd_trig),//.rd_trig(1'b0),.rd_en(rd_en),.rd_req(rd_req),.rd_end(rd_end),.aref_req(ref_req),.rd_cmd(rd_cmd),.rd_addr(rd_addr),.bank_addr(rd_bank_addr),.rd_data(rd_data),.rfifo_wr_data(rfifo_wr_data),.rfifo_wr_en(rfifo_wr_en)
);sdram_auto_write_read #(.data_width(16),.data_depth(512),.addr_width(9),.read_width(16),.WFIFO_RD_CNT(256),.RFIFO_WR_CNT(256)      
)sdram_auto_write_read_inst1
(. s_rstn(s_rstn),//wfifo//write.wfifo_wr_clk(wfifo_wr_clk),.wfifo_wr_en(wfifo_wr_en),.wfifo_wr_data(wfifo_wr_data),//read.wfifo_rd_clk(sclk),.wfifo_rd_en(wfifo_rd_en),.wfifo_rd_data(wfifo_rd_data),.wfifo_out_full_w(),.wfifo_out_empty_w(),.wfifo_out_wrfifo_rd_cnt(),//写fifo,能最少读256个计数标志.wfifo_out_rdfifo_wr_cnt(), //读fifo,能最少写256个计数标志.wr_trig(wr_trig),//rdfifo //write.rfifo_wr_clk(sclk),.rfifo_wr_en(rfifo_wr_en),.rfifo_wr_data(rfifo_wr_data),////read.rfifo_rd_clk(rfifo_rd_clk),.rfifo_rd_en(rfifo_rd_en),.rfifo_rd_data(rfifo_rd_data),.rfifo_out_full_w(),.rfifo_out_empty_w(),.rfifo_out_wrfifo_rd_cnt(),//写fifo,能最少读256个计数标志.rfifo_out_rdfifo_wr_cnt(), //读fifo,能最少写256个计数标志.rd_trig(rd_trig),       //告诉主机我写入了256个数据可以进行读取了.rd_ready(rd_ready)
);endmodule
module sdram_init (input  wire sclk,input  wire s_rstn,output reg [3:0] cmd_reg,output wire [12:0]sdram_addr,output wire flag_init_end);
//cs ras cas we
localparam DELAY_200US=10000;
localparam NOP=4'b0111;
localparam PREC=4'b0010;
localparam AREF=4'b0001;
localparam modset=4'b0000;
//localparam active=4'b1000;reg [13:0] cnt_200us;
wire 	   flag_200us;
reg [3:0]  cnt_cmd;//200us����
always @(posedge sclk or negedge s_rstn) beginif(~s_rstn)cnt_200us<='b0;else if(~flag_200us)cnt_200us<=cnt_200us+1'b1;else if(flag_200us)cnt_200us<=cnt_200us;
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn)cnt_cmd<='b0;else if(flag_200us & ~flag_init_end)cnt_cmd<=cnt_cmd+1'b1;//else if(flag_init_end)//	cnt_cmd<='b0;
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn)cmd_reg<=NOP;//else if(flag_200us && ~flag_init_end) beginelse if(flag_200us) begincase(cnt_cmd)'d0:cmd_reg<=PREC;//cmd_reg<=NOP;'d1:cmd_reg<=AREF;'d2:cmd_reg<=NOP;'d5:cmd_reg<=AREF;'d6:cmd_reg<=NOP;'d10:cmd_reg<=modset;//'d10:cmd_reg<=NOP;//'d11:cmd_reg<=active;default:cmd_reg<=NOP;endcaseend
end
assign sdram_addr=(cmd_reg==modset)?13'b0_0000_0011_0010:13'b0_0100_0000_0000;
assign  flag_init_end=(cnt_cmd>='d12)?1'b1:1'b0;
assign flag_200us=(cnt_200us>=DELAY_200US)?1'b1:1'b0;endmodule
module sdram_aref(input sclk,input s_rstn,input ref_en,output wire ref_req,output wire flag_aref_end,output reg [3:0] aref_cmd,output wire [12:0] sdram_addr,input flag_init_end);localparam DELAY_78US=390;
reg [3:0] cmd_cnt;
reg [9:0] ref_cnt;
reg       flag_ref;localparam cmd_aref=4'b0001;
localparam cmd_nop=4'b0111;
localparam cmd_pre=4'b0010;always @(posedge sclk or negedge s_rstn) beginif(~s_rstn)ref_cnt<='b0;else if(ref_cnt==DELAY_78US-1)ref_cnt<='b0;else if(flag_init_end)ref_cnt<=ref_cnt+1'b1;
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn)flag_ref<='b0;else if(flag_aref_end)flag_ref<=1'b0;else if(ref_en)flag_ref<=1'b1;
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn)cmd_cnt<='b0;else if(flag_ref)cmd_cnt<=cmd_cnt+1'b1;else cmd_cnt<='b0;
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn)aref_cmd<=cmd_nop;else if (flag_ref)begincase(cmd_cnt)1:aref_cmd<=cmd_pre;2:aref_cmd<=cmd_aref;7:aref_cmd<=cmd_aref;default:aref_cmd<=cmd_nop;endcaseendelse beginaref_cmd<=cmd_nop;end
endreg ref_req_r;
assign sdram_addr=13'b0_0100_0000_0000;
//assign ref_req=(ref_cnt==DELAY_78US-1)?1'b1:'b0;
assign flag_aref_end=(cmd_cnt>='d9)?1'b1:1'b0;always @(posedge sclk or negedge s_rstn) beginif(~s_rstn)ref_req_r<='b0;else if(ref_req_r) beginif(ref_en)ref_req_r<='b0;else ref_req_r<=ref_req_r;end    else if(ref_cnt==DELAY_78US-1)ref_req_r<='b1;else beginref_req_r<='b0;end
end
assign ref_req=ref_req_r;endmodule
//假设FIFO深度不是2的n次幂,但要满足时4的倍数
//这里设计为深度28,利用格雷码的对称性,则格雷码转换的时候需要加32-28=4个地址
//module async_fifo #(parameter data_width = 16,parameter data_depth = 28,parameter addr_width = 5,parameter read_width = 16,parameter   WFIFO_RD_CNT    =       256    ,parameter   RFIFO_WR_CNT    =       256       
)
(input s_rstn,//writeinput wr_clk,input wr_en,input [data_width-1:0] wr_data,//readinput rd_clk,input rd_en,output reg [read_width-1:0] rd_data,output  wire out_full_w,output  wire out_empty_w,output reg out_wrfifo_rd_cnt,//写fifo,能读出256个计数标志output reg out_rdfifo_wr_cnt //读fifo,能写进256个计数标志);reg [addr_width:0] wr_address;
reg [addr_width:0] rd_address;
reg [addr_width:0] gray_wr_address;
reg [addr_width:0] gray_rd_address;
reg [addr_width:0] g2b_r2w;
reg [addr_width:0] g2b_w2r;reg [addr_width:0] async_w2r_r2,async_w2r_r1;
reg [addr_width:0] async_r2w_r2,async_r2w_r1;always @(posedge rd_clk or negedge s_rstn) beginif(~s_rstn) beginrd_address<='d0;endelse if (rd_en && ~out_empty_w) beginif(rd_address=='d511)rd_address<='d0;else rd_address<=rd_address+1'b1;end
end
always @(posedge wr_clk or negedge s_rstn) beginif(~s_rstn) beginwr_address<='d0;endelse if (wr_en && ~out_full_w) beginif(wr_address=='d511)wr_address<='d0;else wr_address<=wr_address+1'b1;end
end
always @(posedge wr_clk ) begingray_wr_address<=(wr_address) ^ ((wr_address)>>1);
end
always @(posedge rd_clk) begingray_rd_address<=(rd_address) ^ ((rd_address)>>1);
endalways @(posedge rd_clk or negedge s_rstn) beginif(~s_rstn) begin{async_w2r_r2,async_w2r_r1}<='b0;endelse begin{async_w2r_r2,async_w2r_r1}<={async_w2r_r1,gray_wr_address};end
endalways @(posedge wr_clk or negedge s_rstn) beginif(~s_rstn) begin{async_r2w_r2,async_r2w_r1}<='b0;endelse begin{async_r2w_r2,async_r2w_r1}<={async_r2w_r1,gray_rd_address};end
end//full and empty signal sheng chengassign out_empty_w=(async_w2r_r2==gray_rd_address);integer i;
always @(*) beginfor(i=0;i<=addr_width;i=i+1) g2b_r2w[i]=^(async_r2w_r2>>i);
endinteger j;
always @(*) beginfor(j=0;j<=addr_width;j=j+1) g2b_w2r[j]=^(async_w2r_r2>>j);
endassign out_full_w=((g2b_r2w+'d510)==wr_address)||((g2b_r2w-'d510)==wr_address);reg [data_width-1:0] register1 [data_depth-1:0];always @(posedge rd_clk) beginif (rd_en && ~out_empty_w) beginif(rd_address[addr_width]==1)   //判断高位是否为1,为一直接截取就可以,为0则要减去相应的数值rd_data<=register1[rd_address[addr_width-1:0]];//直接截取低位就可以else beginrd_data<=register1[rd_address[addr_width-1:0]-'d0];endend
endalways @(posedge wr_clk ) beginif (wr_en && ~out_full_w) beginif(wr_address[addr_width])register1[wr_address[addr_width-1:0]]<=wr_data;else beginregister1[wr_address[addr_width-1:0]-'d0]<=wr_data;endend
end//g2b_r2w
//g2b_w2ralways @(posedge rd_clk or negedge s_rstn) beginif(~s_rstn)out_wrfifo_rd_cnt<=1'b0;else if(~g2b_w2r[addr_width] & rd_address[addr_width])out_wrfifo_rd_cnt<=((g2b_w2r+{addr_width{1'b1}}-rd_address)>=WFIFO_RD_CNT)?1'b1:1'b0;elseout_wrfifo_rd_cnt<=((g2b_w2r-rd_address)>=WFIFO_RD_CNT)?1'b1:1'b0;
endalways @(posedge wr_clk or negedge s_rstn) beginif(~s_rstn)out_rdfifo_wr_cnt<=1'b1;else if(~wr_address[addr_width] & g2b_r2w[addr_width])out_rdfifo_wr_cnt<=((data_depth-(wr_address+{addr_width{1'b1}}-g2b_r2w))>=RFIFO_WR_CNT)?1'b1:1'b0;elseout_rdfifo_wr_cnt<=((data_depth-(wr_address-g2b_r2w))>=RFIFO_WR_CNT)?1'b1:1'b0;
endendmodule
module sdram_write(input sclk,input s_rstn,input wr_trig,input wr_en,output reg write_req,output reg write_end,input aref_req,output reg [3:0] write_cmd,output reg [12:0] wr_addr,output wire [1:0] bank_addr,output wire [15:0] wr_data,input [15:0] wfifo_rd_data,output wire wfifo_rd_en
);localparam cmd_active=4'b0011;
localparam cmd_nop   =4'b0111;
localparam cmd_write =4'b0100;
localparam cmd_precharge=4'b0010;
localparam cmd_autorefresh=4'b0001;//这里可以使用cmd_cnt计数,同初始化和自动刷新模块相似
//也可以使用状态机进行读时序操作,建议状态机,因为读操作
//可以转到其他操作状态,状态机就显得更加方便localparam S_IDLE=5'b0_0001;
localparam S_REQ =5'b0_0010;
localparam S_ACTIVE =5'b0_0100;
localparam S_WRITE_S=5'b0_1000;
localparam S_PER = 5'b1_0000;reg [4:0] state,next_state;reg aref_req_r;
reg flag_act_end_r;
reg flag_data_end_r;
reg row_end_r;
reg [1:0] burst_cnt_r;reg [12:0] row_addr;
reg [8:0] col_addr;parameter  WROW_ADDR_END    =   937         ;
parameter  WCOL_MADDR_END   =   256         ;always @(posedge sclk or negedge s_rstn) beginif(~s_rstn)state<=S_IDLE;elsestate<=next_state;
endalways @(*) begincase (state)S_IDLE:beginif(wr_trig)next_state=S_REQ;elsenext_state=S_IDLE;endS_REQ:beginif(wr_en)next_state=S_ACTIVE;elsenext_state<=S_REQ;endS_ACTIVE:beginif(state==S_ACTIVE && write_cmd==cmd_active)next_state=S_WRITE_S;elsenext_state=S_ACTIVE;endS_WRITE_S:beginif(col_addr== (WCOL_MADDR_END-'d4)&&burst_cnt_r==2'd2)next_state=S_PER;   else if(aref_req_r && burst_cnt_r==2'd2)next_state=S_PER;elsenext_state=state;endS_PER:beginif(flag_data_end_r && write_cmd==cmd_precharge)next_state=S_IDLE;else if(aref_req_r && write_cmd==cmd_precharge)next_state=S_REQ;else if(row_end_r && write_cmd==cmd_precharge)next_state=S_ACTIVE;else next_state=S_PER;enddefault:next_state=S_IDLE;endcase
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn)flag_act_end_r<='b0;else if(state==S_ACTIVE && write_cmd==cmd_active)flag_act_end_r<='b1;elseflag_act_end_r<='b0;
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn)flag_data_end_r<='b0;else if(state==S_WRITE_S && col_addr== (WCOL_MADDR_END-'d4) && burst_cnt_r=='d2)flag_data_end_r<='b1;else if(state==S_IDLE)flag_data_end_r<='b0;
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn)row_end_r<='b0;else if(state==S_WRITE_S && col_addr== (WCOL_MADDR_END-'d4) && burst_cnt_r=='d2)beginrow_end_r<=1'b1;end//else if(row_end_r==1'b1 && write_cmd==cmd_active )else if(row_end_r)row_end_r<=1'b0;
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn)aref_req_r<='b0;else if(aref_req && wr_en)beginaref_req_r<=1'b1;endelse if(write_cmd==cmd_precharge && state==S_PER && aref_req_r==1'b1)aref_req_r<=1'b0;
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn)row_addr<='b0;//else if(flag_data_end_r  )beginelse if(row_end_r && row_addr==(WROW_ADDR_END-'d1)) beginrow_addr<='b0;endelse if(row_end_r)beginrow_addr<=row_addr+'b1;end// end// else if(state==S_ACTIVE && row_end_r=='b0 &&write_cmd==cmd_nop)// row_addr<=row_addr+'d1;
end
always @(posedge sclk or negedge s_rstn) beginif(~s_rstn)col_addr<='b0;else if(state==S_WRITE_S && wr_addr[9:0]==(WCOL_MADDR_END-'d4)&& burst_cnt_r=='d2)col_addr<=1'b0;else if(state==S_WRITE_S && burst_cnt_r=='d2)begincol_addr<=col_addr+'d4;endendalways @(posedge sclk or negedge s_rstn) beginif(!s_rstn)burst_cnt_r<='d2;else if(state==S_WRITE_S && burst_cnt_r=='d3)burst_cnt_r<='d0;else if(state==S_WRITE_S && flag_act_end_r)burst_cnt_r<='d0;    else if(state==S_WRITE_S)burst_cnt_r<=burst_cnt_r+1'b1;elseburst_cnt_r<='b0;
end//always @(*) begin//   case(state)
always @(posedge sclk or negedge s_rstn) beginif(~s_rstn)wr_addr<=13'b0_0000_0000_0000;else case(state)S_IDLE:beginwr_addr<=13'b0_0000_0000_0000;endS_REQ:beginwr_addr<='b0_0000_0000_0000;endS_ACTIVE:beginif(write_cmd==cmd_active)wr_addr<=13'b0_0000_0000_0000;elsewr_addr<=row_addr;endS_WRITE_S:begin/*if(burst_cnt_r=='b11)wr_addr<={3'b000,col_addr};else beginwr_addr<=13'b0_0000_0000_0000;end*/wr_addr<={3'b000,col_addr};endS_PER:beginwr_addr<=13'b0_0100_0000_0000;enddefault:wr_addr<=13'b0_0000_0000_0000;endcase
endassign bank_addr='b00;wire write_end_w;
assign write_end_w=(state==S_PER)&&(flag_data_end_r ||aref_req_r);
always@(posedge sclk ) write_end<=write_end_w;always @(posedge sclk or negedge s_rstn) beginif(~s_rstn)write_cmd<=cmd_nop;else case(state)S_IDLE:beginwrite_cmd<=cmd_nop;endS_REQ:beginwrite_cmd<=cmd_nop;endS_ACTIVE:beginif(write_cmd!=cmd_active)write_cmd<=cmd_active;  elsewrite_cmd<=cmd_nop;endS_WRITE_S:beginif(burst_cnt_r=='d3 || flag_act_end_r)write_cmd<=cmd_write;else beginwrite_cmd<=cmd_nop;endendS_PER:beginif(write_cmd==cmd_precharge)write_cmd<=cmd_nop;elsewrite_cmd<=cmd_precharge;enddefault:write_cmd<=cmd_nop;endcase
endreg write_req_r;always @(posedge sclk or negedge s_rstn) beginif(~s_rstn) beginwrite_req_r<=1'b0;write_req  <=1'b0;endelse if (state==S_REQ)begin//write_req  <=write_req_r;write_req  <=1'b1;write_req_r=1'b1;endelse begin//write_req  <=write_req_r;write_req  <=1'b0;write_req_r=1'b0; end
end
/*
always @(posedge sclk or negedge s_rstn) beginif(~s_rstn)wr_data<='b0;else if(state==S_WRITE_S ||next_state==S_WRITE_S)wr_data<=wfifo_rd_data;elsewr_data<=wr_data;
end*///assign wr_data=(state==S_WRITE_S)?wfifo_rd_data:'b0;
assign wr_data=wfifo_rd_data;
/*
always @(posedge sclk or negedge s_rstn) beginif(~s_rstn)wfifo_rd_en<=1'b0;else if(state==S_WRITE_S)wfifo_rd_en<=1'b1;
end*/assign wfifo_rd_en=(state==S_WRITE_S)?1'b1:1'b0;endmodule
module sdram_read(input sclk,input s_rstn,input rd_trig,input rd_en,output wire rd_req,output wire rd_end,input aref_req,output reg [3:0] rd_cmd,output reg [11:0] rd_addr,output wire [1:0] bank_addr,input  [15:0] rd_data,output [15:0] rfifo_wr_data,output wire rfifo_wr_en
);
parameter RROW_ADDR_END =937;
parameter RCOL_ADDR_END =256;reg [1:0] burst_cnt_r;
reg [4:0] current_state,next_state;localparam S_IDLE=5'b01000;
localparam S_REQ =5'b1_0000;
localparam S_ACTIVE =5'b00001;
localparam S_READ   =5'b00010;
localparam S_PRECHARGE =5'b00100;
//localparam S_ACTIVE =4'b1000;
//localparam S_ACTIVE =4'b0001;localparam cmd_active=4'b0011;
localparam cmd_nop   =4'b0111;
localparam cmd_read =4'b0101;
localparam cmd_precharge=4'b0010;
localparam cmd_autorefresh=4'b0001;reg flag_row_end_r;
reg flag_read_end_r;reg [8:0] col_address;
reg [11:0] row_address;
reg [1:0] col_cnt_r;
reg flag_row_end_r_r,flag_row_end_r_r1,flag_row_end_r_r2;always @(posedge sclk or negedge s_rstn) beginif(~s_rstn)current_state<=S_IDLE;elsecurrent_state<=next_state;
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn){flag_row_end_r_r,flag_row_end_r_r1,flag_row_end_r_r2}<='b0;else begin{flag_row_end_r_r2,flag_row_end_r_r1,flag_row_end_r_r}<={flag_row_end_r_r1,flag_row_end_r_r,flag_row_end_r};end
endalways @(*) begincase(current_state)S_IDLE:beginif(rd_trig)next_state=S_REQ;elsenext_state=S_IDLE;endS_REQ:beginif(rd_en)next_state=S_ACTIVE;elsenext_state=S_REQ;endS_ACTIVE:beginif(rd_cmd==cmd_active)next_state=S_READ;elsenext_state=S_ACTIVE;endS_READ:beginif((flag_read_end_r||flag_row_end_r_r)&& burst_cnt_r=='d3)next_state=S_PRECHARGE;else if(aref_req && burst_cnt_r=='d3)next_state=S_PRECHARGE;else beginnext_state=S_READ;endend///S_PRECHARGE:beginif(flag_read_end_r)next_state=S_IDLE;else if(aref_req && rd_cmd==cmd_precharge)begin   next_state=S_REQ;endelse if(flag_row_end_r) beginnext_state=S_ACTIVE;endelse beginnext_state=S_IDLE;endenddefault:next_state=S_IDLE;endcase
endassign rd_req=(current_state==S_REQ);
assign rd_end=(current_state==S_PRECHARGE && ((aref_req==1'b1)||( rd_cmd==cmd_precharge && flag_read_end_r)));
assign bank_addr='b00;//    output reg [3:0] rd_cmd,
//    output reg [11:0] rd_addr,always @(*) begincase(current_state)S_IDLE:beginrd_cmd=cmd_nop;//rd_addr='b0;endS_REQ:beginrd_cmd=cmd_nop;//rd_addr='b0;            endS_ACTIVE:begin//rd_addr='b0;   if(rd_cmd==cmd_active)rd_cmd=cmd_nop;else beginrd_cmd=cmd_active;endendS_READ:beginif(burst_cnt_r=='b0)rd_cmd=cmd_read;else beginrd_cmd=cmd_nop;endend///S_PRECHARGE:beginif(rd_cmd==cmd_precharge)rd_cmd=cmd_nop;else beginrd_cmd=cmd_precharge;endenddefault:rd_cmd=cmd_nop;endcase
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn)burst_cnt_r<='b0;else if(current_state==S_READ) beginif(burst_cnt_r=='d3)burst_cnt_r<='b0;elseburst_cnt_r<=burst_cnt_r+1'b1;end
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn) beginflag_read_end_r<='b0;end//else if(col_cnt_r=='b1 && col_address=='d508 && burst_cnt_r=='d0)begin//else if(col_cnt_r=='b1 && col_address==(RCOL_ADDR_END-'d4) && burst_cnt_r=='d0)beginelse if( col_address==(RCOL_ADDR_END-'d4) && burst_cnt_r=='d0)beginflag_read_end_r<='b1;endelse if(rd_cmd==cmd_precharge && flag_read_end_r==1'b1)flag_read_end_r<='b0;
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn) begincol_cnt_r<='b0;endelse if(flag_read_end_r)col_cnt_r<='b0;else if(flag_row_end_r)col_cnt_r<='b1;else begincol_cnt_r<=col_cnt_r;            end
endalways @(posedge sclk or negedge s_rstn) beginif(~s_rstn) beginflag_row_end_r<='b0;endelse if(col_address=='d508 && burst_cnt_r=='d3)beginflag_row_end_r<='b1;endelse if(rd_cmd==cmd_precharge && flag_row_end_r==1'b1)flag_row_end_r<='b0;elseflag_row_end_r<=flag_row_end_r;
endalways @(*) begincase(current_state)S_IDLE:beginrd_addr<='b0;endS_REQ:beginrd_addr<='b0;endS_ACTIVE:beginrd_addr<=row_address;endS_READ:beginrd_addr<={3'b0,col_address};end///S_PRECHARGE:begin                           rd_addr<='b0100_0000_0000;enddefault:rd_addr<='b0000_0000_0000;endcase
end//reg [8:0] col_address;
//reg [11:0] row_address;
always @(posedge sclk or negedge s_rstn) beginif (~s_rstn) begincol_address<='d0;     endelse if((col_address=='d508 ||col_address==RCOL_ADDR_END-'d4)&& current_state == S_READ && burst_cnt_r=='d1)col_address<='d0;else if(current_state == S_READ && burst_cnt_r=='d1)col_address<=col_address+4'd4;
endalways @(posedge sclk or negedge s_rstn) beginif (~s_rstn) beginrow_address<='d0;     endelse if(row_address==(RROW_ADDR_END-1'd1) &&current_state == S_PRECHARGE && flag_row_end_r)row_address<='d0;else if(current_state == S_PRECHARGE && (flag_row_end_r||flag_read_end_r))row_address<=row_address+'d1;else beginrow_address<=row_address;endendreg [7:0] rfifo_wr_en_cnt;
//rfifo_wr_en
wire rfifo_wr_en_w;
reg rfifo_wr_en_r,rfifo_wr_en_r1;/*
always @(posedge sclk or negedge s_rstn) beginif (~s_rstn) beginrfifo_wr_en_r<='d0;     endelse if(current_state == S_PRECHARGE && rd_cmd==cmd_precharge)rfifo_wr_en_r<='d0;else if(current_state == S_READ && burst_cnt_r==1'b1)rfifo_wr_en_r<='d1;else beginrfifo_wr_en_r<=rfifo_wr_en;end
end*/
assign rfifo_wr_en_w=(current_state == S_READ)?1'b1:1'b0;always @(posedge sclk or negedge s_rstn) beginif(~s_rstn){rfifo_wr_en_r1,rfifo_wr_en_r}<='b0; else begin{rfifo_wr_en_r1,rfifo_wr_en_r}<={rfifo_wr_en_r,rfifo_wr_en_w};end  
endassign rfifo_wr_en=rfifo_wr_en_r1;assign rfifo_wr_data=rd_data;endmodule

http://chatgpt.dhexx.cn/article/vigrUHvY.shtml

相关文章

SDRAM读写控制

SDRAM读写控制器&#xff0c;这里分为三个部分&#xff0c;分别是SDRAM的基本操作实现&#xff0c;SDRAM控制器&#xff0c;封装成FIFO,以方便使用。 一、SDRAM的基本操作&#xff1a;初始化模块、自动刷新模块、写操作模块、读操作模块、SDRAM仲裁模块&#xff0c;顶层模块。 …

SDRAM 控制器(二)——初始化模块

1、初始化模块 SDRAM 的初始化是芯片上电后必须进行的一项操作&#xff0c;只有进行了初始化操作的 SDRAM 芯片才可被正常使用。SDRAM 的初始化是一套预先定义好的流程&#xff0c;除此之外的其 他操作会导致 SDRAM 出现不可预知的后果。 初始化时序图&#xff1a; CK&#xf…

SDRAM详细介绍

概念介绍&#xff1a; SDRAM&#xff1a;Synchronous Dynamic Random Access Memory&#xff0c;同步动态随机存储器。同步是指其时钟频率和CPU前端总线的系统时钟相同&#xff0c;并且内部命令的发送与数据的传输都以它为基准&#xff1b;动态是指存储阵列需要不断的刷新来保证…

sdram简易控制器设计

耗时一周&#xff0c;终于完成sdram简易控制器的所有代码设计&#xff0c;其中感谢开源骚客 – 邓堪文老师在b站发布的相关视频学习教材&#xff1b;其中仿真模块及所使用到的sdram仿真文件来源于开源骚客&#xff1b; 因为时间较为紧迫&#xff0c;其中就不做代码的一些注释&…

基于FPGA的SDRAM控制器设计(一)

基于FPGA的SDRAM控制器设计&#xff08;一&#xff09; 1. SDRAM控制器整体框架2.UART_RX模块3.UART_TX模块4. RX与TX模块的整合5.需要注意的问题6.代码7.参考资料 1. SDRAM控制器整体框架 图1.1整体框架 PC端通过串口模块UART_RX发送读写命令以及数据到Cmd_encode模块&#xf…

基于FPGA的SDRAM控制器设计(1)

基于FPGA的SDRAM初始化配置 SDRAM简述SDRAM的引脚及作用SDRAM初始化时序控制SDRAM上电时序代码SDRAM测试模块的代码仿真测试结果参考文献总结 SDRAM简述 SDRAM&#xff08; Synchronous Dynamic Random Access Memory&#xff09;&#xff0c;同步动态随机存储器。同步是指 Me…

FPGA进阶(3):SDRAM读写控制器的设计与验证

文章目录 第50讲&#xff1a;SDRAM读写控制器的设计与验证理论部分设计与实现1. sdram_ctrlsdram_initsdram_a_refsdram_writesdram_readsdram_arbitsdram_ctrl 2. sdram_topfifo_ctrlsdram_top 3. uart_sdramuart_rxuart_txfifo_readuart_sdram 第50讲&#xff1a;SDRAM读写控…

SDRAM

简介、优缺点、历史 1、译为“同步动态随机存取内存”&#xff0c;区别于异步DRAM。SRAM是异步静态存储器。 2、同步(Synchronous)&#xff1a;与通常的异步 DRAM 不同&#xff0c; SDRAM 存在一个同步接口&#xff0c;其工作时钟的时钟频率与对应控制器(CPU/FPGA上的读写控制…

关于SDRAM存储器

一、对SDRAM的初步认识 1.1 什么是SDRAM SDRAM&#xff08;Synchronous Dynamic Random Access Memory&#xff09;&#xff0c;同步动态随机存取存储器。 同步&#xff1a;工作频率与对应控制器的系统时钟频率相同&#xff0c;且内存内部的命令以及数据的传输都以此为基准 …

内存控制器与SDRAM

内存接口概念&#xff1a; 通常ARM芯片内置的内存很少&#xff0c;要运行Linux&#xff0c;需要扩展内存。ARM9扩展内存使用SDRAM内存&#xff0c;ARM11使用 DDR SDRAM。S3C2440通常外接32位64MBytes的SDRAM&#xff0c;采用两片16位32M的SDRAM芯片&#xff0c;SDRAM芯片通过地…

SDRAM驱动篇之简易SDRAM控制器的verilog代码实现

在Kevin写的上一篇博文《SDRAM理论篇之基础知识及操作时序》中&#xff0c;已经把SDRAM工作的基本原理和SDRAM初始化、读、写及自动刷新操作的时序讲清楚了&#xff0c;在这一片博文中&#xff0c;Kevin来根据在上一篇博文中分析的思路来把写一个简单的SDRAM控制器。 我们在上一…

FPGA之SDRAM控制器设计(一)

MT48LC128M4A2 – 32 Meg x 4 x 4 banks是512M SRAM&#xff0c;总体概述如下图 分别从上电初始化&#xff0c;刷新&#xff0c;写&#xff0c;读四个部分进行设计&#xff0c;此外还包含主控状态机&#xff0c;一个顶层。 1&#xff1a;上电初始化 整体架构&#xff1a;从控…

内存控制器与SDRAM【赞】

原文链接&#xff1a;https://blog.csdn.net/qq_31216691/article/details/87115697 内存接口概念&#xff1a; 通常ARM芯片内置的内存很少&#xff0c;要运行Linux&#xff0c;需要扩展内存。ARM9扩展内存使用SDRAM内存&#xff0c;ARM11使用 DDR SDRAM。S3C2440通常外接32位6…

SDRAM 介绍

目录 1、名词解释 2、SDRAM 内部结构 3、SDRAM 外部信号描述 4、SDRAM 命令 4.1、COMMAND INHIBIT 4.2、NO OERATION 4.3、ACTIVE 4.4、LOAD MODE REGISTER (LMR) 4.5、READ 4.6、WRITE 4.7、PRECHARGE 4.8、BURST TERMINATE 4.9、REFRESH 4.9.1、AUTO REFRESH …

SDRAM控制器操作时序

此为学习http://dengkanwen.com/137.html整理的笔记&#xff0c;侵删&#xff01; SDRAM工作原理 内部的状态跳转图 我们所需关注的几个地方&#xff1a; 1&#xff09;粗黑线表示在该状态下会自动跳转到另一个状态&#xff0c;细黑线表示需要给命令才会跳转。 2&#xff09…

SDR SDRAM控制器设计

目录 前言 1、关于刷新 2、关于数据中心对齐 3、SDRAM芯片手册介绍 3.1SDRAM芯片的管脚 3.2 SDRAM指令集 3.3 模式寄存器 3.4 关于SDRAM上电初始化和装载模式寄存器 3.5 SDRAM刷新时序 3.6 关于写访问 3.7 关于突发访问 4、FPGA工程设计 4.1状态机设计 5、仿真测试…

【GD32】从零开始学GD32单片机高级篇——外部存储器控制器EXMC详解+SDRAM读写例程

目录 简介外部设备地址映射NOR和PSRAM的地址映射NAND/PC Card地址映射SDRAM地址映射 NOR/PSRAM控制器接口描述控制时序模式1模式2 NAND Flash或PC Card控制器接口描述控制时序 SDRAM控制器接口描述控制时序突发读操作突发写操作读写FIFO跨边界读写操作低功耗模式自刷新模式掉电…

初识内存控制器和SDRAM【一文了解】

原文链接&#xff1a;https://blog.csdn.net/qq_36243942/article/details/85596249 目录 1.引入内存控制器 2.不同位宽内存设备之间的连接 3.如何确定芯片的访问地址 4.分析读写NOR FLASH的读写时序 5.SDRAM初识 6.编程读/写 SDRAM 附录&#xff1a;源代码 1.引入内存控制器 我…

存储控制器(SDRAM操作)

什么是存储控制器 2440是32位单片机&#xff0c;进行数据访问时通过32位地址访问。 CPU发出32位地址信号给存储控制器&#xff0c;存储控制器根据地址信号设置片选信号及地址总线&#xff0c;将相应数据通过数据总线传回存储控制器&#xff0c;存储控制器将收到的数据以字节为…

数字IC实践项目(2)——高速SDRAM控制器的设计与综合(入门级工程项目)

数字IC实践项目&#xff08;2&#xff09;—高速SDRAM控制器的设计与综合&#xff08;入门级工程项目&#xff09; 写在前面的话项目简介和学习目的SDRAM简介SDRAM控制器简介完整项目框图SDRAM控制器项目框图SDRAM初始化模块SDRAM自动刷新模块SDRAM写模块SDRAM读模块SDRAM仲裁机…