FPGA学习日记(八)SDRAM的读写测试

目的:对SDRAM进行读写测试,使用FIFO对SDRAM进行封装。

SDRAM功能框图:

SDRAM原理图:

初始化状态机:

工作状态机:

 

代码如下:

SDRAM顶层模块:连接外部芯片与测试灯,并通过pll例化三个时钟,供fifo(50)与SDRAM(100)控制模块使用,测试读写SDRAM数据的一致性。输出到SDRAM芯片的时钟为(100m_shift).


module sdram_rw_test(
    input         clk,                      //FPGA外部时钟,50M
    input         rst_n,                    //按键复位,低电平有效
    //SDRAM 芯片接口
    output        sdram_clk,                //SDRAM 芯片时钟
    output        sdram_cke,                //SDRAM 时钟有效
    output        sdram_cs_n,               //SDRAM 片选
    output        sdram_ras_n,              //SDRAM 行有效
    output        sdram_cas_n,              //SDRAM 列有效
    output        sdram_we_n,               //SDRAM 写有效
    output [ 1:0] sdram_ba,                 //SDRAM Bank地址
    output [12:0] sdram_addr,               //SDRAM 行/列地址
    inout  [15:0] sdram_data,               //SDRAM 数据
    output [ 1:0] sdram_dqm,                //SDRAM 数据掩码
    //LED
    output        led                       //状态指示灯
    );
    
//wire define
wire        clk_50m;                        //SDRAM 读写测试时钟
wire        clk_100m;                       //SDRAM 控制器时钟
wire        clk_100m_shift;                 //相位偏移时钟
     
wire        wr_en;                          //SDRAM 写端口:写使能
wire [15:0] wr_data;                        //SDRAM 写端口:写入的数据
wire        rd_en;                          //SDRAM 读端口:读使能
wire [15:0] rd_data;                        //SDRAM 读端口:读出的数据
wire        sdram_init_done;                //SDRAM 初始化完成信号

wire        locked;                         //PLL输出有效标志
wire        sys_rst_n;                      //系统复位信号
wire        error_flag;                     //读写测试错误标志

//*****************************************************
//**                    main code
//***************************************************** 

//待PLL输出稳定之后,停止系统复位
assign sys_rst_n = rst_n & locked;

//例化PLL, 产生各模块所需要的时钟
pll_clk u_pll_clk(
    .inclk0             (clk),
    .areset             (~rst_n),
    
    .c0                 (clk_50m),
    .c1                 (clk_100m),
    .c2                 (clk_100m_shift),
    .locked             (locked)
    );

//SDRAM测试模块,对SDRAM进行读写测试
sdram_test u_sdram_test(
    .clk_50m            (clk_50m),
    .rst_n              (sys_rst_n),
    
    .wr_en              (wr_en),
    .wr_data            (wr_data),
    .rd_en              (rd_en),
    .rd_data            (rd_data),   
    
    .sdram_init_done    (sdram_init_done),    
    .error_flag         (error_flag)
    );

//利用LED灯指示SDRAM读写测试的结果
led_disp u_led_disp(
    .clk_50m            (clk_50m),
    .rst_n              (sys_rst_n),
   
    .error_flag         (error_flag),
    .led                (led)             
    );

