2018/7/26
受教于邓堪文老师,开始真真学习控制sdram
由于自己买的sdram模块是256的,原来老师的是128,所以边学边改,不知道最后好不好使,但是我有信心
一.sdram的初始化
sdram介绍啥的就不用了,上来就是干,简单粗暴。
1.下面是引脚说明,看不懂自己可以用百度翻译,需要注意的是红框内的地址引脚和行列地址是复用的,A0~A12是行地址,A0~8是列地址
简单说一下SDRAM的容量计算:数据位宽 *行地址*列地址*bank数,我们用的256有4个bank,就是:16*8192*512*4
2.我的fpga是50m时钟,20ns一个周期,下图是初始化的时序图
sdram上电要延时至少100us,我们是延时200us,然后precharge(预充电)命令,隔tRP时间也就是一个时钟周期20ns进行第一次auto_refresh(自刷新),再隔tRC时间也就是四个时钟周期进行第二次auto_refresh命令,
又tRC时间进行mode_register(模式寄存器配置)。期间的NOP是空操作命令。还有就是这几个时间要看自己使用sdram的datasheet
3.上面说的命令也是要去datasheet手册去找,对应CS,RAS,CAS,WE的操作
4.模式配置对应datasheet ,根据红框addr:0_0000_0010_0010
5.再来一张时序图
6.该上源码了,应该没啥看不懂的吧
1 `timescale 1ns/1ns 2 3 module tb_sdram_top; 4 5 reg sclk ; 6 reg s_rst_n ; 7 8 //---------------------------------------------------------- 9 wire sdram_clk ; 10 wire sdram_cke ; 11 wire sdram_cs_n ; 12 wire sdram_cas_n ; 13 wire sdram_ras_n ; 14 wire sdram_we_n ; 15 wire [1:0] sdram_bank ; 16 wire [12:0] sdram_addr ; 17 wire [1:0] sdram_dqm ; 18 wire [15:0] sdram_dq ; 19 20 21 22 23 24 initial begin 25 sclk = 1; 26 s_rst_n <= 0; 27 #100 28 s_rst_n <= 1; 29 end 30 31 always #10 sclk = ~sclk; 32 33 34 35 sdram_top sdram_top_inst( 36 //system signals 37 .sclk (sclk ), 38 .s_rst_n (s_rst_n ), 39 //SDRAM Interfaces 40 .sdram_clk (sdram_clk ), 41 .sdram_cke (sdram_cke ), 42 .sdram_cs_n (sdram_cs_n ), 43 .sdram_cas_n (sdram_cas_n ), 44 .sdram_ras_n (sdram_ras_n ), 45 .sdram_we_n (sdram_we_n ), 46 .sdram_bank (sdram_bank ), 47 .sdram_addr (sdram_addr ), 48 .sdram_dqm (sdram_dqm ), 49 .sdram_dq (sdram_dq ) 50 ); 51 52 53 sdram_model_plus sdram_model_plus_inst( 54 .Dq (sdram_dq ), 55 .Addr (sdram_addr ), 56 .Ba (sdram_bank ), 57 .Clk (sdram_clk ), 58 .Cke (sdram_cke ), 59 .Cs_n (sdram_cs_n ), 60 .Ras_n (sdram_ras_n ), 61 .Cas_n (sdram_cas_n ), 62 .We_n (sdram_we_n ), 63 .Dqm (sdram_dqm ), 64 .Debug (1'b1 ) 65 ); 66 67 endmodule
1 module sdram_ini( 2 //systejm signal 3 input sclk , 4 input s_rst_n , 5 //others 6 output reg [3:0] cmd_reg , 7 output wire [12:0] sdram_addr , 8 output flag_ini_end 9 ); 10 11 //==============================================================================\ 12 //*********************Define Parameter and Internal Signal ******************** 13 //==============================================================================/ 14 15 localparam DELAY_200US = 10000 ; 16 //SDRAM Command 17 localparam NOP = 4'b0111 ; 18 localparam PRE = 4'b0010 ; 19 localparam AREF = 4'b0001 ; 20 localparam MSET = 4'b0000 ; 21 22 reg [13:0] cnt_200us ; 23 wire flag_200us ; 24 reg [3:0] cnt_cmd ; 25 26 //=============================================================================\ 27 //********************** Main Code *************************************** 28 //=============================================================================/ 29 30 always @(posedge sclk or negedge s_rst_n) begin 31 if(s_rst_n == 1'b0) 32 cnt_200us <= 14'd0; 33 else if (flag_200us == 1'b0) 34 cnt_200us <= cnt_200us + 1'b1; 35 end 36 37 always @(posedge sclk or negedge s_rst_n) begin 38 if(s_rst_n == 1'b0) 39 cnt_cmd <= 4'd0; 40 else if(flag_200us == 1'b1 && flag_ini_end == 1'b0) 41 cnt_cmd <= cnt_cmd + 1'b1; 42 end 43 44 //cmd_reg 45 always @(posedge sclk or negedge s_rst_n ) begin 46 if(s_rst_n == 1'b0) 47 cmd_reg <= NOP; 48 else if(flag_200us == 1'b1) 49 case(cnt_cmd) 50 0: cmd_reg <= PRE ; 51 1: cmd_reg <= AREF ; 52 4: cmd_reg <= AREF ; 53 9: cmd_reg <= MSET ; 54 default : cmd_reg <= NOP ; 55 endcase 56 end 57 assign flag_ini_end = (cnt_cmd >= 4'd10) ? 1'b1 : 1'b0; 58 assign sdram_addr = (cmd_reg == MSET) ? 13'b0_0000_0011_0010 : 13'b0_0100_0000_0000; 59 assign flag_200us = (cnt_200us >= DELAY_200US) ? 1'b1 : 1'b0; 60 61 endmodule
1 module sdram_top( 2 //system signals 3 input sclk , 4 input s_rst_n , 5 //SDRAM Interfaces 6 output wire sdram_clk , 7 output wire sdram_cke , 8 output wire sdram_cs_n , 9 output wire sdram_cas_n , 10 output wire sdram_ras_n , 11 output wire sdram_we_n , 12 output wire [1:0] sdram_bank , 13 output wire [12:0] sdram_addr , 14 output wire [1:0] sdram_dqm , 15 inout [15:0] sdram_dq 16 ); 17 18 //==============================================================================\ 19 //*********************Define Parameter and Internal Signal ******************** 20 //==============================================================================/ 21 //init module 22 wire flag_ini_end ; 23 wire [3:0] init_cmd ; 24 wire [12:0] init_addr ; 25 26 27 //=============================================================================\ 28 //********************** Main Code *************************************** 29 //=============================================================================/ 30 assign sdram_cke = 1'b1; 31 assign sdram_addr = init_addr; 32 assign {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = init_cmd ; 33 assign sdram_dqm = 2'd0; 34 assign sdram_clk = ~sclk; 35 36 37 sdram_ini sdram_ini_inst( 38 //systejm signal 39 .sclk (sclk ), 40 .s_rst_n (s_rst_n ), 41 //others 42 .cmd_reg (init_cmd ), 43 .sdram_addr (init_addr ), 44 .flag_ini_end (flag_ini_end ) 45 ); 46 47 48 endmodule
这用了一个sdram仿真模型,堪文老师是128的,我的256的不能用,但是我改好了
1 /*************************************************************************************** 2 作者: 李晟 3 2003-08-27 V0.1 李晟 4 5 添加内存模块倒空功能,在外部需要创建事件:sdram_r ,本SDRAM的内容将会按Bank 顺序damp out 至文件 6 sdram_data.txt 中 7 ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××*/ 8 //2004-03-04 陈乃奎 修改原程序中将BANK的数据转存入TXT文件的格式 9 //2004-03-16 陈乃奎 修改SDRAM 的初始化数据 10 //2004/04/06 陈乃奎 将SDRAM的操作命令以字符形式表示,以便用MODELSIM监视 11 //2004/04/19 陈乃奎 修改参数 parameter tAC = 8; 12 //2010/09/17 罗瑶 修改sdram的大小,数据位宽,dqm宽度; 13 /**************************************************************************************** 14 * 15 * File Name: sdram_model.V 16 * Version: 0.0f 17 * Date: July 8th, 1999 18 * Model: BUS Functional 19 * Simulator: Model Technology (PC version 5.2e PE) 20 * 21 * Dependencies: None 22 * 23 * Author: Son P. Huynh 24 * Email: [email protected] 25 * Phone: (208) 368-3825 26 * Company: Micron Technology, Inc. 27 * Model: sdram_model (1Meg x 16 x 4 Banks) 28 * 29 * Description: 64Mb SDRAM Verilog model 30 * 31 * Limitation: - Doesn't check for 4096 cycle refresh 32 * 33 * Note: - Set simulator resolution to "ps" accuracy 34 * - Set Debug = 0 to disable $display messages 35 * 36 * Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY 37 * WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY 38 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR 39 * A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. 40 * 41 * Copyright ?1998 Micron Semiconductor Products, Inc. 42 * All rights researved 43 * 44 * Rev Author Phone Date Changes 45 * ---- ---------------------------- ---------- --------------------------------------- 46 * 0.0f Son Huynh 208-368-3825 07/08/1999 - Fix tWR = 1 Clk + 7.5 ns (Auto) 47 * Micron Technology Inc. - Fix tWR = 15 ns (Manual) 48 * - Fix tRP (Autoprecharge to AutoRefresh) 49 * 50 * 0.0a Son Huynh 208-368-3825 05/13/1998 - First Release (from 64Mb rev 0.0e) 51 * Micron Technology Inc. 52 ****************************************************************************************/ 53 54 `timescale 1ns / 100ps 55 56 module sdram_model_plus (Dq, Addr, Ba, Clk, Cke, Cs_n, Ras_n, Cas_n, We_n, Dqm,Debug); 57 58 parameter addr_bits = 13; 59 parameter data_bits = 16; 60 parameter col_bits = 9; 61 parameter mem_sizes = 4*1024*1024 -1;//1 Meg 62 63 inout [data_bits - 1 : 0] Dq; 64 input [addr_bits - 1 : 0] Addr; 65 input [1 : 0] Ba; 66 input Clk; 67 input Cke; 68 input Cs_n; 69 input Ras_n; 70 input Cas_n; 71 input We_n; 72 input [1 : 0] Dqm; //高低各8bit 73 //added by xzli 74 input Debug; 75 76 reg [data_bits - 1 : 0] Bank0 [0 : mem_sizes];//存储器类型数据 77 reg [data_bits - 1 : 0] Bank1 [0 : mem_sizes]; 78 reg [data_bits - 1 : 0] Bank2 [0 : mem_sizes]; 79 reg [data_bits - 1 : 0] Bank3 [0 : mem_sizes]; 80 81 reg [1 : 0] Bank_addr [0 : 3]; // Bank Address Pipeline 82 reg [col_bits - 1 : 0] Col_addr [0 : 3]; // Column Address Pipeline 83 reg [3 : 0] Command [0 : 3]; // Command Operation Pipeline 84 reg [3 : 0] Dqm_reg0, Dqm_reg1; // DQM Operation Pipeline 85 reg [addr_bits - 1 : 0] B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr; 86 87 reg [addr_bits - 1 : 0] Mode_reg; 88 reg [data_bits - 1 : 0] Dq_reg, Dq_dqm; 89 reg [col_bits - 1 : 0] Col_temp, Burst_counter; 90 91 reg Act_b0, Act_b1, Act_b2, Act_b3; // Bank Activate 92 reg Pc_b0, Pc_b1, Pc_b2, Pc_b3; // Bank Precharge 93 94 reg [1 : 0] Bank_precharge [0 : 3]; // Precharge Command 95 reg A10_precharge [0 : 3]; // Addr[10] = 1 (All banks) 96 reg Auto_precharge [0 : 3]; // RW AutoPrecharge (Bank) 97 reg Read_precharge [0 : 3]; // R AutoPrecharge 98 reg Write_precharge [0 : 3]; // W AutoPrecharge 99 integer Count_precharge [0 : 3]; // RW AutoPrecharge (Counter) 100 reg RW_interrupt_read [0 : 3]; // RW Interrupt Read with Auto Precharge 101 reg RW_interrupt_write [0 : 3]; // RW Interrupt Write with Auto Precharge 102 103 reg Data_in_enable; 104 reg Data_out_enable; 105 106 reg [1 : 0] Bank, Previous_bank; 107 reg [addr_bits - 1 : 0] Row; 108 reg [col_bits - 1 : 0] Col, Col_brst; 109 110 // Internal system clock 111 reg CkeZ, Sys_clk; 112 113 reg [24:0] dd; 114 115 // Commands Decode 116 wire Active_enable = ~Cs_n & ~Ras_n & Cas_n & We_n; 117 wire Aref_enable = ~Cs_n & ~Ras_n & ~Cas_n & We_n; 118 wire Burst_term = ~Cs_n & Ras_n & Cas_n & ~We_n; 119 wire Mode_reg_enable = ~Cs_n & ~Ras_n & ~Cas_n & ~We_n; 120 wire Prech_enable = ~Cs_n & ~Ras_n & Cas_n & ~We_n; 121 wire Read_enable = ~Cs_n & Ras_n & ~Cas_n & We_n; 122 wire Write_enable = ~Cs_n & Ras_n & ~Cas_n & ~We_n; 123 124 // Burst Length Decode 125 wire Burst_length_1 = ~Mode_reg[2] & ~Mode_reg[1] & ~Mode_reg[0]; 126 wire Burst_length_2 = ~Mode_reg[2] & ~Mode_reg[1] & Mode_reg[0]; 127 wire Burst_length_4 = ~Mode_reg[2] & Mode_reg[1] & ~Mode_reg[0]; 128 wire Burst_length_8 = ~Mode_reg[2] & Mode_reg[1] & Mode_reg[0]; 129 130 // CAS Latency Decode 131 wire Cas_latency_2 = ~Mode_reg[6] & Mode_reg[5] & ~Mode_reg[4]; 132 wire Cas_latency_3 = ~Mode_reg[6] & Mode_reg[5] & Mode_reg[4]; 133 134 // Write Burst Mode 135 wire Write_burst_mode = Mode_reg[9]; 136 137 wire Debug; // Debug messages : 1 = On; 0 = Off 138 wire Dq_chk = Sys_clk & Data_in_enable; // Check setup/hold time for DQ 139 140 reg [31:0] mem_d; 141 142 event sdram_r,sdram_w,compare; 143 144 145 146 147 assign Dq = Dq_reg; // DQ buffer 148 149 // Commands Operation 150 `define ACT 0 151 `define NOP 1 152 `define READ 2 153 `define READ_A 3 154 `define WRITE 4 155 `define WRITE_A 5 156 `define PRECH 6 157 `define A_REF 7 158 `define BST 8 159 `define LMR 9 160 161 // // Timing Parameters for -75 (PC133) and CAS Latency = 2 162 // parameter tAC = 8; //test 6.5 163 // parameter tHZ = 7.0; 164 // parameter tOH = 2.7; 165 // parameter tMRD = 2.0; // 2 Clk Cycles 166 // parameter tRAS = 44.0; 167 // parameter tRC = 66.0; 168 // parameter tRCD = 20.0; 169 // parameter tRP = 20.0; 170 // parameter tRRD = 15.0; 171 // parameter tWRa = 7.5; // A2 Version - Auto precharge mode only (1 Clk + 7.5 ns) 172 // parameter tWRp = 0.0; // A2 Version - Precharge mode only (15 ns) 173 174 // Timing Parameters for -7 (PC143) and CAS Latency = 3 175 parameter tAC = 6.5; //test 6.5 176 parameter tHZ = 5.5; 177 parameter tOH = 2; 178 parameter tMRD = 2.0; // 2 Clk Cycles 179 parameter tRAS = 48.0; 180 parameter tRC = 70.0; 181 parameter tRCD = 20.0; 182 parameter tRP = 20.0; 183 parameter tRRD = 14.0; 184 parameter tWRa = 7.5; // A2 Version - Auto precharge mode only (1 Clk + 7.5 ns) 185 parameter tWRp = 0.0; // A2 Version - Precharge mode only (15 ns) 186 187 // Timing Check variable 188 integer MRD_chk; 189 integer WR_counter [0 : 3]; 190 time WR_chk [0 : 3]; 191 time RC_chk, RRD_chk; 192 time RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3; 193 time RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3; 194 time RP_chk0, RP_chk1, RP_chk2, RP_chk3; 195 196 integer test_file; 197 198 //*****display the command of the sdram************************************** 199 200 parameter Mode_Reg_Set =4'b0000; 201 parameter Auto_Refresh =4'b0001; 202 parameter Row_Active =4'b0011; 203 parameter Pre_Charge =4'b0010; 204 parameter PreCharge_All =4'b0010; 205 parameter Write =4'b0100; 206 parameter Write_Pre =4'b0100; 207 parameter Read =4'b0101; 208 parameter Read_Pre =4'b0101; 209 parameter Burst_Stop =4'b0110; 210 parameter Nop =4'b0111; 211 parameter Dsel =4'b1111; 212 213 wire [3:0] sdram_control; 214 reg cke_temp; 215 reg [8*13:1] sdram_command; 216 217 always@(posedge Clk) 218 cke_temp<=Cke; 219 220 assign sdram_control={Cs_n,Ras_n,Cas_n,We_n}; 221 222 always@(sdram_control or cke_temp) 223 begin 224 case(sdram_control) 225 Mode_Reg_Set: sdram_command<="Mode_Reg_Set"; 226 Auto_Refresh: sdram_command<="Auto_Refresh"; 227 Row_Active: sdram_command<="Row_Active"; 228 Pre_Charge: sdram_command<="Pre_Charge"; 229 Burst_Stop: sdram_command<="Burst_Stop"; 230 Dsel: sdram_command<="Dsel"; 231 232 Write: if(cke_temp==1) 233 sdram_command<="Write"; 234 else 235 sdram_command<="Write_suspend"; 236 237 Read: if(cke_temp==1) 238 sdram_command<="Read"; 239 else 240 sdram_command<="Read_suspend"; 241 242 Nop: if(cke_temp==1) 243 sdram_command<="Nop"; 244 else 245 sdram_command<="Self_refresh"; 246 247 default: sdram_command<="Power_down"; 248 endcase 249 end 250 251 //***************************************************** 252 253 initial 254 begin 255 //test_file=$fopen("test_file.txt"); 256 end 257 258 initial 259 begin 260 Dq_reg = {data_bits{1'bz}}; 261 {Data_in_enable, Data_out_enable} = 0; 262 {Act_b0, Act_b1, Act_b2, Act_b3} = 4'b0000; 263 {Pc_b0, Pc_b1, Pc_b2, Pc_b3} = 4'b0000; 264 {WR_chk[0], WR_chk[1], WR_chk[2], WR_chk[3]} = 0; 265 {WR_counter[0], WR_counter[1], WR_counter[2], WR_counter[3]} = 0; 266 {RW_interrupt_read[0], RW_interrupt_read[1], RW_interrupt_read[2], RW_interrupt_read[3]} = 0; 267 {RW_interrupt_write[0], RW_interrupt_write[1], RW_interrupt_write[2], RW_interrupt_write[3]} = 0; 268 {MRD_chk, RC_chk, RRD_chk} = 0; 269 {RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3} = 0; 270 {RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3} = 0; 271 {RP_chk0, RP_chk1, RP_chk2, RP_chk3} = 0; 272 $timeformat (-9, 0, " ns", 12); 273 //$readmemh("bank0.txt", Bank0); 274 //$readmemh("bank1.txt", Bank1); 275 //$readmemh("bank2.txt", Bank2); 276 //$readmemh("bank3.txt", Bank3); 277 /* 278 for(dd=0;dd<=mem_sizes;dd=dd+1) 279 begin 280 Bank0[dd]=dd[data_bits - 1 : 0]; 281 Bank1[dd]=dd[data_bits - 1 : 0]+1; 282 Bank2[dd]=dd[data_bits - 1 : 0]+2; 283 Bank3[dd]=dd[data_bits - 1 : 0]+3; 284 end 285 */ 286 initial_sdram(0); 287 end 288 289 task initial_sdram; 290 291 input data_sign; 292 reg [3:0] data_sign; 293 294 for(dd=0;dd<=mem_sizes;dd=dd+1) 295 begin 296 mem_d = {data_sign,data_sign,data_sign,data_sign,data_sign,data_sign,data_sign,data_sign}; 297 if(data_bits==16) 298 begin 299 Bank0[dd]=mem_d[15:0]; 300 Bank1[dd]=mem_d[15:0]; 301 Bank2[dd]=mem_d[15:0]; 302 Bank3[dd]=mem_d[15:0]; 303 end 304 else if(data_bits==32) 305 begin 306 Bank0[dd]=mem_d[31:0]; 307 Bank1[dd]=mem_d[31:0]; 308 Bank2[dd]=mem_d[31:0]; 309 Bank3[dd]=mem_d[31:0]; 310 end 311 end 312 313 endtask 314 315 // System clock generator 316 always 317 begin 318 @(posedge Clk) 319 begin 320 Sys_clk = CkeZ; 321 CkeZ = Cke; 322 end 323 @(negedge Clk) 324 begin 325 Sys_clk = 1'b0; 326 end 327 end 328 329 always @ (posedge Sys_clk) begin 330 // Internal Commamd Pipelined 331 Command[0] = Command[1]; 332 Command[1] = Command[2]; 333 Command[2] = Command[3]; 334 Command[3] = `NOP; 335 336 Col_addr[0] = Col_addr[1]; 337 Col_addr[1] = Col_addr[2]; 338 Col_addr[2] = Col_addr[3]; 339 Col_addr[3] = {col_bits{1'b0}}; 340 341 Bank_addr[0] = Bank_addr[1]; 342 Bank_addr[1] = Bank_addr[2]; 343 Bank_addr[2] = Bank_addr[3]; 344 Bank_addr[3] = 2'b0; 345 346 Bank_precharge[0] = Bank_precharge[1]; 347 Bank_precharge[1] = Bank_precharge[2]; 348 Bank_precharge[2] = Bank_precharge[3]; 349 Bank_precharge[3] = 2'b0; 350 351 A10_precharge[0] = A10_precharge[1]; 352 A10_precharge[1] = A10_precharge[2]; 353 A10_precharge[2] = A10_precharge[3]; 354 A10_precharge[3] = 1'b0; 355 356 // Dqm pipeline for Read 357 Dqm_reg0 = Dqm_reg1; 358 Dqm_reg1 = Dqm; 359 360 // Read or Write with Auto Precharge Counter 361 if (Auto_precharge[0] == 1'b1) begin 362 Count_precharge[0] = Count_precharge[0] + 1; 363 end 364 if (Auto_precharge[1] == 1'b1) begin 365 Count_precharge[1] = Count_precharge[1] + 1; 366 end 367 if (Auto_precharge[2] == 1'b1) begin 368 Count_precharge[2] = Count_precharge[2] + 1; 369 end 370 if (Auto_precharge[3] == 1'b1) begin 371 Count_precharge[3] = Count_precharge[3] + 1; 372 end 373 374 // tMRD Counter 375 MRD_chk = MRD_chk + 1; 376 377 // tWR Counter for Write 378 WR_counter[0] = WR_counter[0] + 1; 379 WR_counter[1] = WR_counter[1] + 1; 380 WR_counter[2] = WR_counter[2] + 1; 381 WR_counter[3] = WR_counter[3] + 1; 382 383 // Auto Refresh 384 if (Aref_enable == 1'b1) begin 385 if (Debug) $display ("at time %t AREF : Auto Refresh", $time); 386 // Auto Refresh to Auto Refresh 387 if (($time - RC_chk < tRC)&&Debug) begin 388 $display ("at time %t ERROR: tRC violation during Auto Refresh", $time); 389 end 390 // Precharge to Auto Refresh 391 if (($time - RP_chk0 < tRP || $time - RP_chk1 < tRP || $time - RP_chk2 < tRP || $time - RP_chk3 < tRP)&&Debug) begin 392 $display ("at time %t ERROR: tRP violation during Auto Refresh", $time); 393 end 394 // Precharge to Refresh 395 if (Pc_b0 == 1'b0 || Pc_b1 == 1'b0 || Pc_b2 == 1'b0 || Pc_b3 == 1'b0) begin 396 $display ("at time %t ERROR: All banks must be Precharge before Auto Refresh", $time); 397 end 398 // Record Current tRC time 399 RC_chk = $time; 400 end 401 402 // Load Mode Register 403 if (Mode_reg_enable == 1'b1) begin 404 // Decode CAS Latency, Burst Length, Burst Type, and Write Burst Mode 405 if (Pc_b0 == 1'b1 && Pc_b1 == 1'b1 && Pc_b2 == 1'b1 && Pc_b3 == 1'b1) begin 406 Mode_reg = Addr; 407 if (Debug) begin 408 $display ("at time %t LMR : Load Mode Register", $time); 409 // CAS Latency 410 if (Addr[6 : 4] == 3'b010) 411 $display (" CAS Latency = 2"); 412 else if (Addr[6 : 4] == 3'b011) 413 $display (" CAS Latency = 3"); 414 else 415 $display (" CAS Latency = Reserved"); 416 // Burst Length 417 if (Addr[2 : 0] == 3'b000) 418 $display (" Burst Length = 1"); 419 else if (Addr[2 : 0] == 3'b001) 420 $display (" Burst Length = 2"); 421 else if (Addr[2 : 0] == 3'b010) 422 $display (" Burst Length = 4"); 423 else if (Addr[2 : 0] == 3'b011) 424 $display (" Burst Length = 8"); 425 else if (Addr[3 : 0] == 4'b0111) 426 $display (" Burst Length = Full"); 427 else 428 $display (" Burst Length = Reserved"); 429 // Burst Type 430 if (Addr[3] == 1'b0) 431 $display (" Burst Type = Sequential"); 432 else if (Addr[3] == 1'b1) 433 $display (" Burst Type = Interleaved"); 434 else 435 $display (" Burst Type = Reserved"); 436 // Write Burst Mode 437 if (Addr[9] == 1'b0) 438 $display (" Write Burst Mode = Programmed Burst Length"); 439 else if (Addr[9] == 1'b1) 440 $display (" Write Burst Mode = Single Location Access"); 441 else 442 $display (" Write Burst Mode = Reserved"); 443 end 444 end else begin 445 $display ("at time %t ERROR: all banks must be Precharge before Load Mode Register", $time); 446 end 447 // REF to LMR 448 if ($time - RC_chk < tRC) begin 449 $display ("at time %t ERROR: tRC violation during Load Mode Register", $time); 450 end 451 // LMR to LMR 452 if (MRD_chk < tMRD) begin 453 $display ("at time %t ERROR: tMRD violation during Load Mode Register", $time); 454 end 455 MRD_chk = 0; 456 end 457 458 // Active Block (Latch Bank Address and Row Address) 459 if (Active_enable == 1'b1) begin 460 if (Ba == 2'b00 && Pc_b0 == 1'b1) begin 461 {Act_b0, Pc_b0} = 2'b10; 462 B0_row_addr = Addr [addr_bits - 1 : 0]; 463 RCD_chk0 = $time; 464 RAS_chk0 = $time; 465 if (Debug) $display ("at time %t ACT : Bank = 0 Row = %d", $time, Addr); 466 // Precharge to Activate Bank 0 467 if ($time - RP_chk0 < tRP) begin 468 $display ("at time %t ERROR: tRP violation during Activate bank 0", $time); 469 end 470 end else if (Ba == 2'b01 && Pc_b1 == 1'b1) begin 471 {Act_b1, Pc_b1} = 2'b10; 472 B1_row_addr = Addr [addr_bits - 1 : 0]; 473 RCD_chk1 = $time; 474 RAS_chk1 = $time; 475 if (Debug) $display ("at time %t ACT : Bank = 1 Row = %d", $time, Addr); 476 // Precharge to Activate Bank 1 477 if ($time - RP_chk1 < tRP) begin 478 $display ("at time %t ERROR: tRP violation during Activate bank 1", $time); 479 end 480 end else if (Ba == 2'b10 && Pc_b2 == 1'b1) begin 481 {Act_b2, Pc_b2} = 2'b10; 482 B2_row_addr = Addr [addr_bits - 1 : 0]; 483 RCD_chk2 = $time; 484 RAS_chk2 = $time; 485 if (Debug) $display ("at time %t ACT : Bank = 2 Row = %d", $time, Addr); 486 // Precharge to Activate Bank 2 487 if ($time - RP_chk2 < tRP) begin 488 $display ("at time %t ERROR: tRP violation during Activate bank 2", $time); 489 end 490 end else if (Ba == 2'b11 && Pc_b3 == 1'b1) begin 491 {Act_b3, Pc_b3} = 2'b10; 492 B3_row_addr = Addr [addr_bits - 1 : 0]; 493 RCD_chk3 = $time; 494 RAS_chk3 = $time; 495 if (Debug) $display ("at time %t ACT : Bank = 3 Row = %d", $time, Addr); 496 // Precharge to Activate Bank 3 497 if ($time - RP_chk3 < tRP) begin 498 $display ("at time %t ERROR: tRP violation during Activate bank 3", $time); 499 end 500 end else if (Ba == 2'b00 && Pc_b0 == 1'b0) begin 501 $display ("at time %t ERROR: Bank 0 is not Precharged.", $time); 502 end else if (Ba == 2'b01 && Pc_b1 == 1'b0) begin 503 $display ("at time %t ERROR: Bank 1 is not Precharged.", $time); 504 end else if (Ba == 2'b10 && Pc_b2 == 1'b0) begin 505 $display ("at time %t ERROR: Bank 2 is not Precharged.", $time); 506 end else if (Ba == 2'b11 && Pc_b3 == 1'b0) begin 507 $display ("at time %t ERROR: Bank 3 is not Precharged.", $time); 508 end 509 // Active Bank A to Active Bank B 510 if ((Previous_bank != Ba) && ($time - RRD_chk < tRRD)) begin 511 $display ("at time %t ERROR: tRRD violation during Activate bank = %d", $time, Ba); 512 end 513 // Load Mode Register to Active 514 if (MRD_chk < tMRD ) begin 515 $display ("at time %t ERROR: tMRD violation during Activate bank = %d", $time, Ba); 516 end 517 // Auto Refresh to Activate 518 if (($time - RC_chk < tRC)&&Debug) begin 519 $display ("at time %t ERROR: tRC violation during Activate bank = %d", $time, Ba); 520 end 521 // Record variables for checking violation 522 RRD_chk = $time; 523 Previous_bank = Ba; 524 end 525 526 // Precharge Block 527 if (Prech_enable == 1'b1) begin 528 if (Addr[10] == 1'b1) begin 529 {Pc_b0, Pc_b1, Pc_b2, Pc_b3} = 4'b1111; 530 {Act_b0, Act_b1, Act_b2, Act_b3} = 4'b0000; 531 RP_chk0 = $time; 532 RP_chk1 = $time; 533 RP_chk2 = $time; 534 RP_chk3 = $time; 535 if (Debug) $display ("at time %t PRE : Bank = ALL",$time); 536 // Activate to Precharge all banks 537 if (($time - RAS_chk0 < tRAS) || ($time - RAS_chk1 < tRAS) || 538 ($time - RAS_chk2 < tRAS) || ($time - RAS_chk3 < tRAS)) begin 539 $display ("at time %t ERROR: tRAS violation during Precharge all bank", $time); 540 end 541 // tWR violation check for write 542 if (($time - WR_chk[0] < tWRp) || ($time - WR_chk[1] < tWRp) || 543 ($time - WR_chk[2] < tWRp) || ($time - WR_chk[3] < tWRp)) begin 544 $display ("at time %t ERROR: tWR violation during Precharge all bank", $time); 545 end 546 end else if (Addr[10] == 1'b0) begin 547 if (Ba == 2'b00) begin 548 {Pc_b0, Act_b0} = 2'b10; 549 RP_chk0 = $time; 550 if (Debug) $display ("at time %t PRE : Bank = 0",$time); 551 // Activate to Precharge Bank 0 552 if ($time - RAS_chk0 < tRAS) begin 553 $display ("at time %t ERROR: tRAS violation during Precharge bank 0", $time); 554 end 555 end else if (Ba == 2'b01) begin 556 {Pc_b1, Act_b1} = 2'b10; 557 RP_chk1 = $time; 558 if (Debug) $display ("at time %t PRE : Bank = 1",$time); 559 // Activate to Precharge Bank 1 560 if ($time - RAS_chk1 < tRAS) begin 561 $display ("at time %t ERROR: tRAS violation during Precharge bank 1", $time); 562 end 563 end else if (Ba == 2'b10) begin 564 {Pc_b2, Act_b2} = 2'b10; 565 RP_chk2 = $time; 566 if (Debug) $display ("at time %t PRE : Bank = 2",$time); 567 // Activate to Precharge Bank 2 568 if ($time - RAS_chk2 < tRAS) begin 569 $display ("at time %t ERROR: tRAS violation during Precharge bank 2", $time); 570 end 571 end else if (Ba == 2'b11) begin 572 {Pc_b3, Act_b3} = 2'b10; 573 RP_chk3 = $time; 574 if (Debug) $display ("at time %t PRE : Bank = 3",$time); 575 // Activate to Precharge Bank 3 576 if ($time - RAS_chk3 < tRAS) begin 577 $display ("at time %t ERROR: tRAS violation during Precharge bank 3", $time); 578 end 579 end 580 // tWR violation check for write 581 if ($time - WR_chk[Ba] < tWRp) begin 582 $display ("at time %t ERROR: tWR violation during Precharge bank %d", $time, Ba); 583 end 584 end 585 // Terminate a Write Immediately (if same bank or all banks) 586 if (Data_in_enable == 1'b1 && (Bank == Ba || Addr[10] == 1'b1)) begin 587 Data_in_enable = 1'b0; 588 end 589 // Precharge Command Pipeline for Read 590 if (Cas_latency_3 == 1'b1) begin 591 Command[2] = `PRECH; 592 Bank_precharge[2] = Ba; 593 A10_precharge[2] = Addr[10]; 594 end else if (Cas_latency_2 == 1'b1) begin 595 Command[1] = `PRECH; 596 Bank_precharge[1] = Ba; 597 A10_precharge[1] = Addr[10]; 598 end 599 end 600 601 // Burst terminate 602 if (Burst_term == 1'b1) begin 603 // Terminate a Write Immediately 604 if (Data_in_enable == 1'b1) begin 605 Data_in_enable = 1'b0; 606 end 607 // Terminate a Read Depend on CAS Latency 608 if (Cas_latency_3 == 1'b1) begin 609 Command[2] = `BST; 610 end else if (Cas_latency_2 == 1'b1) begin 611 Command[1] = `BST; 612 end 613 if (Debug) $display ("at time %t BST : Burst Terminate",$time); 614 end 615 616 // Read, Write, Column Latch 617 if (Read_enable == 1'b1 || Write_enable == 1'b1) begin 618 // Check to see if bank is open (ACT) 619 if ((Ba == 2'b00 && Pc_b0 == 1'b1) || (Ba == 2'b01 && Pc_b1 == 1'b1) || 620 (Ba == 2'b10 && Pc_b2 == 1'b1) || (Ba == 2'b11 && Pc_b3 == 1'b1)) begin 621 $display("at time %t ERROR: Cannot Read or Write - Bank %d is not Activated", $time, Ba); 622 end 623 // Activate to Read or Write 624 if ((Ba == 2'b00) && ($time - RCD_chk0 < tRCD)) 625 $display("at time %t ERROR: tRCD violation during Read or Write to Bank 0", $time); 626 if ((Ba == 2'b01) && ($time - RCD_chk1 < tRCD)) 627 $display("at time %t ERROR: tRCD violation during Read or Write to Bank 1", $time); 628 if ((Ba == 2'b10) && ($time - RCD_chk2 < tRCD)) 629 $display("at time %t ERROR: tRCD violation during Read or Write to Bank 2", $time); 630 if ((Ba == 2'b11) && ($time - RCD_chk3 < tRCD)) 631 $display("at time %t ERROR: tRCD violation during Read or Write to Bank 3", $time); 632 // Read Command 633 if (Read_enable == 1'b1) begin 634 // CAS Latency pipeline 635 if (Cas_latency_3 == 1'b1) begin 636 if (Addr[10] == 1'b1) begin 637 Command[2] = `READ_A; 638 end else begin 639 Command[2] = `READ; 640 end 641 Col_addr[2] = Addr; 642 Bank_addr[2] = Ba; 643 end else if (Cas_latency_2 == 1'b1) begin 644 if (Addr[10] == 1'b1) begin 645 Command[1] = `READ_A; 646 end else begin 647 Command[1] = `READ; 648 end 649 Col_addr[1] = Addr; 650 Bank_addr[1] = Ba; 651 end 652 653 // Read interrupt Write (terminate Write immediately) 654 if (Data_in_enable == 1'b1) begin 655 Data_in_enable = 1'b0; 656 end 657 658 // Write Command 659 end else if (Write_enable == 1'b1) begin 660 if (Addr[10] == 1'b1) begin 661 Command[0] = `WRITE_A; 662 end else begin 663 Command[0] = `WRITE; 664 end 665 Col_addr[0] = Addr; 666 Bank_addr[0] = Ba; 667 668 // Write interrupt Write (terminate Write immediately) 669 if (Data_in_enable == 1'b1) begin 670 Data_in_enable = 1'b0; 671 end 672 673 // Write interrupt Read (terminate Read immediately) 674 if (Data_out_enable == 1'b1) begin 675 Data_out_enable = 1'b0; 676 end 677 end 678 679 // Interrupting a Write with Autoprecharge 680 if (Auto_precharge[Bank] == 1'b1 && Write_precharge[Bank] == 1'b1) begin 681 RW_interrupt_write[Bank] = 1'b1; 682 if (Debug) $display ("at time %t NOTE : Read/Write Bank %d interrupt Write Bank %d with Autoprecharge", $time, Ba, Bank); 683 end 684 685 // Interrupting a Read with Autoprecharge 686 if (Auto_precharge[Bank] == 1'b1 && Read_precharge[Bank] == 1'b1) begin 687 RW_interrupt_read[Bank] = 1'b1; 688 if (Debug) $display ("at time %t NOTE : Read/Write Bank %d interrupt Read Bank %d with Autoprecharge", $time, Ba, Bank); 689 end 690 691 // Read or Write with Auto Precharge 692 if (Addr[10] == 1'b1) begin 693 Auto_precharge[Ba] = 1'b1; 694 Count_precharge[Ba] = 0; 695 if (Read_enable == 1'b1) begin 696 Read_precharge[Ba] = 1'b1; 697 end else if (Write_enable == 1'b1) begin 698 Write_precharge[Ba] = 1'b1; 699 end 700 end 701 end 702 703 // Read with Auto Precharge Calculation 704 // The device start internal precharge: 705 // 1. CAS Latency - 1 cycles before last burst 706 // and 2. Meet minimum tRAS requirement 707 // or 3. Interrupt by a Read or Write (with or without AutoPrecharge) 708 if ((Auto_precharge[0] == 1'b1) && (Read_precharge[0] == 1'b1)) begin 709 if ((($time - RAS_chk0 >= tRAS) && // Case 2 710 ((Burst_length_1 == 1'b1 && Count_precharge[0] >= 1) || // Case 1 711 (Burst_length_2 == 1'b1 && Count_precharge[0] >= 2) || 712 (Burst_length_4 == 1'b1 && Count_precharge[0] >= 4) || 713 (Burst_length_8 == 1'b1 && Count_precharge[0] >= 8))) || 714 (RW_interrupt_read[0] == 1'b1)) begin // Case 3 715 Pc_b0 = 1'b1; 716 Act_b0 = 1'b0; 717 RP_chk0 = $time; 718 Auto_precharge[0] = 1'b0; 719 Read_precharge[0] = 1'b0; 720 RW_interrupt_read[0] = 1'b0; 721 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 0", $time); 722 end 723 end 724 if ((Auto_precharge[1] == 1'b1) && (Read_precharge[1] == 1'b1)) begin 725 if ((($time - RAS_chk1 >= tRAS) && 726 ((Burst_length_1 == 1'b1 && Count_precharge[1] >= 1) || 727 (Burst_length_2 == 1'b1 && Count_precharge[1] >= 2) || 728 (Burst_length_4 == 1'b1 && Count_precharge[1] >= 4) || 729 (Burst_length_8 == 1'b1 && Count_precharge[1] >= 8))) || 730 (RW_interrupt_read[1] == 1'b1)) begin 731 Pc_b1 = 1'b1; 732 Act_b1 = 1'b0; 733 RP_chk1 = $time; 734 Auto_precharge[1] = 1'b0; 735 Read_precharge[1] = 1'b0; 736 RW_interrupt_read[1] = 1'b0; 737 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 1", $time); 738 end 739 end 740 if ((Auto_precharge[2] == 1'b1) && (Read_precharge[2] == 1'b1)) begin 741 if ((($time - RAS_chk2 >= tRAS) && 742 ((Burst_length_1 == 1'b1 && Count_precharge[2] >= 1) || 743 (Burst_length_2 == 1'b1 && Count_precharge[2] >= 2) || 744 (Burst_length_4 == 1'b1 && Count_precharge[2] >= 4) || 745 (Burst_length_8 == 1'b1 && Count_precharge[2] >= 8))) || 746 (RW_interrupt_read[2] == 1'b1)) begin 747 Pc_b2 = 1'b1; 748 Act_b2 = 1'b0; 749 RP_chk2 = $time; 750 Auto_precharge[2] = 1'b0; 751 Read_precharge[2] = 1'b0; 752 RW_interrupt_read[2] = 1'b0; 753 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 2", $time); 754 end 755 end 756 if ((Auto_precharge[3] == 1'b1) && (Read_precharge[3] == 1'b1)) begin 757 if ((($time - RAS_chk3 >= tRAS) && 758 ((Burst_length_1 == 1'b1 && Count_precharge[3] >= 1) || 759 (Burst_length_2 == 1'b1 && Count_precharge[3] >= 2) || 760 (Burst_length_4 == 1'b1 && Count_precharge[3] >= 4) || 761 (Burst_length_8 == 1'b1 && Count_precharge[3] >= 8))) || 762 (RW_interrupt_read[3] == 1'b1)) begin 763 Pc_b3 = 1'b1; 764 Act_b3 = 1'b0; 765 RP_chk3 = $time; 766 Auto_precharge[3] = 1'b0; 767 Read_precharge[3] = 1'b0; 768 RW_interrupt_read[3] = 1'b0; 769 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 3", $time); 770 end 771 end 772 773 // Internal Precharge or Bst 774 if (Command[0] == `PRECH) begin // Precharge terminate a read with same bank or all banks 775 if (Bank_precharge[0] == Bank || A10_precharge[0] == 1'b1) begin 776 if (Data_out_enable == 1'b1) begin 777 Data_out_enable = 1'b0; 778 end 779 end 780 end else if (Command[0] == `BST) begin // BST terminate a read to current bank 781 if (Data_out_enable == 1'b1) begin 782 Data_out_enable = 1'b0; 783 end 784 end 785 786 if (Data_out_enable == 1'b0) begin 787 Dq_reg <= #tOH {data_bits{1'bz}}; 788 end 789 790 // Detect Read or Write command 791 if (Command[0] == `READ || Command[0] == `READ_A) begin 792 Bank = Bank_addr[0]; 793 Col = Col_addr[0]; 794 Col_brst = Col_addr[0]; 795 if (Bank_addr[0] == 2'b00) begin 796 Row = B0_row_addr; 797 end else if (Bank_addr[0] == 2'b01) begin 798 Row = B1_row_addr; 799 end else if (Bank_addr[0] == 2'b10) begin 800 Row = B2_row_addr; 801 end else if (Bank_addr[0] == 2'b11) begin 802 Row = B3_row_addr; 803 end 804 Burst_counter = 0; 805 Data_in_enable = 1'b0; 806 Data_out_enable = 1'b1; 807 end else if (Command[0] == `WRITE || Command[0] == `WRITE_A) begin 808 Bank = Bank_addr[0]; 809 Col = Col_addr[0]; 810 Col_brst = Col_addr[0]; 811 if (Bank_addr[0] == 2'b00) begin 812 Row = B0_row_addr; 813 end else if (Bank_addr[0] == 2'b01) begin 814 Row = B1_row_addr; 815 end else if (Bank_addr[0] == 2'b10) begin 816 Row = B2_row_addr; 817 end else if (Bank_addr[0] == 2'b11) begin 818 Row = B3_row_addr; 819 end 820 Burst_counter = 0; 821 Data_in_enable = 1'b1; 822 Data_out_enable = 1'b0; 823 end 824 825 // DQ buffer (Driver/Receiver) 826 if (Data_in_enable == 1'b1) begin // Writing Data to Memory 827 // Array buffer 828 if (Bank == 2'b00) Dq_dqm [data_bits - 1 : 0] = Bank0 [{Row, Col}]; 829 if (Bank == 2'b01) Dq_dqm [data_bits - 1 : 0] = Bank1 [{Row, Col}]; 830 if (Bank == 2'b10) Dq_dqm [data_bits - 1 : 0] = Bank2 [{Row, Col}]; 831 if (Bank == 2'b11) Dq_dqm [data_bits - 1 : 0] = Bank3 [{Row, Col}]; 832 // Dqm operation 833 if (Dqm[0] == 1'b0) Dq_dqm [ 7 : 0] = Dq [ 7 : 0]; 834 if (Dqm[1] == 1'b0) Dq_dqm [15 : 8] = Dq [15 : 8]; 835 //if (Dqm[2] == 1'b0) Dq_dqm [23 : 16] = Dq [23 : 16]; 836 // if (Dqm[3] == 1'b0) Dq_dqm [31 : 24] = Dq [31 : 24]; 837 // Write to memory 838 if (Bank == 2'b00) Bank0 [{Row, Col}] = Dq_dqm [data_bits - 1 : 0]; 839 if (Bank == 2'b01) Bank1 [{Row, Col}] = Dq_dqm [data_bits - 1 : 0]; 840 if (Bank == 2'b10) Bank2 [{Row, Col}] = Dq_dqm [data_bits - 1 : 0]; 841 if (Bank == 2'b11) Bank3 [{Row, Col}] = Dq_dqm [data_bits - 1 : 0]; 842 if (Bank == 2'b11 && Row==10'h3 && Col[7:4]==4'h4) 843 $display("at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col); 844 //$fdisplay(test_file,"bank:%h row:%h col:%h write:%h",Bank,Row,Col,Dq_dqm); 845 // Output result 846 if (Dqm == 4'b1111) begin 847 if (Debug) $display("at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col); 848 end else begin 849 if (Debug) $display("at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = %d, Dqm = %b", $time, Bank, Row, Col, Dq_dqm, Dqm); 850 // Record tWR time and reset counter 851 WR_chk [Bank] = $time; 852 WR_counter [Bank] = 0; 853 end 854 // Advance burst counter subroutine 855 #tHZ Burst; 856 end else if (Data_out_enable == 1'b1) begin // Reading Data from Memory 857 //$display("%h , %h, %h",Bank0,Row,Col); 858 // Array buffer 859 if (Bank == 2'b00) Dq_dqm [data_bits - 1 : 0] = Bank0 [{Row, Col}]; 860 if (Bank == 2'b01) Dq_dqm [data_bits - 1 : 0] = Bank1 [{Row, Col}]; 861 if (Bank == 2'b10) Dq_dqm [data_bits - 1 : 0] = Bank2 [{Row, Col}]; 862 if (Bank == 2'b11) Dq_dqm [data_bits - 1 : 0] = Bank3 [{Row, Col}]; 863 864 // Dqm operation 865 if (Dqm_reg0[0] == 1'b1) Dq_dqm [ 7 : 0] = 8'bz; 866 if (Dqm_reg0[1] == 1'b1) Dq_dqm [15 : 8] = 8'bz; 867 if (Dqm_reg0[2] == 1'b1) Dq_dqm [23 : 16] = 8'bz; 868 if (Dqm_reg0[3] == 1'b1) Dq_dqm [31 : 24] = 8'bz; 869 // Display result 870 Dq_reg [data_bits - 1 : 0] = #tAC Dq_dqm [data_bits - 1 : 0]; 871 if (Dqm_reg0 == 4'b1111) begin 872 if (Debug) $display("at time %t READ : Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col); 873 end else begin 874 if (Debug) $display("at time %t READ : Bank = %d Row = %d, Col = %d, Data = %d, Dqm = %b", $time, Bank, Row, Col, Dq_reg, Dqm_reg0); 875 end 876 // Advance burst counter subroutine 877 Burst; 878 end 879 end 880 881 // Write with Auto Precharge Calculation 882 // The device start internal precharge: 883 // 1. tWR Clock after last burst 884 // and 2. Meet minimum tRAS requirement 885 // or 3. Interrupt by a Read or Write (with or without AutoPrecharge) 886 always @ (WR_counter[0]) begin 887 if ((Auto_precharge[0] == 1'b1) && (Write_precharge[0] == 1'b1)) begin 888 if ((($time - RAS_chk0 >= tRAS) && // Case 2 889 (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [0] >= 1) || // Case 1 890 (Burst_length_2 == 1'b1 && Count_precharge [0] >= 2) || 891 (Burst_length_4 == 1'b1 && Count_precharge [0] >= 4) || 892 (Burst_length_8 == 1'b1 && Count_precharge [0] >= 8))) || 893 (RW_interrupt_write[0] == 1'b1 && WR_counter[0] >= 2)) begin // Case 3 (stop count when interrupt) 894 Auto_precharge[0] = 1'b0; 895 Write_precharge[0] = 1'b0; 896 RW_interrupt_write[0] = 1'b0; 897 #tWRa; // Wait for tWR 898 Pc_b0 = 1'b1; 899 Act_b0 = 1'b0; 900 RP_chk0 = $time; 901 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 0", $time); 902 end 903 end 904 end 905 always @ (WR_counter[1]) begin 906 if ((Auto_precharge[1] == 1'b1) && (Write_precharge[1] == 1'b1)) begin 907 if ((($time - RAS_chk1 >= tRAS) && 908 (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [1] >= 1) || 909 (Burst_length_2 == 1'b1 && Count_precharge [1] >= 2) || 910 (Burst_length_4 == 1'b1 && Count_precharge [1] >= 4) || 911 (Burst_length_8 == 1'b1 && Count_precharge [1] >= 8))) || 912 (RW_interrupt_write[1] == 1'b1 && WR_counter[1] >= 2)) begin 913 Auto_precharge[1] = 1'b0; 914 Write_precharge[1] = 1'b0; 915 RW_interrupt_write[1] = 1'b0; 916 #tWRa; // Wait for tWR 917 Pc_b1 = 1'b1; 918 Act_b1 = 1'b0; 919 RP_chk1 = $time; 920 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 1", $time); 921 end 922 end 923 end 924 always @ (WR_counter[2]) begin 925 if ((Auto_precharge[2] == 1'b1) && (Write_precharge[2] == 1'b1)) begin 926 if ((($time - RAS_chk2 >= tRAS) && 927 (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [2] >= 1) || 928 (Burst_length_2 == 1'b1 && Count_precharge [2] >= 2) || 929 (Burst_length_4 == 1'b1 && Count_precharge [2] >= 4) || 930 (Burst_length_8 == 1'b1 && Count_precharge [2] >= 8))) || 931 (RW_interrupt_write[2] == 1'b1 && WR_counter[2] >= 2)) begin 932 Auto_precharge[2] = 1'b0; 933 Write_precharge[2] = 1'b0; 934 RW_interrupt_write[2] = 1'b0; 935 #tWRa; // Wait for tWR 936 Pc_b2 = 1'b1; 937 Act_b2 = 1'b0; 938 RP_chk2 = $time; 939 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 2", $time); 940 end 941 end 942 end 943 always @ (WR_counter[3]) begin 944 if ((Auto_precharge[3] == 1'b1) && (Write_precharge[3] == 1'b1)) begin 945 if ((($time - RAS_chk3 >= tRAS) && 946 (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [3] >= 1) || 947 (Burst_length_2 == 1'b1 && Count_precharge [3] >= 2) || 948 (Burst_length_4 == 1'b1 && Count_precharge [3] >= 4) || 949 (Burst_length_8 == 1'b1 && Count_precharge [3] >= 8))) || 950 (RW_interrupt_write[3] == 1'b1 && WR_counter[3] >= 2)) begin 951 Auto_precharge[3] = 1'b0; 952 Write_precharge[3] = 1'b0; 953 RW_interrupt_write[3] = 1'b0; 954 #tWRa; // Wait for tWR 955 Pc_b3 = 1'b1; 956 Act_b3 = 1'b0; 957 RP_chk3 = $time; 958 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 3", $time); 959 end 960 end 961 end 962 963 task Burst; 964 begin 965 // Advance Burst Counter 966 Burst_counter = Burst_counter + 1; 967 968 // Burst Type 969 if (Mode_reg[3] == 1'b0) begin // Sequential Burst 970 Col_temp = Col + 1; 971 end else if (Mode_reg[3] == 1'b1) begin // Interleaved Burst 972 Col_temp[2] = Burst_counter[2] ^ Col_brst[2]; 973 Col_temp[1] = Burst_counter[1] ^ Col_brst[1]; 974 Col_temp[0] = Burst_counter[0] ^ Col_brst[0]; 975 end 976 977 // Burst Length 978 if (Burst_length_2) begin // Burst Length = 2 979 Col [0] = Col_temp [0]; 980 end else if (Burst_length_4) begin // Burst Length = 4 981 Col [1 : 0] = Col_temp [1 : 0]; 982 end else if (Burst_length_8) begin // Burst Length = 8 983 Col [2 : 0] = Col_temp [2 : 0]; 984 end else begin // Burst Length = FULL 985 Col = Col_temp; 986 end 987 988 // Burst Read Single Write 989 if (Write_burst_mode == 1'b1) begin 990 Data_in_enable = 1'b0; 991 end 992 993 // Data Counter 994 if (Burst_length_1 == 1'b1) begin 995 if (Burst_counter >= 1) begin 996 Data_in_enable = 1'b0; 997 Data_out_enable = 1'b0; 998 end 999 end else if (Burst_length_2 == 1'b1) begin 1000 if (Burst_counter >= 2) begin 1001 Data_in_enable = 1'b0; 1002 Data_out_enable = 1'b0; 1003 end 1004 end else if (Burst_length_4 == 1'b1) begin 1005 if (Burst_counter >= 4) begin 1006 Data_in_enable = 1'b0; 1007 Data_out_enable = 1'b0; 1008 end 1009 end else if (Burst_length_8 == 1'b1) begin 1010 if (Burst_counter >= 8) begin 1011 Data_in_enable = 1'b0; 1012 Data_out_enable = 1'b0; 1013 end 1014 end 1015 end 1016 endtask 1017 1018 //**********************将SDRAM内的数据直接输出到外部文件*******************************// 1019 1020 /* 1021 integer sdram_data,ind; 1022 1023 1024 always@(sdram_r) 1025 begin 1026 sdram_data=$fopen("sdram_data.txt"); 1027 $display("Sdram dampout begin ",sdram_data); 1028 // $fdisplay(sdram_data,"Bank0:"); 1029 for(ind=0;ind<=mem_sizes;ind=ind+1) 1030 $fdisplay(sdram_data,"%h %b",ind,Bank0[ind]); 1031 // $fdisplay(sdram_data,"Bank1:"); 1032 for(ind=0;ind<=mem_sizes;ind=ind+1) 1033 $fdisplay(sdram_data,"%h %b",ind,Bank1[ind]); 1034 // $fdisplay(sdram_data,"Bank2:"); 1035 for(ind=0;ind<=mem_sizes;ind=ind+1) 1036 $fdisplay(sdram_data,"%h %b",ind,Bank2[ind]); 1037 // $fdisplay(sdram_data,"Bank3:"); 1038 for(ind=0;ind<=mem_sizes;ind=ind+1) 1039 $fdisplay(sdram_data,"%h %b",ind,Bank3[ind]); 1040 1041 $fclose("sdram_data.txt"); 1042 //->compare; 1043 end 1044 */ 1045 integer sdram_data,sdram_mem; 1046 reg [24:0] aa,cc; 1047 reg [24:0] bb,ee; 1048 1049 always@(sdram_r) 1050 begin 1051 $display("Sdram dampout begin ",$realtime); 1052 sdram_data=$fopen("sdram_data.txt"); 1053 for(aa=0;aa<4*(mem_sizes+1);aa=aa+1) 1054 begin 1055 bb=aa[18:0]; 1056 if(aa<=mem_sizes) 1057 $fdisplay(sdram_data,"%0d %0h",aa,Bank0[bb]); 1058 else if(aa<=2*mem_sizes+1) 1059 $fdisplay(sdram_data,"%0d %0h",aa,Bank1[bb]); 1060 else if(aa<=3*mem_sizes+2) 1061 $fdisplay(sdram_data,"%0d %0h",aa,Bank2[bb]); 1062 else 1063 $fdisplay(sdram_data,"%0d %0h",aa,Bank3[bb]); 1064 end 1065 $fclose("sdram_data.txt"); 1066 1067 sdram_mem=$fopen("sdram_mem.txt"); 1068 for(cc=0;cc<4*(mem_sizes+1);cc=cc+1) 1069 begin 1070 ee=cc[18:0]; 1071 if(cc<=mem_sizes) 1072 $fdisplay(sdram_mem,"%0h",Bank0[ee]); 1073 else if(cc<=2*mem_sizes+1) 1074 $fdisplay(sdram_mem,"%0h",Bank1[ee]); 1075 else if(cc<=3*mem_sizes+2) 1076 $fdisplay(sdram_mem,"%0h",Bank2[ee]); 1077 else 1078 $fdisplay(sdram_mem,"%0h",Bank3[ee]); 1079 end 1080 $fclose("sdram_mem.txt"); 1081 1082 end 1083 1084 1085 1086 // // Timing Parameters for -75 (PC133) and CAS Latency = 2 1087 // specify 1088 // specparam 1089 //// tAH = 0.8, // Addr, Ba Hold Time 1090 //// tAS = 1.5, // Addr, Ba Setup Time 1091 //// tCH = 2.5, // Clock High-Level Width 1092 //// tCL = 2.5, // Clock Low-Level Width 1093 // tCK = 10.0, // Clock Cycle Time 100mhz 1094 // tCK = 7.5, // Clock Cycle Time 133mhz 1095 //// tCK = 7, // Clock Cycle Time 143mhz 1096 //// tDH = 0.8, // Data-in Hold Time 1097 //// tDS = 1.5, // Data-in Setup Time 1098 //// tCKH = 0.8, // CKE Hold Time 1099 //// tCKS = 1.5, // CKE Setup Time 1100 //// tCMH = 0.8, // CS#, RAS#, CAS#, WE#, DQM# Hold Time 1101 //// tCMS = 1.5; // CS#, RAS#, CAS#, WE#, DQM# Setup Time 1102 // tAH = 1, // Addr, Ba Hold Time 1103 // tAS = 1.5, // Addr, Ba Setup Time 1104 // tCH = 1, // Clock High-Level Width 1105 // tCL = 3, // Clock Low-Level Width 1106 //// tCK = 10.0, // Clock Cycle Time 100mhz 1107 //// tCK = 7.5, // Clock Cycle Time 133mhz 1108 // tCK = 7, // Clock Cycle Time 143mhz 1109 // tDH = 1, // Data-in Hold Time 1110 // tDS = 2, // Data-in Setup Time 1111 // tCKH = 1, // CKE Hold Time 1112 // tCKS = 2, // CKE Setup Time 1113 // tCMH = 0.8, // CS#, RAS#, CAS#, WE#, DQM# Hold Time 1114 // tCMS = 1.5; // CS#, RAS#, CAS#, WE#, DQM# Setup Time 1115 // $width (posedge Clk, tCH); 1116 // $width (negedge Clk, tCL); 1117 // $period (negedge Clk, tCK); 1118 // $period (posedge Clk, tCK); 1119 // $setuphold(posedge Clk, Cke, tCKS, tCKH); 1120 // $setuphold(posedge Clk, Cs_n, tCMS, tCMH); 1121 // $setuphold(posedge Clk, Cas_n, tCMS, tCMH); 1122 // $setuphold(posedge Clk, Ras_n, tCMS, tCMH); 1123 // $setuphold(posedge Clk, We_n, tCMS, tCMH); 1124 // $setuphold(posedge Clk, Addr, tAS, tAH); 1125 // $setuphold(posedge Clk, Ba, tAS, tAH); 1126 // $setuphold(posedge Clk, Dqm, tCMS, tCMH); 1127 // $setuphold(posedge Dq_chk, Dq, tDS, tDH); 1128 // endspecify 1129 1130 endmodule
7.最后附上仿真结果
打印信息,简单明了,这是我喜欢的风格
再来看看波形吧
完美,忙活了一天有些坑真的自己填,因为每填完一个坑,起身更强大,明天继续
2018/730
今天继续更新,有很多事耽搁了两天
二.仲裁机制和刷新操作
1.刷新操作是sdram必须的操作,使用不当数据指定丢失,具体为什么自己去查一下,我省的废话了。
既然是刷新,那么就应该有刷新的周期,这个怎么计算呢,打开datasheet,看图。红框意思是64ms内要进行8192次刷新,那么刷新周期大约7.8us
2.该刷新时序以及命令了
看下面的时序图等初始化完成后,刷新操作的第一步就是预充电(precharge),然后等tRP时间进行auto refresh(自刷新),后面再一次刷新和active都不用进行。前面哪个时间自己对应手册查一下,一般不会有错
这儿提一下,在预充电的时候,地址引脚要同时进行操作,A0~A9、A11、A12不用管,只对A10进行操作,如果A10位1,就是对所有bank进行充电,为0时选择bank进行充电,我们是为1。
3.刷新就说完了,该附上源代码了
1 module sdram_aref( 2 //system signals 3 input sclk , 4 input s_rst_n , 5 //comunicat with ARBIT 6 input ref_en , 7 output wire ref_req , 8 output wire flag_ref_end , 9 //others 10 output reg [3:0] aref_cmd , 11 output wire [12:0] sdram_addr , 12 input flag_init_end 13 ); 14 15 //==============================================================================\ 16 //*********************Define Parameter and Internal Signal ******************** 17 //==============================================================================/ 18 localparam DELAY_78us = 390 ; 19 localparam CMD_AREF = 4'b0001 ; 20 localparam CMD_NOP = 4'b0111 ; 21 localparam CMD_PRE = 4'b0010 ; 22 reg [3:0] cmd_cnt ; 23 reg [8:0] ref_cnt ; 24 reg flag_ref ; 25 26 //=============================================================================\ 27 //********************** Main Code *************************************** 28 //=============================================================================/ 29 always @(posedge sclk or negedge s_rst_n) begin 30 if(s_rst_n == 1'b0) 31 ref_cnt <= 9'd0; 32 else if(ref_cnt >= DELAY_78us) 33 ref_cnt <= 9'd0; 34 else if(flag_init_end == 1'b1) 35 ref_cnt <= ref_cnt +1'b1; 36 end 37 38 always @(posedge sclk or negedge s_rst_n) begin 39 if(s_rst_n == 1'b0) 40 flag_ref <= 1'b0; 41 else if(flag_ref_end == 1'b1) 42 flag_ref <= 1'b0; 43 else if(ref_en == 1'b1) 44 flag_ref <= 1'b1; 45 end 46 47 always @(posedge sclk or negedge s_rst_n ) begin 48 if(s_rst_n == 1'b0) 49 cmd_cnt <= 4'd0; 50 else if(flag_ref == 1'b1) 51 cmd_cnt <= cmd_cnt + 1'b1; 52 else 53 cmd_cnt <= 4'd0; 54 end 55 56 57 always @(posedge sclk or negedge s_rst_n) begin 58 if(s_rst_n == 1'b0) 59 aref_cmd <= CMD_NOP; 60 else case(cmd_cnt) 61 1: aref_cmd <= CMD_PRE; 62 2: aref_cmd <= CMD_AREF; 63 default:aref_cmd <= CMD_NOP; 64 endcase 65 end 66 67 assign flag_ref_end = (cmd_cnt >= 4'd3) ? 1'b1 : 1'b0; 68 assign sdram_addr = 13'd0_0100_0000_0000; 69 assign ref_req = (ref_cnt >= DELAY_78us) ? 1'b1 : 1'b0; 70 71 72 73 endmodule
4.仲裁机制
为什么要这个仲裁机制,sdram工作是有刷新、写和读3个操作,我们需要这个仲裁机制来协调这三个操作,引用邓堪文老师一个图,大家一看就应该很明白了
5.具体的操作在sdram_top模块里,附上源码自己研究一下,这只写了三种状态,其他状态后面学习了在更新
1 module sdram_top( 2 //system signals 3 input sclk , 4 input s_rst_n , 5 //SDRAM Interfaces 6 output wire sdram_clk , 7 output wire sdram_cke , 8 output wire sdram_cs_n , 9 output wire sdram_cas_n , 10 output wire sdram_ras_n , 11 output wire sdram_we_n , 12 output wire [1:0] sdram_bank , 13 output wire [12:0] sdram_addr , 14 output wire [1:0] sdram_dqm , 15 inout [15:0] sdram_dq 16 ); 17 18 //==============================================================================\ 19 //*********************Define Parameter and Internal Signal ******************** 20 //==============================================================================/ 21 localparam IDLE = 5'b0_0001 ; 22 localparam ARBIT = 5'b0_0010 ; 23 localparam AREF = 5'b0_0100 ; 24 25 //init module 26 wire flag_init_end ; 27 wire [3:0] init_cmd ; 28 wire [12:0] init_addr ; 29 // 30 reg [4:0] state ; 31 //refresh module 32 wire ref_req ; 33 wire flag_ref_end ; 34 reg ref_en ; 35 wire [3:0] ref_cmd ; 36 wire [12:0] ref_addr ; 37 38 39 //=============================================================================\ 40 //********************** Main Code *************************************** 41 //=============================================================================/ 42 always @(posedge sclk or negedge s_rst_n) begin 43 if(s_rst_n == 1'b0) 44 state <= IDLE; 45 46 else case(state) 47 IDLE: 48 if(flag_init_end == 1'b1) 49 state <= ARBIT; 50 else 51 state <= IDLE; 52 ARBIT: 53 if(ref_en == 1'b1) 54 state <= AREF; 55 else 56 state <= ARBIT; 57 AREF: 58 if(flag_ref_end == 1'b1) 59 state <= ARBIT; 60 else 61 state <=AREF; 62 default: 63 state <= IDLE; 64 endcase 65 end 66 67 68 //ref_en 69 always @(posedge sclk or negedge s_rst_n) begin 70 if(s_rst_n == 1'b0) 71 ref_en <= 1'b0; 72 else if(state == ARBIT && ref_req == 1'b1) 73 ref_en <= 1'b1; 74 else 75 ref_en <= 1'b0; 76 end 77 78 assign sdram_cke = 1'b1; 79 assign sdram_addr = (state == IDLE) ? init_addr : ref_addr; 80 assign {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = (state == IDLE) ? init_cmd : ref_cmd; 81 assign sdram_dqm = 2'd0; 82 assign sdram_clk = ~sclk; 83 84 85 sdram_ini sdram_ini_inst( 86 //systejm sign 87 .sclk (sclk ), 88 .s_rst_n (s_rst_n ), 89 //others 90 .cmd_reg (init_cmd ), 91 .sdram_addr (init_addr ), 92 .flag_init_end (flag_init_end ) 93 ); 94 95 sdram_aref sdram_aref_inst( 96 //system signals 97 .sclk (sclk ), 98 .s_rst_n (s_rst_n ), 99 //comunicat with ARBIT 100 .ref_en (ref_en ), 101 .ref_req (ref_req ), 102 .flag_ref_end (flag_ref_end ), 103 //others 104 .aref_cmd (ref_cmd ), 105 .sdram_addr (ref_addr ), 106 .flag_init_end (flag_init_end ) 107 ); 108 109 110 endmodule
6.最后老规矩放上仿真结果以及仿真波形图
初始化没有错,刷星也一直进行,没有错误
在看看波形图,没次看到这些信号就觉得自己就是个大牛,哈哈哈! 自恋了,但是还是个入了门的菜鸡。看图信号和数据都没问题,完美!
2018.9.14
首先骂一下狗逼学校都要写完了停电了。我靠全没了,暑假就停了我那么久的网,还到处开挖,挖金子啊绝地三尺关键是堵道。无语了。。。
消气还是重写吧,一个多月了,打算每做好一个功能就更的,可惜就该这个狗逼学校事多还停水停网,但是我也没停下。现在补上吧,下午都快写完了突然停电主机关机了,呵呵,现在就这样了
首先看一下现在做好的图片显示系统,用串口发送640*480的图片给FPGA,波特率是1562500,最快的了,VGA驱动显示屏。
说实话我不想再从写了,很烦,还有很多事要忙,真心要学的可以私聊我!