04-SDRAM:读操作(突发)

设计文件

// SDRAM 读操作
// 1. rd_data_reg:		SDRAM 工作时间和模块的系统时钟有相位差,需要打拍同步
// 2. state
// 3. cnt_cmd:		指令执行时长
// 4. cnt_cmd_reset:上一个计数器的清零信号			 (依赖计满信号:trp_end、trfc_end、tmrd_end)
// 5. trcd_end、tcl_end、tread_end、trp_end: 自家延时结束的信号(依赖 状态)
// 6. rd_ack:		写数据期间的状态,整个过程都拉高
// 7. rd_end:		状态终止

module  sdram_read(
	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 wire 			rd_ack,
	output wire 			rd_end,
	output reg 	[3:0] 		read_cmd,
	output reg 	[1:0] 		read_bank,
	output reg 	[12:0] 		read_addr,
	output wire [15:0] 		rd_sdram_data
);


//==========================================parameter===========================================================

parameter   TRCD =	10'd2   ,   		//激活等待周期
            TCL  =	10'd3   ,   		//潜伏期
            TRP  =	10'd4   ;   		//预充电等待周期
			
parameter   RD_IDLE     =   4'b0000 ,   //空闲
            RD_ACT	    =   4'b0001 ,   //行激活
            RD_TRCD     =   4'b0011 ,   //激活等待
            RD_READ     =   4'b0010 ,   //读操作
            RD_CL       =   4'b0100 ,   //潜伏期
            RD_DATA     =   4'b0101 ,   //读数据
            RD_PRE      =   4'b0111 ,   //预充电
            RD_TRP      =   4'b0110 ,   //预充电等待
            RD_END      =   4'b1100 ;   //一次突发读结束
parameter   NOP         =   4'b0111 ,   //空操作指令
            ACTIVE      =   4'b0011 ,   //激活指令
            READ        =   4'b0101 ,   //数据读指令
            BURST_STOP  =   4'b0110 ,   //突发停止指令
            PRECHARGE   =   4'b0010 ;   //预充电指令

//==========================================reg=================================================================			
reg [8:0]   state;
reg [8:0]   next_state;
reg [9:0]   cnt_cmd;//2、12
reg [15:0]  rd_data_reg;//跨时钟域打拍

//==========================================wire=================================================================

wire trcd_end;
wire tcl_end;
wire tread_end;
wire trp_end;
wire rdburst_end;

wire cnt_cmd_reset;
//==========================================assign=================================================================

