Tue, 10 Aug 2010 17:42:18 +0100
add NOP after read to avoid bus contention when doing back-to-back R/Ws
| philpem@0 | 1 | /**************************************************************************** |
| philpem@0 | 2 | * |
| philpem@0 | 3 | * |
| philpem@0 | 4 | ****************************************************************************/ |
| philpem@0 | 5 | |
| philpem@0 | 6 | module wb_sdram ( |
| philpem@0 | 7 | // Clocks and resets |
| philpem@0 | 8 | input wb_clk_i, // WISHBONE clock |
| philpem@0 | 9 | input wb_rst_i, // WISHBONE reset |
| philpem@0 | 10 | |
| philpem@0 | 11 | // WISHBONE bus |
| philpem@0 | 12 | input [31:0] wb_adr_i, // WISHBONE address |
| philpem@0 | 13 | input [31:0] wb_dat_i, // WISHBONE data in |
| philpem@0 | 14 | output reg [31:0] wb_dat_o, // WISHBONE data out |
| philpem@0 | 15 | input [3:0] wb_sel_i, // WISHBONE byte select |
| philpem@0 | 16 | input wb_we_i, // WISHBONE write enable (R/#W) |
| philpem@0 | 17 | input wb_cyc_i, // WISHBONE cycle |
| philpem@0 | 18 | input wb_stb_i, // WISHBONE strobe |
| philpem@0 | 19 | output wb_ack_o, // WISHBONE cycle acknowledge (data available, DTACK) |
| philpem@0 | 20 | output wb_err_o, // WISHBONE bus error |
| philpem@0 | 21 | output wb_rty_o, // WISHBONE retry-later |
| philpem@0 | 22 | |
| philpem@0 | 23 | // SDRAM |
| philpem@0 | 24 | output reg sdram_cke, // SDRAM clock enable |
| philpem@0 | 25 | output sdram_cs_n, // SDRAM chip select (active low) |
| philpem@0 | 26 | output sdram_ras_n, // SDRAM row address strobe (active low) |
| philpem@0 | 27 | output sdram_cas_n, // SDRAM column address strobe (active low) |
| philpem@0 | 28 | output sdram_we_n, // SDRAM write enable (active low) |
| philpem@0 | 29 | output [11:0] sdram_a, // SDRAM address |
| philpem@0 | 30 | output reg [1:0] sdram_ba, // SDRAM bank address |
| philpem@0 | 31 | output reg [3:0] sdram_dqm, // SDRAM data mask (OE#; 0=active, 1=disabled) |
| philpem@0 | 32 | inout [31:0] sdram_dq, // SDRAM data bus |
| philpem@0 | 33 | |
| philpem@0 | 34 | // Debugging |
| philpem@3 | 35 | output /*reg*/ [2:0] debug // debug bits |
| philpem@0 | 36 | ); |
| philpem@0 | 37 | |
| philpem@0 | 38 | |
| philpem@0 | 39 | /**** |
| philpem@0 | 40 | * SDRAM data output buffer |
| philpem@0 | 41 | ****/ |
| philpem@0 | 42 | // OE=1 for output mode, 0 for input |
| philpem@0 | 43 | reg sdram_dq_oe; |
| philpem@0 | 44 | // SDRAM output register |
| philpem@0 | 45 | reg [31:0] sdram_dq_r; |
| philpem@0 | 46 | assign sdram_dq = sdram_dq_oe ? sdram_dq_r : 32'hZZZZ; |
| philpem@0 | 47 | |
| philpem@0 | 48 | |
| philpem@0 | 49 | |
| philpem@0 | 50 | /**** |
| philpem@0 | 51 | * State timer |
| philpem@0 | 52 | * This is used to ensure that the state machine abides by RAM timing |
| philpem@0 | 53 | * restrictions. |
| philpem@0 | 54 | ****/ |
| philpem@0 | 55 | reg [31:0] timer; |
| philpem@0 | 56 | |
| philpem@0 | 57 | |
| philpem@0 | 58 | /**** |
| philpem@0 | 59 | * MODE logic |
| philpem@0 | 60 | ****/ |
| philpem@0 | 61 | reg [5:0] sdram_mode; |
| philpem@0 | 62 | reg [11:0] sdram_addr; |
| philpem@0 | 63 | assign sdram_cs_n = sdram_mode[3]; |
| philpem@0 | 64 | assign sdram_ras_n = sdram_mode[2]; |
| philpem@0 | 65 | assign sdram_cas_n = sdram_mode[1]; |
| philpem@0 | 66 | assign sdram_we_n = sdram_mode[0]; |
| philpem@0 | 67 | assign sdram_a = {sdram_addr[11], (sdram_mode[5] ? sdram_mode[4] : sdram_addr[10]), sdram_addr[9:0]}; |
| philpem@0 | 68 | |
| philpem@0 | 69 | // SDRAM chip instructions |
| philpem@0 | 70 | // The bit order is as specified in the ISSI datasheet: A10 Override, A10, CS#, RAS#, CAS#, WE#. |
| philpem@0 | 71 | // If A10 Override is set, then A10 will be overridden to the value specified in the M_ constant. |
| philpem@0 | 72 | localparam M_BankActivate = 6'b0X0011; |
| philpem@0 | 73 | localparam M_PrechargeBank = 6'b100010; |
| philpem@0 | 74 | localparam M_PrechargeAll = 6'b110010; |
| philpem@0 | 75 | localparam M_Write = 6'b100100; |
| philpem@0 | 76 | localparam M_WritePrecharge = 6'b110100; |
| philpem@0 | 77 | localparam M_Read = 6'b100101; |
| philpem@0 | 78 | localparam M_ReadPrecharge = 6'b110101; |
| philpem@2 | 79 | localparam M_LoadModeRegister = 6'b0X0000; |
| philpem@0 | 80 | localparam M_Nop = 6'b0X0111; |
| philpem@0 | 81 | localparam M_BurstStop = 6'b0X0110; |
| philpem@0 | 82 | localparam M_Inhibit = 6'b0X1XXX; // maybe X1111? |
| philpem@0 | 83 | localparam M_AutoRefresh = 6'b0X0001; |
| philpem@0 | 84 | |
| philpem@0 | 85 | |
| philpem@0 | 86 | /**** |
| philpem@3 | 87 | * Refresh Timer |
| philpem@3 | 88 | ****/ |
| philpem@3 | 89 | parameter REFRESH_INTERVAL = 32'd390 - 32'd1; |
| philpem@3 | 90 | reg [31:0] refresh_timer; |
| philpem@3 | 91 | reg refresh_req, refresh_ack, refresh_timer_en; |
| philpem@3 | 92 | always @(posedge wb_clk_i) begin |
| philpem@3 | 93 | if (wb_rst_i | !refresh_timer_en) begin |
| philpem@3 | 94 | // Reset; clear timer, unset REFRESH REQUEST |
| philpem@3 | 95 | refresh_req <= 1'b0; |
| philpem@3 | 96 | refresh_timer <= REFRESH_INTERVAL; |
| philpem@3 | 97 | end else if (refresh_ack) begin |
| philpem@3 | 98 | // Refresh Ack, clear Refresh Request. |
| philpem@3 | 99 | refresh_req <= 1'b0; |
| philpem@3 | 100 | end else if (refresh_timer == 0) begin |
| philpem@3 | 101 | // Refresh timer timed out, make a Refresh Request and reload the timer |
| philpem@3 | 102 | refresh_req <= 1'b1; |
| philpem@3 | 103 | refresh_timer <= REFRESH_INTERVAL; |
| philpem@3 | 104 | end else begin |
| philpem@3 | 105 | // Otherwise just decrement the timer |
| philpem@3 | 106 | refresh_timer <= refresh_timer - 32'd1; |
| philpem@3 | 107 | end |
| philpem@3 | 108 | end |
| philpem@3 | 109 | |
| philpem@3 | 110 | assign debug = { 1'b0, refresh_req, refresh_ack }; |
| philpem@3 | 111 | |
| philpem@4 | 112 | |
| philpem@4 | 113 | /**** |
| philpem@4 | 114 | * Address decoder |
| philpem@4 | 115 | ****/ |
| philpem@4 | 116 | wire [8:0] column_addr; |
| philpem@4 | 117 | wire [11:0] row_addr; |
| philpem@4 | 118 | wire [1:0] bank_addr; |
| philpem@4 | 119 | |
| philpem@4 | 120 | // Convert a 22-bit linear address into an SDRAM address |
| philpem@4 | 121 | assign column_addr = wb_adr_i[8:0]; |
| philpem@4 | 122 | assign bank_addr = wb_adr_i[10:9]; |
| philpem@4 | 123 | assign row_addr = wb_adr_i[21:11]; |
| philpem@4 | 124 | |
| philpem@4 | 125 | |
| philpem@3 | 126 | /**** |
| philpem@0 | 127 | * Finite State Machine |
| philpem@0 | 128 | ****/ |
| philpem@2 | 129 | localparam ST_INIT1 = 32'd0; |
| philpem@2 | 130 | localparam ST_INIT2 = 32'd1; |
| philpem@2 | 131 | localparam ST_NOP1 = 32'd2; |
| philpem@2 | 132 | localparam ST_PrechargeAll = 32'd3; |
| philpem@2 | 133 | localparam ST_PrechargeAll_Wait = 32'd4; |
| philpem@2 | 134 | localparam ST_AutoRefresh1 = 32'd5; |
| philpem@2 | 135 | localparam ST_AutoRefresh1_Wait = 32'd6; |
| philpem@2 | 136 | localparam ST_AutoRefresh2 = 32'd7; |
| philpem@2 | 137 | localparam ST_AutoRefresh2_Wait = 32'd8; |
| philpem@2 | 138 | localparam ST_LoadModeRegister = 32'd9; |
| philpem@2 | 139 | localparam ST_LoadModeRegister_Wait = 32'd10; |
| philpem@3 | 140 | localparam ST_Spin = 32'd11; // <<== main 'spin' / 'idle' state |
| philpem@3 | 141 | localparam ST_Refresh = 32'd12; |
| philpem@3 | 142 | localparam ST_Refresh_Wait = 32'd13; |
| philpem@4 | 143 | localparam ST_Test_Activate = 32'd500; |
| philpem@4 | 144 | localparam ST_Test_Activate_Wait = 32'd501; |
| philpem@4 | 145 | localparam ST_Test_Read = 32'd502; |
| philpem@4 | 146 | localparam ST_Test_Read_Wait = 32'd503; |
| philpem@5 | 147 | localparam ST_Test_Read_Finish = 32'd504; |
| philpem@5 | 148 | localparam ST_Test_Write = 32'd505; |
| philpem@5 | 149 | localparam ST_Test_Precharge_All = 32'd506; |
| philpem@5 | 150 | localparam ST_Test_Precharge_All_Wait = 32'd507; |
| philpem@0 | 151 | |
| philpem@0 | 152 | reg [31:0] state; |
| philpem@0 | 153 | always @(posedge wb_clk_i) begin |
| philpem@0 | 154 | if (wb_rst_i) begin |
| philpem@0 | 155 | // Initialise state machine and timer |
| philpem@0 | 156 | state <= ST_INIT1; |
| philpem@3 | 157 | // debug <= 3'd0; |
| philpem@0 | 158 | timer <= 32'd0; |
| philpem@3 | 159 | |
| philpem@3 | 160 | // Clear REFRESH ACK flag and disable refresh timer |
| philpem@3 | 161 | refresh_ack <= 1'b0; |
| philpem@3 | 162 | refresh_timer_en <= 1'b0; |
| philpem@0 | 163 | |
| philpem@0 | 164 | // Initialisation state for SDRAM |
| philpem@0 | 165 | sdram_cke <= 1'b0; |
| philpem@0 | 166 | sdram_mode <= M_Inhibit; |
| philpem@0 | 167 | sdram_addr <= 12'h000; |
| philpem@0 | 168 | sdram_ba <= 2'b00; |
| philpem@0 | 169 | sdram_dqm <= 4'b0000; |
| philpem@0 | 170 | sdram_dq_oe <= 1'b0; // data output disabled |
| philpem@0 | 171 | sdram_dq_r <= 32'd0; |
| philpem@0 | 172 | end else begin |
| philpem@0 | 173 | // timer logic |
| philpem@0 | 174 | if (timer > 32'd0) begin |
| philpem@0 | 175 | timer <= timer - 32'd1; |
| philpem@0 | 176 | end |
| philpem@0 | 177 | |
| philpem@0 | 178 | // state machine logic |
| philpem@0 | 179 | case (state) |
| philpem@0 | 180 | ST_INIT1: begin |
| philpem@0 | 181 | // INIT1: Set up for initial power-up wait |
| philpem@0 | 182 | state <= ST_INIT2; |
| philpem@0 | 183 | timer <= 32'd50_000; // TODO: dependent on core clock rate. Needs to be >= 100us |
| philpem@0 | 184 | |
| philpem@0 | 185 | // SDRAM state |
| philpem@0 | 186 | sdram_cke <= 1'b0; // clock disabled |
| philpem@0 | 187 | sdram_mode <= M_Inhibit; |
| philpem@0 | 188 | sdram_addr <= 12'h000; |
| philpem@0 | 189 | sdram_ba <= 2'b00; |
| philpem@0 | 190 | sdram_dqm <= 4'b1111; |
| philpem@0 | 191 | sdram_dq_oe <= 1'b0; // data output disabled |
| philpem@0 | 192 | sdram_dq_r <= 32'd0; |
| philpem@0 | 193 | end |
| philpem@0 | 194 | |
| philpem@0 | 195 | ST_INIT2: begin |
| philpem@0 | 196 | // INIT2: Power-up wait. Keep CKE low until ~50 cycles before |
| philpem@0 | 197 | // the end of the power-up wait, then bring CKE high. |
| philpem@0 | 198 | if (timer == 32'd0) begin |
| philpem@0 | 199 | // Timer hit zero. Send a NOP. |
| philpem@2 | 200 | state <= ST_NOP1; |
| philpem@1 | 201 | end else if (timer < 32'd50) begin |
| philpem@0 | 202 | // Timer value is more than zero but less than 50; CKE is on, but |
| philpem@0 | 203 | // keep waiting for the timer to actually expire. |
| philpem@0 | 204 | sdram_cke <= 1'b1; |
| philpem@0 | 205 | state <= ST_INIT2; |
| philpem@3 | 206 | // debug <= 3'd1; |
| philpem@0 | 207 | end |
| philpem@0 | 208 | sdram_mode <= M_Inhibit; |
| philpem@0 | 209 | end |
| philpem@0 | 210 | |
| philpem@2 | 211 | ST_NOP1: begin |
| philpem@2 | 212 | // Apply one or more NOP commands to the SDRAM |
| philpem@2 | 213 | sdram_mode <= M_Nop; |
| philpem@2 | 214 | state <= ST_PrechargeAll; |
| philpem@2 | 215 | end |
| philpem@2 | 216 | |
| philpem@2 | 217 | ST_PrechargeAll: begin |
| philpem@2 | 218 | // Precharge All, then wait T_rp (20ns) |
| philpem@2 | 219 | sdram_mode <= M_PrechargeAll; |
| philpem@2 | 220 | timer <= 32'd0; // wait 1tcy (40ns) ---> TIMER HERE |
| philpem@2 | 221 | state <= ST_PrechargeAll_Wait; |
| philpem@2 | 222 | end |
| philpem@2 | 223 | |
| philpem@2 | 224 | ST_PrechargeAll_Wait: begin |
| philpem@2 | 225 | // Wait for T_rp after Precharge All |
| philpem@2 | 226 | sdram_mode <= M_Nop; |
| philpem@2 | 227 | if (timer == 32'd0) begin |
| philpem@2 | 228 | // Timer hit zero. Continue |
| philpem@2 | 229 | state <= ST_AutoRefresh1; |
| philpem@2 | 230 | end |
| philpem@2 | 231 | end |
| philpem@2 | 232 | |
| philpem@2 | 233 | ST_AutoRefresh1: begin |
| philpem@2 | 234 | // Auto Refresh 1 of 2, wait T_rfc (70ns) after each |
| philpem@2 | 235 | sdram_mode <= M_AutoRefresh; |
| philpem@2 | 236 | timer <= 32'd1; // wait 2tcy (80ns) ---> TIMER HERE |
| philpem@2 | 237 | state <= ST_AutoRefresh1_Wait; |
| philpem@2 | 238 | end |
| philpem@2 | 239 | |
| philpem@2 | 240 | ST_AutoRefresh1_Wait: begin |
| philpem@2 | 241 | // Wait for T_rfc |
| philpem@1 | 242 | sdram_mode <= M_Nop; |
| philpem@2 | 243 | if (timer == 32'd0) begin |
| philpem@2 | 244 | // Timer hit zero. Continue |
| philpem@2 | 245 | state <= ST_AutoRefresh2; |
| philpem@2 | 246 | end |
| philpem@2 | 247 | end |
| philpem@2 | 248 | |
| philpem@2 | 249 | ST_AutoRefresh2: begin |
| philpem@2 | 250 | // Auto Refresh 2 of 2, wait T_rfc (70ns) after each |
| philpem@2 | 251 | sdram_mode <= M_AutoRefresh; |
| philpem@2 | 252 | timer <= 32'd1; // wait 2tcy (80ns) ---> TIMER HERE |
| philpem@2 | 253 | state <= ST_AutoRefresh2_Wait; |
| philpem@2 | 254 | end |
| philpem@2 | 255 | |
| philpem@2 | 256 | ST_AutoRefresh2_Wait: begin |
| philpem@2 | 257 | // Wait for T_rfc |
| philpem@2 | 258 | sdram_mode <= M_Nop; |
| philpem@2 | 259 | if (timer == 32'd0) begin |
| philpem@2 | 260 | // Timer hit zero. Continue |
| philpem@2 | 261 | state <= ST_LoadModeRegister; |
| philpem@2 | 262 | end |
| philpem@2 | 263 | end |
| philpem@2 | 264 | |
| philpem@2 | 265 | ST_LoadModeRegister: begin |
| philpem@2 | 266 | // Load Mode Register |
| philpem@2 | 267 | /** |
| philpem@2 | 268 | * Mode register: |
| philpem@2 | 269 | * - BS0,1 = 00 [RFU] |
| philpem@2 | 270 | * - A11,10 = 00 [RFU] |
| philpem@2 | 271 | * - A9 = 0 [WBL -- write burst length same as read burst length] |
| philpem@2 | 272 | * - A8,7 = 00 [Test Mode off] |
| philpem@2 | 273 | * - A6..4 = 010 [CAS Latency = 2 clocks] |
| philpem@2 | 274 | * - A3 = 0 [Burst type = sequential] |
| philpem@2 | 275 | * - A2..0 = 000 [Burst length = 1 word] |
| philpem@2 | 276 | */ |
| philpem@2 | 277 | sdram_ba <= 2'b00; |
| philpem@2 | 278 | sdram_addr <= 12'b00_0_00_010_000; |
| philpem@2 | 279 | sdram_mode <= M_LoadModeRegister; |
| philpem@2 | 280 | |
| philpem@2 | 281 | // Wait T_mrd (2 clock cycles) |
| philpem@2 | 282 | timer <= 32'd1; // (2cy)-1 ---> TIMER HERE |
| philpem@2 | 283 | state <= ST_LoadModeRegister_Wait; |
| philpem@2 | 284 | end |
| philpem@2 | 285 | |
| philpem@2 | 286 | ST_LoadModeRegister_Wait: begin |
| philpem@2 | 287 | // Wait for LMR to complete |
| philpem@2 | 288 | sdram_mode <= M_Nop; |
| philpem@2 | 289 | sdram_ba <= 2'd0; |
| philpem@2 | 290 | sdram_addr <= 12'd0; |
| philpem@2 | 291 | if (timer == 32'd0) begin |
| philpem@2 | 292 | // Timer hit zero. Continue |
| philpem@2 | 293 | state <= ST_Spin; |
| philpem@2 | 294 | end |
| philpem@2 | 295 | end |
| philpem@2 | 296 | |
| philpem@2 | 297 | ST_Spin: begin |
| philpem@3 | 298 | // Enable refresh timer |
| philpem@3 | 299 | refresh_timer_en <= 1'b1; |
| philpem@3 | 300 | |
| philpem@2 | 301 | sdram_mode <= M_Inhibit; |
| philpem@3 | 302 | |
| philpem@3 | 303 | if (refresh_req) begin |
| philpem@3 | 304 | // Refresh request received. Ack it and do a refresh. |
| philpem@3 | 305 | refresh_ack <= 1'b1; |
| philpem@3 | 306 | state <= ST_Refresh; |
| philpem@3 | 307 | end else begin |
| philpem@4 | 308 | //state <= ST_Spin; // NOTE: turned off to run a ram test... |
| philpem@4 | 309 | state <= ST_Test_Activate; |
| philpem@3 | 310 | end |
| philpem@3 | 311 | end |
| philpem@3 | 312 | |
| philpem@3 | 313 | ST_Refresh: begin |
| philpem@3 | 314 | // Refresh timer timed out; do a refresh run |
| philpem@3 | 315 | // Start by clearing the ACK flag (which was set by the Spin state) |
| philpem@3 | 316 | refresh_ack <= 1'b0; |
| philpem@3 | 317 | // Tell the SDRAM to do a Refresh |
| philpem@3 | 318 | sdram_mode <= M_AutoRefresh; |
| philpem@3 | 319 | // Wait for T_rfc |
| philpem@3 | 320 | timer <= 32'd1; // wait Trfc (70ns ideally, we give 80ns) ---> TIMER HERE |
| philpem@3 | 321 | state <= ST_Refresh_Wait; |
| philpem@3 | 322 | end |
| philpem@3 | 323 | |
| philpem@3 | 324 | ST_Refresh_Wait: begin |
| philpem@3 | 325 | // Wait for T_rfc |
| philpem@3 | 326 | sdram_mode <= M_Nop; |
| philpem@3 | 327 | if (timer == 32'd0) begin |
| philpem@3 | 328 | // Timer hit zero. Go back to spin state. |
| philpem@3 | 329 | state <= ST_Spin; |
| philpem@3 | 330 | end |
| philpem@0 | 331 | end |
| philpem@4 | 332 | |
| philpem@4 | 333 | ST_Test_Activate: begin |
| philpem@4 | 334 | // Activate bank |
| philpem@4 | 335 | sdram_mode <= M_BankActivate; |
| philpem@4 | 336 | sdram_addr <= row_addr; |
| philpem@4 | 337 | sdram_ba <= bank_addr; |
| philpem@4 | 338 | timer <= 32'd0; // wait Trcd (20ns ideally, this is 40ns) ---> TIMER HERE |
| philpem@4 | 339 | state <= ST_Test_Activate_Wait; |
| philpem@4 | 340 | end |
| philpem@4 | 341 | |
| philpem@4 | 342 | ST_Test_Activate_Wait: begin |
| philpem@4 | 343 | // Wait for Activate Bank to complete |
| philpem@4 | 344 | sdram_mode <= M_Nop; |
| philpem@4 | 345 | if (timer == 32'd0) begin |
| philpem@4 | 346 | state <= ST_Test_Read; |
| philpem@4 | 347 | end |
| philpem@4 | 348 | end |
| philpem@4 | 349 | |
| philpem@4 | 350 | ST_Test_Read: begin |
| philpem@4 | 351 | // Do the Read operation |
| philpem@4 | 352 | sdram_mode <= M_Read; |
| philpem@4 | 353 | sdram_addr <= column_addr; |
| philpem@4 | 354 | sdram_dqm <= 4'b0000; // Allow data through (DQM = OE# = 1 to mask off, 0 to allow) |
| philpem@5 | 355 | timer <= 32'd2 - 32'd1; // wait CAS# Latency (2 clock cycles) ---> TIMER HERE |
| philpem@4 | 356 | state <= ST_Test_Read_Wait; |
| philpem@4 | 357 | end |
| philpem@4 | 358 | |
| philpem@4 | 359 | ST_Test_Read_Wait: begin |
| philpem@4 | 360 | // Wait for CAS latency |
| philpem@4 | 361 | sdram_mode <= M_Nop; |
| philpem@4 | 362 | sdram_dqm <= 4'b1111; // Disable SDRAM output buffers |
| philpem@4 | 363 | if (timer == 32'd0) begin |
| philpem@5 | 364 | state <= ST_Test_Read_Finish; |
| philpem@4 | 365 | // TODO: capture data locally |
| philpem@4 | 366 | end |
| philpem@4 | 367 | end |
| philpem@5 | 368 | |
| philpem@5 | 369 | ST_Test_Read_Finish: begin |
| philpem@5 | 370 | // Additional NOP after read to avoid bus contention if next transaction is a write |
| philpem@5 | 371 | sdram_mode <= M_Nop; |
| philpem@5 | 372 | sdram_dqm <= 4'b1111; // Disable SDRAM output buffers |
| philpem@5 | 373 | state <= ST_Test_Write; |
| philpem@5 | 374 | end |
| philpem@4 | 375 | |
| philpem@4 | 376 | ST_Test_Write: begin |
| philpem@4 | 377 | // Write to SDRAM |
| philpem@4 | 378 | sdram_mode <= M_Write; |
| philpem@4 | 379 | sdram_addr <= column_addr; |
| philpem@4 | 380 | sdram_dq_r <= 32'h55AA_BCDE; |
| philpem@4 | 381 | sdram_dq_oe <= 1'b1; // output enable |
| philpem@4 | 382 | sdram_dqm <= 4'b0000; // Allow data through (DQM = OE# = 1 to mask off, 0 to allow) |
| philpem@4 | 383 | state <= ST_Test_Precharge_All; |
| philpem@4 | 384 | end |
| philpem@4 | 385 | |
| philpem@4 | 386 | ST_Test_Precharge_All: begin |
| philpem@4 | 387 | // Precharge All |
| philpem@4 | 388 | sdram_mode <= M_PrechargeAll; |
| philpem@4 | 389 | sdram_addr <= 12'd0; |
| philpem@4 | 390 | sdram_dq_oe <= 1'b0; // output disable |
| philpem@4 | 391 | sdram_dqm <= 4'b1111; // Disable SDRAM output buffers |
| philpem@4 | 392 | sdram_dq_r <= 32'd0; |
| philpem@4 | 393 | state <= ST_Spin; |
| philpem@4 | 394 | // Wait T_rp (20ns) |
| philpem@4 | 395 | timer <= 32'd0; // wait 1tcy (40ns) ---> TIMER HERE |
| philpem@4 | 396 | state <= ST_Test_Precharge_All_Wait; |
| philpem@4 | 397 | end |
| philpem@4 | 398 | |
| philpem@4 | 399 | ST_Test_Precharge_All_Wait: begin |
| philpem@4 | 400 | // Wait for T_rp after Precharge All |
| philpem@4 | 401 | sdram_mode <= M_Nop; |
| philpem@4 | 402 | if (timer == 32'd0) begin |
| philpem@4 | 403 | // Timer hit zero. Continue |
| philpem@4 | 404 | state <= ST_Spin; |
| philpem@4 | 405 | end |
| philpem@4 | 406 | end |
| philpem@0 | 407 | endcase |
| philpem@0 | 408 | end |
| philpem@0 | 409 | end |
| philpem@0 | 410 | |
| philpem@0 | 411 | endmodule |