串口读写SDRAM存储器

SDRAM同步动态随机存储器

SDRAM概念

SDRAM与SRAM区别

SDRAM:同步动态存储器。
同步:需要时钟信号,数据与时钟信号的上升沿同步变化。
动态:每64ms内动态刷新存储器中的数据。电容自放电特性,为了保持数据不变需要刷新。
随机:可以任意选取SDRAM中存储器单元地址进行读写。
SRAM:异步静态存储器。
不需要时钟信号,功耗高,不需要刷新。

SDRAM存储器框图

1bit存储器内部由行地址线与列地址线组成。
1bit存储器内部由行地址线与列地址线组成。
在这里插入图片描述
CLK:时钟输入信号;
CKE:时钟有效信号,高电平有效。
CS_N:片选信号(总开关)。低电平有效。
RAS_N:行地址选通有效信号,使能行地址访问,预充电,在时钟上升沿存行地址。低电平有效。
CAS_N:列地址选通,上升沿传到列地址。低电平有效。
WE_N:写命令使能操作。低电平有效。
BA:bank地址,4个bank。
DQM:高低电平掩码,若DQM[1]=1,则DQ[15:8]为高阻态。
SA:不同的操作命令意义不同。13位宽,共8192行。

SDRAM参数定义

CL:列选通潜伏期;从发送读命令信号2/3个时钟周期后发送数据所需要的时间。写操作不需要列选通潜伏期。(激活列地址后读出数据到IO所需要的时间)。
tRCD:激活行地址(激活命令)后需要tRCDns激活列地址。
tRP:预充电命令(关闭行命令)发送后等待tRP时间才可重新操作。

SDRAM控制器

SDRAM初始化模块

在这里插入图片描述

SDRAM初始化模块时序图

在这里插入图片描述

SDRAM初始化模块状态转移图

在这里插入图片描述

SDRAM初始化模块代码

可参考SDRAM学习(二)之初始化.

module SDRAM_INIT(
	Clk,
	Rst_n,
	
	Init_cmd,
	Init_ba,
	Init_adrr,
	Init_done
);
input Clk;
input Rst_n;

output	reg[3:0]Init_cmd;  //初始化命令 
output	reg[1:0]Init_ba;   //初始化bank地址
output	reg[12:0]Init_adrr;  //选择的地址a0-a12 相当于sa
output	Init_done;     //初始化完成标志信号

localparam  WAIT = 15'd20_000;  //上电后等待时钟数(200us)

localparam  IDLE = 3'd0, //空闲状态
				CHARGE = 3'd1, //预充电状态
				CHARGE_WAIT = 3'd2, //预充电等待状态
				REFRESH = 3'd3, //自刷新状态
				REFRESH_WAIT = 3'd4,//自刷新等待状态
				MODE = 3'd5, //模式寄存器状态
				MODE_WAIT = 3'd6, //模式寄存器等待状态
				END = 3'd7; //结束态
				
parameter   CHARGE_CLK = 3'd2, //预充电等待周期   tRP
				REFRESH_CLK = 3'd7, //自刷新等待周期  tRC
				MODE_CLK = 3'd3; //配置模式寄存器等待周期   tMRD
				
localparam  NONE_CMD = 4'b0111, //空命令指令
				CHARGE_CMD = 4'b0010, //预充电指令
				REFRESH_CMD = 4'b0001, //自动刷新指令
				MODE_CMD = 4'b0000;//配置模式寄存器指令
				
reg [2:0]main_state;				
reg [14:0]cnt_200us;
wire charge_end;
wire refresh_end;
wire mode_end;
reg [3:0]refresh_cnt;
reg [2:0]cnt_clk;
reg cnt_clk_en;

wire wait_end;


always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_200us <= 1'b0;
else 
if(cnt_200us == WAIT)
cnt_200us <= WAIT;
else 
cnt_200us <= cnt_200us + 1'b1;

