IC学习笔记12——SDRAM行为介绍(2)

一、SDRAM基本操作

SDRAM主要有4个基本行为操作,分别是上电初始化,读操作,写操作和刷新。

1.1 上电初始化时序

在这里插入图片描述
SDRAM的上电顺序如上所示:

1.首先等待至少100us,CKE设置为高,命令为NOP。

2.在100us结束后,即可发出一个全部Bank的预充电命令(Precharge all),其中地址总线的A10=1,表示所有Bank预充电,A10=0,对指定bank充电。

3.等待至少tRP,此时的命令为NOP。

4.发出一个自动刷新命令(Auto Refresh)。

5.等待至少tRFC,此时的命令为NOP。

6.再发出一个自动刷新命令(Auto Refresh)。

7.再等待至少tRFC,此时的命令为NOP。

8.使用LMR命令设置模式寄存器,就是对地址总线A[12:0]进行操作,
其中A[2:0]表示突发长度 000:突发长度为1 001:突发长度为2 010:突发长度为4 011:突发长度为8 其余位保留
A[3] 表示突发类型 0表示顺序 1表示逆序
A[6:4] 表示CAS latency 就是潜伏期是多少个时钟周期 010:2 011:3 其余保留
A[9] 表示写突发模式 1:单一写 0:突发写

9:等待至少tMRD,此时的命令为NOP

10:上电初始化时序完成

    module sdram_init(
                                //system signals
                                input sclk,
                                input rst_n,
                               //others
					           output  reg [3:0]    cmd_reg,  //{sdr_cs_n,sdr_ras_n,sdr_cas_n,sdr_we_n}
					           output  reg [12:0]   sdram_addr,
					           output  reg          flag_init_end
                            );
		 localparam  S0=3'b000,
		              S1=3'b001,
					  S2=3'b010,
					  S3=3'b011,
					  S4=3'b100,
					  S5=3'b101,
					  S6=3'b110;
           localparam NOP=4'b0111,
                      PRE=4'b0010,
			          REF=4'b0001,
			          LMR=4'b0000,   
			          OP=13'b0_0000_0011_0010;   // 突发写,突发长度4,CAS latency为3,突发写,顺序
			  
                       localparam  tRP =2, //2
                                   tRFC=7, //7
			                       tMRD=2, //2
				                   T100us=10000; //20000
			  
		reg [14:0] cnt;  
		reg [2:0]  state;
		