//SDRAM 控制器顶层模块,封装成FIFO接口
//SDRAM 控制器地址组成: {bank_addr[1:0],row_addr[12:0],col_addr[8:0]}
sdram_top u_sdram_top(
	.ref_clk			(clk_100m),			//sdram	控制器参考时钟
	.out_clk			(clk_100m_shift),	//用于输出的相位偏移时钟
	.rst_n				(sys_rst_n),		//系统复位
    
    //用户写端口
	.wr_clk 			(clk_50m),		    //写端口FIFO: 写时钟
	.wr_en				(wr_en),			//写端口FIFO: 写使能
	.wr_data		    (wr_data),		    //写端口FIFO: 写数据
	.wr_min_addr		(24'd0),			//写SDRAM的起始地址
	.wr_max_addr		(24'd1024),		    //写SDRAM的结束地址
	.wr_len			    (10'd512),			//写SDRAM时的数据突发长度
	.wr_load			(~sys_rst_n),		//写端口复位: 复位写地址,清空写FIFO
   
    //用户读端口
	.rd_clk 			(clk_50m),			//读端口FIFO: 读时钟
    .rd_en				(rd_en),			//读端口FIFO: 读使能
	.rd_data	    	(rd_data),		    //读端口FIFO: 读数据
	.rd_min_addr		(24'd0),			//读SDRAM的起始地址
	.rd_max_addr		(24'd1024),	    	//读SDRAM的结束地址
	.rd_len 			(10'd512),			//从SDRAM中读数据时的突发长度
	.rd_load			(~sys_rst_n),		//读端口复位: 复位读地址,清空读FIFO
	   
     //用户控制端口  
	.sdram_read_valid	(1'b1),             //SDRAM 读使能
	.sdram_init_done	(sdram_init_done),	//SDRAM 初始化完成标志
   
	//SDRAM 芯片接口
	.sdram_clk			(sdram_clk),        //SDRAM 芯片时钟
	.sdram_cke			(sdram_cke),        //SDRAM 时钟有效
	.sdram_cs_n			(sdram_cs_n),       //SDRAM 片选
	.sdram_ras_n		(sdram_ras_n),      //SDRAM 行有效
	.sdram_cas_n		(sdram_cas_n),      //SDRAM 列有效
	.sdram_we_n			(sdram_we_n),       //SDRAM 写有效
	.sdram_ba			(sdram_ba),         //SDRAM Bank地址
	.sdram_addr			(sdram_addr),       //SDRAM 行/列地址
	.sdram_data			(sdram_data),       //SDRAM 数据
	.sdram_dqm			(sdram_dqm)         //SDRAM 数据掩码
    );

endmodule 

 

SDRAM读写测试模块:测试写入SDRAM的数据,再将数据读出,数据是否发生改变。


module sdram_test(
    input             clk_50m,          //时钟
    input             rst_n,            //复位,低有效
    
    output reg        wr_en,            //SDRAM 写使能
    output reg [15:0] wr_data,          //SDRAM 写入的数据
    output reg        rd_en,            //SDRAM 读使能
    input      [15:0] rd_data,          //SDRAM 读出的数据
    
    input             sdram_init_done,  //SDRAM 初始化完成标志
    output reg        error_flag        //SDRAM 读写测试错误标志
    );

//reg define
reg        init_done_d0;                //寄存SDRAM初始化完成信号
reg        init_done_d1;                //寄存SDRAM初始化完成信号
reg [10:0] wr_cnt;                      //写操作计数器
reg [10:0] rd_cnt;                      //读操作计数器
reg        rd_valid;                    //读数据有效标志
   
//*****************************************************
//**                    main code
//***************************************************** 

//同步SDRAM初始化完成信号
always @(posedge clk_50m or negedge rst_n) begin
    if(!rst_n) begin
        init_done_d0 <= 1'b0;
        init_done_d1 <= 1'b0;
    end
    else begin
        init_done_d0 <= sdram_init_done;
        init_done_d1 <= init_done_d0;
    end
end            

//SDRAM初始化完成之后,写操作计数器开始计数
always @(posedge clk_50m or negedge rst_n) begin
    if(!rst_n) 
        wr_cnt <= 11'd0;  
    else if(init_done_d1 && (wr_cnt <= 11'd1024))
        wr_cnt <= wr_cnt + 1'b1;
    else
        wr_cnt <= wr_cnt;
end    

//SDRAM写端口FIFO的写使能、写数据(1~1024)
always @(posedge clk_50m or negedge rst_n) begin
    if(!rst_n) begin      
        wr_en   <= 1'b0;
        wr_data <= 16'd0;
    end
    else if(wr_cnt >= 11'd1 && (wr_cnt <= 11'd1024)) begin
            wr_en   <= 1'b1;            //写使能拉高
            wr_data <= wr_cnt;          //写入数据1~1024
        end    
    else begin
            wr_en   <= 1'b0;
            wr_data <= 16'd0;
        end                
end        

//写入数据完成后,开始读操作    
always @(posedge clk_50m or negedge rst_n) begin
    if(!rst_n) 
        rd_en <= 1'b0;
    else if(wr_cnt > 11'd1024)          //写数据完成
        rd_en <= 1'b1;                  //读使能拉高
end

//对读操作计数     
always @(posedge clk_50m or negedge rst_n) begin
    if(!rst_n) 
        rd_cnt <= 11'd0;
    else if(rd_en) begin
        if(rd_cnt < 11'd1024)
            rd_cnt <= rd_cnt + 1'b1;
        else
            rd_cnt <= 11'd1;
    end
end

//第一次读取的数据无效,后续读操作所读取的数据才有效
always @(posedge clk_50m or negedge rst_n) begin
    if(!rst_n) 
        rd_valid <= 1'b0;
    else if(rd_cnt == 11'd1024)         //等待第一次读操作结束
        rd_valid <= 1'b1;               //后续读取的数据有效
    else
        rd_valid <= rd_valid;
end            

//读数据有效时,若读取数据错误,给出标志信号
always @(posedge clk_50m or negedge rst_n) begin
    if(!rst_n)
        error_flag <= 1'b0; 
    else if(rd_valid && (rd_data != rd_cnt))
        error_flag <= 1'b1;             //若读取的数据错误,将错误标志位拉高 
    else
        error_flag <= error_flag;
end

endmodule 

 

SDRAM 控制器顶层模块:SDRAM top模块的目的将FIFO控制模块与SDRAM控制模块封装在一起,与用户模块和外部SDRAM交互。


 SDRAM 控制器顶层模块:


module	sdram_top(
	input         ref_clk,                  //sdram 控制器参考时钟
	input         out_clk,                  //用于输出的相位偏移时钟
	input         rst_n,                    //系统复位
    
    //用户写端口			
	input         wr_clk,                   //写端口FIFO: 写时钟
	input         wr_en,                    //写端口FIFO: 写使能
	input  [15:0] wr_data,                  //写端口FIFO: 写数据
	input  [23:0] wr_min_addr,              //写SDRAM的起始地址
	input  [23:0] wr_max_addr,              //写SDRAM的结束地址
	input  [ 9:0] wr_len,                   //写SDRAM时的数据突发长度
	input         wr_load,                  //写端口复位: 复位写地址,清空写FIFO
    
    //用户读端口
	input         rd_clk,                   //读端口FIFO: 读时钟
	input         rd_en,                    //读端口FIFO: 读使能
	output [15:0] rd_data,                  //读端口FIFO: 读数据
	input  [23:0] rd_min_addr,              //读SDRAM的起始地址
	input  [23:0] rd_max_addr,              //读SDRAM的结束地址
	input  [ 9:0] rd_len,                   //从SDRAM中读数据时的突发长度
	input         rd_load,                  //读端口复位: 复位读地址,清空读FIFO
    
    //用户控制端口  
	input         sdram_read_valid,         //SDRAM 读使能
	output        sdram_init_done,          //SDRAM 初始化完成标志
    
	//SDRAM 芯片接口
	output        sdram_clk,                //SDRAM 芯片时钟
	output        sdram_cke,                //SDRAM 时钟有效
	output        sdram_cs_n,               //SDRAM 片选
	output        sdram_ras_n,              //SDRAM 行有效
	output        sdram_cas_n,              //SDRAM 列有效
	output        sdram_we_n,               //SDRAM 写有效
	output [ 1:0] sdram_ba,                 //SDRAM Bank地址
	output [12:0] sdram_addr,               //SDRAM 行/列地址
	inout  [15:0] sdram_data,               //SDRAM 数据
	output [ 1:0] sdram_dqm                 //SDRAM 数据掩码
    );

//wire define
wire        sdram_wr_req;                   //sdram 写请求
wire        sdram_wr_ack;                   //sdram 写响应
wire [23:0]	sdram_wr_addr;                  //sdram 写地址
wire [15:0]	sdram_din;                      //写入sdram中的数据

wire        sdram_rd_req;                   //sdram 读请求
wire        sdram_rd_ack;                   //sdram 读响应
wire [23:0]	sdram_rd_addr;                   //sdram 读地址
wire [15:0]	sdram_dout;                     //从sdram中读出的数据

//*****************************************************
//**                    main code
//***************************************************** 
assign	sdram_clk = out_clk;                //将相位偏移时钟输出给sdram芯片
assign	sdram_dqm = 2'b00;                  //读写过程中均不屏蔽数据线
			
//SDRAM 读写端口FIFO控制模块
sdram_fifo_ctrl u_sdram_fifo_ctrl(
	.clk_ref			(ref_clk),			//SDRAM控制器时钟
	.rst_n				(rst_n),			//系统复位

    //用户写端口
	.clk_write 			(wr_clk),    	    //写端口FIFO: 写时钟
	.wrf_wrreq			(wr_en),			//写端口FIFO: 写请求
	.wrf_din			(wr_data),		    //写端口FIFO: 写数据	
	.wr_min_addr	    (wr_min_addr),		//写SDRAM的起始地址
	.wr_max_addr		(wr_max_addr),		//写SDRAM的结束地址
	.wr_length			(wr_len),		    //写SDRAM时的数据突发长度
	.wr_load			(wr_load),			//写端口复位: 复位写地址,清空写FIFO    
    
    //用户读端口
	.clk_read			(rd_clk),     	    //读端口FIFO: 读时钟
	.rdf_rdreq			(rd_en),			//读端口FIFO: 读请求
	.rdf_dout			(rd_data),		    //读端口FIFO: 读数据
	.rd_min_addr		(rd_min_addr),	    //读SDRAM的起始地址
	.rd_max_addr		(rd_max_addr),		//读SDRAM的结束地址
	.rd_length			(rd_len),		    //从SDRAM中读数据时的突发长度
	.rd_load			(rd_load),			//读端口复位: 复位读地址,清空读FIFO
   
	//用户控制端口	
	.sdram_read_valid	(sdram_read_valid), //sdram 读使能
	.sdram_init_done	(sdram_init_done),	//sdram 初始化完成标志

    //SDRAM 控制器写端口
	.sdram_wr_req		(sdram_wr_req),		//sdram 写请求
	.sdram_wr_ack		(sdram_wr_ack),	    //sdram 写响应
	.sdram_wr_addr		(sdram_wr_addr),	//sdram 写地址
	.sdram_din			(sdram_din),		//写入sdram中的数据
    
    //SDRAM 控制器读端口
	.sdram_rd_req		(sdram_rd_req),		//sdram 读请求
	.sdram_rd_ack		(sdram_rd_ack),	    //sdram 读响应
	.sdram_rd_addr		(sdram_rd_addr),    //sdram 读地址
	.sdram_dout			(sdram_dout)		//从sdram中读出的数据
    );

//SDRAM控制器
sdram_controller u_sdram_controller(
	.clk				(ref_clk),			//sdram 控制器时钟
	.rst_n				(rst_n),			//系统复位
    
	//SDRAM 控制器写端口	
	.sdram_wr_req		(sdram_wr_req), 	//sdram 写请求
	.sdram_wr_ack		(sdram_wr_ack), 	//sdram 写响应
	.sdram_wr_addr		(sdram_wr_addr), 	//sdram 写地址
	.sdram_wr_burst		(wr_len),		    //写sdram时数据突发长度
	.sdram_din  		(sdram_din),    	//写入sdram中的数据
    
    //SDRAM 控制器读端口
	.sdram_rd_req		(sdram_rd_req), 	//sdram 读请求
	.sdram_rd_ack		(sdram_rd_ack),		//sdram 读响应
	.sdram_rd_addr		(sdram_rd_addr), 	//sdram 读地址
	.sdram_rd_burst		(rd_len),		    //读sdram时数据突发长度
	.sdram_dout		    (sdram_dout),   	//从sdram中读出的数据
    
	.sdram_init_done	(sdram_init_done),	//sdram 初始化完成标志

	//SDRAM 芯片接口
	.sdram_cke			(sdram_cke),		//SDRAM 时钟有效
	.sdram_cs_n			(sdram_cs_n),		//SDRAM 片选
	.sdram_ras_n		(sdram_ras_n),		//SDRAM 行有效	
	.sdram_cas_n		(sdram_cas_n),		//SDRAM 列有效
	.sdram_we_n			(sdram_we_n),		//SDRAM 写有效
	.sdram_ba			(sdram_ba),			//SDRAM Bank地址
	.sdram_addr			(sdram_addr),		//SDRAM 行/列地址
	.sdram_data			(sdram_data)		//SDRAM 数据	
    );
    
endmodule 

 

SDRAM 控制器:完成与上层模块及SDRAM的状态控制模块,命令控制模块,数据模块的交互。


module sdram_controller(
    input         clk,		        //SDRAM控制器时钟,100MHz
    input         rst_n,	        //系统复位信号,低电平有效
    
	//SDRAM 控制器写端口	
    input         sdram_wr_req,		//写SDRAM请求信号
    output        sdram_wr_ack,		//写SDRAM响应信号
    input  [23:0] sdram_wr_addr,	//SDRAM写操作的地址
    input  [ 9:0] sdram_wr_burst,   //写sdram时数据突发长度
    input  [15:0] sdram_din,	    //写入SDRAM的数据
    
	//SDRAM 控制器读端口	
    input         sdram_rd_req,		//读SDRAM请求信号
    output        sdram_rd_ack,		//读SDRAM响应信号
    input  [23:0] sdram_rd_addr,	//SDRAM写操作的地址
    input  [ 9:0] sdram_rd_burst,   //读sdram时数据突发长度
    output [15:0] sdram_dout,	    //从SDRAM读出的数据
    
    output	      sdram_init_done,  //SDRAM 初始化完成标志
                                     
	// FPGA与SDRAM硬件接口
    output        sdram_cke,		// SDRAM 时钟有效信号
    output        sdram_cs_n,		// SDRAM 片选信号
    output        sdram_ras_n,		// SDRAM 行地址选通脉冲
    output        sdram_cas_n,		// SDRAM 列地址选通脉冲
    output        sdram_we_n,		// SDRAM 写允许位
    output [ 1:0] sdram_ba,		    // SDRAM L-Bank地址线
    output [12:0] sdram_addr,	    // SDRAM 地址总线
    inout  [15:0] sdram_data		// SDRAM 数据总线
    );

//wire define
wire [4:0] init_state;	            // SDRAM初始化状态
wire [3:0] work_state;	            // SDRAM工作状态
wire [9:0] cnt_clk;		            // 延时计数器
wire       sdram_rd_wr;			    // SDRAM读/写控制信号,低电平为写,高电平为读

//*****************************************************
//**                    main code
//*****************************************************     

// SDRAM 状态控制模块                
sdram_ctrl u_sdram_ctrl(		    
    .clk                (clk),						
    .rst_n              (rst_n),

    .sdram_wr_req       (sdram_wr_req), 
    .sdram_rd_req       (sdram_rd_req),
    .sdram_wr_ack       (sdram_wr_ack),
    .sdram_rd_ack       (sdram_rd_ack),						
    .sdram_wr_burst     (sdram_wr_burst),
    .sdram_rd_burst     (sdram_rd_burst),
    .sdram_init_done    (sdram_init_done),
    
    .init_state         (init_state),
    .work_state         (work_state),
    .cnt_clk            (cnt_clk),
    .sdram_rd_wr        (sdram_rd_wr)
    );

// SDRAM 命令控制模块
sdram_cmd u_sdram_cmd(		        
    .clk                (clk),
    .rst_n              (rst_n),

    .sys_wraddr         (sdram_wr_addr),			
    .sys_rdaddr         (sdram_rd_addr),
    .sdram_wr_burst     (sdram_wr_burst),
    .sdram_rd_burst     (sdram_rd_burst),
    
    .init_state         (init_state),	
    .work_state         (work_state),
    .cnt_clk            (cnt_clk),
    .sdram_rd_wr        (sdram_rd_wr),
    
    .sdram_cke          (sdram_cke),		
    .sdram_cs_n         (sdram_cs_n),	
    .sdram_ras_n        (sdram_ras_n),	
    .sdram_cas_n        (sdram_cas_n),	
    .sdram_we_n         (sdram_we_n),	
    .sdram_ba           (sdram_ba),			
    .sdram_addr         (sdram_addr)
    );

// SDRAM 数据读写模块
sdram_data u_sdram_data(		
    .clk                (clk),
    .rst_n              (rst_n),
    
    .sdram_data_in      (sdram_din),
    .sdram_data_out     (sdram_dout),
    .work_state         (work_state),
    .cnt_clk            (cnt_clk),
    
    .sdram_data         (sdram_data)
    );

endmodule 

状态命令参数:


// SDRAM 初始化过程各个状态
`define		I_NOP	        5'd0		                    //等待上电200us稳定期结束
`define		I_PRE 	        5'd1		                    //预充电状态
`define		I_TRP 	        5'd2		                    //等待预充电完成	      tRP
`define		I_AR 	        5'd3		                    //自动刷新            
`define		I_TRF	        5'd4		                    //等待自动刷新结束	  tRC
`define		I_MRS	        5'd5		                    //模式寄存器设置
`define		I_TRSC	        5'd6		                    //等待模式寄存器设置完成 tRSC
`define		I_DONE	        5'd7		                    //初始化完成

// SDRAM 工作过程各个状态
`define		W_IDLE		    4'd0                            //空闲
`define		W_ACTIVE	    4'd1                            //行有效
`define		W_TRCD		    4'd2                            //行有效等待
`define		W_READ		    4'd3                            //读操作
`define		W_CL		    4'd4                            //潜伏期
`define		W_RD		    4'd5                            //读数据
`define		W_WRITE		    4'd6                            //写操作
`define		W_WD		    4'd7                            //写数据
`define		W_TWR		    4'd8                            //写回
`define		W_PRE		    4'd9                            //预充电
`define		W_TRP		    4'd10                           //预充电等待
`define		W_AR		    4'd11                           //自动刷新
`define		W_TRFC		    4'd12                           //自动刷新等待
  
//延时参数
`define	    end_trp			cnt_clk	== TRP_CLK              //预充电有效周期结束
`define	    end_trfc		cnt_clk	== TRC_CLK              //自动刷新周期结束
`define	    end_trsc		cnt_clk	== TRSC_CLK             //模式寄存器设置时钟周期结束
`define	    end_trcd		cnt_clk	== TRCD_CLK-1           //行选通周期结束
`define     end_tcl			cnt_clk == TCL_CLK-1            //潜伏期结束
`define     end_rdburst		cnt_clk == sdram_rd_burst-4     //读突发终止
`define	    end_tread		cnt_clk	== sdram_rd_burst+2     //突发读结束     
`define     end_wrburst		cnt_clk == sdram_wr_burst-1     //写突发终止
`define	    end_twrite		cnt_clk	== sdram_wr_burst-1     //突发写结束
`define	    end_twr		    cnt_clk	== TWR_CLK	            //写回周期结束

//SDRAM控制信号命令
`define		CMD_INIT 	    5'b01111	                    // INITIATE
`define		CMD_NOP		    5'b10111	                    // NOP COMMAND
`define		CMD_ACTIVE	    5'b10011	                    // ACTIVE COMMAND
`define		CMD_READ	    5'b10101	                    // READ COMMADN
`define		CMD_WRITE	    5'b10100	                    // WRITE COMMAND
`define		CMD_B_STOP	    5'b10110	                    // BURST STOP
`define		CMD_PRGE	    5'b10010	                    // PRECHARGE
`define		CMD_A_REF	    5'b10001	                    // AOTO REFRESH
`define		CMD_LMR		    5'b10000	                    // LODE MODE REGISTER

状态控制模块:初始化状态及工作状态和刷新计数器设置。

//*******
// Descriptions:        SDRAM 状态控制模块

module sdram_ctrl(
    input            clk,			    //系统时钟
    input            rst_n,			    //复位信号,低电平有效
    
    input            sdram_wr_req,	    //写SDRAM请求信号
    input            sdram_rd_req,	    //读SDRAM请求信号
    output           sdram_wr_ack,	    //写SDRAM响应信号
    output           sdram_rd_ack,	    //读SDRAM响应信号
    input      [9:0] sdram_wr_burst,	//突发写SDRAM字节数(1-512个)
    input      [9:0] sdram_rd_burst,	//突发读SDRAM字节数(1-256个)	
    output           sdram_init_done,   //SDRAM系统初始化完毕信号

    output reg [4:0] init_state,	    //SDRAM初始化状态
    output reg [3:0] work_state,	    //SDRAM工作状态
    output reg [9:0] cnt_clk,	        //时钟计数器
    output reg       sdram_rd_wr 		//SDRAM读/写控制信号,低电平为写,高电平为读
    );

`include "sdram_para.v"		            //包含SDRAM参数定义模块
                                        
//parameter define                      
parameter  TRP_CLK	  = 10'd4;	        //预充电有效周期
parameter  TRC_CLK	  = 10'd6;	        //自动刷新周期
parameter  TRSC_CLK	  = 10'd6;	        //模式寄存器设置时钟周期
parameter  TRCD_CLK	  = 10'd2;	        //行选通周期
parameter  TCL_CLK	  = 10'd3;	        //列潜伏期
parameter  TWR_CLK	  = 10'd2;	        //写入校正
                                        
//reg define                            
reg [14:0] cnt_200us;                   //SDRAM 上电稳定期200us计数器
reg [10:0] cnt_refresh;	                //刷新计数寄存器
reg        sdram_ref_req;		        //SDRAM 自动刷新请求信号
reg        cnt_rst_n;		            //延时计数器复位信号,低有效	
reg [ 3:0] init_ar_cnt;                 //初始化过程自动刷新计数器
                                        
//wire define                           
wire       done_200us;		            //上电后200us输入稳定期结束标志位
wire       sdram_ref_ack;		        //SDRAM自动刷新请求应答信号	

//*****************************************************
//**                    main code
//***************************************************** 

//SDRAM上电后200us稳定期结束后,将标志信号拉高
assign done_200us = (cnt_200us == 15'd20_000);

//SDRAM初始化完成标志 
assign sdram_init_done = (init_state == `I_DONE);

//SDRAM 自动刷新应答信号
assign sdram_ref_ack = (work_state == `W_AR);

//写SDRAM响应信号
assign sdram_wr_ack = ((work_state == `W_TRCD) & ~sdram_rd_wr) | 
					  ( work_state == `W_WRITE)|
					  ((work_state == `W_WD) & (cnt_clk < sdram_wr_burst - 2'd2));
                      
//读SDRAM响应信号
assign sdram_rd_ack = (work_state == `W_RD) & 
					  (cnt_clk >= 10'd1) & (cnt_clk < sdram_rd_burst + 2'd1);
                      
//上电后计时200us,等待SDRAM状态稳定
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) 
        cnt_200us <= 15'd0;
	else if(cnt_200us < 15'd20_000) 
        cnt_200us <= cnt_200us + 1'b1;
    else
        cnt_200us <= cnt_200us;
end
 
//刷新计数器循环计数7812ns (60ms内完成全部8192行刷新操作)
always @ (posedge clk or negedge rst_n)
	if(!rst_n) 
        cnt_refresh <= 11'd0;
	else if(cnt_refresh < 11'd781)      // 64ms/8192 =7812ns
        cnt_refresh <= cnt_refresh + 1'b1;	
	else 
        cnt_refresh <= 11'd0;	

//SDRAM 刷新请求
always @ (posedge clk or negedge rst_n)
	if(!rst_n) 
        sdram_ref_req <= 1'b0;
	else if(cnt_refresh == 11'd780) 
        sdram_ref_req <= 1'b1;	        //刷新计数器计时达7812ns时产生刷新请求
	else if(sdram_ref_ack) 
        sdram_ref_req <= 1'b0;		    //收到刷新请求响应信号后取消刷新请求 

//延时计数器对时钟计数
always @ (posedge clk or negedge rst_n) 
	if(!rst_n) 
        cnt_clk <= 10'd0;
	else if(!cnt_rst_n)                 //在cnt_rst_n为低电平时延时计数器清零
        cnt_clk <= 10'd0;
	else 
        cnt_clk <= cnt_clk + 1'b1;
        
//初始化过程中对自动刷新操作计数
always @ (posedge clk or negedge rst_n) 
	if(!rst_n) 
        init_ar_cnt <= 4'd0;
	else if(init_state == `I_NOP) 
        init_ar_cnt <= 4'd0;
	else if(init_state == `I_AR)
        init_ar_cnt <= init_ar_cnt + 1'b1;
    else
        init_ar_cnt <= init_ar_cnt;
	
//SDRAM的初始化状态机
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) 
        init_state <= `I_NOP;
	else 
		case (init_state)
                                        //上电复位后200us结束则进入下一状态
            `I_NOP:  init_state <= done_200us  ? `I_PRE : `I_NOP;
                                        //预充电状态
			`I_PRE:  init_state <= `I_TRP;
                                        //预充电等待,TRP_CLK个时钟周期
			`I_TRP:  init_state <= (`end_trp)  ? `I_AR  : `I_TRP;
                                        //自动刷新
			`I_AR :  init_state <= `I_TRF;	
                                        //等待自动刷新结束,TRC_CLK个时钟周期
			`I_TRF:  init_state <= (`end_trfc) ? 
                                        //连续8次自动刷新操作
                                   ((init_ar_cnt == 4'd8) ? `I_MRS : `I_AR) : `I_TRF;
                                        //模式寄存器设置
			`I_MRS:	 init_state <= `I_TRSC;	
                                        //等待模式寄存器设置完成,TRSC_CLK个时钟周期
			`I_TRSC: init_state <= (`end_trsc) ? `I_DONE : `I_TRSC;
                                        //SDRAM的初始化设置完成标志
			`I_DONE: init_state <= `I_DONE;
			default: init_state <= `I_NOP;
		endcase
end

//SDRAM的工作状态机,工作包括读、写以及自动刷新操作
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) 
		work_state <= `W_IDLE;          //空闲状态
	else
		case(work_state)
                                        //定时自动刷新请求,跳转到自动刷新状态
            `W_IDLE: if(sdram_ref_req & sdram_init_done) begin
						 work_state <= `W_AR; 		
					     sdram_rd_wr <= 1'b1;
				     end 		        
                                        //写SDRAM请求,跳转到行有效状态
					 else if(sdram_wr_req & sdram_init_done) begin
						 work_state <= `W_ACTIVE;
						 sdram_rd_wr <= 1'b0;	
					 end                
                                        //读SDRAM请求,跳转到行有效状态
					 else if(sdram_rd_req && sdram_init_done) begin
						 work_state <= `W_ACTIVE;
						 sdram_rd_wr <= 1'b1;	
					 end                
                                        //无操作请求,保持空闲状态
					 else begin 
						 work_state <= `W_IDLE;
						 sdram_rd_wr <= 1'b1;
					 end
                     
            `W_ACTIVE:                  //行有效,跳转到行有效等待状态
                         work_state <= `W_TRCD;
            `W_TRCD: if(`end_trcd)      //行有效等待结束,判断当前是读还是写
						 if(sdram_rd_wr)//读:进入读操作状态
                             work_state <= `W_READ;
						 else           //写:进入写操作状态
                             work_state <= `W_WRITE;
					 else 
                         work_state <= `W_TRCD;
                         
            `W_READ:	                //读操作,跳转到潜伏期
                         work_state <= `W_CL;	
            `W_CL:		                //潜伏期:等待潜伏期结束,跳转到读数据状态
                         work_state <= (`end_tcl) ? `W_RD:`W_CL;	                                        
            `W_RD:		                //读数据:等待读数据结束,跳转到预充电状态
                         work_state <= (`end_tread) ? `W_PRE:`W_RD;
                         
            `W_WRITE:	                //写操作:跳转到写数据状态
                         work_state <= `W_WD;
            `W_WD:		                //写数据:等待写数据结束,跳转到写回周期状态
                         work_state <= (`end_twrite) ? `W_TWR:`W_WD;                         
            `W_TWR:	                    //写回周期:写回周期结束,跳转到预充电状态
                         work_state <= (`end_twr) ? `W_PRE:`W_TWR;
                         
            `W_PRE:		                //预充电:跳转到预充电等待状态
                         work_state <= `W_TRP;
            `W_TRP:	                //预充电等待:预充电等待结束,进入空闲状态
                         work_state <= (`end_trp) ? `W_IDLE:`W_TRP;
                         
            `W_AR:		                //自动刷新操作,跳转到自动刷新等待
                         work_state <= `W_TRFC;             
            `W_TRFC:	                //自动刷新等待:自动刷新等待结束,进入空闲状态
                         work_state <= (`end_trfc) ? `W_IDLE:`W_TRFC;
            default: 	 work_state <= `W_IDLE;
		endcase
end

//计数器控制逻辑
always @ (*) begin
	case (init_state)
        `I_NOP:	 cnt_rst_n <= 1'b0;     //延时计数器清零(cnt_rst_n低电平复位)
                                        
        `I_PRE:	 cnt_rst_n <= 1'b1;     //预充电:延时计数器启动(cnt_rst_n高电平启动)
                                        //等待预充电延时计数结束后,清零计数器
        `I_TRP:	 cnt_rst_n <= (`end_trp) ? 1'b0 : 1'b1;
                                        //自动刷新:延时计数器启动
        `I_AR:
                 cnt_rst_n <= 1'b1;
                                        //等待自动刷新延时计数结束后,清零计数器
        `I_TRF:
                 cnt_rst_n <= (`end_trfc) ? 1'b0 : 1'b1;	
                                        
        `I_MRS:  cnt_rst_n <= 1'b1;	    //模式寄存器设置:延时计数器启动
                                        //等待模式寄存器设置延时计数结束后,清零计数器
        `I_TRSC: cnt_rst_n <= (`end_trsc) ? 1'b0:1'b1;
                                        
        `I_DONE: begin                  //初始化完成后,判断工作状态
		    case (work_state)
				`W_IDLE:	cnt_rst_n <= 1'b0;
                                        //行有效:延时计数器启动
				`W_ACTIVE: 	cnt_rst_n <= 1'b1;
                                        //行有效延时计数结束后,清零计数器
				`W_TRCD:	cnt_rst_n <= (`end_trcd)   ? 1'b0 : 1'b1;
                                        //潜伏期延时计数结束后,清零计数器
				`W_CL:		cnt_rst_n <= (`end_tcl)    ? 1'b0 : 1'b1;
                                        //读数据延时计数结束后,清零计数器
				`W_RD:		cnt_rst_n <= (`end_tread)  ? 1'b0 : 1'b1;
                                        //写数据延时计数结束后,清零计数器
				`W_WD:		cnt_rst_n <= (`end_twrite) ? 1'b0 : 1'b1;
                                        //写回周期延时计数结束后,清零计数器
				`W_TWR:	    cnt_rst_n <= (`end_twr)    ? 1'b0 : 1'b1;
                                        //预充电等待延时计数结束后,清零计数器
				`W_TRP:	cnt_rst_n <= (`end_trp) ? 1'b0 : 1'b1;
                                        //自动刷新等待延时计数结束后,清零计数器
				`W_TRFC:	cnt_rst_n <= (`end_trfc)   ? 1'b0 : 1'b1;
				default:    cnt_rst_n <= 1'b0;
		    endcase
        end
		default: cnt_rst_n <= 1'b0;
	endcase
end
 
endmodule 

SDRAM数据读写模块:根据输入的读写数据及控制读写信号,写数据进入SDRAM,读数据进寄存器,传入上层模块。


module sdram_data(
    input             clk,			    //系统时钟
    input             rst_n,			//低电平复位信号

    input   [15:0]    sdram_data_in,    //写入SDRAM中的数据
    output  [15:0]    sdram_data_out,   //从SDRAM中读取的数据
    input   [ 3:0]    work_state,	    //SDRAM工作状态寄存器
    input   [ 9:0]    cnt_clk, 		    //时钟计数
    
    inout   [15:0]    sdram_data		//SDRAM数据总线
    );

`include "sdram_para.v"		            //包含SDRAM参数定义模块

//reg define
reg        sdram_out_en;		        //SDRAM数据总线输出使能
reg [15:0] sdram_din_r;	                //寄存写入SDRAM中的数据
reg [15:0] sdram_dout_r;	            //寄存从SDRAM中读取的数据

//*****************************************************
//**                    main code
//***************************************************** 

//SDRAM 双向数据线作为输入时保持高阻态
assign sdram_data = sdram_out_en ? sdram_din_r : 16'hzzzz;

//输出SDRAM中读取的数据
assign sdram_data_out = sdram_dout_r;

//SDRAM 数据总线输出使能
always @ (posedge clk or negedge rst_n) begin 
	if(!rst_n) 
       sdram_out_en <= 1'b0;
   else if((work_state == `W_WRITE) | (work_state == `W_WD)) 
       sdram_out_en <= 1'b1;            //向SDRAM中写数据时,输出使能拉高
   else 
       sdram_out_en <= 1'b0;
end

//将待写入数据送到SDRAM数据总线上
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) 
        sdram_din_r <= 16'd0;
	else if((work_state == `W_WRITE) | (work_state == `W_WD))
        sdram_din_r <= sdram_data_in;	//寄存写入SDRAM中的数据
end

//读数据时,寄存SDRAM数据线上的数据
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) 
        sdram_dout_r <= 16'd0;
	else if(work_state == `W_RD) 
        sdram_dout_r <= sdram_data;	    //寄存从SDRAM中读取的数据