assign wait_end = (cnt_200us == (WAIT - 1'b1))?1'b1 : 1'b0;

//主状态机 格雷码
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
main_state <= 3'd0;
else 
begin
	case(main_state)
	
	IDLE:
	begin
		if(wait_end)
		main_state <= CHARGE;
		else 
		main_state <= IDLE;
	end
	
	CHARGE:
	main_state <= CHARGE_WAIT;
	
	CHARGE_WAIT:  
	begin
		if(charge_end)
		main_state <= REFRESH;
		else 
		main_state <= CHARGE_WAIT;
	end
	
	REFRESH:
	main_state <= REFRESH_WAIT;
	
	REFRESH_WAIT:
	begin
		if(refresh_end)
		begin
			if(refresh_cnt == 4'd8)
			main_state <= MODE;
			else 
			main_state <= REFRESH;
		end
		else 
		main_state <= REFRESH_WAIT;
	end
	
	MODE: 
	main_state <= MODE_WAIT;
	
	MODE_WAIT:
	begin
		if(mode_end)
		main_state <= END;
		else 
		main_state <= MODE_WAIT;
	end
	
	END: main_state <= END;
	
	default : main_state <= IDLE;
	endcase
end

//计数时钟计数器
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_clk <= 1'b0;
else 
if(cnt_clk_en)
cnt_clk <= 1'b0;
else 
cnt_clk <= cnt_clk + 1'b1;

assign charge_end = ((cnt_clk == CHARGE_CLK) && (main_state == CHARGE_WAIT))? 1'b1:1'b0;
assign refresh_end = ((cnt_clk == REFRESH_CLK) && (main_state == REFRESH_WAIT))? 1'b1:1'b0;
assign mode_end = ((cnt_clk == MODE_CLK) && (main_state == MODE_WAIT))? 1'b1:1'b0;

//产生时钟计数器使能信号
always @(*)
begin
	case(main_state)
		IDLE : cnt_clk_en <= 1'b1;
		CHARGE_WAIT : cnt_clk_en <= (charge_end == 1'b1)? 1'b1:1'b0;
		REFRESH_WAIT : cnt_clk_en <= (refresh_end == 1'b1)? 1'b1:1'b0;	
		MODE_WAIT : cnt_clk_en <= (mode_end == 1'b1)? 1'b1:1'b0;
		END : cnt_clk_en <= 1'b1;	
		default: cnt_clk_en <= 1'b0;
	endcase 
end

//输出信号
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
begin
		Init_cmd	<= NONE_CMD;
		Init_ba <= 2'b11;
		Init_adrr  <= 13'h1fff;
end
else 
begin
	case(main_state)
	
		IDLE,CHARGE_WAIT,REFRESH_WAIT,MODE_WAIT,END:
		begin
		Init_cmd	<= NONE_CMD;
		Init_ba <= 2'b11;
		Init_adrr  <= 13'h1fff;		
		end
		
		CHARGE:
		begin
		Init_cmd	<= CHARGE_CMD;
		Init_ba <= 2'b11;
		Init_adrr  <= 13'h1fff;
		end

		REFRESH:
		begin
		Init_cmd	<= REFRESH_CMD;
		Init_ba <= 2'b11;
		Init_adrr  <= 13'h1fff;		
		end
		
		MODE:
		begin
		Init_cmd	<= MODE_CMD;
		Init_ba <= 2'b00;
		Init_adrr  <= 
		{ 地址辅助配置模式寄存器,参数不同,配置的模式不同
		 3'b000, //A12-A10;预留
		 1'b0, //A9=0; 读写方式,0:突发读&突发写,1:突发读&单写
		 2'b00, //{A8,A7}=00:标准模式,默认
		 3'b011,//{A6,A5,A4}=011:CAS潜伏期,010:2,011:3,其他:保留
		 1'b0, //A3=0:突发传输方式,0:顺序,1:隔行
		 3'b111 //{A2,A1,A0}=111:突发长度,000:单字节,001:2字节
					//010:4字节,011:8字节,111:整页,其他:保留
		};			
		end
		
		
		default:
		begin
		Init_cmd	<= NONE_CMD;
		Init_ba <= 2'b11;
		Init_adrr  <= 13'h1fff;
		end
	endcase


end

//产生Done信号
assign Init_done = (main_state == END)? 1'b1:1'b0;

//计数刷新次数
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
refresh_cnt <= 1'b0;
else 
if(main_state == IDLE)
refresh_cnt <= 1'b0;
else 
if(main_state == REFRESH)
refresh_cnt <= refresh_cnt + 1'b1;
else 
refresh_cnt <= refresh_cnt;


endmodule 
SDRAM初始化模块仿真文件
`timescale 1ns/1ns
`define CLK_period 20
module SDRAM_INIT_tb;

wire            clk_50m         ;   //PLL输出50M时钟
wire            clk_100m        ;   //PLL输出100M时钟
wire            clk_100m_shift  ;   //PLL输出100M时钟,相位偏移-30deg
wire            locked          ;   //PLL时钟锁定信号
wire            rst_n           ;   //复位信号,低有效
//sdram_init
wire    [3:0]   init_cmd        ;   //初始化阶段指令
wire    [1:0]   init_ba         ;   //初始化阶段L-Bank地址
wire    [12:0]  init_addr       ;   //初始化阶段地址总线
wire            init_end        ;   //初始化完成信号

reg             sys_clk         ;   //系统时钟
reg             sys_rst_n       ;   //复位信号

//defparam
//重定义仿真模型中的相关参数
defparam sdram_model_plus_inst.addr_bits = 13;          //地址位宽
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; //L-Bank容量


//时钟、复位信号
initial
  begin
    sys_clk     =   1'b1  ;
    sys_rst_n   <=  1'b0  ;
    #200
    sys_rst_n   <=  1'b1  ;
  end

always  #10 sys_clk = ~sys_clk;

//rst_n:复位信号
assign  rst_n = sys_rst_n & locked;

CLK_STRAT	CLK_STRAT_inst (  //IP核PLL
	.areset ( !sys_rst_n ),
	.inclk0 ( sys_clk ),
	.c0 (  clk_50m       ),
	.c1 (  clk_100m      ),
	.c2 (  clk_100m_shift),
	.locked ( locked )
	);

SDRAM_INIT SDRAM_INIT(
	.Clk(clk_100m),
	.Rst_n(rst_n),
	
	.Init_cmd(init_cmd),
	.Init_ba(init_ba),
	.Init_adrr(init_addr),
	.Init_done(init_end)
);	

sdram_model_plus sdram_model_plus_inst(
    .Dq     (               ),
    .Addr   (init_addr      ),
    .Ba     (init_ba        ),
    .Clk    (clk_100m_shift ),
    .Cke    (1'b1           ),
    .Cs_n   (init_cmd[3]    ),
    .Ras_n  (init_cmd[2]    ),
    .Cas_n  (init_cmd[1]    ),
    .We_n   (init_cmd[0]    ),
    .Dqm    (2'b0           ),
    .Debug  (1'b1           )

);
endmodule 
SDRAM初始化模块仿真波形图

在这里插入图片描述

对所有bank自刷新8次,产生end结束信号。

SDRAM自刷新模块

SDRAM自动刷新模块图

在这里插入图片描述
时钟指令为高时输入自刷新指令为自动刷新模式。需要外步时钟写入。
时钟指令为低时输入自刷新指令为自刷新模式。低功耗模式。此模式下其他指令无效。不需要外步时钟写入。时钟指令为高退出自刷新模式。
64MS内刷新8192行,13位宽,在100M时钟下(周期10ns)计数值设为750.
64MS内刷新4096行,在100M时钟下(周期10ns)计数值设为1510.

SDRAM自动刷新模块时序

在这里插入图片描述

SDRAM自动刷新模块状态转移图

在这里插入图片描述

SDRAM自动刷新模块代码
module SDRAM_REFRESH(
	Clk,
	Rst_n,
	Init_end,
	Re_en,
	
	Re_cmd,
	Re_addr,
	Re_ba,
	Re_end,
	Re_req  
	);
	
input	Clk      ;
input	Rst_n    ;
input	Init_end ;
input	Re_en    ;	
output	reg[3:0]Re_cmd;
output	reg[12:0]Re_addr;
output	reg[1:0]Re_ba;   
output	Re_end;
output reg	Re_req;

parameter CNT_MAX = 9'd450;  //刷新时间计数
localparam RE_IDLE         = 3'b000   ,   //空闲
			  RE_CHARGE       = 3'b001   ,   //预充电
			  RE_CHARGE_WAIT  = 3'b010   ,   //预充电等待
			  RE_REFRESH      = 3'b011   ,   //自动刷新
			  RE_REFRESH_WAIT = 3'b100   ,   //自动刷新等待
			  RE_END          = 3'b101   ;   //结束
			  
parameter  CHARGE_CLK = 3'd2, //预充电等待周期
				REFRESH_CLK = 3'd7; //自刷新等待周期		  
				
localparam  NONE_CMD = 4'b0111, //空命令指令
				CHARGE_CMD = 4'b0010, //预充电指令 行地址
				REFRESH_CMD = 4'b0001; //自刷新指令

			  
reg [8:0]re_cnt; 
reg [2:0]main_state;
wire charge_end;
wire refresh_end;
reg [1:0]refresh_cnt;
reg [2:0]cnt_clk;
reg cnt_clk_en;  //高电平清零
wire re_ack;
  

//64ms内刷新13位宽8192行 每4500ns刷新一次
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
re_cnt <= 1'b0;
else 
if(re_cnt >= CNT_MAX)
re_cnt <= 1'b0;
else
if(Init_end == 1'b1)
re_cnt <= re_cnt + 1'b1;
 


//请求刷新信号
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Re_req <= 1'b0;
else 
if(re_cnt == (CNT_MAX - 1'b1))
Re_req <= 1'b1;
else 
if(re_ack == 1'b1)
Re_req <= 1'b0;

assign re_ack = (main_state == RE_REFRESH)?1'b1:1'b0 ; 

//主状态
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
main_state <= 1'b0;
else 
begin
	case(main_state)
		
		RE_IDLE:
			begin
				if(Init_end && Re_en)
				main_state <= RE_CHARGE;
				else 
				main_state <= RE_IDLE;
			end
			
		RE_CHARGE:    
			main_state <= RE_CHARGE_WAIT;


		RE_CHARGE_WAIT:
			begin
				if(charge_end)
				main_state <= RE_REFRESH;
				else 
				main_state <= RE_CHARGE_WAIT;
			end
			
		RE_REFRESH:    
			main_state <= RE_REFRESH_WAIT;

		RE_REFRESH_WAIT:
			begin
				if(refresh_end)
					begin
						if(refresh_cnt == 2'd2)
						main_state <= RE_END;
						else 
						main_state <= RE_REFRESH;
					end
				else 
				main_state <= RE_REFRESH_WAIT;
			end
			
		RE_END : main_state <= RE_IDLE;  
	
	default : main_state <= RE_IDLE;
	
	endcase

end

always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_clk <= 1'b0;
else 
if(cnt_clk_en)
cnt_clk <= 1'b0;
else 
cnt_clk <= cnt_clk + 1'b1;

always @(*)
begin
	case(main_state)
	RE_IDLE : cnt_clk_en <= 1'b1;
	RE_CHARGE_WAIT : cnt_clk_en <= (charge_end == 1'b1) ? 1'b1:1'b0;
	RE_REFRESH_WAIT : cnt_clk_en <= (refresh_end == 1'b1) ? 1'b1:1'b0;
	default: cnt_clk_en <= 1'b0;
	endcase
end

assign charge_end = ((cnt_clk == CHARGE_CLK) && (main_state == RE_CHARGE_WAIT))? 1'b1:1'b0;
assign refresh_end = ((cnt_clk == REFRESH_CLK) && (main_state == RE_REFRESH_WAIT))? 1'b1:1'b0;

//输出信号
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
begin
Re_cmd	<= 1'b0;
Re_ba <= 1'b0;
Re_addr  <= 1'b0;
end    
else 
begin
	case(main_state)
	
		RE_IDLE,RE_CHARGE_WAIT,RE_REFRESH_WAIT,RE_END:
		begin
		Re_cmd	<= NONE_CMD;
		Re_ba <= 2'b11;
		Re_addr  <= 13'h1fff;		
		end
		
		RE_CHARGE:
		begin
		Re_cmd	<= CHARGE_CMD;
		Re_ba <= 2'b11;
		Re_addr  <= 13'h1fff;
		end

		RE_REFRESH:
		begin
		Re_cmd	<= REFRESH_CMD;
		Re_ba <= 2'b11;
		Re_addr  <= 13'h1fff;		
		end
		
		default:
		begin
		Re_cmd	<= NONE_CMD;
		Re_ba <= 2'b11;
		Re_addr  <= 13'h1fff;
		end
	endcase
end

//产生Done信号
assign Re_end = (main_state == RE_END)? 1'b1:1'b0;

//计数刷新次数
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
refresh_cnt <= 1'b0;
else 
if(main_state == RE_END)
refresh_cnt <= 1'b0;
else 
if(main_state == RE_REFRESH)
refresh_cnt <= refresh_cnt + 1'b1;
else 
refresh_cnt <= refresh_cnt;


 endmodule 
SDRAM自动刷新模块仿真文件

初始化后自动刷新。

`timescale  1ns/1ns
module  SDRAM_REFRESH_tb();
//sdram
wire    [3:0]   sdram_cmd       ;   //SDRAM操作指令
wire    [1:0]   sdram_ba        ;   //SDRAM L-Bank地址
wire    [12:0]  sdram_addr      ;   //SDRAM地址总线
//clk_gen   
wire            clk_50m         ;   //PLL输出50M时钟
wire            clk_100m        ;   //PLL输出100M时钟
wire            clk_100m_shift  ;   //PLL输出100M时钟,相位偏移-30deg
wire            locked          ;   //PLL时钟锁定信号
wire            rst_n           ;   //复位信号,低有效
//sdram_init
wire    [3:0]   init_cmd        ;   //初始化阶段指令
wire    [1:0]   init_ba         ;   //初始化阶段L-Bank地址
wire    [12:0]  init_addr       ;   //初始化阶段地址总线
wire            init_end        ;   //初始化完成信号
//sdram_a_ref
wire            aref_req        ;   //自动刷新请求
wire            re_end        ;   //自动刷新结束
wire    [3:0]   re_cmd        ;   //自动刷新阶段指令
wire    [1:0]   re_ba         ;   //自动刷新阶段L-Bank地址
wire    [12:0]  re_addr       ;   //自动刷新阶段地址总线

//reg define    
reg             sys_clk         ;   //系统时钟
reg             sys_rst_n       ;   //复位信号
reg             re_en         ;   //自动刷新使能

//defparam
//重定义仿真模型中的相关参数
defparam sdram_model_plus_inst.addr_bits = 13;          //地址位宽
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; //L-Bank容量

//时钟、复位信号
initial
  begin
    sys_clk     =   1'b1  ;
    sys_rst_n   <=  1'b0  ;
    #200
    sys_rst_n   <=  1'b1  ;
  end

always  #10 sys_clk = ~sys_clk;

//rst_n:复位信号
assign  rst_n = sys_rst_n & locked;

//re_en:自动刷新使能
always@(posedge clk_100m or negedge rst_n)
    if(rst_n == 1'b0)
        re_en <=  1'b0;
    else    if((init_end == 1'b1) && (aref_req == 1'b1))
        re_en <=  1'b1;
    else    if(re_end == 1'b1)
        re_en <=  1'b0;

assign  sdram_cmd = (init_end == 1'b1) ? re_cmd : init_cmd;
assign  sdram_ba = (init_end == 1'b1) ? re_ba : init_ba;
assign  sdram_addr = (init_end == 1'b1) ? re_addr : init_addr;

CLK_STRAT	CLK_STRAT_inst (  //IP核PLL
	.areset ( !sys_rst_n ),
	.inclk0 ( sys_clk ),
	.c0 (  clk_50m       ),
	.c1 (  clk_100m      ),
	.c2 (  clk_100m_shift),
	.locked ( locked )
	);

SDRAM_REFRESH SDRAM_REFRESH(
	.Clk(clk_100m),
	.Rst_n(rst_n),
	.Init_end(init_end),
	.Re_en(re_en),
	
	.Re_cmd(re_cmd),
	.Re_addr(re_addr),
	.Re_ba(re_ba),
	.Re_end(re_end),
	.Re_req(aref_req)  
	);

SDRAM_INIT SDRAM_INIT(
	.Clk(clk_100m),
	.Rst_n(rst_n),
	
	.Init_cmd(init_cmd),
	.Init_ba(init_ba),
	.Init_adrr(init_addr),
	.Init_done(init_end)
);


//SDRAM模型
sdram_model_plus    sdram_model_plus_inst(
    .Dq     (               ),
    .Addr   (sdram_addr     ),
    .Ba     (sdram_ba       ),
    .Clk    (clk_100m_shift ),
    .Cke    (1'b1           ),
    .Cs_n   (sdram_cmd[3]   ),
    .Ras_n  (sdram_cmd[2]   ),
    .Cas_n  (sdram_cmd[1]   ),
    .We_n   (sdram_cmd[0]   ),
    .Dqm    (2'b0           ),
    .Debug  (1'b1           )
);
endmodule 
SDRAM自动刷新模块仿真结果

在这里插入图片描述

re_cnt计数到750发出re_req自动刷新请求信号。

SDRAM写操作模块

SDRAM写模块框图

在这里插入图片描述

SDRAM写模块时序

在这里插入图片描述

SDRAM写模块状态转移图

在这里插入图片描述

写模块代码
module SDRAM_WR(
	Clk,
	Rst_n,
	Init_end,
	Wr_addr,  
	Wr_data,
	Wr_burst_len,
	Wr_en,
	
	Wr_ba,
	Wr_cmd,
	Wr_sdram_addr,
	Wr_sdram_data,
	Wr_end,
	Wr_sdram_en,
	Wr_ack
);
input	Clk;       
input	Rst_n;
input	Init_end;
input	[23:0]Wr_addr;  //写SDRAM地址  bank地址 行/列地址组成
input	[15:0]Wr_data;
input	[9:0]Wr_burst_len; //写突发长度max512
input	Wr_en;
	
output	reg[1:0]Wr_ba;
output	reg[3:0]Wr_cmd;
output	reg[12:0]Wr_sdram_addr;//地址数据,辅助预充电操作,行、列地址,A12-A0,13位地址
output	[15:0]Wr_sdram_data;//写入SDRAM的数据
output	Wr_end; 
output	reg Wr_sdram_en; //写SDRAM使能信号
output	Wr_ack; 

localparam WR_IDLE     =3'b000,//空闲态 
			  WR_ACTIVE   =3'b001,//写激活
			  ACTIVE_WAIT =3'b010,//激活等待
			  WRITE       =3'b011,//写命令 写指令    行地址传入RAS_n端(SDRAM )端
			  WR_DATA     =3'b100,//写数据   传列地址Cas_n端为低电平
			  WR_CHAR     =3'b101,//预充电
			  WR_CHAR_WAIT=3'b110,//预充电等待
			  WR_END      =3'b111;//写结束
			  
parameter  CHARGE_CLK = 3'd2, //预充电等待周期
			  ACTIVE_CLK = 3'd2; //激活等待周期		  
				
localparam  NONE_CMD = 4'b0111, //空命令指令
				CHARGE_CMD = 4'b0010, //预充电指令  行地址传入RAS_n端(SDRAM )端
				WR_CMD = 4'b0100, //写指令    列地址传入CAS_n端(SDRAM )端
				ACTIVE_CMD = 4'b0011,//激活命令
				STOP = 4'b0110; //突发停止指令

reg [2:0]state;
reg [9:0]cnt_clk;
reg cnt_clk_en;
wire active_end;
wire wr_data_end;
wire char_end;



//主状态机
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
state <= 1'b0;
else 
begin
	
	case(state)
		WR_IDLE     :
		begin
			if(Init_end && Wr_en)
			state <= WR_ACTIVE;
			else 
			state <= WR_IDLE;
		end 
		
		WR_ACTIVE   :
		state <= ACTIVE_WAIT;
		
		ACTIVE_WAIT :
		begin
			if(active_end)
			state <= WRITE;
			else 
			state <= ACTIVE_WAIT;
		end
		
		WRITE       :		//写命令
		state <= WR_DATA;
		
		WR_DATA     :	     
		begin
			if(wr_data_end)
			state <= WR_CHAR;
			else 
			state <= WR_DATA;
		end
		
		WR_CHAR     :
		state <= WR_CHAR_WAIT;
		
		WR_CHAR_WAIT:
		begin
			if(char_end)
			state <= WR_END;
			else 
			state <= WR_CHAR_WAIT;		
		end
		
		WR_END      :
		state <= WR_IDLE;

		default: state <= WR_IDLE;
   endcase                     
		
end

//使能计数器计数时钟
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_clk <= 1'b0;
else 
if(cnt_clk_en)
cnt_clk <= 1'b0;
else 
cnt_clk <= cnt_clk + 1'b1;


//使能CLK计数信号
always @(*)
begin
	case(state)
	
	WR_END,WR_IDLE,WRITE:
	cnt_clk_en <= 1'b1;
	
	ACTIVE_WAIT:
	cnt_clk_en <= (active_end == 1'b1)?1'b1:1'b0;
	
	WR_DATA:
	cnt_clk_en <= (wr_data_end == 1'b1)?1'b1:1'b0;	
	
	WR_CHAR_WAIT:
	cnt_clk_en <= (char_end == 1'b1)?1'b1:1'b0;	
	
	default : cnt_clk_en <= 1'b0;
	endcase 
	
end

//产生end信号
assign active_end = (cnt_clk == ACTIVE_CLK)?1'b1:1'b0;
assign wr_data_end = (cnt_clk == (Wr_burst_len - 1'b1))?1'b1:1'b0;
assign char_end = (cnt_clk == CHARGE_CLK)?1'b1:1'b0;

//产生应答信号
assign Wr_ack = ((state == WRITE) || ( (state == WR_DATA) && (cnt_clk <= (Wr_burst_len - 2'd2)) ))?1'b1 : 1'b0;

//结束信号
assign Wr_end = (state == WR_END)?1'b1:1'b0;

//输出信号
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
begin
Wr_ba <= 2'd0;
Wr_cmd <= 4'd0;
Wr_sdram_addr <= 13'd0;
end
else 
begin
	
	case(state)
	
	WR_IDLE,ACTIVE_WAIT,WR_CHAR_WAIT,WR_END:
		begin
		Wr_ba <= 2'b11;
		Wr_cmd <= NONE_CMD;
		Wr_sdram_addr <= 13'h1fff;
		end
	
	WR_ACTIVE: //写激活指令
		begin
		Wr_ba <= Wr_addr[23:22];
		Wr_cmd <= ACTIVE_CMD;
		Wr_sdram_addr <= Wr_addr[21:9];		//行地址
		end
	
	WRITE:
		begin
		Wr_ba <= Wr_addr[23:22];
		Wr_cmd <= WR_CMD;
		Wr_sdram_addr <= {4'b0000,Wr_addr[8:0]};		//行地址高4位清零 写列地址
		end	
	
	WR_DATA:
		begin
			if(wr_data_end)
			Wr_cmd <= STOP;
			else		
				begin
					Wr_ba <= 2'b11;
					Wr_cmd <= NONE_CMD;
					Wr_sdram_addr <= 13'h1fff;		
				end
		end			
	
	 WR_CHAR:
		begin
		Wr_ba <= Wr_addr[23:22];
		Wr_cmd <= CHARGE_CMD;
		Wr_sdram_addr <= 13'h0400;	
		end

	default : 
		begin
		Wr_ba <= 2'b11;
		Wr_cmd <= NONE_CMD;
		Wr_sdram_addr <= 13'h1fff;
		end
	endcase
end

//写SDRAM使能信号
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Wr_sdram_en <= 1'b0;
else 
Wr_sdram_en <= Wr_ack;

assign Wr_sdram_data = (Wr_sdram_en == 1'b1)?Wr_data : 16'd0;


endmodule 
写模块仿真代码
`timescale  1ns/1ns

module  sdram_wr_tb();

//wire define
//clk_gen
wire            clk_50m         ;   //PLL输出50M时钟
wire            clk_100m        ;   //PLL输出100M时钟
wire            clk_100m_shift  ;   //PLL输出100M时钟,相位偏移-30deg
wire            locked          ;   //PLL时钟锁定信号
wire            rst_n           ;   //复位信号,低有效
//sdram_init
wire    [3:0]   init_cmd        ;   //初始化阶段指令
wire    [1:0]   init_ba         ;   //初始化阶段L-Bank地址
wire    [12:0]  init_addr       ;   //初始化阶段地址总线
wire            init_end        ;   //初始化完成信号
//sdram_write
wire    [12:0]  write_addr      ;   //数据写阶段地址总线
wire    [1:0]   write_ba        ;   //数据写阶段L-Bank地址
wire    [3:0]   write_cmd       ;   //数据写阶段指令
wire    [15:0]  wr_sdram_data   ;   //数据写阶段写入SDRAM数据
wire            wr_sdram_en     ;   //数据写阶段写数据有效使能信号
wire            wr_end          ;   //数据写阶段一次突发写结束
wire            sdram_wr_ack    ;   //数据写阶段写响应
//sdram_addr
wire    [12:0]  sdram_addr      ;   //SDRAM地址总线
wire    [1:0]   sdram_ba        ;   //SDRAML-Bank地址
wire    [3:0]   sdram_cmd       ;   //SDRAM指令
wire    [15:0]  sdram_dq        ;   //SDRAM数据总线
//reg define
reg             sys_clk         ;   //系统时钟
reg             sys_rst_n       ;   //复位信号
reg             wr_en           ;   //写使能
reg     [15:0]  wr_data_in      ;   //写数据

//defparam
//重定义仿真模型中的相关参数
defparam sdram_model_plus_inst.addr_bits = 13;          //地址位宽
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; //L-Bank容量


//时钟、复位信号
initial
  begin
    sys_clk     =   1'b1  ;
    sys_rst_n   <=  1'b0  ;
    #200
    sys_rst_n   <=  1'b1  ;
  end

always  #10 sys_clk = ~sys_clk;

//rst_n:复位信号
assign  rst_n = sys_rst_n & locked;

//wr_en:写数据使能
always@(posedge clk_100m or negedge rst_n)
    if(!rst_n)
        wr_en   <=  1'b0;
    else    if(wr_end == 1'b1)
        wr_en   <=  1'b0;
    else    if(init_end == 1'b1)
        wr_en   <=  1'b1;
    else
        wr_en   <=  wr_en;

//wr_data_in:写数据
always@(posedge clk_100m or negedge rst_n)
    if(!rst_n)
        wr_data_in  <=  16'd0;
    else    if(wr_data_in == 16'd10)
        wr_data_in  <=  16'd0;
    else    if(sdram_wr_ack == 1'b1)
        wr_data_in  <=  wr_data_in + 1'b1;
    else
        wr_data_in  <=  wr_data_in;

//sdram_cmd,sdram_ba,sdram_addr
assign  sdram_cmd = (init_end == 1'b1) ? write_cmd : init_cmd;
assign  sdram_ba = (init_end == 1'b1) ? write_ba : init_ba;
assign  sdram_addr = (init_end == 1'b1) ? write_addr : init_addr;

//wr_sdram_data
assign  sdram_dq = (wr_sdram_en == 1'b1) ? wr_sdram_data : 16'hz;


CLK_STRAT	CLK_STRAT_inst (  //IP核PLL
	.areset ( !sys_rst_n ),
	.inclk0 ( sys_clk ),
	.c0 (  clk_50m       ),
	.c1 (  clk_100m      ),
	.c2 (  clk_100m_shift),
	.locked ( locked )
	);

SDRAM_INIT SDRAM_INIT(
	.Clk(clk_100m),
	.Rst_n(rst_n),
	
	.Init_cmd(init_cmd),
	.Init_ba(init_ba),
	.Init_adrr(init_addr),
	.Init_done(init_end)
);	

SDRAM_WR SDRAM_WR(
	.Clk(clk_100m),
	.Rst_n(rst_n),
	.Init_end(init_end),
	.Wr_addr(24'h000_000), //初始地址
	.Wr_data(wr_data_in),
	.Wr_burst_len(10'd10),
	.Wr_en(wr_en),
	
	.Wr_ba(write_ba),
	.Wr_cmd(write_cmd),
	.Wr_sdram_addr(write_addr),
	.Wr_sdram_data(wr_sdram_data),
	.Wr_end(wr_end),
	.Wr_sdram_en(wr_sdram_en),
	.Wr_ack(sdram_wr_ack)
);
sdram_model_plus    sdram_model_plus_inst(
    .Dq     (sdram_dq       ),
    .Addr   (sdram_addr     ),
    .Ba     (sdram_ba       ),
    .Clk    (clk_100m_shift ),
    .Cke    (1'b1           ),
    .Cs_n   (sdram_cmd[3]   ),
    .Ras_n  (sdram_cmd[2]   ),
    .Cas_n  (sdram_cmd[1]   ),
    .We_n   (sdram_cmd[0]   ),
    .Dqm    (2'b0           ),
    .Debug  (1'b1           )
);
endmodule 
写模块仿真图

在这里插入图片描述

PRE:预充电所有bank。
AREF:自动刷新8次。
LMR: 为Load Mode Register,即设置命令,用来配置设备参数。常用命令中的设置命令。
ACT:激活。
WRITE: 写。
BST:连续页面突发与BURST TERMINATE命令一起使用以产生任意突发长度。由于潜伏期在第7列提前。
可参考ALINX技术博客.

SDRAM读操作模块

SDRAM读模块框图

在这里插入图片描述
不带预充电的页突发读模式

SDRAM读模块时序

在这里插入图片描述

SDRAM读模块状态转移图

在这里插入图片描述

SDRAM读模块代码
module SDRAM_RD(
	Clk,
	Rst_n,
	Init_end,
	Rd_en,
	Rd_addr,
	Rd_data,
	Rd_burst_len,
	
	Rd_ack,
	Rd_end,
	Rd_cmd,
	Rd_ba,
	Rd_sdram_addr,
	Rd_sdram_data
	
);

input	Clk;
input	Rst_n;
input	Init_end;
input	Rd_en;
input	[23:0]Rd_addr;
input	[15:0]Rd_data;
input	[9:0]Rd_burst_len;
	
output	Rd_ack;
output	Rd_end;
output	reg[3:0]Rd_cmd;
output	reg[1:0]Rd_ba;
output	reg[12:0]Rd_sdram_addr; 
output	[15:0]Rd_sdram_data;

reg [15:0]rd_data_reg;
reg [3:0] state;
reg [9:0]cnt_clk;
reg cnt_clk_en;
wire active_end;
wire cl_end;
wire rd_data_end;
wire char_end;
wire rd_b_end; //读突发结束信号
 
localparam RD_IDLE     =4'b0000,//空闲态             
			  RD_ACTIVE   =4'b0001,//读激活           
			  ACTIVE_WAIT =4'b0010,//激活等待      
			  READ        =4'b0011,//读命令        
			  RD_CL       =4'b0100, //列潜伏等待期  
			  RD_DATA     =4'b0101,//读数据           
			  RD_CHAR     =4'b0110,//预充电           
			  CHAR_WAIT   =4'b0111,//预充电等待     
			  RD_END      =4'b1000;//读结束          
			  		  
parameter  CHARGE_CLK = 3'd2, //预充电等待周期
			  ACTIVE_CLK = 3'd2, //激活等待周期	
			  TCL_CLK    = 3'd3; //潜伏期
			
localparam  NONE_CMD = 4'b0111, //空命令指令
				CHARGE_CMD = 4'b0010, //预充电指令  行地址传入RAS_n端(SDRAM )端
				ACTIVE_CMD = 4'b0011,//激活命令  第三位位低位行地址传入RAS_n端(SDRAM )端
				STOP_CMD = 4'b0110, //突发停止指令
				READ_CMD = 4'b0101; //读数据指令   列地址

//数据打拍,同一时钟,同时钟变化
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
	rd_data_reg <= 16'd0;
else 
	rd_data_reg <= Rd_data;

//主状态机
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
	state <= 1'b0;
else 
begin
	case(state)
	
	RD_IDLE    : //空闲态 
		state <= (Init_end && Rd_en) ? RD_ACTIVE : RD_IDLE; //三元运算符
		
	RD_ACTIVE  : //读激活    
		state <= ACTIVE_WAIT;
		
	ACTIVE_WAIT: //激活等待  
		state <= (active_end) ? READ : ACTIVE_WAIT;		

	READ       : //读命令       
		state <= RD_CL;
		
	RD_CL      :  //列潜伏等待期 
		state <= (cl_end) ? RD_DATA : RD_CL;		

		
	RD_DATA    : //读数据 
		state <= (rd_data_end) ? RD_CHAR : RD_DATA;

	RD_CHAR    : //预充电   
		state <= CHAR_WAIT;
		
	CHAR_WAIT  : //预充电等待
		state <= (char_end) ? RD_END : CHAR_WAIT;

	RD_END     : //读结束     
		state <= RD_IDLE;
	
	default : state <= RD_IDLE;
	endcase 
end

//使能计数器计数时钟
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_clk <= 1'b0;
else 
if(cnt_clk_en)
cnt_clk <= 1'b0;
else 
cnt_clk <= cnt_clk + 1'b1;


//使能CLK计数信号
always @(*)
begin
    case(state)
    
    RD_IDLE,READ,RD_END:
    cnt_clk_en <= 1'b1;
    
    ACTIVE_WAIT:
    cnt_clk_en <= (active_end == 1'b1)?1'b1:1'b0;
    
    RD_CL:
    cnt_clk_en <= (cl_end == 1'b1)?1'b1:1'b0;	
    
    RD_DATA:
    cnt_clk_en <= (rd_data_end == 1'b1)?1'b1:1'b0;	
    
    CHAR_WAIT:
    cnt_clk_en <= (char_end == 1'b1)?1'b1:1'b0;	
    
    default : cnt_clk_en <= 1'b0;
    endcase 
end

//end信号产生
assign active_end = ((state == ACTIVE_WAIT) && (cnt_clk  == ACTIVE_CLK)) ? 1'b1:1'b0;
assign cl_end = ((state == RD_CL) && (cnt_clk == (TCL_CLK - 1'b1))) ? 1'b1:1'b0;
assign rd_data_end = ((state == RD_DATA) && (cnt_clk == (Rd_burst_len + TCL_CLK - 1'b1)))? 1'b1:1'b0;
assign char_end = ((state == CHAR_WAIT) && (cnt_clk == CHARGE_CLK ))? 1'b1:1'b0;
assign rd_b_end = ((state == RD_DATA) && (cnt_clk == (Rd_burst_len - TCL_CLK - 1'b1)))? 1'b1:1'b0;

//应答信号产生
assign Rd_ack = ((state == RD_DATA) && (cnt_clk >= 10'b0) && (cnt_clk < Rd_burst_len));

//产生读结束标志信号 一个时钟周期
assign Rd_end = (state == RD_END)?1'b1:1'b0;

//产生输出信号
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
begin
			Rd_cmd <= NONE_CMD;
			Rd_ba <= 2'b11;
			Rd_sdram_addr <= 13'h1fff;		
end
else 
begin
	case(state)
	
	RD_IDLE,ACTIVE_WAIT,RD_CL,CHAR_WAIT,RD_END:
		begin
			Rd_cmd <= NONE_CMD;
			Rd_ba <= 2'b11;
			Rd_sdram_addr <= 13'h1fff;			
		end
	
	RD_ACTIVE:  //读激活
		begin
			Rd_cmd <= ACTIVE_CMD;
			Rd_ba <= Rd_addr[23:22];
			Rd_sdram_addr <= Rd_addr[21:9];   //激活行地址
		end
	
	READ :	//读命令
		begin
			Rd_cmd <= READ_CMD;
			Rd_ba <= Rd_addr[23:22];
			Rd_sdram_addr <= {4'b0000,Rd_addr[8:0]};  
		end
		
	RD_DATA:  //读数据
		begin
			if(rd_b_end)
				Rd_cmd <= STOP_CMD;
			else 
				Rd_cmd <= NONE_CMD;
				Rd_ba <= 2'b11;
				Rd_sdram_addr <= 13'h1fff;				
		end
	
	RD_CHAR:   //预充电指令
		begin
			Rd_cmd <= CHARGE_CMD;
			Rd_ba <= Rd_addr[23:22];
			Rd_sdram_addr <= 13'h0400;	
		end
	
	
	default :
		begin
			Rd_cmd <= NONE_CMD;
			Rd_ba <= 2'b11;
			Rd_sdram_addr <= 13'h1fff;
		end

	endcase
end

//输出读出的SDRAM数据
assign Rd_sdram_data = (Rd_ack  == 1'b1)?rd_data_reg : 16'b0;

endmodule 

SDRAM读模块仿真代码
`timescale  1ns/1ns

module  sdram_read_tb();


//wire define
//clk_gen
wire            clk_50m         ;   //PLL输出50M时钟
wire            clk_100m        ;   //PLL输出100M时钟
wire            clk_100m_shift  ;   //PLL输出100M时钟,相位偏移-30deg
wire            locked          ;   //PLL时钟锁定信号
wire            rst_n           ;   //复位信号,低有效
//sdram_init
wire    [3:0]   init_cmd        ;   //初始化阶段指令
wire    [1:0]   init_ba         ;   //初始化阶段L-Bank地址
wire    [12:0]  init_addr       ;   //初始化阶段地址总线
wire            init_end        ;   //初始化完成信号
//sdram_write
wire    [12:0]  write_addr      ;   //数据写阶段地址总线
wire    [1:0]   write_ba        ;   //数据写阶段L-Bank地址
wire    [3:0]   write_cmd       ;   //数据写阶段指令
wire    [15:0]  wr_sdram_data   ;   //数据写阶段写入SDRAM数据
wire            wr_sdram_en     ;   //数据写阶段写数据有效使能信号
wire            wr_end          ;   //数据写阶段一次突发写结束
//sdram_read
wire    [12:0]  read_addr       ;   //数据读阶段地址总线
wire    [1:0]   read_ba         ;   //数据读阶段L-Bank地址
wire    [3:0]   read_cmd        ;   //数据读阶段指令
wire    [15:0]  sdram_data_out  ;   //数据读阶段写入SDRAM数据
wire            rd_end          ;   //数据读阶段一次突发写结束
wire            sdram_wr_ack    ;   //数据写阶段写响应
//sdram_addr
wire    [12:0]  sdram_addr      ;   //SDRAM地址总线
wire    [1:0]   sdram_ba        ;   //SDRAML-Bank地址
wire    [3:0]   sdram_cmd       ;   //SDRAM指令
wire    [15:0]  sdram_dq        ;   //SDRAM数据总线

wire    [12:0]  w_r_addr        ;   //数据读阶段地址总线
wire    [1:0]   w_r_ba          ;   //数据读阶段L-Bank地址
wire    [3:0]   w_r_cmd         ;   //数据读阶段指令

//reg define
reg             sys_clk         ;   //系统时钟
reg             sys_rst_n       ;   //复位信号
reg             wr_en           ;   //写使能
reg     [15:0]  wr_data_in      ;   //写数据
reg             rd_en           ;   //读使能


//defparam
//重定义仿真模型中的相关参数
defparam sdram_model_plus_inst.addr_bits = 13;          //地址位宽
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; //L-Bank容量

//时钟、复位信号
initial
  begin
    sys_clk     =   1'b1  ;
    sys_rst_n   <=  1'b0  ;
    #200
    sys_rst_n   <=  1'b1  ;
  end

always  #10 sys_clk = ~sys_clk;

//rst_n:复位信号
assign  rst_n = sys_rst_n & locked;

//wr_en:写数据使能
always@(posedge clk_100m or negedge rst_n)
    if(rst_n == 1'b0)
        wr_en   <=  1'b1;
    else    if(wr_end == 1'b1)
        wr_en   <=  1'b0;
    else
        wr_en   <=  wr_en;

//wr_data_in:写数据
always@(posedge clk_100m or negedge rst_n)
    if(rst_n == 1'b0)
        wr_data_in  <=  16'd0;
    else    if(wr_data_in == 16'd10)
        wr_data_in  <=  16'd0;
    else    if(sdram_wr_ack == 1'b1)
        wr_data_in  <=  wr_data_in + 1'b1;
    else
        wr_data_in  <=  wr_data_in;

//rd_en:读数据使能
always@(posedge clk_100m or negedge rst_n)
    if(rst_n == 1'b0)
        rd_en   <=  1'b0;
    else    if(rd_end == 1'b1)
        rd_en   <=  1'b0;
    else    if(wr_en == 1'b0)
        rd_en   <=  1'b1;
    else
        rd_en   <=  rd_en;

//sdram_cmd,sdram_ba,sdram_addr
assign  sdram_cmd = (init_end == 1'b1) ? w_r_cmd : init_cmd;
assign  sdram_ba = (init_end == 1'b1) ? w_r_ba : init_ba;
assign  sdram_addr = (init_end == 1'b1) ? w_r_addr : init_addr;

//w_r_cmd,w_r_ba,w_r_addr
assign  w_r_cmd = (wr_en == 1'b1) ? write_cmd : read_cmd;
assign  w_r_ba = (wr_en == 1'b1) ? write_ba : read_ba;
assign  w_r_addr = (wr_en == 1'b1) ? write_addr : read_addr;

//wr_sdram_data
assign  sdram_dq = (wr_sdram_en == 1'b1) ? wr_sdram_data : 16'hz;

CLK_STRAT	CLK_STRAT_inst (  //IP核PLL
	.areset ( !sys_rst_n ),
	.inclk0 ( sys_clk ),
	.c0 (  clk_50m       ),
	.c1 (  clk_100m      ),
	.c2 (  clk_100m_shift),
	
	.locked ( locked )
	);

SDRAM_INIT SDRAM_INIT(
	.Clk(clk_100m),
	.Rst_n(rst_n),
	
	.Init_cmd(init_cmd),
	.Init_ba(init_ba),
	.Init_adrr(init_addr),
	.Init_done(init_end)
);	

SDRAM_WR SDRAM_WR(
	.Clk(clk_100m),
	.Rst_n(rst_n),
	.Init_end(init_end),
	.Wr_addr(24'h000_000), //初始地址
	.Wr_data(wr_data_in),
	.Wr_burst_len(10'd10),
	.Wr_en(wr_en),
	
	.Wr_ba(write_ba),
	.Wr_cmd(write_cmd),
	.Wr_sdram_addr(write_addr),
	.Wr_sdram_data(wr_sdram_data),
	.Wr_end(wr_end),
	.Wr_sdram_en(wr_sdram_en),
	.Wr_ack(sdram_wr_ack)
);


SDRAM_RD SDRAM_RD(
	.Clk(clk_100m),
	.Rst_n(rst_n),
	.Init_end(init_end),
	.Rd_en(rd_en),
	.Rd_addr(24'h000_000 ),
	.Rd_data(sdram_dq),
	.Rd_burst_len(10'd10 ),
	
	.Rd_ack(),
	.Rd_end(rd_end),
	.Rd_cmd(read_cmd),
	.Rd_ba(read_ba),
	.Rd_sdram_addr(read_addr),
	.Rd_sdram_data(sdram_data_out)
	
);

sdram_model_plus    sdram_model_plus_inst(
    .Dq     (sdram_dq       ),
    .Addr   (sdram_addr     ),
    .Ba     (sdram_ba       ),
    .Clk    (clk_100m_shift ),
    .Cke    (1'b1           ),
    .Cs_n   (sdram_cmd[3]   ),
    .Ras_n  (sdram_cmd[2]   ),
    .Cas_n  (sdram_cmd[1]   ),
    .We_n   (sdram_cmd[0]   ),
    .Dqm    (2'b0           ),
    .Debug  (1'b1           )

);

endmodule   
SDRAM读模块仿真波形

在这里插入图片描述

SDRAM判断模块

SDRAM判断模块设计图

在这里插入图片描述

SDRAM判断模块时序图

在这里插入图片描述

SDRAM判断模块状态转移图

在这里插入图片描述

SDRAM判断模块代码
module  SDRAM_JUDGE(    //判断读写自动刷新模块优先级模块  

    input   wire    Clk         ,
    input   wire    Rst_n       ,

    input   wire    [3:0]Init_cmd    ,//初始化
    input   wire    [1:0]Init_ba     ,
    input   wire    [12:0]Init_addr  ,
    input   wire    Init_end         ,

    input   wire    Re_req           ,//自刷新
    input   wire    [3:0]Re_cmd      ,
    input   wire    [12:0]Re_addr    ,
    input   wire    Re_end           ,
    input   wire    [1:0]Re_ba       ,

    input   wire    Wr_req           , //写
    input   wire    [3:0]Wr_cmd      ,
    input   wire    [12:0]Wr_addr    ,
    input   wire    [15:0]Wr_data    ,
    input   wire    Wr_end           ,
    input   wire    [1:0]Wr_ba       ,
    input   wire    Wr_sdram_en      ,

    input   wire    Rd_req           ,     //读
    input   wire    [12:0]Rd_addr    ,
    input   wire    Rd_end           ,
    input   wire    [1:0]Rd_ba       ,
    input   wire    [3:0]Rd_cmd      ,

    output  wire    Sdram_cke        ,        //SDRAM接口
    output  wire    Sdram_cs_n       ,
    output  wire    Sdram_ras_n      ,
    output  wire    Sdram_cas_n      ,
    output  wire    Sdram_we_n       ,
    output  reg    [1:0]Sdram_ba    ,
    output  reg    [12:0]Sdram_addr ,
    inout  wire    [15:0]Sdram_dq   ,
    
    output  reg     Re_en            , //使能信号
    output  reg     Wr_en            ,   
    output  reg     Rd_en      
);
//定义状态
localparam   IDLE    = 5'b000_01,  //独热码
             JUDGE   = 5'b000_10,
             READ    = 5'b001_00,
             WRITE   = 5'b010_00,
             REFRESH = 5'b100_00;
             
//定义命令
localparam  NONE_CMD = 4'b0111; //空命令指令

reg [4:0]ju_state;
reg [3:0]sdram_cmd;



//主状态机
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
    ju_state <= IDLE;
    else
    begin
        case(ju_state)
  
            IDLE    :
                begin
                    if(Init_end)
                        ju_state <= JUDGE;
                    else 
                        ju_state <= IDLE;
                end
            
            JUDGE   :
                begin
                    if(Re_req)
                        ju_state <= REFRESH;
                    else
                    if(Rd_req)
                        ju_state <= READ;
                    else 
                    if(Wr_req)
                        ju_state <= WRITE;
                    else
                        ju_state <= JUDGE;
                end
            
            READ    :
                begin
                    if(Rd_end)
                        ju_state <= JUDGE;
                    else
                        ju_state <= READ;
                end
                
            WRITE   :
                begin
                    if(Wr_end)
                        ju_state <= JUDGE;
                    else
                        ju_state <= WRITE;
                end 
            REFRESH :
                begin
                if(Re_end)
                    ju_state <= JUDGE;
                else
                    ju_state <= REFRESH;
                end
            
            default: ju_state <= JUDGE;
        
        endcase 
    end
  
  //自动刷新使能信号
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        Re_en <= 1'b0;
    else
    if((ju_state == JUDGE) && (Re_req == 1'b1))
        Re_en <= 1'b1;
    else
    if(Re_end)
        Re_en <= 1'b0;
     //写使能信号
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        Wr_en <= 1'b0;
    else
    if((ju_state == JUDGE) && (Re_req == 1'b0) && (Wr_req == 1'b1))
        Wr_en <= 1'b1;
    else
    if(Wr_end)
        Wr_en <= 1'b0;
    //读使能信号
 always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        Rd_en <= 1'b0;
    else
    if((ju_state == JUDGE) && (Re_req == 1'b0) && (Rd_req == 1'b1))
        Rd_en <= 1'b1;
    else
    if(Rd_end)
        Rd_en <= 1'b0;
        
        
//Sdram_ba Sdram_addr  sdram_cmd输出
always @(*)
begin
    case(ju_state)
        
        JUDGE:
            begin
                Sdram_addr<= 13'h1fff;
                Sdram_ba  <= 2'b11;
                sdram_cmd <= NONE_CMD;
            end
        
        IDLE:
            begin
                Sdram_addr<= Init_addr;
                Sdram_ba  <= Init_ba;
                sdram_cmd <= Init_cmd;
            end
            
        WRITE:
            begin
                Sdram_addr<= Wr_addr;
                Sdram_ba  <= Wr_ba;
                sdram_cmd <= Wr_cmd;
            end
    
        READ:
            begin
                Sdram_addr<= Rd_addr;
                Sdram_ba  <= Rd_ba;
                sdram_cmd <= Rd_cmd;
            end
           
        REFRESH:
            begin
                Sdram_addr<= Re_addr;
                Sdram_ba  <= Re_ba;
                sdram_cmd <= Re_cmd;
            end
    
        default:
            begin
                Sdram_addr<= 13'h1fff;
                Sdram_ba  <= 2'b11;
                sdram_cmd <= NONE_CMD;
            end
    
    endcase
    
end

//Sdram_dq
assign Sdram_dq = (Wr_sdram_en) ? Wr_data : 16'bz;
//片选信号,行地址选通信号,列地址选通信号,写使能信号
assign {Sdram_cs_n , Sdram_ras_n , Sdram_cas_n ,  Sdram_we_n} = sdram_cmd;

assign Sdram_cke = 1'b1;

endmodule  

SDRAM主控制模块

SDRAM控制模块图

在这里插入图片描述

SDRAM控制模块时序

在这里插入图片描述

SDRAM控制模块代码
module SDRAM_CTRL(
    input   wire           Clk           ,
    input   wire           Rst_n         ,

    input   wire           Rd_req        ,                                            //读
    input   wire  [23:0]   Rd_addr       ,    //24位宽 行地址列地址bank地址 写入的首地址
    input   wire  [9:0]    Rd_burst_len  ,
    output  wire           Rd_ack        ,
    output  wire   [15:0]  Sdram_data_out,//从SDRAM读出的数据
    
    input   wire           Wr_req        ,                                     //写
    input   wire  [23:0]   Wr_addr       ,
    input   wire  [15:0]   Wr_sdram_data       ,//写入SDRAM的数据
    input   wire  [9:0]    Wr_burst_len  ,
    output  wire           Wr_ack        ,
    output  wire           Init_end      ,   //SDRAM 初始化完成标志
    
      
    output  wire           Sdram_cke     ,                                 //与SDRAM的硬件接口
    output  wire           Sdram_cs_n    ,
    output  wire           Sdram_cas_n   ,
    output  wire           Sdram_ras_n   ,
    output  wire           Sdram_we_n    ,
    output  wire   [1:0]   Sdram_ba      ,
    output  wire   [12:0]  Sdram_addr    ,
    inout   wire   [15:0]  Sdram_dq            // SDRAM 数据总线
);

    wire  [3:0]         Init_cmd      ;//初始化
    wire  [1:0]         Init_ba       ;
    wire  [12:0]        Init_addr     ;//初始化行地址 8192行

    wire                Rd_en         ;  //读
    wire  [15:0]        Rd_data       ;
    wire                Rd_end        ;
    wire  [3:0]         Rd_cmd        ;
    wire  [1:0]         Rd_ba         ;
    wire  [12:0]        Rd_sdram_addr ;
    
    wire                Wr_en         ;  //写
    wire  [1:0]         Wr_ba         ;
    wire  [3:0]         Wr_cmd        ;
    wire  [12:0]        Wr_sdram_addr ;
    wire  [15:0]        WR_MID_DATA ;    //
    wire                Wr_end        ;
    wire                Wr_sdram_en   ;

    wire  [3:0]         Re_cmd        ;//自动刷新
    wire  [12:0]        Re_addr       ;
    wire  [1:0]         Re_ba         ;
    wire                Re_end        ;
    wire                Re_req        ;
    wire                Re_en         ;
        
SDRAM_INIT      SDRAM_INIT(
    .Clk            (Clk),
    .Rst_n          (Rst_n),

    .Init_cmd       (Init_cmd ),
    .Init_ba        (Init_ba  ),
    .Init_addr      (Init_addr),
    .Init_done      (Init_end)
);

SDRAM_RD        SDRAM_RD(
    .Clk            (Clk  ),
    .Rst_n          (Rst_n),
    .Init_end       (Init_end     ),
    .Rd_en          (Rd_en        ),
    .Rd_addr        (Rd_addr      ),
    .Rd_data        (Sdram_dq      ),
    .Rd_burst_len   (Rd_burst_len ),

    .Rd_ack         (Rd_ack       ),
    .Rd_end         (Rd_end       ),
    .Rd_cmd         (Rd_cmd       ),
    .Rd_ba          (Rd_ba        ),
    .Rd_sdram_addr  (Rd_sdram_addr),
    .Rd_sdram_data  (Sdram_data_out)
    
);

SDRAM_WR        SDRAM_WR(
   .Clk            (Clk  ) ,
   .Rst_n          (Rst_n) ,
   .Init_end       (Init_end     ) ,
   .Wr_addr        (Wr_addr      ) ,  
   .Wr_data        (Wr_sdram_data      ) ,
   .Wr_burst_len   (Wr_burst_len ) ,
   .Wr_en          (Wr_en        ) ,

   .Wr_ba          (Wr_ba        ) ,
   .Wr_cmd         (Wr_cmd       ) ,
   .Wr_sdram_addr  (Wr_sdram_addr) ,
   .Wr_sdram_data  (WR_MID_DATA  ) ,     //
   .Wr_end         (Wr_end       ) ,
   .Wr_sdram_en    (Wr_sdram_en  ) ,
   .Wr_ack         (Wr_ack       )
);

SDRAM_REFRESH       SDRAM_REFRESH(
   .Clk         (Clk  ),
   .Rst_n       (Rst_n),
   .Init_end    (Init_end),
   .Re_en       (Re_en   ),

   .Re_cmd      (Re_cmd  ),
   .Re_addr     (Re_addr ),
   .Re_ba       (Re_ba   ),
   .Re_end      (Re_end  ),
   .Re_req      (Re_req  )
);

SDRAM_JUDGE     SDRAM_JUDGE(     //判断读写自动刷新模块优先级模块  
    .Clk         (Clk)         ,
    .Rst_n       (Rst_n)         ,
                               
    .Init_cmd    (Init_cmd)         ,//初始化
    .Init_ba     (Init_ba)         ,
    .Init_addr   (Init_addr)        ,
    .Init_end    (Init_end)              ,
                               
    .Re_req      (Re_req)              ,//自刷新
    .Re_cmd      (Re_cmd)         ,
    .Re_addr     (Re_addr)        ,
    .Re_end      (Re_end)              ,
    .Re_ba       (Re_ba)         ,
                               
    .Wr_req      (Wr_req)              , //写
    .Wr_cmd      (Wr_cmd)         ,
    .Wr_addr     (Wr_sdram_addr    )      ,
    .Wr_data     (WR_MID_DATA    )      ,    ///
    .Wr_end      (Wr_end     )            ,
    .Wr_ba       (Wr_ba      )       ,
    .Wr_sdram_en (Wr_sdram_en)     ,

    .Rd_req      (Rd_req )             ,     //读
    .Rd_addr     (Rd_sdram_addr)       ,
    .Rd_end      (Rd_end )             ,
    .Rd_ba       (Rd_ba  )        ,
    .Rd_cmd      (Rd_cmd )        ,

    .Sdram_cke   (Sdram_cke  )     ,        //SDRAM接口
    .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_dq    (Sdram_dq   )      ,

    .Re_en       (Re_en)     , //使能信号
    .Wr_en       (Wr_en)     ,   
    .Rd_en       (Rd_en)
);
endmodule
SDRAM控制模块仿真波形

在这里插入图片描述

自动刷新后写,写完读。读后自动刷新。
在这里插入图片描述
写入的数据wr_data_in为1 2 3 4 5 6 7 8 9 10,SDRAM输出的数据sdram_data_out1 2 3 4 5 6 7 8 9 10。

SDRAM——FIFO控制模块

将准备输入输出SDRAM的数据做缓存。

SDRAM——FIFO控制模块图

在这里插入图片描述

SDRAM——FIFO控制模块时序

在这里插入图片描述

SDRAM——FIFO控制模块代码
module FIFO_CTRL(

input       wire                Clk               ,
input       wire                Rst_n             ,
//写FIFO
input       wire                Wr_fifo_wr_clk    ,
input       wire                Wr_fifo_wr_req    ,
input       wire     [15:0]     Wr_fifo_wr_data   ,      //写入写FIFO中的数据
input       wire     [23:0]     Sdram_wr_b_addr   ,
input       wire     [23:0]     Sdram_wr_e_addr   ,
input       wire     [9:0]      Wr_burst_len      ,
input       wire                Wr_rst            ,      //写复位信号
//读FIFO
input       wire                Rd_fifo_rd_clk    ,
input       wire                Rd_fifo_rd_req    ,
input       wire     [23:0]     Sdram_rd_b_addr   ,
input       wire     [23:0]     Sdram_rd_e_addr   ,
input       wire     [9:0]      Rd_burst_len      ,      //读突发长度
input       wire                Rd_rst            ,      //读复位信号
output      wire     [15:0]     Rd_fifo_rd_data   ,      //读FIFO中读出的数据
output      wire     [9:0]      Rd_fifo_num       ,      //读FIFO中存在的数据个数
//SDRAM写信号
input       wire                Sdram_wr_ack      ,      //SDRAM写响应
output      reg                 Sdram_wr_req      ,      //写请求信号
output      wire      [15:0]    Sdram_data_in     ,      //从写FIFO中读出数据传给SDRAM
output      reg       [23:0]    Sdram_wr_addr     ,      //SDRAM写地址
//SDRAM读信号
input       wire      [15:0]    Sdram_data_out    ,      //SDRAM读出的信号
input       wire                Sdram_rd_ack      ,      //SDRAM读回应信号
output      reg                 Sdram_rd_req      ,      //读请求信号
output      reg       [23:0]    Sdram_rd_addr     ,      //读地址

input       wire                Init_end          ,      //初始化结束信号
input       wire                Rd_value                 //写有效信号

);


wire         [9:0]      wr_fifo_num               ;      //写FIFO中的数据个数
reg                     rd_ack_dly                ;      //读应答信号打拍
reg                     wr_ack_dly                ;      //写应答信号打拍
wire                    rd_ack_dly_fall           ;      //读应答信号下降沿
wire                    wr_ack_dly_fall           ;      //写应答信号下降沿


//应答信号打拍
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        begin
            rd_ack_dly <= 1'b0;
            wr_ack_dly <= 1'b0;
        end
    else
        begin
            rd_ack_dly <= Sdram_rd_ack;
            wr_ack_dly <= Sdram_wr_ack;
        end

//应答信号下降沿
assign      rd_ack_dly_fall   =   (!Sdram_rd_ack && rd_ack_dly)  ;
assign      wr_ack_dly_fall   =   (!Sdram_wr_ack && wr_ack_dly)  ;


//写地址更新  写优先级高于读
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        Sdram_wr_addr <= 1'b0;
    else
    if(Wr_rst)
        Sdram_wr_addr <= Sdram_wr_b_addr;
    else
    if(wr_ack_dly_fall)  //一次突发写结束,更改写地址
        begin
            if(Sdram_wr_addr < (Sdram_wr_e_addr - Wr_burst_len))
                Sdram_wr_addr <= Sdram_wr_addr + Wr_burst_len;
            else
                Sdram_wr_addr <= Sdram_wr_b_addr; //到达末地址,回到写起始地址
        end
    else
        Sdram_wr_addr <= Sdram_wr_addr;

//读地址更新
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        Sdram_rd_addr <= 1'b0;
    else
    if(Wr_rst)
        Sdram_rd_addr <= Sdram_rd_b_addr;
    else
    if(rd_ack_dly_fall)  //一次突发写结束,更改写地址
        begin
            if(Sdram_rd_addr < (Sdram_rd_e_addr - Rd_burst_len))
                Sdram_rd_addr <= Sdram_rd_addr + Rd_burst_len;
            else
                Sdram_rd_addr <= Sdram_rd_b_addr; //到达末地址,回到写起始地址
        end
    else
        Sdram_rd_addr <= Sdram_rd_addr;

//读写请求信号
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        begin
            Sdram_wr_req <= 1'b0;
            Sdram_rd_req <= 1'b0;
        end
    else                                          //优先执行写操作,防止写入SDRAM中的数据丢失
    if(Init_end)                                  //初始化完成后响应读写请求
        begin
            if(wr_fifo_num >= Wr_burst_len)       //写FIFO中的数据量达到写突发长度
                begin
                    Sdram_wr_req <= 1'b1;
                    Sdram_rd_req <= 1'b0;
                end
            else
            if((Rd_fifo_num < Rd_burst_len) && Rd_value)  //读FIFO中的数据量小于读突发长度,且读使能信号有效
                begin
                    Sdram_wr_req <= 1'b0;
                    Sdram_rd_req <= 1'b1;
                end
            else
                begin
                    Sdram_wr_req <= 1'b0;
                    Sdram_rd_req <= 1'b0;
                end
        end
    else
        begin
            Sdram_wr_req <= 1'b0;
            Sdram_rd_req <= 1'b0;
        end

FIFO_DATA	FIFO_WR_DATA_inst (    //写FIFO列化      读时钟要 大于等于 写时钟 读位宽要大于写位宽
	//用户端口
	.wrclk   (  Wr_fifo_wr_clk       ),
	.wrreq   (  Wr_fifo_wr_req       ),
 	.data    (  Wr_fifo_wr_data      ),
    //SDRAM端口
	.rdclk   (  Clk      ),
	.rdreq   (  Sdram_wr_ack      ),
	.q       (  Sdram_data_in      ),

    .aclr    (  !Rst_n || Wr_rst     ),
	.rdusedw (  wr_fifo_num      ),  //FIFO中的数据量
	.wrusedw (        )
	);

FIFO_DATA	FIFO_RD_DATA_inst (    //读FIFO列化      读时钟要 大于等于 写时钟 读位宽要大于写位宽
	//SDRAM端口
	.wrclk   (    Clk             ),
	.wrreq   (  Sdram_rd_ack       ),
 	.data    (  Sdram_data_out      ),
    //用户端口
	.rdclk   (  Rd_fifo_rd_clk          ),
	.rdreq   (  Rd_fifo_rd_req       ),
	.q       (  Rd_fifo_rd_data       ),

    .aclr    (  !Rst_n || Rd_rst    ),
	.rdusedw (        ),
	.wrusedw (  Rd_fifo_num      )  //FIFO中的数据量
	);
endmodule

SDRAM_TOP顶层模块

SDRAM顶层模块设计图

在这里插入图片描述

SDRAM顶层模块代码
module SDRAM_TOP(

input       wire                Clk               ,
input       wire                Rst_n             ,
input       wire                Clk_out           ,     //输入相位偏移时钟
//写FIFO    
input       wire                Wr_fifo_wr_clk    ,    
input       wire                Wr_fifo_wr_req    ,
input       wire     [15:0]     Wr_fifo_wr_data   ,      //写入写FIFO中的
input       wire     [23:0]     Sdram_wr_b_addr   ,
input       wire     [23:0]     Sdram_wr_e_addr   ,
input       wire     [9:0]      Wr_burst_len      ,
input       wire                Wr_rst            ,      //写复位信号
//读FIFO
input       wire                Rd_fifo_rd_clk    ,
input       wire                Rd_fifo_rd_req    ,
input       wire     [23:0]     Sdram_rd_b_addr   ,
input       wire     [23:0]     Sdram_rd_e_addr   ,
input       wire     [9:0]      Rd_burst_len      ,      //读突发长度
input       wire                Rd_rst            ,      //读复位信号
input       wire                Rd_value          ,
output      wire     [15:0]     Rd_fifo_rd_data   ,      //读FIFO中读出的数据
output      wire     [9:0]      Rd_fifo_num       ,      //读FIFO中存在的数据个数
//与SDRAM的硬件接口    
output      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      wire     [1:0]      Sdram_ba          ,
output      wire     [12:0]     Sdram_addr        ,
inout       wire     [15:0]     Sdram_dq          ,     // SDRAM 数据总线
output      wire     [1:0]      Sdram_dqm           

);

wire       [23:0]        sdram_rd_addr        ;   
wire                     sdram_rd_req         ;
wire                     init_end             ;
wire                     sdram_wr_req         ;
wire       [23:0]        sdram_wr_addr        ;
wire       [15:0]        sdram_data_in        ;
wire                     sdram_wr_ack         ;
wire                     sdram_rd_ack         ;
wire       [15:0]        sdram_data_out       ;
    
assign  Sdram_dqm   =   2'b00;
//sdram_clk:SDRAM芯片时钟
assign  Sdram_clk   =   Clk_out; 

SDRAM_CTRL  SDRAM_CTRL_inst(
    .Clk               (Clk             )  ,
    .Rst_n             (Rst_n           )  ,
//SDRAM 控制器读端口
    .Rd_req            (sdram_rd_req    )  ,//读SDRAM请求信号
    .Rd_addr           (sdram_rd_addr   )  ,    //24位宽 行地址列地址bank地址 写入的首地址
    .Rd_burst_len      (Rd_burst_len    )  ,
    .Init_end          (init_end        ),   //SDRAM 初始化完成标志
//SDRAM 控制器写端口
    .Wr_req            (sdram_wr_req    )  ,       //写SDRAM请求信号
    .Wr_addr           (sdram_wr_addr   )  ,
    .Wr_sdram_data     (sdram_data_in  )  ,
    .Wr_burst_len      (Wr_burst_len    )  ,


    .Wr_ack            (sdram_wr_ack    )  ,   //写SDRAM响应信号
    .Rd_ack            (sdram_rd_ack    )  ,   //读SDRAM响应信号
//从SDRAM读出的数据
    .Sdram_data_out    (sdram_data_out  )  ,
//与SDRAM的硬件接口
    .Sdram_cke         (Sdram_cke       )  ,// SDRAM 时钟有效信号
    .Sdram_cs_n        (Sdram_cs_n      )  ,      // SDRAM 片选信号
    .Sdram_cas_n       (Sdram_cas_n     )  ,     // SDRAM 列地址选通脉冲
    .Sdram_ras_n       (Sdram_ras_n     )  ,     // SDRAM 行地址选通脉冲
    .Sdram_we_n        (Sdram_we_n      )  ,      // SDRAM 写允许位
    .Sdram_ba          (Sdram_ba        )  ,        // SDRAM L-Bank地址线
    .Sdram_addr        (Sdram_addr      )  ,        // SDRAM 地址总线
    .Sdram_dq          (Sdram_dq        )           // SDRAM 数据总线
);


FIFO_CTRL   FIFO_CTRL_inst(

    .Clk               (Clk   )      ,
    .Rst_n             (Rst_n )      ,
//写FIFO                  
    .Wr_fifo_wr_clk    (Wr_fifo_wr_clk)       ,
    .Wr_fifo_wr_req    (Wr_fifo_wr_req )      ,
    .Wr_fifo_wr_data   (Wr_fifo_wr_data)      ,      //写入写FIFO中的数据
    .Sdram_wr_b_addr   (Sdram_wr_b_addr)      ,
    .Sdram_wr_e_addr   (Sdram_wr_e_addr)      ,
    .Wr_burst_len      (Wr_burst_len   )      ,
    .Wr_rst            (Wr_rst         )      ,      //写复位信号
//读FIFO                   
    .Rd_fifo_rd_clk    (Rd_fifo_rd_clk )      ,
    .Rd_fifo_rd_req    (Rd_fifo_rd_req )      ,
    .Sdram_rd_b_addr   (Sdram_rd_b_addr)      ,
    .Sdram_rd_e_addr   (Sdram_rd_e_addr)      ,
    .Rd_burst_len      (Rd_burst_len   )      ,      //读突发长度
    .Rd_rst            (Rd_rst)               ,      //读复位信号
    .Rd_fifo_rd_data   (Rd_fifo_rd_data)      ,      //读FIFO中读出的数据
    .Rd_fifo_num       (Rd_fifo_num    )      ,      //读FIFO中存在的数据个数
//SDRAM写信号                      
    .Sdram_wr_ack      (sdram_wr_ack)      ,      //SDRAM写响应
    .Sdram_wr_req      (sdram_wr_req)      ,      //写请求信号
    .Sdram_data_in     (sdram_data_in)      ,      //从写FIFO中读出数据传给SDRAM
    .Sdram_wr_addr     (sdram_wr_addr)      ,      //SDRAM写地址
//SDRAM读信号                     
    .Sdram_data_out    (sdram_data_out)      ,      //SDRAM读出的信号
    .Sdram_rd_ack      (sdram_rd_ack)      ,      //SDRAM读回应信号
    .Sdram_rd_req      (sdram_rd_req)      ,      //读请求信号
    .Sdram_rd_addr     (sdram_rd_addr)      ,      //读地址

    .Init_end          (init_end)      ,      //初始化结束信号
    .Rd_value          (Rd_value)             //写有效信号

);

endmodule  
SDRAM顶层模块仿真代码
`timescale  1ns/1ns

module  SDRAM_TOP_tb();

//wire define
//clk_gen
wire            clk_50m         ;   //PLL输出50M时钟
wire            clk_100m        ;   //PLL输出100M时钟
wire            clk_100m_shift  ;   //PLL输出100M时钟,相位偏移30deg
wire            locked          ;   //PLL时钟锁定信号
wire            rst_n           ;   //复位信号,低有效
//sdram
wire            sdram_clk       ;   //SDRAM时钟
wire            sdram_cke       ;   //SDRAM时钟使能信号
wire            sdram_cs_n      ;   //SDRAM片选信号
wire            sdram_ras_n     ;   //SDRAM行选通信号
wire            sdram_cas_n     ;   //SDRAM列选题信号
wire            sdram_we_n      ;   //SDRAM写使能信号
wire    [1:0]   sdram_ba        ;   //SDRAM L-Bank地址
wire    [12:0]  sdram_addr      ;   //SDRAM地址总线
wire    [15:0]  sdram_dq        ;   //SDRAM数据总线
wire            sdram_dqm       ;   //SDRAM数据总线


wire    [9:0]   rd_fifo_num     ;   //fifo_ctrl模块中读fifo中的数据量
wire    [15:0]  rfifo_rd_data   ;   //fifo_ctrl模块中读fifo读数据

//reg define
reg             sys_clk         ;   //系统时钟
reg             sys_rst_n       ;   //复位信号
reg             wr_en           ;   //写使能
reg             wr_en_dly       ;   //写使能打拍
reg     [15:0]  wr_data_in      ;   //写数据
reg             rd_en           ;   //读使能
reg     [2:0]   cnt_wr_wait     ;   //数据写入间隔计数
reg     [3:0]   cnt_rd_data     ;   //读出数据计数
reg             wr_data_flag    ;   //fifo_ctrl模块中写fifo写使能
reg             read_valid      ;   //读有效信号

//defparam
//重定义仿真模型中的相关参数
defparam sdram_model_plus_inst.addr_bits = 13;          //地址位宽
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; //L-Bank容量

//重定义自动刷新模块自动刷新间隔时间计数最大值
defparam SDRAM_TOP_inst.SDRAM_CTRL_inst.SDRAM_REFRESH.CNT_MAX = 39;


//时钟、复位信号
initial
  begin
    sys_clk     =   1'b1  ;
    sys_rst_n   <=  1'b0  ;
    #200
    sys_rst_n   <=  1'b1  ;
  end

always  #10 sys_clk = ~sys_clk;

//rst_n:复位信号
assign  rst_n = sys_rst_n & locked;

//wr_en:写数据使能
always@(posedge clk_50m or negedge rst_n)
    if(rst_n == 1'b0)
        wr_en   <=  1'b1;
    else    if(wr_data_in == 10'd10)
        wr_en   <=  1'b0;
    else
        wr_en   <=  wr_en;

//cnt_wr_wait:数据写入间隔计数
always@(posedge clk_50m or negedge rst_n)
    if(rst_n == 1'b0)
        cnt_wr_wait <=  3'd0;
    else    if(wr_en == 1'b1)
        cnt_wr_wait <=  cnt_wr_wait + 1'b1;
    else
        cnt_wr_wait <=  3'd0;

//wr_data_flag:fifo_ctrl模块中写fifo写使能
always@(posedge clk_50m or negedge rst_n)
    if(rst_n == 1'b0)
        wr_data_flag    <=  1'b0;
    else    if(cnt_wr_wait == 3'd7)
        wr_data_flag    <=  1'b1;
    else
        wr_data_flag    <=  1'b0;

//read_valid:数据读使能
always@(posedge clk_50m or negedge rst_n)
    if(rst_n == 1'b0)
        read_valid  <=  1'b1;
    else    if(rd_fifo_num == 10'd10)
        read_valid  <=  1'b0;

//wr_en_dly:写数据使能打拍
always@(posedge clk_50m or negedge rst_n)
    if(rst_n == 1'b0)
        wr_en_dly   <=  1'b0;
    else
        wr_en_dly   <=  wr_en;

//wr_data_in:写数据
always@(posedge clk_50m or negedge rst_n)
    if(rst_n == 1'b0)
        wr_data_in  <=  16'd0;
    else    if(cnt_wr_wait == 3'd7)
        wr_data_in  <=  wr_data_in + 1'b1;
    else
        wr_data_in  <=  wr_data_in;

//rd_en:读数据使能
always@(posedge clk_50m or negedge rst_n)
    if(rst_n == 1'b0)
        rd_en   <=  1'b0;
    else    if(cnt_rd_data == 4'd9)
        rd_en   <=  1'd0;
    else    if((wr_en == 1'b0) && (rd_fifo_num == 10'd10))
        rd_en   <=  1'b1;
    else
        rd_en   <=  rd_en;

//cnt_rd_data:读出数据计数
always@(posedge clk_50m or negedge rst_n)
    if(rst_n == 1'b0)
        cnt_rd_data <=  4'd0;
    else    if(rd_en == 1'b1)
        cnt_rd_data <=  cnt_rd_data + 1'b1;
    else
        cnt_rd_data <=  4'd0;



CLK_STRAT   CLK_STRAT_inst (  //IP核PLL
    .areset ( !sys_rst_n ),
    .inclk0 ( sys_clk ),
    .c0 (  clk_50m       ),
    .c1 (  clk_100m      ),
    .c2 (  clk_100m_shift),
    .locked ( locked )
    );

SDRAM_TOP       SDRAM_TOP_inst(

    .Clk               (clk_100m       )        ,
    .Rst_n             (rst_n          )        ,
    .Clk_out           (clk_100m_shift )        ,     //输入相位偏移时钟
//用户写端口          
    .Wr_fifo_wr_clk    (clk_50m        )        ,    
    .Wr_fifo_wr_req    (wr_data_flag   )        ,
    .Wr_fifo_wr_data   (wr_data_in     )        ,      //写入写FIFO中的
    .Sdram_wr_b_addr   (24'd0          )        ,
    .Sdram_wr_e_addr   (24'd10         )        ,
    .Wr_burst_len      (10'd10         )        ,
    .Wr_rst            (~rst_n         )        ,      //写复位信号
//用户读端口            
    .Rd_fifo_rd_clk    (clk_50m        )        ,
    .Rd_fifo_rd_req    (rd_en          )        ,
    .Rd_fifo_rd_data   (rfifo_rd_data  )        ,      //读FIFO中读出的数据
    .Sdram_rd_b_addr   (24'd0          )        ,
    .Sdram_rd_e_addr   (24'd10         )        ,
    .Rd_burst_len      (10'd10         )        ,      //读突发长度
    .Rd_rst            (~rst_n         )        ,      //读复位信号
    .Rd_fifo_num       (rd_fifo_num    )        ,      //读FIFO中存在的数据个数
//用户控制端口
    .Rd_value          (read_valid     )        ,
//SDRAM 芯片接口           
    .Sdram_clk         (sdram_clk      )        ,
    .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_dq          (sdram_dq       )        ,     // SDRAM 数据总线
    .Sdram_dqm         (sdram_dqm      )          
);

sdram_model_plus    sdram_model_plus_inst(
    .Dq     (sdram_dq       ),
    .Addr   (sdram_addr     ),
    .Ba     (sdram_ba       ),
    .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    (2'b0           ),
    .Debug  (1'b1           )

);

endmodule   
SDRAM顶层模块仿真图

在这里插入图片描述

写入的数据wr_data_in与读出的数据rfifo_rd_data都为1 2 3 4 5 6 7 8 9 10。
在这里插入图片描述

FIFO_READ模块

SDRAM读出的数据匹配串口发送的速率;将SDRAM读出的数据做缓存,计数比特个数,满足一次串口发送条件时将书数据传给tx模块。

FIFO_READ模块设计图

在这里插入图片描述

FIFO_READ模块设计时序

在这里插入图片描述

FIFO_READ模块代码
module  FIFO_READ(
   
input           wire         Clk                ,                         
input           wire         Rst_n              ,      
input           wire  [9:0]  Rd_fifo_num        ,      
input           wire  [7:0]  Rd_fifo_rd_data    ,     
input           wire  [9:0]  Burst_num          ,             

output          reg          Rd_en               ,
output          wire  [7:0]  Tx_data             ,
output          reg          Tx_flag             
);

reg             rd_en_dly        ;   
wire    [9:0]   data_num         ;
reg             rd_value         ;
reg     [12:0]  baud_cnt         ;
reg             bit_flag         ;
reg     [3:0]   bit_cnt          ;
reg             read_fifo_en     ;
reg     [9:0]   read_cnt         ;

parameter   BAUD_CNT_END     =   13'd433     ;

//读SDRAM读FIFO使能信号产生
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        Rd_en   <=  1'b0;
    else
    if(Rd_fifo_num == Burst_num)
        Rd_en   <=  1'b1;
    else
    if(data_num ==  (Burst_num - 2'd2))
        Rd_en   <=  1'b0;
//读SDRAM读FIFO使能信号延迟一周期 写入READ_FIFO使能信号
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        rd_en_dly   <=  1'b0;
    else
        rd_en_dly   <=  Rd_en;
//读有效标志信号
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        rd_value    <=  1'b0;
    else
    if(data_num ==  Burst_num)
        rd_value    <=  1'b1;
    else
    if(read_cnt ==  Burst_num)
        rd_value    <=  1'b0;
    else
        rd_value    <=  rd_value;
//计数比特时钟周期个数
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        baud_cnt    <= 1'b0;
    else
    if(rd_value)
        begin
            if(baud_cnt ==  BAUD_CNT_END)
                baud_cnt    <=  1'b0;    
            else
                baud_cnt    <=  baud_cnt    +   1'b1;
        end
    else
        baud_cnt    <=  1'b0;

        
//计数比特周期数标志信号产生
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        bit_flag    <= 1'b0;
    else
    if(baud_cnt ==  (BAUD_CNT_END >> 1))
        bit_flag    <= 1'b1;
    else
        bit_flag    <= 1'b0;
//计数比特标志信号个数
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        bit_cnt     <= 1'b0;
    else
    if(bit_flag)
        begin
            if(bit_cnt  ==  4'd10)
                bit_cnt <=  1'b0;
            else
                bit_cnt <=  bit_cnt  +  1'b1;  
        end
    else
    bit_cnt <=  bit_cnt;
//READ_FIFO读使能信号产生
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        read_fifo_en    <=  1'b0;
    else
    if(bit_flag &&  (bit_cnt == 4'd10))
        read_fifo_en    <=  1'b1;
    else
        read_fifo_en    <=  1'b0;
//READ_FIFO读数据个数计数
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        read_cnt    <=  1'b0;
    else
    if(read_cnt ==  Burst_num)
        read_cnt    <=  10'd0;
    else
    if(read_fifo_en)
        read_cnt    <=  read_cnt + 1'b1;
//Tx输出使能信号产生
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        Tx_flag <=  1'b0;
    else
        Tx_flag <=  read_fifo_en;
        
READ	READ_inst (
	.clock (   Clk      ),
	.data  (   Rd_fifo_rd_data      ),
	.rdreq (   read_fifo_en      ),
	.wrreq (   rd_en_dly      ),
    
	.q     (   Tx_data       ),
	.usedw (   data_num      )
	);


endmodule 

UART_SDRAM模块

UART_SDRAM模块设计图

在这里插入图片描述

UART_SDRAM模块代码
module  UART_SDRAM(

input       wire                Clk               ,
input       wire                Rst_n             ,
input       wire                Rx                ,
input       wire   [2:0]        Bps_set           ,  
//与SDRAM的硬件接口                
output      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      wire     [1:0]      Sdram_ba          ,            
output      wire     [12:0]     Sdram_addr        ,            
inout       wire     [15:0]     Sdram_dq          ,            
output      wire     [1:0]      Sdram_dqm         ,
        
output      wire                Tx                 
);

parameter   DATA_NUM    =   10'd5           ;   //写入SDRAM数据个数
parameter   WAIT_MAX    =   16'd750         ;   //等待计数最大值

wire            clk_50M          ;  
wire            clk_100M         ;
wire            clk_100M_shift   ;
wire            locked           ;
wire            sys_rst_n        ;
wire    [7:0]   rx_data_out      ;
wire            done_rx          ;
wire            tx_flag          ;
wire    [7:0]   tx_data          ;
wire    [9:0]   rd_fifo_num      ;
wire    [7:0]   rd_fifo_rd_data  ;
wire            rd_fifo_rd_en    ;
reg     [23:0]  data_num         ;
reg             read_valid       ;
reg     [15:0]  cnt_wait         ;


assign      sys_rst_n   =   Rst_n & locked ;

//data_num:写入SDRAM数据个数计数
always@(posedge clk_50M or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_num    <=  1'd0;
    else    if(read_valid == 1'b1)
        data_num    <=  1'd0;
    else    if(done_rx == 1'b1)
        data_num    <=  data_num + 1'b1;
    else
        data_num    <=  data_num;

//cnt_wait:等待计数器
always@(posedge clk_50M or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_wait    <=  16'd0;
    else    if(cnt_wait == WAIT_MAX)
        cnt_wait    <=  16'd0;
    else    if(data_num == DATA_NUM)
        cnt_wait    <=  cnt_wait + 1'b1;

//read_valid:数据读使能
always@(posedge clk_50M or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        read_valid  <=  1'b0;
    else    if(cnt_wait == WAIT_MAX)
        read_valid  <=  1'b1;
    else    if(rd_fifo_num == DATA_NUM)
        read_valid  <=  1'b0;
        




CLK_STRAT	CLK_STRAT_inst (
	.areset (!Rst_n     )       ,
	.inclk0 (Clk   )            ,
	.c0     (clk_50M   )        ,
	.c1     (clk_100M   )       ,
	.c2     (clk_100M_shift   ) ,
	.locked (locked   )
	);

UART_RX     RX_inst(  //串口接收模块
    .Clk      (clk_50M  )    ,
    .Rst_n    (sys_rst_n)    ,
    .Rs232_rx (Rx)           ,
    .Bps_set  (Bps_set)      ,
    
    .Data_out (rx_data_out)  ,
    .Done_rx  (done_rx)
);

UART_TX     TX_inst(
    .Clk        (clk_50M)    ,
    .Rst_n      (sys_rst_n)  ,
    .Bps_set    (Bps_set)    ,
    .Con_en     (tx_flag)    ,
    .Data_in    (tx_data)    ,
                
    .Rs232_tx   (Tx)         ,
    .Done_tx    ()           ,
    .Uart_state ()
);
FIFO_READ   FIFO_READ_inst(
   
   .Clk              (clk_50M)            ,                         
   .Rst_n            (sys_rst_n)          ,      
   .Rd_fifo_num      (rd_fifo_num)        ,      
   .Rd_fifo_rd_data  (rd_fifo_rd_data)    ,     
   .Burst_num        (DATA_NUM)           ,             

   .Rd_en            (rd_fifo_rd_en)      ,
   .Tx_data          (tx_data)            ,
   .Tx_flag          (tx_flag)   
);

SDRAM_TOP   SDRAM_TOP_inst(

    .Clk             (clk_100M)               ,
    .Rst_n           (sys_rst_n)              ,
    .Clk_out         (clk_100M_shift)         ,     //输入相位偏移时钟

    .Wr_fifo_wr_clk  (clk_50M)                ,    
    .Wr_fifo_wr_req  ( done_rx )              ,
    .Wr_fifo_wr_data ({8'd0,rx_data_out})     ,      //写入写FIFO中的
    .Sdram_wr_b_addr (24'd0)                  ,
    .Sdram_wr_e_addr ({14'd0,DATA_NUM} )              ,
    .Wr_burst_len    (DATA_NUM)               ,
    .Wr_rst          (!sys_rst_n)             ,      //写复位信号
                                              
    .Rd_fifo_rd_clk  (clk_50M)                ,
    .Rd_fifo_rd_req  (rd_fifo_rd_en)          ,
    .Sdram_rd_b_addr (24'd0)                  ,
    .Sdram_rd_e_addr ({14'd0,DATA_NUM} )              ,
    .Rd_burst_len    (DATA_NUM)               ,      //读突发长度
    .Rd_rst          (!sys_rst_n)             ,      //读复位信号
    .Rd_value        (read_valid)             ,
    .Rd_fifo_rd_data (rd_fifo_rd_data)        ,      //读FIFO中读出的数据
    .Rd_fifo_num     (rd_fifo_num)            ,      //读FIFO中存在的数据个数
 
    .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_ba        (Sdram_ba   )     ,
    .Sdram_addr      (Sdram_addr )     ,
    .Sdram_dq        (Sdram_dq   )     ,     // SDRAM 数据总线
    .Sdram_dqm       (Sdram_dqm  )    
);
endmodule  
UART_SDRAM模块仿真代码

使用串口发送模块向UART_SDRAM发送10,15,20,25,30,35,6个数据。突发长度为整页突发,设置满足5个数据长度写入SDRAM中并读取。

`timescale  1ns/1ns
`define CLK_PER 20
module  UART_SDRAM_tb();

wire            tx          ;
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_ba    ;
wire    [12:0]  sdram_addr  ;
wire    [1:0]   sdram_dqm   ;
wire    [15:0]  sdram_dq    ;
wire            rx          ;
wire            tx_done     ;

//reg define
reg             sys_clk     ;
reg             sys_rst_n   ;
reg             con_en      ;
reg   [7:0]     data_in     ;

  
//时钟
initial     sys_clk     =   1'b1;
always  #(`CLK_PER/2) sys_clk = ~sys_clk;


UART_TX     UART_TX_inst(
    .Clk         (sys_clk)   ,
	.Rst_n       (sys_rst_n)   ,
	.Bps_set     (3'd4)   ,
	.Con_en      (con_en)   ,
	.Data_in     (data_in)   ,

	.Rs232_tx    (rx)   ,
	.Done_tx     (tx_done)   ,
	.Uart_state  ()
  );


//重定义defparam,用于修改参数,缩短仿真时间
//defparam UART_SDRAM_inst.FIFO_READ_inst.BAUD_CNT_END  = 52;
defparam sdram_model_plus_inst.addr_bits = 13;
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;

UART_SDRAM      UART_SDRAM_inst(

    .Clk           (sys_clk     )    ,
    .Rst_n         (sys_rst_n   )    ,
    .Rx            (rx          )    ,
    .Tx            (tx          )    ,
    
    .Bps_set       (3'd4        )    ,  

    .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_ba      (sdram_ba    )    ,            
    .Sdram_addr    (sdram_addr  )    ,            
    .Sdram_dq      (sdram_dq    )    ,            
    .Sdram_dqm     (sdram_dqm   )    
);
sdram_model_plus    sdram_model_plus_inst(   
    .Dq     (sdram_dq       ), 
    .Addr   (sdram_addr     ),
    .Ba     (sdram_ba       ),
    .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    ({2'd0,sdram_dqm}   ),
    .Debug  (1'b1           )
);

initial
begin
    sys_rst_n   =   1'b0;
    data_in     =   8'd0;
    con_en      =   1'b0;
    #(`CLK_PER*10+1);
    sys_rst_n   =   1'b1;

    @(posedge   UART_SDRAM_inst.SDRAM_TOP_inst.SDRAM_CTRL_inst.Init_end)
    #(`CLK_PER*10+1);   
    data_in     =   8'd10;
    con_en      =   1'b1;
    #(`CLK_PER);    
    con_en      =   1'b0;
    
    @(posedge   tx_done)    
    #(`CLK_PER*2);   
    data_in     =   8'd15;
    con_en      =   1'b1;
    #(`CLK_PER);    
    con_en      =   1'b0;
    
    @(posedge   tx_done)
    #(`CLK_PER*2);   
    data_in     =   8'd20;
    con_en      =   1'b1;
    #(`CLK_PER);    
    con_en      =   1'b0;
    
    @(posedge   tx_done)    
    #(`CLK_PER*2);   
    data_in     =   8'd25;
    con_en      =   1'b1;
    #(`CLK_PER);    
    con_en      =   1'b0; 
    
    @(posedge   tx_done)    
    #(`CLK_PER*2);   
    data_in     =   8'd30;
    con_en      =   1'b1;
    #(`CLK_PER);    
    con_en      =   1'b0;

    @(posedge   tx_done)    
    #(`CLK_PER*2);   
    data_in     =   8'd35;
    con_en      =   1'b1;
    #(`CLK_PER);    
    con_en      =   1'b0;
    
    @(posedge   tx_done)   
    #(`CLK_PER*7000);
    
    $stop;
end
endmodule    
UART_SDRAM模块仿图

data_in输入6个数据,tx信号输出前5个数据的波形,并且Tx_inst模块中的Done_tx信号产生5次;SDRAM写入5个数据并读出,(sdram_dq信号)仿真成功。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值