wb_sdram.v

Wed, 11 Aug 2010 01:15:20 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 11 Aug 2010 01:15:20 +0100
changeset 15
da71a5efdf98
parent 14
b541478bbb73
child 16
49f3a5bd860e
permissions
-rw-r--r--

fully parameterise CLOCK_RATE and SDRAM timing

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