always@(posedge sclk or negedge rst_n)
  begin
    if(rst_n==1'b0)
			 begin
				cmd_reg       <=NOP;
				sdram_addr    <=13'b1_1111_1111_1111;                               
				state         <=S0;
				flag_init_end <='d0;
				cnt           <='d0;   
			 end
    else
          case(state)
			   S0:if(cnt<T100us-1)                                          //等待至少100us
					      begin
								  cmd_reg       <=NOP;
								  sdram_addr    <=13'b1_1111_1111_1111;  
						          state         <=S0;
								  flag_init_end <='d0;
								  cnt           <=cnt+1'b1;
							end
				else
						 begin
					              state         <=S1;
								  cnt           <='d0;   
						 end
				S1:   begin                                                 //全部Bank的预充电命令
					        cmd_reg       <=PRE;
					        state         <=S2;
							sdram_addr[10]<=1'b1;
				      end
				S2:if(cnt<tRP-1)                                           // 等待至少tRP时间
				      begin
						  cmd_reg       <=NOP;
						  state            <=S2;
						  cnt              <=cnt+1'b1;
					  end
				   else                                                    //发出一个自动刷新命令
					   begin                     
							  state              <=S3;
							  cnt                <='d0;
							  cmd_reg       <=REF;  
						end
				S3:if(cnt<tRFC-1)                                          //等待至少tRFC
				      begin
						  cmd_reg       <=NOP;
						  state         <=S3;
						  cnt           <=cnt+1'b1;
						end
				   else                                                    //再发出一个自动刷新命令
					   begin
						  state         <=S4;
						  cnt           <='d0;
						  cmd_reg       <=REF;  
						end 
            S4:if(cnt<tRFC-1)                                              //等待至少tRFC
				       begin
						  cmd_reg       <=NOP;
						  state         <=S4;
						  cnt           <=cnt+1'b1;
						end
				   else                                                    //使用LMR命令设置模式寄存器
					   begin
						  state         <=S5;
						  cnt           <='d0;
						  cmd_reg       <=LMR; 
                 	      sdram_addr	 <=OP;			  
						end
            S5:if(cnt<tMRD-1)                                    //等待至少tMRD
                   begin
						  cmd_reg       <=NOP;
						  sdram_addr    <=13'b1_1111_1111_1111;  
						  state         <=S5;
						  cnt           <=cnt+1'b1;
						 end 
                else
					   begin
						  state         <=S6;                   //上电初始化时序完成
						  cnt           <='d0;
			           flag_init_end <='d1;
						end
				 S6:      state       <=S6;
             default: state       <=S0;						
			 endcase
  end
endmodule

1.2 读操作时序

在这里插入图片描述
在这里插入图片描述1.首先执行行激活命令,命令为ACT,地址总线A[12:0]设置为要激活的行地址row_addr

2.等待tRCD时间,此时命令为NOP

3.tRCD时间之后,执行读命令READ,地址总线A[12:0]设置为要读的列地址{3b000,col_addr},注意此时采用的SDRAM,行地址为13位,列地址为10位

4:潜伏周期后,数据出现在Dq总线上

module Rd_fsm(
         //输入
            rd_en,
			rd_row,
			rd_col,
			rd_ba,
			soft_rst_n,
		   clk,
			capture_clk,
			dq_in,
		
			//输出
			rd_bus,
			rdata,
			rd_done,
			load_l,
			load_h
);     
		
		input             clk,capture_clk;
		input             soft_rst_n;
		input             rd_en;
		input   [12:0]    rd_row;
		input    [9:0]    rd_col;
		input    [1:0]    rd_ba;
		input   [15:0]    dq_in;
		
		output reg [19:0] rd_bus;// rd_bus[19:7]=sdr_a,rd_bus[6:5]=sdr_ba,rd_bus[4:1]={sdr_cs_n,sdr_ras_n,sdr_cas_n,sdr_we_n},rd_bus[0]=sdr_cke
	
		output reg [31:0] rdata;
		output reg        rd_done;
		

	          reg [15:0] dq_cap,dq_sym;
            reg [2:0]  state;
	          reg [2:0]  cnt;
		output reg        load_l;
		output reg        load_h;
				 
     localparam         S0=3'b000;
		localparam         S1=3'b001;	 
		localparam         S2=3'b010;	
		localparam         S3=3'b011;				  
		localparam         S4=3'b100;	
		
		always@(posedge clk or negedge soft_rst_n)
		 begin
		    if(!soft_rst_n)
			    begin
				    rd_done         <=   1'b0;
					 rd_bus[19:7]    <=   13'd0;
				    rd_bus[6:5]     <=   2'd0;
					 rd_bus[4:1]     <=   `NOP;
					 rd_bus[0]       <=   1'b1;
				    cnt             <=   3'd0;
					 load_l          <=   1'b0;
					 load_h          <=   1'b0;
					 state           <=   S0;
				 end
		    else
		       case(state)
				    S0:if(!rd_en)
					       begin
							   state        <=     S0;
							 end
		             else
						    begin
							   rd_bus[4:1]  <=   `ACT;                       // 激活行命令
							   rd_bus[19:7] <=    rd_row;                  //行地址A[12:0]
								rd_bus[6:5]  <=    rd_ba;                    //BANK 地址
								rd_done      <=    1'b0;
								state        <=    S1;
							 end			 
		         S1:if(cnt<`tRCD-1)                                            //等待tRCD时间
					       begin
							   state        <=    S1;           
								rd_bus[4:1]  <=   `NOP;
								cnt          <=    cnt+1'b1;
							 end
						else
						    begin
							   rd_bus[4:1]  <=   `RD;                      //读命令READ
								rd_bus[16:7] <=   rd_col;                //列地址A[9:0]
								rd_bus[6:5]  <=   rd_ba;                  //BANK 地址
								rd_bus[17]   <=   1'b1;                    //自动预充电
							   cnt          <=   3'd0;
								state        <=   S2;
							 end
					S2:if(cnt<`CL+`SL-1)                             // 潜伏周期后 
                     begin
                                state        <=    S2;
								rd_bus[4:1]  <=   `NOP;
								cnt          <=    cnt+1'b1;
                     end
                    else
                     begin
                               load_l       <=    1'b1;
								state        <=    S3;
								cnt          <=    3'd0;
                     end								 
					S3: begin
                                load_l       <=    1'b0;
								load_h       <=    1'b1;
								state        <=    S4;
                  end	
              S4: begin
								load_h       <=    1'b0;
								rd_done      <=    1'b1;
								state        <=    S0;
                  end	 
             default:	state        <=    S0;						 
		   endcase 
      end
		 
		 always@(posedge capture_clk)
			  begin
			      dq_cap       <=    dq_in;
			  end
      
		 always@(posedge clk)
		     begin
			      dq_sym       <=    dq_cap;
			  end
 
       always@(posedge clk)
		    begin
			   if(!soft_rst_n)
				   rdata        <=    32'd0;  
			   else if(load_l)
				   rdata[15:0]  <=    dq_sym;
           else if(load_h)
				   rdata[31:16] <=    dq_sym;						
			 end

endmodule

1.3 写操作时序

在这里插入图片描述在这里插入图片描述
1.首先执行行激活命令,命令为ACT,地址总线A[12:0]设置为要激活的行地址row_addr,和读操作一样

2.等待tRCD时间,此时命令为NOP

3.tRCD时间之后,执行读命令Write,地址总线A[12:0]设置为要读的列地址{3b000,col_addr},注意此时采用的SDRAM,行地址为13位,列地址为10位。sdram写操作没有潜伏周期概念,直接将数据写入数据总线上。

            module Wr_fsm( 
			  //输入
						 wr_en,
		                 wr_row,
		                 wr_col,
		                 wr_ba,
		                 wdata,
						 soft_rst_n,
						 clk,
			  
          //输出				 			
		
		            wr_bus,  //wr_bus  
                    wr_done,
			  
                   dq_out,
			      dq_en       				 
);
          input              soft_rst_n;
		  input              clk;
          input              wr_en;
          input       [12:0] wr_row;
          input       [9:0]  wr_col;
		  input       [1:0]  wr_ba;
          input       [31:0] wdata; 
		 
	 
	     output  reg [19:0] wr_bus;   // wr_bus[19:7]=sdr_a,wr_bus[6:5]=sdr_ba,wr_bus[4:1]={sdr_cs_n,sdr_ras_n,sdr_cas_n,sdr_we_n},wr_bus[0]=sdr_cke
	
		  
		  output  reg        wr_done;
		  
        output  reg [15:0] dq_out;
       output  reg        dq_en;

               reg [1:0]  state;
					 reg [1:0]  cnt;
		  
		  localparam         S0=2'b00;
		  localparam         S1=2'b01;	 
		  localparam         S2=2'b10;	
		  localparam         S3=2'b11;				  
			
       always@(posedge clk)
		    begin
			   if(!soft_rst_n)
						 begin
								wr_bus[19:7]   <= 13'd0;
								wr_bus[6:5]    <=  2'd0;
								wr_bus[4:1]    <=  `NOP;
								wr_bus[0]      <=  1'b1;
								dq_en          <=  1'b0;
								dq_out         <= 16'd0;
								state          <=    S0;
								wr_done        <=  1'b0;
								cnt            <=  2'd0;
						 end
			    else
				    case(state)
			             S0:if(!wr_en)
									  begin
										   state         <=  S0;
									  end
					         else 
									  begin
											wr_bus[4:1]   <= `ACT;                         // 激活行命令
											wr_bus[19:7]  <=  wr_row;                    //行地址A[12:0]
										   wr_bus[6:5]   <=  wr_ba;                        //BANK 地址
											wr_done       <=  1'b0;
										   state         <=  S1;
									  end	
                  S1:if(cnt<`tRCD-1)                                                          //等待tRCD时间
									  begin
										   state         <=  S1;
										   cnt           <=  cnt+1'b1;
										   wr_bus[4:1]   <= `NOP;
									  end
                     else
									  begin
										   state         <=  S2;
										   wr_bus[4:1]   <= `WR;                          //写命令READ
											wr_bus[6:5]   <=  wr_ba;                      //BANK 地址
										   wr_bus[16:7]  <=  wr_col;                     //列地址A[9:0]
										   wr_bus[17]    <=  1'b1;                          //自动预充电
										   dq_en         <=  1'b1;
										   dq_out        <=  wdata[15:0];
										   cnt           <=  2'd0;
									  end	
                  S2: begin
										   wr_bus[4:1]   <=  `NOP; 
										   dq_out    <=  wdata[31:16];
										   state     <=  S3;
							  end	
                  S3: begin
										   dq_en     <=  1'b0; 
										   wr_done   <=  1'b1; 
										   state     <=  S0;
							  end	
						 
					 endcase 
			 end

endmodule

1.4 自刷新操作时序

在这里插入图片描述
SDRAM的自刷新操作是必须的,由已知SDRAM是动态随机存取存储器,一段时间不进行刷新,所存储的数据就会出错。

自刷新和预充电都是对行进行充电,不同的区别是,预充电是对之前执行完的行进行操作,而自刷新是从第一行自动递增到最后一行进行充电,我们这里是约每7.8us刷新一行,每经过7.8us,执行自刷新操作。

1.首先执行预充电,为之前读写操作的行充电,命令为PRE

2.等待tRP时间

3.执行自刷新操作,命令为REF

4.等待tRFC时间后,自刷新操作结束

	  module Ref_fsm(
         //输入
                ref_en,
			    soft_rst_n,
		     	clk,
		 //输出
			    ref_done,	
                ref_bus			
    );
input                 ref_en;
output  reg        ref_done;
input                 soft_rst_n;
input                 clk;
 
 output  reg[19:0]  ref_bus;// ref_bus[19:7]=sdr_a,ref_bus[6:5]=sdr_ba,ref_bus[4:1]={sdr_cs_n,sdr_ras_n,sdr_cas_n,sdr_we_n},ref_bus[0]=sdr_cke
 

 reg     [1:0]      state;
 reg     [3:0]      cnt;       
 
 localparam  S0=3'b000;
localparam  S1=3'b001;	 
 localparam  S2=3'b010;	
 localparam  S3=3'b011;	
 
 
 always@(posedge clk)
 begin
    if(!soft_rst_n)
	   begin
			 ref_bus[19:7]     <= 13'd0;         //边界
			 ref_bus[6:5]      <= 2'd0;
			 ref_bus[4:1]      <= `NOP;
			 ref_bus[0]        <= 1'd1;          
			 cnt               <= 4'd0;
			 ref_done          <= 1'd0;
			 state             <= S0;
      end
	 else	
      begin
		   case(state)
			  S0:if(ref_en==1'b1)
			        begin
			          state          <=  S1;
                   ref_bus[4:1]   <= `PRE; 
                  ref_bus[17]    <= 1'b1;
                  cnt            <= 4'd0;							 
					  end
			     else
				     begin
				       state          <=  S0;          							 
					  end
          S1:if(cnt<`tRP-1)
			       begin
                  cnt            <=cnt+1'b1;
                  state          <=S1;
 						 ref_bus[4:1]   <= `NOP; 	 
               end						 
             else
				    begin
					     cnt           <= 4'd0;
						  state         <=S2;
						  ref_bus[4:1]  <= `REF; 	 
						 end
				S2:if(cnt<`tRFC-1)	
					 begin
						  cnt           <=  cnt+1'b1;
						  ref_bus[4:1]  <= `NOP ;
						  state         <=  S2;
					 end
					else
					  begin
						 cnt       <= 4'd0;		
						 state     <=  S3;
						 ref_done  <= 1'd1;
					  end  
			  S3:  begin
			          state     <=  S0;
			          ref_done  <= 1'd0;
				    end
         endcase
     end
  end
 endmodule
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值