assign trcd_end   	 = ((state == RD_TRCD)  && (cnt_cmd == TRCD    -1))?1'd1:1'd0;
assign tcl_end   	 = ((state == RD_CL)    && (cnt_cmd == TCL     -1))?1'd1:1'd0;
assign tread_end 	 = ((state == RD_DATA)  && (cnt_cmd == rd_burst_len -1 + TCL))?1'd1:1'd0;//突发长度+CL
assign trp_end    	 = ((state == RD_TRP)   && (cnt_cmd == TRP   -1))?1'd1:1'd0;
assign rdburst_end   = ((state == RD_DATA)  && (cnt_cmd == rd_burst_len   - 3'd4))?1'd1:1'd0;

assign cnt_cmd_reset = ((state == RD_IDLE)  || (state == RD_TRCD) || (state == RD_END) || trcd_end || tcl_end || tread_end || trp_end)?1'd1:1'd0;

assign rd_ack		 = ((state == RD_DATA) && (cnt_cmd >= 10'd1) && (cnt_cmd <= 10'd11))?1'd1:1'd0;//在数据低8位末拉低,计数器要在一个完整时钟周期才有效,因此这里是在低8位
assign rd_end		 = ((state == RD_END)) ? 1'd1 : 1'd0;
assign rd_sdram_data = (rd_ack) ? rd_data_reg : 16'd0;
//==========================================always=================================================================

always@(posedge clk or negedge rst_n)begin
	if(!rst_n )begin
		cnt_cmd <= 10'd0;
	end
	else if(cnt_cmd_reset)begin
		cnt_cmd <= 10'd0;
	end
	else
		cnt_cmd <= cnt_cmd + 10'd1;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n )begin
		rd_data_reg <= 16'd0;
	end
	else 
		rd_data_reg <= rd_data;
end


//==========================================状态机=================================================================

// 第一段
always@(posedge clk or negedge rst_n)begin
	if(!rst_n )begin
		state <= RD_IDLE;
	end
	else 
		state <= next_state;
end
//--状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
always@(*)begin
	next_state = RD_IDLE;
	case(state)
		RD_IDLE:
			if(rd_en && init_end)						//初始化完成且读使能有效则跳转到下一个状态,否则保持在该状态
				next_state = RD_ACT;			
			else			
				next_state = RD_IDLE;					
		RD_ACT:			
			next_state = RD_TRCD;						//跳转到TRCD等待状态
		RD_TRCD:			
			if(trcd_end)							//TRCD等待标志拉高则跳转到下一个状态,否则保持在该状态
				next_state = RD_READ;			
			else			
				next_state = RD_TRCD;			
		RD_READ:			
			next_state = RD_CL;							//跳转潜伏期状态	
		RD_CL:			
			if(tcl_end)							//潜伏期结束标志拉高则跳转到下一个状态,否则保持在该状态
				next_state = RD_DATA;			
			else			
				next_state = RD_CL;			
		RD_DATA:										//突发读取数据状态
			if(tread_end)							//突发读取数据结束标志拉高则跳转到下一个状态,否则保持在该状态
				next_state = RD_PRE;			
			else			
				next_state = RD_DATA;			
		RD_PRE:			
				next_state = RD_TRP;					//预充电状态
		RD_TRP:			
			if(trp_end)							//TRP等待标志拉高则跳转到下一个状态,否则保持在该状态
				next_state = RD_END;			
			else			
				next_state = RD_TRP;					
		RD_END:			
			next_state = RD_IDLE;						//跳转到初始状态
		default:next_state = RD_IDLE;					//默认在初始状态
	endcase
end

// 第三段
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n )begin
			read_cmd	 <= NOP;
			read_bank	 <= 2'b11;
			read_addr	 <= 13'h1fff;
			
		end
		else 
			case(state)
				RD_IDLE : begin
					read_cmd	 <= NOP;
					read_bank	 <= 2'b11;
					read_addr	 <= 13'h1fff;
				end
				RD_ACT  : begin
					read_cmd	 <= ACTIVE;
					read_bank	 <= rd_addr[23:22];//wr_addr有3个地址,bank+13位行地址+9位列地址
					read_addr	 <= rd_addr[21:9];
				end
				RD_TRCD : begin
					read_cmd	 <= NOP;
					read_bank	 <= 2'b11;
					read_addr	 <= 13'h1fff;
				end
				RD_READ   : begin
					read_cmd	 <= READ;
					read_bank	 <= rd_addr[23:22];//wr_addr有3个地址,bank+13位行地址+9位列地址
					read_addr	 <= {{4{1'b0}},rd_addr[8:0]};
				end
				RD_DATA : begin
					read_bank	 <= 2'b11;
					read_addr	 <= 13'h1fff;
					if(rdburst_end)
						read_cmd	 <= BURST_STOP;//写完数据,就停止,然后再预充电
					else
						read_cmd	 <= NOP;
				end
				RD_PRE  : begin
					read_cmd	 <= PRECHARGE;
					read_bank	 <= rd_addr[23:22];
					read_addr	 <= 13'h0400;//拉高A10,对所有bank预充电
				end
				RD_TRP:	begin
					read_cmd	 <= NOP;
					read_bank	 <= 2'b11;
					read_addr	 <= 13'h1fff;
				end
				RD_END: begin
					read_cmd	 <= NOP;
					read_bank	 <= 2'b11;
					read_addr	 <= 13'h1fff;
				end 
			default:begin
			read_cmd	 <= NOP;
			read_bank	 <= 2'b11;
			read_addr	 <= 13'h1fff;
			
		end
			endcase
	end

endmodule 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值