wb_sdram.v

Tue, 10 Aug 2010 18:04:05 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Tue, 10 Aug 2010 18:04:05 +0100
changeset 6
39984d9ff640
parent 5
dd6f40c05963
child 7
001f5282bff0
permissions
-rw-r--r--

make test work like a R/W checkerboard instead (looks better on the LA)

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@6 153 reg [31:0] captured_data;
philpem@0 154 always @(posedge wb_clk_i) begin
philpem@0 155 if (wb_rst_i) begin
philpem@0 156 // Initialise state machine and timer
philpem@0 157 state <= ST_INIT1;
philpem@3 158 // debug <= 3'd0;
philpem@0 159 timer <= 32'd0;
philpem@3 160
philpem@3 161 // Clear REFRESH ACK flag and disable refresh timer
philpem@3 162 refresh_ack <= 1'b0;
philpem@3 163 refresh_timer_en <= 1'b0;
philpem@0 164
philpem@0 165 // Initialisation state for SDRAM
philpem@0 166 sdram_cke <= 1'b0;
philpem@0 167 sdram_mode <= M_Inhibit;
philpem@0 168 sdram_addr <= 12'h000;
philpem@0 169 sdram_ba <= 2'b00;
philpem@0 170 sdram_dqm <= 4'b0000;
philpem@0 171 sdram_dq_oe <= 1'b0; // data output disabled
philpem@0 172 sdram_dq_r <= 32'd0;
philpem@0 173 end else begin
philpem@0 174 // timer logic
philpem@0 175 if (timer > 32'd0) begin
philpem@0 176 timer <= timer - 32'd1;
philpem@0 177 end
philpem@0 178
philpem@0 179 // state machine logic
philpem@0 180 case (state)
philpem@0 181 ST_INIT1: begin
philpem@0 182 // INIT1: Set up for initial power-up wait
philpem@0 183 state <= ST_INIT2;
philpem@0 184 timer <= 32'd50_000; // TODO: dependent on core clock rate. Needs to be >= 100us
philpem@0 185
philpem@0 186 // SDRAM state
philpem@0 187 sdram_cke <= 1'b0; // clock disabled
philpem@0 188 sdram_mode <= M_Inhibit;
philpem@0 189 sdram_addr <= 12'h000;
philpem@0 190 sdram_ba <= 2'b00;
philpem@0 191 sdram_dqm <= 4'b1111;
philpem@0 192 sdram_dq_oe <= 1'b0; // data output disabled
philpem@0 193 sdram_dq_r <= 32'd0;
philpem@0 194 end
philpem@0 195
philpem@0 196 ST_INIT2: begin
philpem@0 197 // INIT2: Power-up wait. Keep CKE low until ~50 cycles before
philpem@0 198 // the end of the power-up wait, then bring CKE high.
philpem@0 199 if (timer == 32'd0) begin
philpem@0 200 // Timer hit zero. Send a NOP.
philpem@2 201 state <= ST_NOP1;
philpem@1 202 end else if (timer < 32'd50) begin
philpem@0 203 // Timer value is more than zero but less than 50; CKE is on, but
philpem@0 204 // keep waiting for the timer to actually expire.
philpem@0 205 sdram_cke <= 1'b1;
philpem@0 206 state <= ST_INIT2;
philpem@3 207 // debug <= 3'd1;
philpem@0 208 end
philpem@0 209 sdram_mode <= M_Inhibit;
philpem@0 210 end
philpem@0 211
philpem@2 212 ST_NOP1: begin
philpem@2 213 // Apply one or more NOP commands to the SDRAM
philpem@2 214 sdram_mode <= M_Nop;
philpem@2 215 state <= ST_PrechargeAll;
philpem@2 216 end
philpem@2 217
philpem@2 218 ST_PrechargeAll: begin
philpem@2 219 // Precharge All, then wait T_rp (20ns)
philpem@2 220 sdram_mode <= M_PrechargeAll;
philpem@2 221 timer <= 32'd0; // wait 1tcy (40ns) ---> TIMER HERE
philpem@2 222 state <= ST_PrechargeAll_Wait;
philpem@2 223 end
philpem@2 224
philpem@2 225 ST_PrechargeAll_Wait: begin
philpem@2 226 // Wait for T_rp after Precharge All
philpem@2 227 sdram_mode <= M_Nop;
philpem@2 228 if (timer == 32'd0) begin
philpem@2 229 // Timer hit zero. Continue
philpem@2 230 state <= ST_AutoRefresh1;
philpem@2 231 end
philpem@2 232 end
philpem@2 233
philpem@2 234 ST_AutoRefresh1: begin
philpem@2 235 // Auto Refresh 1 of 2, wait T_rfc (70ns) after each
philpem@2 236 sdram_mode <= M_AutoRefresh;
philpem@2 237 timer <= 32'd1; // wait 2tcy (80ns) ---> TIMER HERE
philpem@2 238 state <= ST_AutoRefresh1_Wait;
philpem@2 239 end
philpem@2 240
philpem@2 241 ST_AutoRefresh1_Wait: begin
philpem@2 242 // Wait for T_rfc
philpem@1 243 sdram_mode <= M_Nop;
philpem@2 244 if (timer == 32'd0) begin
philpem@2 245 // Timer hit zero. Continue
philpem@2 246 state <= ST_AutoRefresh2;
philpem@2 247 end
philpem@2 248 end
philpem@2 249
philpem@2 250 ST_AutoRefresh2: begin
philpem@2 251 // Auto Refresh 2 of 2, wait T_rfc (70ns) after each
philpem@2 252 sdram_mode <= M_AutoRefresh;
philpem@2 253 timer <= 32'd1; // wait 2tcy (80ns) ---> TIMER HERE
philpem@2 254 state <= ST_AutoRefresh2_Wait;
philpem@2 255 end
philpem@2 256
philpem@2 257 ST_AutoRefresh2_Wait: begin
philpem@2 258 // Wait for T_rfc
philpem@2 259 sdram_mode <= M_Nop;
philpem@2 260 if (timer == 32'd0) begin
philpem@2 261 // Timer hit zero. Continue
philpem@2 262 state <= ST_LoadModeRegister;
philpem@2 263 end
philpem@2 264 end
philpem@2 265
philpem@2 266 ST_LoadModeRegister: begin
philpem@2 267 // Load Mode Register
philpem@2 268 /**
philpem@2 269 * Mode register:
philpem@2 270 * - BS0,1 = 00 [RFU]
philpem@2 271 * - A11,10 = 00 [RFU]
philpem@2 272 * - A9 = 0 [WBL -- write burst length same as read burst length]
philpem@2 273 * - A8,7 = 00 [Test Mode off]
philpem@2 274 * - A6..4 = 010 [CAS Latency = 2 clocks]
philpem@2 275 * - A3 = 0 [Burst type = sequential]
philpem@2 276 * - A2..0 = 000 [Burst length = 1 word]
philpem@2 277 */
philpem@2 278 sdram_ba <= 2'b00;
philpem@2 279 sdram_addr <= 12'b00_0_00_010_000;
philpem@2 280 sdram_mode <= M_LoadModeRegister;
philpem@2 281
philpem@2 282 // Wait T_mrd (2 clock cycles)
philpem@2 283 timer <= 32'd1; // (2cy)-1 ---> TIMER HERE
philpem@2 284 state <= ST_LoadModeRegister_Wait;
philpem@2 285 end
philpem@2 286
philpem@2 287 ST_LoadModeRegister_Wait: begin
philpem@2 288 // Wait for LMR to complete
philpem@2 289 sdram_mode <= M_Nop;
philpem@2 290 sdram_ba <= 2'd0;
philpem@2 291 sdram_addr <= 12'd0;
philpem@2 292 if (timer == 32'd0) begin
philpem@2 293 // Timer hit zero. Continue
philpem@2 294 state <= ST_Spin;
philpem@2 295 end
philpem@2 296 end
philpem@2 297
philpem@2 298 ST_Spin: begin
philpem@3 299 // Enable refresh timer
philpem@3 300 refresh_timer_en <= 1'b1;
philpem@3 301
philpem@2 302 sdram_mode <= M_Inhibit;
philpem@3 303
philpem@3 304 if (refresh_req) begin
philpem@3 305 // Refresh request received. Ack it and do a refresh.
philpem@3 306 refresh_ack <= 1'b1;
philpem@3 307 state <= ST_Refresh;
philpem@3 308 end else begin
philpem@4 309 //state <= ST_Spin; // NOTE: turned off to run a ram test...
philpem@4 310 state <= ST_Test_Activate;
philpem@3 311 end
philpem@3 312 end
philpem@3 313
philpem@3 314 ST_Refresh: begin
philpem@3 315 // Refresh timer timed out; do a refresh run
philpem@3 316 // Start by clearing the ACK flag (which was set by the Spin state)
philpem@3 317 refresh_ack <= 1'b0;
philpem@3 318 // Tell the SDRAM to do a Refresh
philpem@3 319 sdram_mode <= M_AutoRefresh;
philpem@3 320 // Wait for T_rfc
philpem@3 321 timer <= 32'd1; // wait Trfc (70ns ideally, we give 80ns) ---> TIMER HERE
philpem@3 322 state <= ST_Refresh_Wait;
philpem@3 323 end
philpem@3 324
philpem@3 325 ST_Refresh_Wait: begin
philpem@3 326 // Wait for T_rfc
philpem@3 327 sdram_mode <= M_Nop;
philpem@3 328 if (timer == 32'd0) begin
philpem@3 329 // Timer hit zero. Go back to spin state.
philpem@3 330 state <= ST_Spin;
philpem@3 331 end
philpem@0 332 end
philpem@4 333
philpem@4 334 ST_Test_Activate: begin
philpem@4 335 // Activate bank
philpem@4 336 sdram_mode <= M_BankActivate;
philpem@4 337 sdram_addr <= row_addr;
philpem@4 338 sdram_ba <= bank_addr;
philpem@4 339 timer <= 32'd0; // wait Trcd (20ns ideally, this is 40ns) ---> TIMER HERE
philpem@4 340 state <= ST_Test_Activate_Wait;
philpem@4 341 end
philpem@4 342
philpem@4 343 ST_Test_Activate_Wait: begin
philpem@4 344 // Wait for Activate Bank to complete
philpem@4 345 sdram_mode <= M_Nop;
philpem@4 346 if (timer == 32'd0) begin
philpem@4 347 state <= ST_Test_Read;
philpem@4 348 end
philpem@4 349 end
philpem@4 350
philpem@4 351 ST_Test_Read: begin
philpem@4 352 // Do the Read operation
philpem@4 353 sdram_mode <= M_Read;
philpem@4 354 sdram_addr <= column_addr;
philpem@4 355 sdram_dqm <= 4'b0000; // Allow data through (DQM = OE# = 1 to mask off, 0 to allow)
philpem@5 356 timer <= 32'd2 - 32'd1; // wait CAS# Latency (2 clock cycles) ---> TIMER HERE
philpem@4 357 state <= ST_Test_Read_Wait;
philpem@4 358 end
philpem@4 359
philpem@4 360 ST_Test_Read_Wait: begin
philpem@4 361 // Wait for CAS latency
philpem@4 362 sdram_mode <= M_Nop;
philpem@4 363 sdram_dqm <= 4'b1111; // Disable SDRAM output buffers
philpem@4 364 if (timer == 32'd0) begin
philpem@5 365 state <= ST_Test_Read_Finish;
philpem@6 366 captured_data <= sdram_dq;
philpem@4 367 end
philpem@4 368 end
philpem@5 369
philpem@5 370 ST_Test_Read_Finish: begin
philpem@5 371 // Additional NOP after read to avoid bus contention if next transaction is a write
philpem@5 372 sdram_mode <= M_Nop;
philpem@5 373 sdram_dqm <= 4'b1111; // Disable SDRAM output buffers
philpem@5 374 state <= ST_Test_Write;
philpem@5 375 end
philpem@4 376
philpem@4 377 ST_Test_Write: begin
philpem@4 378 // Write to SDRAM
philpem@4 379 sdram_mode <= M_Write;
philpem@4 380 sdram_addr <= column_addr;
philpem@6 381 sdram_dq_r <= ~captured_data; //32'h55AA_BCDE;
philpem@4 382 sdram_dq_oe <= 1'b1; // output enable
philpem@4 383 sdram_dqm <= 4'b0000; // Allow data through (DQM = OE# = 1 to mask off, 0 to allow)
philpem@4 384 state <= ST_Test_Precharge_All;
philpem@4 385 end
philpem@4 386
philpem@4 387 ST_Test_Precharge_All: begin
philpem@4 388 // Precharge All
philpem@4 389 sdram_mode <= M_PrechargeAll;
philpem@4 390 sdram_addr <= 12'd0;
philpem@4 391 sdram_dq_oe <= 1'b0; // output disable
philpem@4 392 sdram_dqm <= 4'b1111; // Disable SDRAM output buffers
philpem@4 393 sdram_dq_r <= 32'd0;
philpem@4 394 state <= ST_Spin;
philpem@4 395 // Wait T_rp (20ns)
philpem@4 396 timer <= 32'd0; // wait 1tcy (40ns) ---> TIMER HERE
philpem@4 397 state <= ST_Test_Precharge_All_Wait;
philpem@4 398 end
philpem@4 399
philpem@4 400 ST_Test_Precharge_All_Wait: begin
philpem@4 401 // Wait for T_rp after Precharge All
philpem@4 402 sdram_mode <= M_Nop;
philpem@4 403 if (timer == 32'd0) begin
philpem@4 404 // Timer hit zero. Continue
philpem@4 405 state <= ST_Spin;
philpem@4 406 end
philpem@4 407 end
philpem@0 408 endcase
philpem@0 409 end
philpem@0 410 end
philpem@0 411
philpem@0 412 endmodule