end

endmodule 


 

SDRAM命令控制模块:通过不同的状态,向SDRAM芯片输入不同的命令数据。


module sdram_cmd(
    input             clk,			    //系统时钟
    input             rst_n,			//低电平复位信号

    input      [23:0] sys_wraddr,		//写SDRAM时地址
    input      [23:0] sys_rdaddr,		//读SDRAM时地址
    input      [ 9:0] sdram_wr_burst,	//突发写SDRAM字节数
    input      [ 9:0] sdram_rd_burst,	//突发读SDRAM字节数
    
    input      [ 4:0] init_state,		//SDRAM初始化状态
    input      [ 3:0] work_state, 		//SDRAM工作状态
    input      [ 9:0] cnt_clk,		    //延时计数器	
    input             sdram_rd_wr,	    //SDRAM读/写控制信号,低电平为写
    
    output            sdram_cke,		//SDRAM时钟有效信号
    output            sdram_cs_n,		//SDRAM片选信号
    output            sdram_ras_n,	    //SDRAM行地址选通脉冲
    output            sdram_cas_n,	    //SDRAM列地址选通脉冲
    output            sdram_we_n,		//SDRAM写允许位
    output reg [ 1:0] sdram_ba,		    //SDRAM的L-Bank地址线
    output reg [12:0] sdram_addr	    //SDRAM地址总线
    );

