• 03-SDRAM:写操作(突发)


    SDRAM 数据写操作(页突发)

    1. state:
    2. cnt_cmd: 指令执行时长
    3. cnt_cmd_reset:上一个计数器的清零信号 (依赖计满信号:trp_end、trfc_end、tmrd_end)
    4. trcd_end、twrite_end、trp_end: 自家延时结束的信号(依赖 状态)
    5. wr_ack: 写数据期间的状态,整个过程都拉高
    6. wr_end: 状态终止
    7. wr_sdram_en:

    设计文件

    // SDRAM 数据写操作(页突发)
    // 1. state:		
    // 2. cnt_cmd:		指令执行时长
    // 3. cnt_cmd_reset:上一个计数器的清零信号			 (依赖计满信号:trp_end、trfc_end、tmrd_end)
    // 4. trcd_end、twrite_end、trp_end: 自家延时结束的信号(依赖 状态)
    // 5. wr_ack:		写数据期间的状态,整个过程都拉高
    // 6. wr_end:		状态终止
    // 7. wr_sdram_en:	
    
    module sdram_write(
    	input 				    clk,
    	input 				    rst_n,
    	input 				    init_end,
    	input 	   	  			wr_en,
    	input 		[23:0]		wr_addr,
    	input 		[15:0]		wr_data,
    	input 		[9:0]		wr_burst_len,
    	
    	output wire 			wr_ack,
    	output wire 			wr_end,
    	output reg 	[3:0] 		write_cmd,
    	output reg 	[1:0] 		write_bank,
    	output reg 	[12:0] 		write_addr,
    	output reg 				wr_sdram_en, 
    	output wire [15:0] 		wr_sdram_data
    );
    
    //==========================================parameter===========================================================
    //状态机
    localparam	WR_IDLE = 3'b000,				//写操作初始状态
    			WR_ACT  = 3'b001,				//行激活状态
    			WR_TRCD = 3'b011,				//行激活等待状态
    			WR_WR 	= 3'b010,				//写操作状态
    			WR_DATA = 3'b100,				//突发写操作状态,突发写入多个数据,直到突发终止
    			WR_PRE 	= 3'b101,             	//预充电状态
    			WR_TRP 	= 3'b111,             	//预充电状态等待状态
    			WR_END 	= 3'b110;             	//结束状态
    			
    //等待时间参数定义	
    localparam	TRP  = 3'd2	,					//预充电等待周期
    			TRCD = 3'd2	;					//激活等待周期
    			
    //命令指令参数				
    localparam 	NOP		  	= 4'b0111 ,			//空操作指令
    			PRECHARGE 	= 4'b0010 ,			//预充电指令
    			ACTIVE    	= 4'b0011 ,			//激活指令
    			WRITE     	= 4'b0100 ,			//写指令
    			BURST_STOP  = 4'b0110 ;			//突发终止指令
    // 突发长度——从外部传入
    //parameter MAX_WR = 4'd10;
    //==========================================reg=================================================================			
    reg [7:0]   state;
    reg [7:0]   next_state;
    reg [9:0]   cnt_cmd;//2、9
    
    //==========================================wire=================================================================
    
    wire trcd_end;
    wire twrite_end;
    wire trp_end;
    wire cnt_cmd_reset;
    //==========================================assign=================================================================
    
    assign trcd_end   	 = ((state == WR_TRCD)  && (cnt_cmd == TRCD    -1))?1'd1:1'd0;
    assign twrite_end 	 = ((state == WR_DATA) && (cnt_cmd == wr_burst_len -1))?1'd1:1'd0;
    assign trp_end    	 = ((state == WR_TRP)  && (cnt_cmd == TRP   -1))?1'd1:1'd0;
    assign cnt_cmd_reset = ((state == WR_IDLE)||(state == WR_WR) || (state == WR_END) || trcd_end || twrite_end || trp_end)?1'd1:1'd0;
    assign wr_ack		 = ((state == WR_WR)  || (state == WR_DATA) && (cnt_cmd <= wr_burst_len -2'd2))?1'd1:1'd0;//在数据低8位末拉低,计数器要在一个完整时钟周期才有效,因此这里是在低8位
    assign wr_end		 = ((state == WR_END)) ? 1'd1 : 1'd0;
    assign wr_sdram_data = (wr_sdram_en) ? wr_data : 16'd0;
    //==========================================always=================================================================
    
    always@(posedge clk or negedge rst_n)begin
    	if(!rst_n )begin
    		wr_sdram_en <= 1'd0;
    	end
    	else 
    		wr_sdram_en <= wr_ack;
    end
    
    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
    		state <= WR_IDLE;
    	end
    	else 
    		state <= next_state;
    end
    //第二段
    always@(*)begin
    	case(state)
    		WR_IDLE:
    			if(init_end && wr_en)
    				next_state = WR_ACT;
    			else 
    				next_state = WR_IDLE;
    		WR_ACT :next_state = WR_TRCD;
    		WR_TRCD :
    			if(trcd_end)
    				next_state = WR_WR;
    			else
    				next_state = WR_TRCD;
    		WR_WR  :next_state = WR_DATA;
    	    WR_DATA:
    			if(twrite_end)
    				next_state = WR_PRE;
    			else
    				next_state = WR_DATA;
    	    WR_PRE :next_state = WR_TRP;
    		WR_TRP :
    			if(trp_end)
    				next_state = WR_END;
    			else
    				next_state = WR_TRP;
    		WR_END: next_state = WR_IDLE;
    	default:	next_state = WR_IDLE;
    	endcase
    end
    
    // 第三段
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n )begin
    			write_cmd	 <= NOP;
    			write_bank	 <= 2'b11;
    			write_addr	 <= 13'h1fff;
    			
    		end
    		else 
    			case(state)
    				WR_IDLE : begin
    					write_cmd	 <= NOP;
    					write_bank	 <= 2'b11;
    					write_addr	 <= 13'h1fff;
    				end
    				WR_ACT  : begin
    					write_cmd	 <= ACTIVE;
    					write_bank	 <= wr_addr[23:22];//wr_addr有3个地址,bank+13位行地址+9位列地址
    					write_addr	 <= wr_addr[21:9];
    				end
    				WR_TRCD : begin
    					write_cmd	 <= NOP;
    					write_bank	 <= 2'b11;
    					write_addr	 <= 13'h1fff;
    				end
    				WR_WR   : begin
    					write_cmd	 <= WRITE;
    					write_bank	 <= wr_addr[23:22];//wr_addr有3个地址,bank+13位行地址+9位列地址
    					write_addr	 <= {{4{1'b0}},wr_addr[8:0]};
    				end
    				WR_DATA : begin
    					write_bank	 <= 2'b11;
    					write_addr	 <= 13'h1fff;
    					if(twrite_end)
    						write_cmd	 <= BURST_STOP;//写完数据,就停止,然后再预充电
    					else
    						write_cmd	 <= NOP;
    				end
    				WR_PRE  : begin
    					write_cmd	 <= PRECHARGE;
    					write_bank	 <= wr_addr[23:22];
    					write_addr	 <= 13'h0400;//拉高A10,对所有bank预充电
    				end
    				WR_TRP:	begin
    					write_cmd	 <= NOP;
    					write_bank	 <= 2'b11;
    					write_addr	 <= 13'h1fff;
    				end
    				WR_END: begin
    					write_cmd	 <= NOP;
    					write_bank	 <= 2'b11;
    					write_addr	 <= 13'h1fff;
    				end 
    			default:begin
    			write_cmd	 <= NOP;
    			write_bank	 <= 2'b11;
    			write_addr	 <= 13'h1fff;
    			
    		end
    			endcase
    	end
    endmodule 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195

    测试文件

    
    `timescale  1ns/1ns
    
    // Author        : EmbedFire
    // Create Date   : 2019/08/25
    // Module Name   : tb_sdram_init
    // Project Name  : uart_sdram
    // Target Devices: Altera EP4CE10F17C8N
    // Tool Versions : Quartus 13.0
    // Description   : SDRAM初始化模块仿真
    // 
    // Revision      : V1.0
    // Additional Comments:
    // 
    // 实验平台: 野火_征途Pro_FPGA开发板
    // 公司    : http://www.embedfire.com
    // 论坛    : http://www.firebbs.cn
    // 淘宝    : https://fire-stm32.taobao.com
    
    
    module  tb_sdram_write();
    
    //********************************************************************//
    //****************** Internal Signal and Defparam ********************//
    //********************************************************************//
    
    //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        ;   //初始化完成信号
    
    // wire            auto_ref_req ;
    // wire   [3:0]    auto_ref_cmd ;
    // wire   [1:0]    auto_ref_bank;
    // wire   [12:0]   auto_ref_addr;
    // wire            auto_ref_end ;
    //sdram
    wire    [3:0]   sdram_cmd       ;   //SDRAM操作指令
    wire    [1:0]   sdram_bank		;   //SDRAM L-Bank地址
    wire    [12:0]  sdram_addr      ;   //SDRAM地址总线
    wire    [15:0]  sdram_dq;
    wire        wr_ack;
    wire        wr_end;
    wire        wr_sdram_en;
    wire [3:0]  write_cmd;
    wire [1:0]  write_bank;
    wire [12:0] write_addr;
    wire [15:0] wr_sdram_data;
    
    //reg define
    reg             clk_c1         ;   //系统时钟
    reg             sys_rst_n       ;   //复位信号
    // reg             auto_ref_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容量
    
    //********************************************************************//
    //**************************** Clk And Rst ***************************//
    //********************************************************************//
    
    //时钟、复位信号
    initial
      begin
        clk_c1     =   1'b1  ;
        sys_rst_n   <=  1'b0  ;
        #200
        sys_rst_n   <=  1'b1  ;
      end
    
    always  #10 clk_c1 = ~clk_c1;
    
    //rst_n:复位信号
    assign  rst_n = sys_rst_n & locked;
    
    
    
    // //atref_en:自动刷新使能
    // always@(posedge clk_100m or negedge rst_n)begin
    //     if(rst_n == 1'b0)
    //         auto_ref_en <=  1'b0;
    //     else if((init_end == 1'b1) && (auto_ref_req == 1'b1))
    //         auto_ref_en <=  1'b1;
    //     else if(auto_ref_end == 1'b1)
    //         auto_ref_en <=  1'b0;
    // end 
    
    reg wr_en;
    //wr_en:写数据使能
    always@(posedge clk_100m or negedge rst_n)
        if(rst_n == 1'b0)
            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;
    
    reg [15:0] wr_data_in;
    //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(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_bank = (init_end == 1'b1) ? write_bank : 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;
    //********************************************************************//
    //*************************** Instantiation **************************//
    //********************************************************************//
    
    //------------- clk_gen_inst -------------
    clk_gen clk_gen_inst (
        .inclk0     (clk_c1        ),
        .areset     (~sys_rst_n     ),
        .c0         (clk_50m        ),
        .c1         (clk_100m       ),
        .c2         (clk_100m_shift ),
    
        .locked     (locked         )
    );
    
    //------------- sdram_init_inst -------------
    sdram_initial  sdram_initial_inst(
    
        .clk        (clk_100m   ),
        .rst_n      (rst_n      ),
    
        .init_cmd   (init_cmd   ),
        .init_bank  (init_ba    ),
        .init_addr  (init_addr  ),
        .init_end   (init_end   )
    
    );
    // sdram_auto_ref  sdram_auto_ref_inst(
    
    //     .clk          (clk_100m   ),
    //     .rst_n        (rst_n      ),
    //     .init_end     (init_end   ),
    //     .auto_ref_en  (auto_ref_en),
    
    //     .auto_ref_req   (auto_ref_req   ),
    //     .auto_ref_cmd   (auto_ref_cmd   ),
    //     .auto_ref_bank  (auto_ref_bank  ),
    //     .auto_ref_addr  (auto_ref_addr  ),
    //     .auto_ref_end   (auto_ref_end   )
    
    // );
    
    
    
    sdram_write sdram_write_inst(
    	.clk(clk_100m),
    	.rst_n(rst_n),
    	.init_end(init_end),
    	.wr_en(wr_en),
    	.wr_addr(24'h000_000 ),
    	.wr_data(wr_data_in),
    	.wr_burst_len(10'd10 ),
    	
    	.wr_ack(wr_ack),
    	.wr_end(wr_end),
    	.write_cmd(write_cmd),
    	.write_bank(write_bank),
    	.write_addr(write_addr),
    	.wr_sdram_en(wr_sdram_en), 
    	.wr_sdram_data(wr_sdram_data)
    );
    
    
    //-------------sdram_model_plus_inst-------------
    sdram_model_plus    sdram_model_plus_inst(
        .Dq     (sdram_dq        ),
        .Addr   (sdram_addr      ),
        .Ba     (sdram_bank     ),
        .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           )
    
    );
    
    
    //------------------------------------------------
    //--    状态机名称查看器
    //------------------------------------------------
    reg [79:0]	name_state_cur;				//每字符8位宽,这里取最多10个字符80位宽
     
    always @(*) begin
        case(sdram_write_inst.state)
            3'b000:		name_state_cur = "WR_IDLE";
            3'b001:		name_state_cur = "WR_ACT ";
            3'b011:		name_state_cur = "WR_TRCD ";
            3'b010:		name_state_cur = "WR_WR  "; 
            3'b100:     name_state_cur = "WR_DATA  "; 
            3'b101:     name_state_cur = "WR_PRE  ";
    		3'b110:		name_state_cur = "WR_END"; 
    		3'b111:		name_state_cur = "WR_TRP "; 
            default:	name_state_cur = "WR_IDLE";
        endcase
    end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230

    打印信息

    在这里插入图片描述

  • 相关阅读:
    Qt控件按钮大全
    【软考】14.2 统一建模语言UML/事务关系图
    VR点亮元宇宙丨酷雷曼与你相约2022世界VR产业大会
    SPASS-指数平滑法
    区域运营推广策划案
    Oracle Primavera Unifier 23.4 新特征
    伦敦金今日走势怎么做?
    矢量(vector)瓦片与栅格(raster)瓦片对比
    矩阵分析与应用(22)
    【高并发优化手段】基于Springboot项目
  • 原文地址:https://blog.csdn.net/m0_46830519/article/details/126073637