wb_sdram.v

Wed, 18 Aug 2010 14:17:42 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 18 Aug 2010 14:17:42 +0100
changeset 19
d39b0f302ca3
parent 18
275105a6a36b
permissions
-rw-r--r--

comment cleanup

philpem@17 1 /****************************************************************************
philpem@19 2 * WISHBONE SDRAM CONTROLLER MODULE / IP CORE
philpem@19 3 * (C) 2010 Philip Pemberton. All Rights Reserved.
philpem@0 4 *
philpem@19 5 * This IP core provides a WISHBONE-compliant interface for most standard
philpem@19 6 * SDR SDRAM ICs (e.g. the ISSI part on the Enterpoint Drigmorn2 and
philpem@19 7 * Craignell2 boards).
philpem@0 8 ****************************************************************************/
philpem@0 9
philpem@17 10 module wb_sdram #(
philpem@18 11 // Data and address bus parameters
philpem@17 12 parameter DATA_BITS = 32, // Width of SDRAM data bus
philpem@17 13 parameter COLADDR_BITS = 9, // Number of SDRAM Column Address bits
philpem@17 14 parameter BANKADDR_BITS = 2, // Number of SDRAM Bank Address bits
philpem@18 15 parameter ROWADDR_BITS = 12, // Number of SDRAM Row Address bits
philpem@18 16
philpem@18 17 // Timer parameters
philpem@19 18 parameter CAS_LATENCY = 3'd2, // CAS latency -- either 2 or 3
philpem@19 19 parameter CLOCK_RATE = 25_000_000, // System clock frequency in Hz
philpem@18 20
philpem@18 21 // SDRAM timings in nanoseconds
philpem@18 22 // Precharge to refresh/row activate command (same bank) -- Trp
philpem@18 23 parameter TIME_Trp = 20,
philpem@18 24 // RAS# to CAS# delay -- Trcd
philpem@18 25 parameter TIME_Trcd = 20,
philpem@18 26 // Row cycle time -- Trfc, also known as Trc
philpem@18 27 parameter TIME_Trfc = 70,
philpem@18 28 // Time between refresh cycles -- refresh interval divided by number of rows to refresh (in this case, 64e-3/4096*1e9 --> 15.625us or 15,625ns)
philpem@18 29 parameter TIME_Refresh = 15_625,
philpem@18 30 // 2ms power-up init period (2e6 nanoseconds = 2ms)
philpem@18 31 parameter TIME_InitDelay = 2_000_000,
philpem@18 32 // 2us before the end of the init period, raise CKE (2000ns = 2us)
philpem@18 33 parameter TIME_InitFinal = 2_000
philpem@17 34 ) (
philpem@0 35 // Clocks and resets
philpem@17 36 input wb_clk_i, // WISHBONE clock
philpem@17 37 input wb_rst_i, // WISHBONE reset
philpem@0 38
philpem@0 39 // WISHBONE bus
philpem@17 40 input [31:0] wb_adr_i, // WISHBONE address
philpem@17 41 input [DATA_BITS-1:0] wb_dat_i, // WISHBONE data in
philpem@17 42 output reg [DATA_BITS-1:0] wb_dat_o, // WISHBONE data out
philpem@17 43 input [(DATA_BITS/4)-1:0] wb_sel_i, // WISHBONE byte select
philpem@17 44 input wb_we_i, // WISHBONE write enable (R/#W)
philpem@17 45 input wb_cyc_i, // WISHBONE cycle
philpem@17 46 input wb_stb_i, // WISHBONE strobe
philpem@17 47 output reg wb_ack_o, // WISHBONE cycle acknowledge (data available, DTACK)
philpem@17 48 output wb_err_o, // WISHBONE bus error
philpem@17 49 output wb_rty_o, // WISHBONE retry-later
philpem@0 50
philpem@0 51 // SDRAM
philpem@17 52 output reg sdram_cke, // SDRAM clock enable
philpem@17 53 output sdram_cs_n, // SDRAM chip select (active low)
philpem@17 54 output sdram_ras_n, // SDRAM row address strobe (active low)
philpem@17 55 output sdram_cas_n, // SDRAM column address strobe (active low)
philpem@17 56 output sdram_we_n, // SDRAM write enable (active low)
philpem@17 57 output [ROWADDR_BITS-1:0] sdram_a, // SDRAM address
philpem@17 58 output reg [BANKADDR_BITS-1:0] sdram_ba, // SDRAM bank address
philpem@17 59 output reg [(DATA_BITS/4)-1:0] sdram_dqm, // SDRAM data mask (OE#; 0=active, 1=disabled)
philpem@17 60 inout [DATA_BITS-1:0] sdram_dq // SDRAM data bus
philpem@0 61 );
philpem@0 62
philpem@0 63 /****
philpem@18 64 * Timer values -- don't touch!
philpem@10 65 ****/
philpem@15 66 // Calculate clock period in nanoseconds
philpem@15 67 localparam CLOCK_PERIOD = 1_000_000_000 / CLOCK_RATE;
philpem@15 68
philpem@10 69 // T_rp ==> 20ns
philpem@15 70 localparam TCY_Trp = (TIME_Trp+CLOCK_PERIOD-1) / CLOCK_PERIOD - 1;
philpem@10 71 // T_rcd ==> 20ns
philpem@15 72 localparam TCY_Trcd = (TIME_Trcd+CLOCK_PERIOD-1) / CLOCK_PERIOD - 1;
philpem@10 73 // T_rfc (a.k.a. T_rc) ==> 70ns
philpem@15 74 localparam TCY_Trfc = (TIME_Trfc+CLOCK_PERIOD-1) / CLOCK_PERIOD - 1;
philpem@10 75 // T_mrd ==> 2 clock cycles
philpem@15 76 localparam TCY_Tmrd = 32'd2;
philpem@12 77 // Maximum allowed time between two refresh cycles
philpem@15 78 localparam TCY_Refresh = (TIME_Refresh+CLOCK_PERIOD-1) / CLOCK_PERIOD - 1;
philpem@15 79
philpem@15 80 localparam TCY_InitDelay = (TIME_InitDelay+CLOCK_PERIOD-1) / CLOCK_PERIOD - 1;
philpem@15 81 localparam TCY_InitFinal = (TIME_InitFinal+CLOCK_PERIOD-1) / CLOCK_PERIOD - 1;
philpem@10 82
philpem@10 83
philpem@10 84 /****
philpem@8 85 * WISHBONE status pins
philpem@8 86 ****/
philpem@8 87 // Can't raise bus errors
philpem@8 88 assign wb_err_o = 1'b0;
philpem@8 89 // Can't request retries
philpem@8 90 assign wb_rty_o = 1'b0;
philpem@8 91
philpem@14 92
philpem@8 93 /****
philpem@0 94 * SDRAM data output buffer
philpem@0 95 ****/
philpem@0 96 // OE=1 for output mode, 0 for input
philpem@0 97 reg sdram_dq_oe;
philpem@0 98 // SDRAM output register
philpem@17 99 reg [DATA_BITS-1:0] sdram_dq_r;
philpem@17 100 assign sdram_dq = sdram_dq_oe ? sdram_dq_r : {DATA_BITS{1'bZ}};
philpem@0 101
philpem@0 102
philpem@0 103 /****
philpem@0 104 * State timer
philpem@0 105 * This is used to ensure that the state machine abides by RAM timing
philpem@0 106 * restrictions.
philpem@0 107 ****/
philpem@0 108 reg [31:0] timer;
philpem@0 109
philpem@0 110
philpem@0 111 /****
philpem@0 112 * MODE logic
philpem@0 113 ****/
philpem@0 114 reg [5:0] sdram_mode;
philpem@0 115 reg [11:0] sdram_addr;
philpem@0 116 assign sdram_cs_n = sdram_mode[3];
philpem@0 117 assign sdram_ras_n = sdram_mode[2];
philpem@0 118 assign sdram_cas_n = sdram_mode[1];
philpem@0 119 assign sdram_we_n = sdram_mode[0];
philpem@0 120 assign sdram_a = {sdram_addr[11], (sdram_mode[5] ? sdram_mode[4] : sdram_addr[10]), sdram_addr[9:0]};
philpem@0 121
philpem@0 122 // SDRAM chip instructions
philpem@0 123 // The bit order is as specified in the ISSI datasheet: A10 Override, A10, CS#, RAS#, CAS#, WE#.
philpem@0 124 // If A10 Override is set, then A10 will be overridden to the value specified in the M_ constant.
philpem@0 125 localparam M_BankActivate = 6'b0X0011;
philpem@0 126 localparam M_PrechargeBank = 6'b100010;
philpem@0 127 localparam M_PrechargeAll = 6'b110010;
philpem@0 128 localparam M_Write = 6'b100100;
philpem@0 129 localparam M_WritePrecharge = 6'b110100;
philpem@0 130 localparam M_Read = 6'b100101;
philpem@0 131 localparam M_ReadPrecharge = 6'b110101;
philpem@2 132 localparam M_LoadModeRegister = 6'b0X0000;
philpem@0 133 localparam M_Nop = 6'b0X0111;
philpem@0 134 localparam M_BurstStop = 6'b0X0110;
philpem@0 135 localparam M_Inhibit = 6'b0X1XXX; // maybe X1111?
philpem@0 136 localparam M_AutoRefresh = 6'b0X0001;
philpem@0 137
philpem@0 138
philpem@0 139 /****
philpem@3 140 * Refresh Timer
philpem@3 141 ****/
philpem@3 142 reg [31:0] refresh_timer;
philpem@3 143 reg refresh_req, refresh_ack, refresh_timer_en;
philpem@3 144 always @(posedge wb_clk_i) begin
philpem@3 145 if (wb_rst_i | !refresh_timer_en) begin
philpem@3 146 // Reset; clear timer, unset REFRESH REQUEST
philpem@3 147 refresh_req <= 1'b0;
philpem@15 148 refresh_timer <= TCY_Refresh - 32'd1;
philpem@3 149 end else if (refresh_ack) begin
philpem@3 150 // Refresh Ack, clear Refresh Request.
philpem@3 151 refresh_req <= 1'b0;
philpem@3 152 end else if (refresh_timer == 0) begin
philpem@3 153 // Refresh timer timed out, make a Refresh Request and reload the timer
philpem@3 154 refresh_req <= 1'b1;
philpem@15 155 refresh_timer <= TCY_Refresh - 32'd1;
philpem@3 156 end else begin
philpem@3 157 // Otherwise just decrement the timer
philpem@3 158 refresh_timer <= refresh_timer - 32'd1;
philpem@3 159 end
philpem@3 160 end
philpem@3 161
philpem@4 162
philpem@4 163 /****
philpem@4 164 * Address decoder
philpem@4 165 ****/
philpem@17 166 wire [COLADDR_BITS-1:0] column_addr;
philpem@17 167 wire [ROWADDR_BITS-1:0] row_addr;
philpem@17 168 wire [BANKADDR_BITS-1:0] bank_addr;
philpem@4 169
philpem@7 170 // Convert a 23-bit linear address into an SDRAM address
philpem@17 171 assign column_addr = wb_adr_i[COLADDR_BITS-1:0];
philpem@17 172 assign bank_addr = wb_adr_i[COLADDR_BITS+BANKADDR_BITS-1:COLADDR_BITS];
philpem@17 173 assign row_addr = wb_adr_i[COLADDR_BITS+BANKADDR_BITS+ROWADDR_BITS-1:COLADDR_BITS+BANKADDR_BITS];
philpem@4 174
philpem@4 175
philpem@3 176 /****
philpem@0 177 * Finite State Machine
philpem@0 178 ****/
philpem@2 179 localparam ST_INIT1 = 32'd0;
philpem@2 180 localparam ST_INIT2 = 32'd1;
philpem@2 181 localparam ST_NOP1 = 32'd2;
philpem@2 182 localparam ST_PrechargeAll = 32'd3;
philpem@2 183 localparam ST_PrechargeAll_Wait = 32'd4;
philpem@2 184 localparam ST_AutoRefresh1 = 32'd5;
philpem@2 185 localparam ST_AutoRefresh1_Wait = 32'd6;
philpem@2 186 localparam ST_AutoRefresh2 = 32'd7;
philpem@2 187 localparam ST_AutoRefresh2_Wait = 32'd8;
philpem@2 188 localparam ST_LoadModeRegister = 32'd9;
philpem@2 189 localparam ST_LoadModeRegister_Wait = 32'd10;
philpem@3 190 localparam ST_Spin = 32'd11; // <<== main 'spin' / 'idle' state
philpem@3 191 localparam ST_Refresh = 32'd12;
philpem@3 192 localparam ST_Refresh_Wait = 32'd13;
philpem@7 193 localparam ST_Activate = 32'd30;
philpem@7 194 localparam ST_Activate_Wait = 32'd31;
philpem@7 195 localparam ST_Write = 32'd32;
philpem@7 196 localparam ST_Read = 32'd33;
philpem@7 197 localparam ST_Read_Wait = 32'd34;
philpem@7 198 localparam ST_Wait_Trp = 32'd35;
philpem@7 199 localparam ST_Ack = 32'd36;
philpem@7 200
philpem@0 201
philpem@0 202 reg [31:0] state;
philpem@0 203 always @(posedge wb_clk_i) begin
philpem@0 204 if (wb_rst_i) begin
philpem@0 205 // Initialise state machine and timer
philpem@0 206 state <= ST_INIT1;
philpem@0 207 timer <= 32'd0;
philpem@3 208
philpem@3 209 // Clear REFRESH ACK flag and disable refresh timer
philpem@3 210 refresh_ack <= 1'b0;
philpem@3 211 refresh_timer_en <= 1'b0;
philpem@0 212
philpem@0 213 // Initialisation state for SDRAM
philpem@0 214 sdram_cke <= 1'b0;
philpem@0 215 sdram_mode <= M_Inhibit;
philpem@17 216 sdram_addr <= 0;
philpem@17 217 sdram_ba <= 0;
philpem@17 218 sdram_dqm <= 0;
philpem@17 219 sdram_dq_oe <= 0; // data output disabled
philpem@17 220 sdram_dq_r <= 0;
philpem@0 221 end else begin
philpem@0 222 // timer logic
philpem@0 223 if (timer > 32'd0) begin
philpem@0 224 timer <= timer - 32'd1;
philpem@0 225 end
philpem@0 226
philpem@0 227 // state machine logic
philpem@0 228 case (state)
philpem@0 229 ST_INIT1: begin
philpem@0 230 // INIT1: Set up for initial power-up wait
philpem@0 231 state <= ST_INIT2;
philpem@15 232 timer <= TCY_InitDelay; // Needs to be >= 100us
philpem@0 233
philpem@0 234 // SDRAM state
philpem@0 235 sdram_cke <= 1'b0; // clock disabled
philpem@0 236 sdram_mode <= M_Inhibit;
philpem@17 237 sdram_addr <= 0;
philpem@17 238 sdram_ba <= 0;
philpem@17 239 sdram_dqm <= {(DATA_BITS/4){1'b1}};
philpem@17 240 sdram_dq_oe <= 0; // data output disabled
philpem@17 241 sdram_dq_r <= 0;
philpem@0 242 end
philpem@0 243
philpem@0 244 ST_INIT2: begin
philpem@0 245 // INIT2: Power-up wait. Keep CKE low until ~50 cycles before
philpem@0 246 // the end of the power-up wait, then bring CKE high.
philpem@0 247 if (timer == 32'd0) begin
philpem@0 248 // Timer hit zero. Send a NOP.
philpem@2 249 state <= ST_NOP1;
philpem@15 250 end else if (timer < TCY_InitFinal) begin
philpem@0 251 // Timer value is more than zero but less than 50; CKE is on, but
philpem@0 252 // keep waiting for the timer to actually expire.
philpem@0 253 sdram_cke <= 1'b1;
philpem@0 254 state <= ST_INIT2;
philpem@0 255 end
philpem@0 256 sdram_mode <= M_Inhibit;
philpem@0 257 end
philpem@0 258
philpem@2 259 ST_NOP1: begin
philpem@2 260 // Apply one or more NOP commands to the SDRAM
philpem@2 261 sdram_mode <= M_Nop;
philpem@2 262 state <= ST_PrechargeAll;
philpem@2 263 end
philpem@2 264
philpem@2 265 ST_PrechargeAll: begin
philpem@2 266 // Precharge All, then wait T_rp (20ns)
philpem@2 267 sdram_mode <= M_PrechargeAll;
philpem@15 268 timer <= TCY_Trp - 32'd1;
philpem@2 269 state <= ST_PrechargeAll_Wait;
philpem@2 270 end
philpem@2 271
philpem@2 272 ST_PrechargeAll_Wait: begin
philpem@2 273 // Wait for T_rp after Precharge All
philpem@2 274 sdram_mode <= M_Nop;
philpem@2 275 if (timer == 32'd0) begin
philpem@2 276 // Timer hit zero. Continue
philpem@2 277 state <= ST_AutoRefresh1;
philpem@2 278 end
philpem@2 279 end
philpem@2 280
philpem@2 281 ST_AutoRefresh1: begin
philpem@2 282 // Auto Refresh 1 of 2, wait T_rfc (70ns) after each
philpem@2 283 sdram_mode <= M_AutoRefresh;
philpem@15 284 timer <= TCY_Trfc - 32'd1;
philpem@2 285 state <= ST_AutoRefresh1_Wait;
philpem@2 286 end
philpem@2 287
philpem@2 288 ST_AutoRefresh1_Wait: begin
philpem@2 289 // Wait for T_rfc
philpem@1 290 sdram_mode <= M_Nop;
philpem@2 291 if (timer == 32'd0) begin
philpem@2 292 // Timer hit zero. Continue
philpem@2 293 state <= ST_AutoRefresh2;
philpem@2 294 end
philpem@2 295 end
philpem@2 296
philpem@2 297 ST_AutoRefresh2: begin
philpem@2 298 // Auto Refresh 2 of 2, wait T_rfc (70ns) after each
philpem@2 299 sdram_mode <= M_AutoRefresh;
philpem@15 300 timer <= TCY_Trfc - 32'd1;
philpem@2 301 state <= ST_AutoRefresh2_Wait;
philpem@2 302 end
philpem@2 303
philpem@2 304 ST_AutoRefresh2_Wait: begin
philpem@2 305 // Wait for T_rfc
philpem@2 306 sdram_mode <= M_Nop;
philpem@2 307 if (timer == 32'd0) begin
philpem@2 308 // Timer hit zero. Continue
philpem@2 309 state <= ST_LoadModeRegister;
philpem@2 310 end
philpem@2 311 end
philpem@2 312
philpem@2 313 ST_LoadModeRegister: begin
philpem@2 314 // Load Mode Register
philpem@2 315 /**
philpem@2 316 * Mode register:
philpem@2 317 * - BS0,1 = 00 [RFU]
philpem@2 318 * - A11,10 = 00 [RFU]
philpem@2 319 * - A9 = 0 [WBL -- write burst length same as read burst length]
philpem@2 320 * - A8,7 = 00 [Test Mode off]
philpem@10 321 * - A6..4 = 010 [CAS Latency = 2 or 3 clocks, set above]
philpem@2 322 * - A3 = 0 [Burst type = sequential]
philpem@2 323 * - A2..0 = 000 [Burst length = 1 word]
philpem@2 324 */
philpem@17 325 sdram_ba <= 0;
philpem@10 326 sdram_addr <= {5'b00_0_00, CAS_LATENCY[2:0], 3'b000};
philpem@2 327 sdram_mode <= M_LoadModeRegister;
philpem@2 328
philpem@2 329 // Wait T_mrd (2 clock cycles)
philpem@15 330 timer <= TCY_Tmrd - 32'd1;
philpem@2 331 state <= ST_LoadModeRegister_Wait;
philpem@2 332 end
philpem@2 333
philpem@2 334 ST_LoadModeRegister_Wait: begin
philpem@2 335 // Wait for LMR to complete
philpem@2 336 sdram_mode <= M_Nop;
philpem@17 337 sdram_ba <= 0;
philpem@17 338 sdram_addr <= 0;
philpem@2 339 if (timer == 32'd0) begin
philpem@2 340 // Timer hit zero. Continue
philpem@2 341 state <= ST_Spin;
philpem@2 342 end
philpem@2 343 end
philpem@2 344
philpem@2 345 ST_Spin: begin
philpem@3 346 // Enable refresh timer
philpem@3 347 refresh_timer_en <= 1'b1;
philpem@3 348
philpem@7 349 // Idle the SDRAM (Inhibit is lower power than NOP on some SDRAMs)
philpem@2 350 sdram_mode <= M_Inhibit;
philpem@3 351
philpem@9 352 // Check if a refresh is due (these have highest priority)
philpem@3 353 if (refresh_req) begin
philpem@3 354 // Refresh request received. Ack it and do a refresh.
philpem@3 355 refresh_ack <= 1'b1;
philpem@3 356 state <= ST_Refresh;
philpem@3 357 end else begin
philpem@7 358 if (wb_cyc_i & wb_stb_i) begin
philpem@7 359 // CYC and STB high. A Wishbone cycle just started.
philpem@7 360 state <= ST_Activate;
philpem@7 361 end
philpem@3 362 end
philpem@3 363 end
philpem@7 364
philpem@7 365 /////
philpem@7 366 // Refresh logic
philpem@7 367 /////
philpem@3 368
philpem@3 369 ST_Refresh: begin
philpem@3 370 // Refresh timer timed out; do a refresh run
philpem@3 371 // Start by clearing the ACK flag (which was set by the Spin state)
philpem@3 372 refresh_ack <= 1'b0;
philpem@3 373 // Tell the SDRAM to do a Refresh
philpem@3 374 sdram_mode <= M_AutoRefresh;
philpem@3 375 // Wait for T_rfc
philpem@15 376 timer <= TCY_Trfc;
philpem@3 377 state <= ST_Refresh_Wait;
philpem@3 378 end
philpem@3 379
philpem@3 380 ST_Refresh_Wait: begin
philpem@3 381 // Wait for T_rfc
philpem@3 382 sdram_mode <= M_Nop;
philpem@3 383 if (timer == 32'd0) begin
philpem@3 384 // Timer hit zero. Go back to spin state.
philpem@3 385 state <= ST_Spin;
philpem@3 386 end
philpem@0 387 end
philpem@7 388
philpem@7 389 //////
philpem@7 390 // R/W logic
philpem@7 391 //////
philpem@7 392 ST_Activate: begin
philpem@7 393 // Activate the required bank
philpem@4 394 sdram_mode <= M_BankActivate;
philpem@4 395 sdram_addr <= row_addr;
philpem@7 396 sdram_ba <= bank_addr;
philpem@15 397 timer <= TCY_Trcd - 32'd1;
philpem@7 398 state <= ST_Activate_Wait;
philpem@4 399 end
philpem@4 400
philpem@7 401 ST_Activate_Wait: begin
philpem@7 402 // Wait for T_rcd
philpem@4 403 sdram_mode <= M_Nop;
philpem@4 404 if (timer == 32'd0) begin
philpem@7 405 if (wb_we_i) begin
philpem@7 406 // Write cycle.
philpem@7 407 state <= ST_Write;
philpem@7 408 end else begin
philpem@7 409 // Read cycle
philpem@7 410 state <= ST_Read;
philpem@7 411 end
philpem@4 412 end
philpem@4 413 end
philpem@4 414
philpem@7 415 ST_Write: begin
philpem@7 416 // Write cycle handler
philpem@7 417 sdram_mode <= M_WritePrecharge;
philpem@7 418 sdram_addr <= column_addr;
philpem@17 419 sdram_dq_r <= 0;
philpem@17 420 sdram_dq_oe <= 1; // FPGA drives the DQ bus
philpem@9 421 sdram_dqm <= ~wb_sel_i;
philpem@7 422
philpem@7 423 // Wait T_rp (20ns)
philpem@15 424 timer <= TCY_Trp - 32'd1;
philpem@7 425 state <= ST_Wait_Trp;
philpem@7 426 end
philpem@7 427
philpem@7 428 ST_Read: begin
philpem@7 429 // Read cycle handler
philpem@7 430 sdram_mode <= M_ReadPrecharge;
philpem@7 431 sdram_addr <= column_addr;
philpem@17 432 sdram_dq_oe <= 0; // SDRAM drives the DQ bus
philpem@17 433 sdram_dqm <= 0; // Grab all the data (easier than playing with WB_SEL...)
philpem@10 434 timer <= CAS_LATENCY - 32'd1; // CAS# Latency
philpem@7 435 state <= ST_Read_Wait;
philpem@4 436 end
philpem@4 437
philpem@7 438 ST_Read_Wait: begin
philpem@7 439 // Wait for CAS# latency
philpem@7 440 sdram_mode <= M_Nop;
philpem@17 441 sdram_dqm <= {(DATA_BITS/4){1'b1}}; // Make SDRAM DQ bus float
philpem@4 442 if (timer == 32'd0) begin
philpem@7 443 // Latch data
philpem@7 444 wb_dat_o <= sdram_dq;
philpem@7 445 // Wait T_rp (20ns)
philpem@15 446 timer <= TCY_Trp - 32'd1;
philpem@7 447 state <= ST_Wait_Trp;
philpem@4 448 end
philpem@4 449 end
philpem@5 450
philpem@7 451 ST_Wait_Trp: begin
philpem@7 452 // Wait for T_rp, then ack
philpem@7 453 if (timer == 32'd0) begin
philpem@7 454 state <= ST_Ack;
philpem@7 455 end
philpem@4 456 end
philpem@4 457
philpem@7 458 ST_Ack: begin
philpem@7 459 // Ack the transfer to the WISHBONE host
philpem@7 460 sdram_mode <= M_Nop;
philpem@17 461 sdram_addr <= 0;
philpem@17 462 sdram_dq_r <= 0;
philpem@17 463 sdram_dq_oe <= 0; // SDRAM drives the DQ bus
philpem@17 464 sdram_dqm <= {(DATA_BITS/4){1'b1}}; // mask off DQM
philpem@7 465 if (wb_cyc_i & wb_stb_i) begin
philpem@7 466 // CYC and STB high, ack the transfer
philpem@7 467 wb_ack_o <= 1'b1;
philpem@7 468 state <= ST_Ack;
philpem@7 469 end else begin
philpem@9 470 // CYC and STB low, go back and wait for another transaction
philpem@9 471 wb_ack_o <= 1'b0;
philpem@7 472 state <= ST_Spin;
philpem@4 473 end
philpem@4 474 end
philpem@0 475 endcase
philpem@0 476 end
philpem@0 477 end
philpem@0 478
philpem@0 479 endmodule