`include "sdram_para.v"		            //包含SDRAM参数定义模块

//reg define
reg  [ 4:0] sdram_cmd_r;	            //SDRAM操作指令

//wire define
wire [23:0] sys_addr;		            //SDRAM读写地址	

//*****************************************************
//**                    main code
//***************************************************** 

//SDRAM 控制信号线赋值
assign {sdram_cke,sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} = sdram_cmd_r;

//SDRAM 读/写地址总线控制
assign sys_addr = sdram_rd_wr ? sys_rdaddr : sys_wraddr;
	
//SDRAM 操作指令控制
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) begin
			sdram_cmd_r <= `CMD_INIT;
			sdram_ba    <= 2'b11;
			sdram_addr  <= 13'h1fff;
	end
	else
		case(init_state)
                                        //初始化过程中,以下状态不执行任何指令
            `I_NOP,`I_TRP,`I_TRF,`I_TRSC: begin
                    sdram_cmd_r <= `CMD_NOP;
                    sdram_ba    <= 2'b11;
                    sdram_addr  <= 13'h1fff;	
                end
            `I_PRE: begin               //预充电指令
                    sdram_cmd_r <= `CMD_PRGE;
                    sdram_ba    <= 2'b11;
                    sdram_addr  <= 13'h1fff;
                end 
            `I_AR: begin
                                        //自动刷新指令
                    sdram_cmd_r <= `CMD_A_REF;
                    sdram_ba    <= 2'b11;
                    sdram_addr  <= 13'h1fff;						
                end 			 	
            `I_MRS: begin	            //模式寄存器设置指令
                    sdram_cmd_r <= `CMD_LMR;
                    sdram_ba    <= 2'b00;
                    sdram_addr  <= {    //利用地址线设置模式寄存器,可根据实际需要进行修改
                        3'b000,		    //预留
                        1'b0,		    //读写方式 A9=0,突发读&突发写
                        2'b00,		    //默认,{A8,A7}=00
                        3'b011,		    //CAS潜伏期设置,这里设置为3,{A6,A5,A4}=011
                        1'b0,		    //突发传输方式,这里设置为顺序,A3=0
                        3'b111		    //突发长度,这里设置为页突发,{A2,A1,A0}=011
					};
                end	
            `I_DONE:                    //SDRAM初始化完成
					case(work_state)    //以下工作状态不执行任何指令
                        `W_IDLE,`W_TRCD,`W_CL,`W_TWR,`W_TRP,`W_TRFC: begin
                                sdram_cmd_r <= `CMD_NOP;
                                sdram_ba    <= 2'b11;
                                sdram_addr  <= 13'h1fff;
                            end
                        `W_ACTIVE: begin//行有效指令
                                sdram_cmd_r <= `CMD_ACTIVE;
                                sdram_ba    <= sys_addr[23:22];
                                sdram_addr  <= sys_addr[21:9];
                            end
                        `W_READ: begin  //读操作指令
                                sdram_cmd_r <= `CMD_READ;
                                sdram_ba    <= sys_addr[23:22];
                                sdram_addr  <= {4'b0000,sys_addr[8:0]};
                            end
                        `W_RD: begin    //突发传输终止指令
                                if(`end_rdburst) 
                                    sdram_cmd_r <= `CMD_B_STOP;
                                else begin
                                    sdram_cmd_r <= `CMD_NOP;
                                    sdram_ba    <= 2'b11;
                                    sdram_addr  <= 13'h1fff;
                                end
                            end								
                        `W_WRITE: begin //写操作指令
                                sdram_cmd_r <= `CMD_WRITE;
                                sdram_ba    <= sys_addr[23:22];
                                sdram_addr  <= {4'b0000,sys_addr[8:0]};
                            end		
                        `W_WD: begin    //突发传输终止指令
                                if(`end_wrburst) 
                                    sdram_cmd_r <= `CMD_B_STOP;
                                else begin
                                    sdram_cmd_r <= `CMD_NOP;
                                    sdram_ba    <= 2'b11;
                                    sdram_addr  <= 13'h1fff;
                                end
                            end
                        `W_PRE:begin    //预充电指令
                                sdram_cmd_r <= `CMD_PRGE;
                                sdram_ba    <= sys_addr[23:22];
                                sdram_addr  <= 13'h0000;
                            end				
                        `W_AR: begin    //自动刷新指令
                                sdram_cmd_r <= `CMD_A_REF;
                                sdram_ba    <= 2'b11;
                                sdram_addr  <= 13'h1fff;
                            end
                        default: begin
                                sdram_cmd_r <= `CMD_NOP;
                                sdram_ba    <= 2'b11;
                                sdram_addr  <= 13'h1fff;
                            end
					endcase
            default: begin
                    sdram_cmd_r <= `CMD_NOP;
                    sdram_ba    <= 2'b11;
                    sdram_addr  <= 13'h1fff;
                end
		endcase
end

endmodule 

 

 

 

fifo读写控制模块:通过两个fifo读写ip核完成与sdram控制模块的交互,及与用户控制的交互

//fifo读写控制模块

/*该fifo控制模块下游读写两个fifo,且两个fifo分别连接yoghurt模块和SDRAM模块,要分别设置接口,
	对fifo来说需要有时钟、数据、请求应答信号,来完成缓冲任务,加上复位、当前容量寄存器*/
module sdram_fifo_ctrl(
	input 			clk_ref;		//参考时钟
	input 			sys_rst;
		
	//用户写端口	
	input			clk_write; 		//用户写时钟50m
	input 			wr_req;			//写请求
	input [15:0]		wr_data;
	input [23:0]		wr_min_addr;
	input [23:0]		wr_max_addr;
	input [9:0]		wr_brust_len;
	input			wr_load_flag;
		
	//用户读端口	
	input			clk_read; 		//用户读时钟50m
	input 			rd_req;			//读请求
	input [15:0]		rd_data;		//读数据
	input [23:0]		rd_min_addr;
	input [23:0]		rd_max_addr;
	input [9:0]		rd_brust_len;       //读突发长度
	input 			rd_load_flag;
		
	//用户控制端口	
	input			sdram_init_done;	//初始化标志信号
	input			sdram_read_valid;	//读使能
		
	//sdram端口定义	
	output			sdram_wr_req;
	input 			sdram_wr_ack;
	output [15:0]		sdram_wr_data;
	output reg [23:0]	sdram_wr_addr;
		
	//sdram端口定义	
	output	reg		sdram_rd_req;
	input 			sdram_rd_ack;
	input	   [15:0]	sdram_rd_data;
	output reg [23:0]	sdram_rd_addr

);

//寄存信号,用于捕获边沿触发

	reg			wr_req_1;				//写响应寄存器
	reg			wr_req_2;
	reg			rd_req_1;			
	reg			rd_req_2;	
	reg			sdram_read_valid_1;			//读有效寄存器
	reg			sdram_read_valid_2;
	reg			wr_load_flag_1;				// //写端口复位寄存器
	reg			wr_load_flag_2;
	reg			rd_load_flag_1;
	reg			rd_load_flag_2;


	wire		wr_done_flag;			//写操作结束下降沿
	wire		rd_done_flag;
	wire		wr_load_flag;			//写复位上升沿
	wire		rd_load_flag;
	wire [9:0] 	wrf_use;                    //写端口FIFO中的数据量
	wire [9:0] 	rdf_use;                    //读端口FIFO中的数据量


//                    main  code

//数据结束下降沿检测

assign	wr_done_flag = wr_req_1 & (~wr_req_2); //不发出请求信号
assign  rd_done_flag = rd_req_1 & (~rd_req_2);

//复位上升沿检测

assign  wr_load_flag = (~wr_load_flag_1) & wr_load_flag_2;
assign  rd_load_flag = (~rd_load_flag_1) & rd_load_flag_2;


//写响应寄存器
always @(posedge clk_ref or negedge sys_rst)begin
	if(!sys_rst)begin
		wr_req_1 <= 1'b0;
	    wr_req_2 <= 1'b0;
	end
	else begin
		wr_req_1 <= wr_req;
		wr_req_2 <= wr_req_1;
	end
end

//读响应器
always @(posedge clk_ref or negedge sys_rst)begin
	if(!sys_rst)begin
		rd_req_1 <= 1'b0;
	    rd_req_2 <= 1'b0;
	end
	else begin
		rd_req_1 <= rd_req;
		rd_req_2 <= rd_req_1;
	end
end

//同步写端口复位信号,用于捕获wr_load上升沿
always @(posedge clk_ref or negedge sys_rst)begin
	if(!sys_rst)begin
		wr_load_flag_1 <= 1'b0; 
	    wr_load_flag_2 <= 1'b0;
	end
	else begin
		wr_load_flag_1 <= wr_load_flag; 
	    wr_load_flag_2 <= wr_load_flag_1;
	end
end

//同步读端口复位信号,用于捕获wr_load上升沿
always @(posedge clk_ref or negedge sys_rst)begin
	if(!sys_rst)begin
		rd_load_flag_1 <= 1'b0; 
	    rd_load_flag_2 <= 1'b0;
	end
	else begin
		rd_load_flag_1 <= rd_load_flag; 
	    rd_load_flag_2 <= rd_load_flag_1;
	end
end

//同步sdram读使能信号
always @(posedge clk_ref or negedge sys_rst)begin
	if(!sys_rst)begin
		sdram_read_valid_1 <= 1'b0;	
        sdram_read_valid_2 <= 1'b0;
	end
	else begin
		sdram_read_valid_1 <= sdram_read_valid;	
		sdram_read_valid_2 <= sdram_read_valid_1;
	end
end

//sdram写地址产生模块
always @(posedge clk_ref or negedge sys_rst)begin
	if(!sys_rst)begin
		sdram_wr_addr <= 24'd0;
	end
	else if(wr_load_flag)     		//写复位
		sdram_wr_addr <= wr_min_addr;
	else if(wr_done_flag)		//当一次写数据传输结束
		begin        //若当前地址未到达最大则写地址累加
			if(sdram_wr_addr < wr_max_addr - wr_brust_len)   
				sdram_wr_addr <= sdram_rd_addr + wr_brust_len;
			else
				sdram_wr_addr <= wr_min_addr;//若到达最大则回到最小地址
		end
end

//sdram读地址产生模块
always @(posedge clk_ref or negedge sys_rst)begin
	if(!sys_rst)begin
		sdram_rd_addr <= 24'd0;
	end
	else if(rd_load_flag)     			 //读复位
		sdram_rd_addr <=rd_min_addr;
	else if(rd_done_flag)					 //当一次读数据传输结束
		begin         //若当前地址未到达最大地址,则读地址累加
			if(sdram_rd_addr < rd_max_addr - rd_brust_len)  
				sdram_rd_addr <= sdram_rd_addr + rd_brust_len;
			else
				sdram_rd_addr <= rd_min_addr;	//若到达最大地址,则回到最小地址
		end
end

//读写请求产生模块
always @(posedge clk_ref or negedge sys_rst)begin
	if(!sys_rst)begin
		sdram_wr_req <= 1'b0;			//对同一SDRAM通信,不可同时为1
		sdram_rd_req <= 1'b0;
	end
	else if(sdram_init_done)begin			//初始化完成,才可发送请求信号
		if(wrf_use > wr_brust_len)begin	//当写fifo大于一个突发长度,可写入到sdram中
			sdram_wr_req <= 1'b1;
		    sdram_rd_req <= 1'b0;
		end                     //当读fifo中数据小于一个突发长度,可从SDRAM中读出数据
		else if((rdf_use < rd_brust_len) && sdram_read_valid_2)begin
			sdram_wr_req <= 1'b0;
		    sdram_rd_req <= 1'b1;
		end
		else
			sdram_wr_req <= 1'b0;
			sdram_rd_req <= 1'b0;
	end
	else begin
			sdram_wr_req <= 1'b0;
			sdram_rd_req <= 1'b0;
	end
end

//例化写fifo ip核
wrfifo u_wrfifo(
//用户接口
	.wrclk		(clk_write),
	.wrreq		(wrf_wrreq),  //请求来自用户输入模块
	.data		(wr_data),

//sdram接口
	.rdclk		(clk_ref),
	.rdreq		(sdram_wr_ack),  //满足写条件发出写请求,接收SDRAM的写应答
	.q			(sdram_wr_data),

	.wrusedw    (wrf_use),
	.aclr		(sys_rst | wr_load_flag)
);

//例化读端口FIFO
rdfifo	u_rdfifo(
	//sdram接口
	.wrclk		(clk_ref),       	     //写时钟
	.wrreq		(sdram_rd_ack),  	     //写请求
	.data		(sdram_rd_data),  		     //写数据
    
	//用户接口
	.rdclk		(clk_read),              //读时钟
	.rdreq		(rd_req),     	     //读请求
	.q			(rd_data),			     //读数据

	.wrusedw	(rdf_use),        	     //FIFO中的数据量
	.aclr		(~sys_rst | rd_load_flag)  //异步清零信号   
    );

endmodule

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值