基于FPGA的SDRAM控制器设计(4)
基于FPGA完整SDRAM控制器
- SDRAM控制器接口简述
- 自动读写模块的框图
- SDRAM控制器完整代码
- SDRAM控制器的测试代码
- 仿真结果
- 总结
SDRAM控制器接口简述
完整的SDRAM控制器的模块框图如下:
前面的三篇文章,我们已经简述了基本的SDRAM的基本操作。这里总结一下SDRAM的几个模块,SDRAM的上电初始化,自刷新、读写模块、顶层仲裁控制。了解了上面的操作,我们已经可以完成SDRAM控制器的代码完成,接下来我们便完善SDRAM控制器的接口,简化该SDRAM控制器设计,使得该SDRAM控制器可以很容易的使用。下面的接口定义如下:
顶层模块的接口主要时上面的接口,我们把SDRAM做成了FIFO类型的接口。
其中1时系统接口:
sclk:是100MHz的时钟,
rst_n:是系统复位信号,
2是SDRAM硬件的接口信号,连接到SDRAM硬件上。
3是SDRAM写FIFO的信号
4是SDRAM读FIFO的信号
5是SDRAM最大的读地址信号,
RROW_ADDR_END是SDRAM的FIFO接口最大的行地址,
RCOL_MADDR_END是SDRAM最大的列地址,超过上面的信号便会清零,注意RCOL_MADDR_END信号必须是4的倍数,因为我们SDRAM中是4突发的。
6是SDRAM最大FIFO接口最大的写地址信号,与5的描述相同。
自动读写模块的框图
这里为了方便同学们理解,我们给出自动读写模块的框图,也是仿照开源骚客的文章设计:
SDRAM控制器完整代码
经过前面三篇文章的学习,我们这里不在给出原理,直接给出使用的SDRAM的代码:
sdram_top模块:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : sdram_top.v
// Create Time : 2020-02-09 17:22:24
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************module sdram_top(//System Interfacesinput sclk ,input rst_n ,//SDRAM Interfacesoutput wire sdram_clk ,output wire sdram_cke ,output reg sdram_cs_n ,output reg sdram_cas_n ,output reg sdram_ras_n ,output reg sdram_we_n ,output reg [ 1:0] sdram_bank ,output reg [11:0] sdram_addr ,output wire [ 1:0] sdram_dqm ,inout [15:0] sdram_dq ,//User Interfacesinput wfifo_wclk ,input wfifo_wr_en ,input [15:0] wfifo_wr_data ,input rfifo_rclk ,input rfifo_rd_en ,output wire [15:0] rfifo_rd_data ,output wire rfifo_rd_ready
);//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
parameter RROW_ADDR_END = 937 ;
parameter RCOL_MADDR_END = 256 ;
parameter WROW_ADDR_END = 937 ;
parameter WCOL_MADDR_END = 256 ;localparam NOP = 4'b0111 ;localparam IDLE = 5'b0_0001 ;
localparam ARBIT = 5'b0_0010 ;
localparam AREF = 5'b0_0100 ;
localparam WRITE = 5'b0_1000 ;
localparam READ = 5'b1_0000 ;
//sdram_init
wire [ 3:0] init_cmd ;
wire [11:0] init_addr ;
wire init_done ;
//AREF
wire aref_req ;
reg aref_en ;
wire aref_end ;
wire [ 3:0] aref_cmd ;
wire [11:0] aref_addr ;
//WRITE
wire [ 3:0] wr_cmd ;
wire [11:0] wr_addr ;
wire [ 1:0] wr_bank_addr ;
wire [15:0] wr_data ;
reg wr_en ;
wire wr_end ;
wire wr_req ;
wire wr_trig ;
//READ
wire [ 3:0] rd_cmd ;
wire [11:0] rd_addr ;
wire [ 1:0] rd_bank_addr ;
reg rd_en ;
wire rd_end ;
wire rd_req ;
wire rd_trig ;
//sdram_auto_write_read
wire wfifo_rd_en ;
wire [15:0] wfifo_rd_data ;
wire rfifo_wr_en ;
wire [15:0] rfifo_wr_data ;//ARBIT
reg [ 4:0] state ;//Others
reg [15:0] sdram_dq1 ;
reg sdram_dq_en ;//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
assign sdram_dqm = 2'b00;
assign sdram_clk = ~sclk;
assign sdram_cke = 1'b1;
assign sdram_dq = sdram_dq_en == 1'b1 ? sdram_dq1 : 16'hzzzz;
assign rfifo_wr_data = sdram_dq;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)state <= IDLE;else case(state)IDLE : if(init_done == 1'b1)state <= ARBIT;else state <= state;ARBIT : if(aref_req == 1'b1)state <= AREF;else if(wr_req == 1'b1)state <= WRITE;else if(rd_req == 1'b1)state <= READ;elsestate <= state;AREF : if(aref_end == 1'b1)state <= ARBIT;elsestate <= state;WRITE : if(wr_end == 1'b1)state <= ARBIT;else state <= state;READ : if(rd_end == 1'b1)state <= ARBIT;elsestate <= state; default : state <= IDLE;endcasealways @(*)case(state)IDLE : beginsdram_addr = init_addr;{sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = init_cmd;sdram_dq_en = 1'b0;endAREF : beginsdram_addr = aref_addr;{sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = aref_cmd;endWRITE : beginsdram_addr = wr_addr;{sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = wr_cmd;sdram_dq1 = wr_data;sdram_bank = wr_bank_addr;sdram_dq_en = 1'b1;endREAD : beginsdram_addr = rd_addr;{sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = rd_cmd;sdram_bank = rd_bank_addr;sdram_dq_en = 1'b0; enddefault : beginsdram_addr = 12'd0;{sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = NOP;sdram_dq1 = 16'd0;sdram_bank = 2'b00;sdram_dq_en = 1'b0;endendcasealways @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)aref_en <= 1'b0;else if(state == ARBIT && aref_req == 1'b1) aref_en <= 1'b1;elsearef_en <= 1'b0;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)wr_en <= 1'b0;else if(state == ARBIT && aref_req == 1'b1) wr_en <= 1'b0;else if(state == ARBIT && wr_req == 1'b1) wr_en <= 1'b1;elsewr_en <= 1'b0;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)rd_en <= 1'b0;else if(state == ARBIT && aref_req == 1'b1) rd_en <= 1'b0;else if(state == ARBIT && wr_req == 1'b1)rd_en <= 1'b0;else if(state == ARBIT && rd_req == 1'b1)rd_en <= 1'b1;elserd_en <= 1'b0;sdram_init sdram_init_inst(//System Interfaces.sclk (sclk ),.rst_n (rst_n ),//SDRAM Interfaces.sdram_cmd (init_cmd ),.sdram_addr (init_addr ),//Others.init_done (init_done )
);sdram_aref sdram_aref_inst(//Sysytem Interfaces.sclk (sclk ),.rst_n (rst_n ),//SDRAM Interfaces.aref_cmd (aref_cmd ),.aref_addr (aref_addr ),//Others.aref_req (aref_req ),.aref_end (aref_end ),.aref_en (aref_en ),.init_done (init_done )
);sdram_auto_write_read sdram_auto_write_read_inst(// system signals.rst_n (rst_n ), // wfifo.wfifo_wclk (wfifo_wclk ),.wfifo_wr_en (wfifo_wr_en ), .wfifo_wr_data (wfifo_wr_data ),.wfifo_rclk (sclk ),.wfifo_rd_en (wfifo_rd_en ), .wfifo_rd_data (wfifo_rd_data ),.wr_trig (wr_trig ),// rfifo.rfifo_wclk (~sclk ), // 100MHz.rfifo_wr_en (rfifo_wr_en ), .rfifo_wr_data (rfifo_wr_data ),.rfifo_rclk (rfifo_rclk ),.rfifo_rd_en (rfifo_rd_en ), .rfifo_rd_data (rfifo_rd_data ),.rd_trig (rd_trig ),// user interfaces.rfifo_rd_ready (rfifo_rd_ready )
);sdram_write #(.WROW_ADDR_END (WROW_ADDR_END ),.WCOL_MADDR_END (WCOL_MADDR_END )) sdram_write_inst(//System Interfaces.sclk (sclk ),.rst_n (rst_n ),//SDRAM Interfaces.wr_cmd (wr_cmd ),.wr_addr (wr_addr ),.bank_addr (wr_bank_addr ),.wr_data (wr_data ), //Communication Interfaces.wr_trig (wr_trig ),.wr_en (wr_en ),.wr_end (wr_end ),.wr_req (wr_req ),.aref_req (aref_req ),.wfifo_rd_en (wfifo_rd_en ),.wfifo_rd_data (wfifo_rd_data )
);sdram_read #(.RROW_ADDR_END (RROW_ADDR_END ),.RCOL_MADDR_END (RCOL_MADDR_END )) sdram_read_inst(//System Interfaces.sclk (sclk ),.rst_n (rst_n ),//SDRAM Interfaces.rd_cmd (rd_cmd ),.rd_addr (rd_addr ),.bank_addr (rd_bank_addr ), //Communication Interfaces.rd_trig (rd_trig ),.rd_en (rd_en ),.rd_end (rd_end ),.rd_req (rd_req ),.aref_req (aref_req ),.rd_data_en (rfifo_wr_en )
);endmodule
sdram_init模块:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : sdram_init.v
// Create Time : 2020-02-09 16:20:31
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************module sdram_init(//System Interfacesinput sclk ,input rst_n ,//SDRAM Interfacesoutput reg [ 3:0] sdram_cmd ,output reg [11:0] sdram_addr ,//Othersoutput reg init_done
);//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
localparam DELAY_200US = 20000 ;
//SDRAM Command
localparam NOP = 4'b0111 ;
localparam PRE = 4'b0010 ;
localparam AREF = 4'b0001 ;
localparam MSET = 4'b0000 ;reg [14:0] cnt_200us ;
reg flag_200us ;
reg [ 4:0] cnt_cmd ;//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)cnt_200us <= 11'd0;else if(flag_200us == 1'b0)cnt_200us <= cnt_200us + 1'b1;elsecnt_200us <= cnt_200us;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)flag_200us <= 1'b0;else if(cnt_200us >= DELAY_200US) flag_200us <= 1'b1;elseflag_200us <= flag_200us;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)cnt_cmd <= 5'd0;else if(flag_200us == 1'b1 && cnt_cmd <= 5'd19)cnt_cmd <= cnt_cmd + 1'b1;else cnt_cmd <= cnt_cmd;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)sdram_cmd <= NOP;else case(cnt_cmd)1 : sdram_cmd <= PRE;3 : sdram_cmd <= AREF;11 : sdram_cmd <= AREF;19 : sdram_cmd <= MSET;default : sdram_cmd <= NOP;endcasealways @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)sdram_addr <= 12'b0100_0000_0000;else if(cnt_cmd == 5'd19) sdram_addr <= 12'b0000_0011_0010;elsesdram_addr <= 12'b0100_0000_0000;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)init_done <= 1'b0; else if(cnt_cmd > 5'd19) init_done <= 1'b1;elseinit_done <= init_done;endmodule
sdram_aref模块:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : sdram_aref.v
// Create Time : 2020-02-10 13:34:03
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************module sdram_aref(//Sysytem Interfacesinput sclk ,input rst_n ,//SDRAM Interfacesoutput reg [ 3:0] aref_cmd ,output wire [11:0] aref_addr ,//Othersinput init_done ,output reg aref_req ,output reg aref_end ,input aref_en
);//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
localparam NOP = 4'b0111 ;
localparam PRE = 4'b0010 ;
localparam AREF = 4'b0001 ;
localparam DELAY_15US = 11'd1500 ;reg aref_flag ;
reg [ 2:0] cnt_cmd ;
reg [10:0] cnt_15ms ;//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
assign aref_addr = 12'b0100_0000_0000;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)aref_flag <= 1'b0; else if(cnt_cmd >= 3'd7)aref_flag <= 1'b0;else if(aref_en == 1'b1)aref_flag <= 1'b1;elsearef_flag <= aref_flag;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)cnt_cmd <= 3'd0;else if(cnt_cmd >= 3'd7)cnt_cmd <= 3'd0;else if(aref_flag == 1'b1)cnt_cmd <= cnt_cmd + 1'b1; always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)aref_cmd <= NOP; else case(cnt_cmd)1 : aref_cmd <= PRE;4 : aref_cmd <= AREF;default : aref_cmd <= NOP;endcasealways @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)aref_end <= 1'b0;else if(cnt_cmd >= 3'd7)aref_end <= 1'b1;elsearef_end <= 1'b0; always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)cnt_15ms <= 20'd0;else if(cnt_15ms == DELAY_15US)cnt_15ms <= 20'd0;else if(init_done == 1'b1) cnt_15ms <= cnt_15ms + 1'b1;elsecnt_15ms <= 20'd0;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)aref_req <= 1'b0; else if(cnt_15ms == DELAY_15US)aref_req <= 1'b1;else if(aref_en == 1'b1)aref_req <= 1'b0;elsearef_req <= aref_req;endmodule
sdram_auto_write_read模块:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : sdram_auto_write_read.v
// Create Time : 2020-02-15 11:26:21
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************module sdram_auto_write_read(// system signalsinput rst_n , // wfifoinput wfifo_wclk ,input wfifo_wr_en , input [15:0] wfifo_wr_data ,input wfifo_rclk ,input wfifo_rd_en , output wire [15:0] wfifo_rd_data ,output reg wr_trig ,// rfifoinput rfifo_wclk , // 100MHzinput rfifo_wr_en , input [15:0] rfifo_wr_data ,input rfifo_rclk ,input rfifo_rd_en , output wire [15:0] rfifo_rd_data ,output reg rd_trig ,// user interfacesoutput reg rfifo_rd_ready
);//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
parameter WFIFO_RD_CNT = 256 ;
parameter RFIFO_WR_CNT = 250 ;wire [10:0] wfifo_rd_count ;
wire [10:0] rfifo_wr_count ;
reg flag_rd ; //========================================================================================\
//************** Main Code **********************************
//========================================================================================/
always @(posedge rfifo_wclk or negedge rst_n)if(rst_n == 1'b0)rfifo_rd_ready <= 1'b0;else if(rfifo_wr_count >= RFIFO_WR_CNT)rfifo_rd_ready <= 1'b1;elserfifo_rd_ready <= rfifo_rd_ready;always @(posedge wfifo_rclk or negedge rst_n)if(rst_n == 1'b0)flag_rd <= 1'b0; else if(wfifo_rd_count >= WFIFO_RD_CNT)flag_rd <= 1'b1;elseflag_rd <= flag_rd;always @(posedge rfifo_wclk or negedge rst_n)if(rst_n == 1'b0)rd_trig <= 1'b0;else if(rfifo_wr_count < RFIFO_WR_CNT && flag_rd == 1'b1)rd_trig <= 1'b1;elserd_trig <= 1'b0; always @(posedge wfifo_rclk or negedge rst_n)if(rst_n == 1'b0)wr_trig <= 1'b0;else if(wfifo_rd_count >= WFIFO_RD_CNT)wr_trig <= 1'b1;elsewr_trig <= 1'b0;//wfifo
fifo_generator_0 wfifo_inst(.rst (~rst_n ), // input wire rst.wr_clk (wfifo_wclk ), // input wire wr_clk.rd_clk (wfifo_rclk ), // input wire rd_clk.din (wfifo_wr_data ), // input wire [15 : 0] din.wr_en (wfifo_wr_en ), // input wire wr_en.rd_en (wfifo_rd_en ), // input wire rd_en.dout (wfifo_rd_data ), // output wire [15 : 0] dout.full ( ), // output wire full.empty ( ), // output wire empty.rd_data_count (wfifo_rd_count ), // output wire [10 : 0] rd_data_count.wr_data_count ( ) // output wire [10 : 0] wr_data_count
);
//rfifo
fifo_generator_0 rfifo_inst(.rst (~rst_n ), // input wire rst.wr_clk (rfifo_wclk ), // input wire wr_clk.rd_clk (rfifo_rclk ), // input wire rd_clk.din (rfifo_wr_data ), // input wire [15 : 0] din.wr_en (rfifo_wr_en ), // input wire wr_en.rd_en (rfifo_rd_en ), // input wire rd_en.dout (rfifo_rd_data ), // output wire [15 : 0] dout.full ( ), // output wire full.empty ( ), // output wire empty.rd_data_count ( ), // output wire [10 : 0] rd_data_count.wr_data_count (rfifo_wr_count ) // output wire [10 : 0] wr_data_count
);endmodule
sdram_write模块:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : sdram_write.v
// Create Time : 2020-02-10 20:05:26
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************module sdram_write(//System Interfacesinput sclk ,input rst_n ,//SDRAM Interfacesoutput reg [ 3:0] wr_cmd ,output reg [11:0] wr_addr ,output wire [ 1:0] bank_addr ,output wire [15:0] wr_data , //Communication Interfacesinput wr_trig ,input wr_en ,output reg wr_end ,output reg wr_req ,input aref_req ,output reg wfifo_rd_en ,input [15:0] wfifo_rd_data
);//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
parameter WROW_ADDR_END = 937 ;
parameter WCOL_MADDR_END = 256 ;
parameter WCOL_FADDR_END = 512 ;
// Define State
localparam S_IDLE = 5'b0_0001 ;
localparam S_REQ = 5'b0_0010 ;
localparam S_ACT = 5'b0_0100 ;
localparam S_WR = 5'b0_1000 ;
localparam S_PRE = 5'b1_0000 ;
// SDRAM Command
localparam CMD_NOP = 4'b0111 ;
localparam CMD_PRE = 4'b0010 ;
localparam CMD_AREF = 4'b0001 ;
localparam CMD_ACT = 4'b0011 ;
localparam CMD_WR = 4'b0100 ;reg [ 4:0] state ;
reg flag_act_end ;
reg row_end ;
reg [ 1:0] burst_cnt ;
reg data_end ;
reg flag_row_end ;
reg flag_data_end ;
reg flag_aref_req ;
reg [ 8:0] col_addr ;
reg [ 1:0] burst_cnt_r ;
reg [11:0] row_addr ;
reg data_end_r ;
reg data_end_r2 ;
reg row_end_r ;
reg row_end_r2 ; //========================================================================================\
//************** Main Code **********************************
//========================================================================================/
assign bank_addr = 2'b00;
assign wr_data = wfifo_rd_data;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)state <= S_IDLE;else case(state)S_IDLE : if(wr_trig == 1'b1)state <= S_REQ;elsestate <= state; S_REQ : if(wr_en == 1'b1)state <= S_ACT;elsestate <= state; S_ACT : if(flag_act_end == 1'b1)state <= S_WR;elsestate <= state; S_WR : if(data_end_r == 1'b1 || row_end_r == 1'b1)state <= S_PRE;else if(burst_cnt_r == 2'd2 && aref_req == 1'b1)state <= S_PRE;elsestate <= state; S_PRE : if(flag_data_end == 1'b1)state <= S_IDLE;else if(flag_aref_req == 1'b1)state <= S_REQ;else if(flag_row_end == 1'b1)state <= S_ACT;else state <= state;default : state <= S_IDLE;endcasealways @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)flag_aref_req <= 1'b0;else if(state == S_PRE && aref_req == 1'b1)flag_aref_req <= 1'b1;elseflag_aref_req <= 1'b0; always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)flag_act_end <= 1'b0; else if(state == S_ACT && wr_cmd == CMD_ACT)flag_act_end <= 1'b1;else flag_act_end <= 1'b0; always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)row_end <= 1'b0;else if(col_addr == 9'd508 && burst_cnt == 2'd1)row_end <= 1'b1;elserow_end <= 1'b0;always @(posedge sclk)beginrow_end_r <= row_end;row_end_r2 <= row_end_r;
endalways @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)burst_cnt <= 2'd0;else if(state == S_WR)burst_cnt <= burst_cnt + 1'b1;elseburst_cnt <= 2'd0;always @(posedge sclk)burst_cnt_r <= burst_cnt;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)data_end <= 1'b0; else if(state == S_WR && wr_cmd == CMD_WR && col_addr == WCOL_MADDR_END - 4 && row_addr == WROW_ADDR_END)data_end <= 1'b1;else if((col_addr == 'd252 || col_addr == 508) && burst_cnt == 2'd1)data_end <= 1'b1;elsedata_end <= 1'b0;always @(posedge sclk)begindata_end_r <= data_end;data_end_r2 <= data_end_r;
end always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)flag_row_end <= 1'b0; else if(state == S_PRE && row_end_r2 == 1'b1)flag_row_end <= 1'b1;else flag_row_end <= 1'b0;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)flag_data_end <= 1'b0; else if(state == S_PRE && data_end_r2 == 1'b1) flag_data_end <= 1'b1;elseflag_data_end <= 1'b0;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)col_addr <= 9'd0;else if(state == S_WR && wr_cmd == CMD_WR && col_addr == WCOL_MADDR_END - 4 && row_addr == WROW_ADDR_END)col_addr <= 9'd0;else if(state == S_WR && wr_cmd == CMD_WR && col_addr == 'd508)col_addr <= 9'd0; else if(state == S_WR && wr_cmd == CMD_WR)col_addr <= col_addr + 3'd4;elsecol_addr <= col_addr;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)row_addr <= 12'd0; else if(state == S_WR && wr_cmd == CMD_WR && col_addr == WCOL_MADDR_END - 4 && row_addr == WROW_ADDR_END)row_addr <= 12'd0;else if(state == S_WR && wr_cmd == CMD_WR && col_addr == 'd508)row_addr <= row_addr + 1'b1;elserow_addr <= row_addr;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)wr_cmd <= CMD_NOP; else case(state)S_ACT : if(wr_cmd != CMD_ACT && flag_act_end == 1'b0)wr_cmd <= CMD_ACT;elsewr_cmd <= CMD_NOP;S_WR : if(data_end == 1'b1 || row_end == 1'b1)wr_cmd <= CMD_NOP;else if(burst_cnt_r == 2'd2 && aref_req == 1'b1)wr_cmd <= CMD_NOP;else if(burst_cnt == 2'd0)wr_cmd <= CMD_WR;elsewr_cmd <= CMD_NOP; S_PRE : if(wr_cmd != CMD_PRE)wr_cmd <= CMD_PRE;else wr_cmd <= CMD_NOP;default : wr_cmd <= CMD_NOP;endcasealways @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)wr_addr <= 12'd0; else case(state)S_ACT : if(wr_cmd != CMD_ACT)wr_addr <= row_addr;elsewr_addr <= 12'd0;S_WR : if(data_end == 1'b1 || row_end == 1'b1)wr_addr <= 12'd0;else if(burst_cnt_r == 2'd2 && aref_req == 1'b1)wr_addr <= 12'd0;else if(burst_cnt == 2'd0)wr_addr <= {3'b000,col_addr};elsewr_addr <= 12'd0; S_PRE : wr_addr <= 12'b0100_0000_0000;default : wr_addr <= 12'd0;endcasealways @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)wfifo_rd_en <= 1'b0; else if(state == S_WR)wfifo_rd_en <= 1'b1;elsewfifo_rd_en <= 1'b0; always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)wr_end <= 1'b0; else if(flag_data_end == 1'b1)wr_end <= 1'b1;else if(state != S_IDLE && flag_aref_req == 1'b1 && wr_end == 1'b0)wr_end <= 1'b1;elsewr_end <= 1'b0;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)wr_req <= 1'b0; else if(wr_en == 1'b1)wr_req <= 1'b0;else if(state == S_REQ)wr_req <= 1'b1;elsewr_req <= wr_req;endmodule
sdram_read模块:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : sdram_read.v
// Create Time : 2020-02-11 20:48:41
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************module sdram_read(//System Interfacesinput sclk ,input rst_n ,//SDRAM Interfacesoutput reg [ 3:0] rd_cmd ,output reg [11:0] rd_addr ,output wire [ 1:0] bank_addr , //Communication Interfacesinput rd_trig ,input rd_en ,output reg rd_end ,output reg rd_req ,input aref_req ,output reg rd_data_en
);//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
parameter RROW_ADDR_END = 937 ;
parameter RCOL_MADDR_END = 256 ;
// Define State
localparam S_IDLE = 5'b0_0001 ;
localparam S_REQ = 5'b0_0010 ;
localparam S_ACT = 5'b0_0100 ;
localparam S_RD = 5'b0_1000 ;
localparam S_PRE = 5'b1_0000 ;
// SDRAM Command
localparam CMD_NOP = 4'b0111 ;
localparam CMD_PRE = 4'b0010 ;
localparam CMD_AREF = 4'b0001 ;
localparam CMD_ACT = 4'b0011 ;
localparam CMD_RD = 4'b0101 ;reg [ 4:0] state ;
reg flag_act_end ;
reg row_end ;
reg [ 1:0] burst_cnt ;
reg data_end ;
reg flag_row_end ;
reg flag_data_end ;
reg flag_aref_req ;
reg [ 8:0] col_addr ;
reg [ 1:0] burst_cnt_r ;
reg [11:0] row_addr ;
reg data_end_r ;
reg data_end_r2 ;
reg row_end_r ;
reg row_end_r2 ;
reg rfifo_wd_en_r1 ;
reg rfifo_wd_en_r2 ;
reg rfifo_wd_en_r3 ;//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
assign bank_addr = 2'b00;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)state <= S_IDLE;else case(state)S_IDLE : if(rd_trig == 1'b1)state <= S_REQ;elsestate <= state; S_REQ : if(rd_en == 1'b1)state <= S_ACT;elsestate <= state; S_ACT : if(flag_act_end == 1'b1)state <= S_RD;elsestate <= state; S_RD : if(data_end_r == 1'b1 || row_end_r == 1'b1)state <= S_PRE;else if(burst_cnt_r == 2'd2 && aref_req == 1'b1)state <= S_PRE;elsestate <= state; S_PRE : if(flag_data_end == 1'b1)state <= S_IDLE;else if(flag_aref_req == 1'b1)state <= S_REQ;else if(flag_row_end == 1'b1)state <= S_ACT;else state <= state;default : state <= S_IDLE;endcasealways @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)flag_aref_req <= 1'b0;else if(state == S_PRE && aref_req == 1'b1)flag_aref_req <= 1'b1;elseflag_aref_req <= 1'b0; always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)flag_act_end <= 1'b0; else if(state == S_ACT && rd_cmd == CMD_ACT)flag_act_end <= 1'b1;else flag_act_end <= 1'b0; always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)row_end <= 1'b0;else if(col_addr == 9'd508 && burst_cnt == 2'd1)row_end <= 1'b1;elserow_end <= 1'b0;always @(posedge sclk)beginrow_end_r <= row_end;row_end_r2 <= row_end_r;
endalways @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)burst_cnt <= 2'd0;else if(state == S_RD)burst_cnt <= burst_cnt + 1'b1;elseburst_cnt <= 2'd0;always @(posedge sclk)burst_cnt_r <= burst_cnt;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)data_end <= 1'b0; else if(state == S_RD && rd_cmd == CMD_RD && col_addr == RCOL_MADDR_END - 4 && row_addr == RROW_ADDR_END)data_end <= 1'b1; else if((col_addr == 'd252 || col_addr == 508) && burst_cnt == 2'd1)data_end <= 1'b1;elsedata_end <= 1'b0;always @(posedge sclk)begindata_end_r <= data_end;data_end_r2 <= data_end_r;
end always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)flag_row_end <= 1'b0; else if(state == S_PRE && row_end_r2 == 1'b1)flag_row_end <= 1'b1;else flag_row_end <= 1'b0;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)flag_data_end <= 1'b0; else if(state == S_PRE && data_end_r2 == 1'b1) flag_data_end <= 1'b1;elseflag_data_end <= 1'b0;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)col_addr <= 12'd0;else if(state == S_RD && rd_cmd == CMD_RD && col_addr == RCOL_MADDR_END - 4 && row_addr == RROW_ADDR_END)col_addr <= 9'd0;else if(state == S_RD && rd_cmd == CMD_RD && col_addr == 'd508)col_addr <= 12'd0; else if(state == S_RD && rd_cmd == CMD_RD)col_addr <= col_addr + 3'd4;elsecol_addr <= col_addr;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)row_addr <= 12'd0; else if(state == S_RD && rd_cmd == CMD_RD && col_addr == RCOL_MADDR_END - 4 && row_addr == RROW_ADDR_END)row_addr <= 12'd0;else if(state == S_RD && rd_cmd == CMD_RD && col_addr == 'd508)row_addr <= row_addr + 1'b1;elserow_addr <= row_addr;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)rd_cmd <= CMD_NOP; else case(state)S_ACT : if(rd_cmd != CMD_ACT && flag_act_end == 1'b0)rd_cmd <= CMD_ACT;elserd_cmd <= CMD_NOP;S_RD : if(data_end == 1'b1 || row_end == 1'b1)rd_cmd <= CMD_NOP;else if(burst_cnt_r == 2'd2 && aref_req == 1'b1)rd_cmd <= CMD_NOP;else if(burst_cnt == 2'd0)rd_cmd <= CMD_RD;elserd_cmd <= CMD_NOP; S_PRE : if(rd_cmd != CMD_PRE)rd_cmd <= CMD_PRE;else rd_cmd <= CMD_NOP;default : rd_cmd <= CMD_NOP;endcasealways @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)rd_addr <= 12'd0; else case(state)S_ACT : if(rd_cmd != CMD_ACT)rd_addr <= row_addr;elserd_addr <= 12'd0;S_RD : if(data_end == 1'b1 || row_end == 1'b1)rd_addr <= 12'd0;else if(burst_cnt_r == 2'd2 && aref_req == 1'b1)rd_addr <= 12'd0;else if(burst_cnt == 2'd0)rd_addr <= {3'b000,col_addr};elserd_addr <= 12'd0; S_PRE : rd_addr <= 12'b0100_0000_0000;default : rd_addr <= 12'd0;endcasealways @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)rd_end <= 1'b0; else if(flag_data_end == 1'b1)rd_end <= 1'b1;else if(state != S_IDLE && flag_aref_req == 1'b1 && rd_end == 1'b0)rd_end <= 1'b1;elserd_end <= 1'b0;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)rd_req <= 1'b0; else if(rd_en == 1'b1)rd_req <= 1'b0;else if(state == S_REQ)rd_req <= 1'b1;elserd_req <= rd_req;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)rfifo_wd_en_r1 <= 1'b0; else if(state == S_RD)rfifo_wd_en_r1 <= 1'b1;elserfifo_wd_en_r1 <= 1'b0; always @(posedge sclk)beginrfifo_wd_en_r2 <= rfifo_wd_en_r1;rfifo_wd_en_r3 <= rfifo_wd_en_r2;
endalways @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)rd_data_en <= 1'b0;else rd_data_en <= rfifo_wd_en_r3;endmodule
SDRAM控制器完整的模块代码如上,一共五个模块,其中SDRAM上电初始化、自刷新与前面的模块一摸一样,SDRAM读写模块只是更改了一小部分内容,又在前面基础上添加了sdram_auto_write_read自动读写模块。
SDRAM控制器的测试代码
这里我们给出顶层测试模块的代码,如下:
`timescale 1ns / 1ps
`define CLOCK 10
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : sdram_init_tb.v
// Create Time : 2020-02-09 17:10:08
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************module sdram_init_tb;
reg sclk ;
reg clk_50m ;
reg rst_n ;
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 wfifo_wr_en ;
reg [15:0] wfifo_wr_data ;
wire [15:0] rfifo_rd_data ;
wire rfifo_rd_ready ;
reg [15:0] rfifo_test_data ;
reg [20:0] err_cnt ;
reg rfifo_rd_en ;initial beginsclk = 1'b0;rst_n <= 1'b0;#(200*`CLOCK)rst_n <= 1'b1;
end
always #(`CLOCK/2) sclk = ~sclk; initial beginclk_50m = 1'b0;wfifo_wr_en <= 1'b0;rfifo_rd_en <= 1'b0;#(250_000)wfifo_wr_en <= 1'b1;#(5_000_000)rfifo_rd_en <= 1'b1;#(459_852_690-250_000);wfifo_wr_en <= 1'b0;rfifo_rd_en <= 1'b0;// #(9_863_860-250_000);// wfifo_wr_en <= 1'b0;// rfifo_rd_en <= 1'b1;
end
always #(`CLOCK*5) clk_50m = ~clk_50m; always @(posedge clk_50m or negedge rst_n)if(rst_n == 1'b0)wfifo_wr_data <= 16'd0;else if(wfifo_wr_en == 1'b1)wfifo_wr_data <= wfifo_wr_data + 1'b1;elsewfifo_wr_data <= wfifo_wr_data;always @(posedge clk_50m or negedge rst_n)if(rst_n == 1'b0)rfifo_test_data <= 16'd0; else if(rfifo_rd_en == 1'b1)rfifo_test_data <= rfifo_test_data + 1'b1;elserfifo_test_data <= rfifo_test_data;always @(posedge clk_50m or negedge rst_n)if(rst_n == 1'b0)err_cnt <= 21'd0;else if(rfifo_rd_en == 1'b1 && rfifo_test_data != rfifo_rd_data) err_cnt <= err_cnt + 1'b1;elseerr_cnt <= err_cnt; sdram_top sdram_top_inst(//System Interfaces.sclk (sclk ),.rst_n (rst_n ),//SDRAM Interfaces.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 ),//User Interfaces.wfifo_wclk (clk_50m ),.wfifo_wr_en (wfifo_wr_en ),.wfifo_wr_data (wfifo_wr_data ),.rfifo_rclk (clk_50m ),.rfifo_rd_en (rfifo_rd_en ),.rfifo_rd_data (rfifo_rd_data ),.rfifo_rd_ready (rfifo_rd_ready )
);defparam sdram_model_plus_inst.addr_bits = 12;
defparam sdram_model_plus_inst.data_bits = 16;
defparam sdram_model_plus_inst.col_bits = 9;
defparam sdram_model_plus_inst.mem_sizes = 2*1024*1024; // 2Msdram_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
测试模型的代码,我们为了简单起见不再给出,有需要的同学可以去前面的文章中自取。
仿真结果
细看我们的测试模块,我们编写的是循环测试的代码,运行了一段时间后,err_cnt依旧是0,证明了我们模块设计的正确性。
总结
创作不易,认为文章有帮助的同学们可以关注点赞支持。(工程也都在群中)对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:
基于FPGA的SDRAM控制器设计(4)相关推荐
- 基于FPGA的SDRAM控制器设计(二)
基于FPGA的SDRAM控制器设计(二) 1. SDRAM理论基础 2. SDRAM初始化模块以及仿真 3.TOP模块的仲裁机制 4. SDRAM刷新模块代码以及仿真 5.代码 6.参考资料 1. S ...
- 基于FPGA的SDRAM控制器设计(1)
基于FPGA的SDRAM初始化配置 SDRAM简述 SDRAM的引脚及作用 SDRAM初始化时序控制 SDRAM上电时序代码 SDRAM测试模块的代码 仿真测试结果 参考文献 总结 SDRAM简述 S ...
- 基于FPGA的SDRAM控制器设计(2)
基于FPGA的SDRAM的自刷新操作 SDRAM自刷新简述 SDRAM自刷新时序图 SDRAM自刷新代码 仿真模块的代码 仿真结果测试 参考文献 总结 SDRAM自刷新简述 SDRAM作为一个RAM并 ...
- 基于FPGA的SDRAM控制器设计(一)----------SDRAM初始化
本文设计思路与讲解于参考邓堪文老师的视频,感谢-(不太适合一点基础都没有的小白) SDRAM简介 SDRAM(synchronous Dynamic Random ),同步动态随机存储器,同步指内存工 ...
- FPGA之SDRAM控制器设计(三)
FPGA之SDRAM控制器设计(三):写 由于已经涉及了上电刷新,写三个大的状态转移,先把状态转移图给出.主控状态转移图是基于手册上描述来的.在代码注释中会给出每个状态的意义解释. 写时序图 写状态转 ...
- 基于 FPGA 的 UART 控制器设计(VHDL)(下)
今天给大侠带来基于FPGA的 UART 控制器设计(VHDL)(下),由于篇幅较长,分三篇.今天带来第三篇,下篇,使用 FPGA 实现 UART.话不多说,上货. 之前有关于 Veriliog HDL ...
- 七、基于FPGA的Flash控制器设计
根据项目需求,设计一个Flash控制器.以便将完成低速数据的存储.Flash选用了S25FL032.使用单线SPI接口,接线如图: 1,Flash S25fl032介绍 1.1 IO描述 1.2 相关 ...
- 基于FPGA的PID控制器设计
1 知识背景 PID控制应该算是应用非常广泛的控制算法了.常见的比如控制环境温度,控制无人机飞行高度速度等.PID我们将其分成三个参数,如下: P-比例控制,基本作用就是控制对象以线性的方式增加,在一 ...
- 基于FPGA的以太网控制器(MAC)设计(中)
今天给大侠带来基于FPGA的以太网控制器(MAC)设计,由于篇幅较长,分三篇.今天带来第二篇,中篇,以太网控制器(MAC)程序的实现.话不多说,上货. 导读 当前,互联网已经极大地改变了我们的生产和生 ...
- 基于FPGA的以太网控制器(MAC)设计(下)
今天给大侠带来基于FPGA的以太网控制器(MAC)设计,由于篇幅较长,分三篇.今天带来第三篇,下篇,程序的仿真与测试和总结.话不多说,上货. 导读 当前,互联网已经极大地改变了我们的生产和生活.与之相 ...
最新文章
- WiresShark 使用方法
- 应用Java程序片段动态生成下拉列表
- 改造消费方解决地址硬编码问题
- flink-jdbc-driver和flink-sql-gateway的作用
- 博客园代码黑色主题高亮设置
- 那些地方会用C语言多线程,如何用C语言实现多线程
- Sharepoint 2013默认dll部署位置
- 内部存储_Mongodb存储特性与内部原理
- 快速开发基于 HTML5 网络拓扑图应用--入门篇(一)
- 安装配置Greenplum
- zabbix自定义SNMP监控项
- 图像处理之对BMP图片的认识
- css绘制一个动态雷达图
- 使用计算机辅助翻译,计算机辅助翻译方法
- Android Studio系统盘瘦身
- cad怎么画立体图形教学_怎么在CAD中绘制三维立体图
- i9 10900k和i7 9700k的区别大吗
- API管理平台,管理企业所有API资产
- uniApp和微信小程序好看的我的页面(有源码)
- windows 定时任务:schtasks,定时关闭网易云音乐