wb_sdram.v

Tue, 10 Aug 2010 13:23:58 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Tue, 10 Aug 2010 13:23:58 +0100
changeset 2
ceaa61ebf8a2
parent 1
05af11892ed8
child 3
6a724779fb48
permissions
-rw-r--r--

implement (almost) complete SDRAM init sequence

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@0 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@0 87 * Finite State Machine
philpem@0 88 ****/
philpem@2 89 localparam ST_INIT1 = 32'd0;
philpem@2 90 localparam ST_INIT2 = 32'd1;
philpem@2 91 localparam ST_NOP1 = 32'd2;
philpem@2 92 localparam ST_PrechargeAll = 32'd3;
philpem@2 93 localparam ST_PrechargeAll_Wait = 32'd4;
philpem@2 94 localparam ST_AutoRefresh1 = 32'd5;
philpem@2 95 localparam ST_AutoRefresh1_Wait = 32'd6;
philpem@2 96 localparam ST_AutoRefresh2 = 32'd7;
philpem@2 97 localparam ST_AutoRefresh2_Wait = 32'd8;
philpem@2 98 localparam ST_LoadModeRegister = 32'd9;
philpem@2 99 localparam ST_LoadModeRegister_Wait = 32'd10;
philpem@2 100 localparam ST_Spin = 32'd999;
philpem@0 101
philpem@0 102 reg [31:0] state;
philpem@0 103 always @(posedge wb_clk_i) begin
philpem@0 104 if (wb_rst_i) begin
philpem@0 105 // Initialise state machine and timer
philpem@0 106 state <= ST_INIT1;
philpem@0 107 debug <= 3'd0;
philpem@0 108 timer <= 32'd0;
philpem@0 109
philpem@0 110 // Initialisation state for SDRAM
philpem@0 111 sdram_cke <= 1'b0;
philpem@0 112 sdram_mode <= M_Inhibit;
philpem@0 113 sdram_addr <= 12'h000;
philpem@0 114 sdram_ba <= 2'b00;
philpem@0 115 sdram_dqm <= 4'b0000;
philpem@0 116 sdram_dq_oe <= 1'b0; // data output disabled
philpem@0 117 sdram_dq_r <= 32'd0;
philpem@0 118 end else begin
philpem@0 119 // timer logic
philpem@0 120 if (timer > 32'd0) begin
philpem@0 121 timer <= timer - 32'd1;
philpem@0 122 end
philpem@0 123
philpem@0 124 // state machine logic
philpem@0 125 case (state)
philpem@0 126 ST_INIT1: begin
philpem@0 127 // INIT1: Set up for initial power-up wait
philpem@0 128 state <= ST_INIT2;
philpem@0 129 timer <= 32'd50_000; // TODO: dependent on core clock rate. Needs to be >= 100us
philpem@0 130
philpem@0 131 // SDRAM state
philpem@0 132 sdram_cke <= 1'b0; // clock disabled
philpem@0 133 sdram_mode <= M_Inhibit;
philpem@0 134 sdram_addr <= 12'h000;
philpem@0 135 sdram_ba <= 2'b00;
philpem@0 136 sdram_dqm <= 4'b1111;
philpem@0 137 sdram_dq_oe <= 1'b0; // data output disabled
philpem@0 138 sdram_dq_r <= 32'd0;
philpem@0 139 end
philpem@0 140
philpem@0 141 ST_INIT2: begin
philpem@0 142 // INIT2: Power-up wait. Keep CKE low until ~50 cycles before
philpem@0 143 // the end of the power-up wait, then bring CKE high.
philpem@0 144 if (timer == 32'd0) begin
philpem@0 145 // Timer hit zero. Send a NOP.
philpem@2 146 state <= ST_NOP1;
philpem@1 147 end else if (timer < 32'd50) begin
philpem@0 148 // Timer value is more than zero but less than 50; CKE is on, but
philpem@0 149 // keep waiting for the timer to actually expire.
philpem@0 150 sdram_cke <= 1'b1;
philpem@0 151 state <= ST_INIT2;
philpem@0 152 debug <= 3'd1;
philpem@0 153 end
philpem@0 154 sdram_mode <= M_Inhibit;
philpem@0 155 end
philpem@0 156
philpem@2 157 ST_NOP1: begin
philpem@2 158 // Apply one or more NOP commands to the SDRAM
philpem@2 159 sdram_mode <= M_Nop;
philpem@2 160 state <= ST_PrechargeAll;
philpem@2 161 end
philpem@2 162
philpem@2 163 ST_PrechargeAll: begin
philpem@2 164 // Precharge All, then wait T_rp (20ns)
philpem@2 165 sdram_mode <= M_PrechargeAll;
philpem@2 166 timer <= 32'd0; // wait 1tcy (40ns) ---> TIMER HERE
philpem@2 167 state <= ST_PrechargeAll_Wait;
philpem@2 168 end
philpem@2 169
philpem@2 170 ST_PrechargeAll_Wait: begin
philpem@2 171 // Wait for T_rp after Precharge All
philpem@2 172 sdram_mode <= M_Nop;
philpem@2 173 if (timer == 32'd0) begin
philpem@2 174 // Timer hit zero. Continue
philpem@2 175 state <= ST_AutoRefresh1;
philpem@2 176 end
philpem@2 177 end
philpem@2 178
philpem@2 179 ST_AutoRefresh1: begin
philpem@2 180 // Auto Refresh 1 of 2, wait T_rfc (70ns) after each
philpem@2 181 sdram_mode <= M_AutoRefresh;
philpem@2 182 timer <= 32'd1; // wait 2tcy (80ns) ---> TIMER HERE
philpem@2 183 state <= ST_AutoRefresh1_Wait;
philpem@2 184 end
philpem@2 185
philpem@2 186 ST_AutoRefresh1_Wait: begin
philpem@2 187 // Wait for T_rfc
philpem@1 188 sdram_mode <= M_Nop;
philpem@2 189 if (timer == 32'd0) begin
philpem@2 190 // Timer hit zero. Continue
philpem@2 191 state <= ST_AutoRefresh2;
philpem@2 192 end
philpem@2 193 end
philpem@2 194
philpem@2 195 ST_AutoRefresh2: begin
philpem@2 196 // Auto Refresh 2 of 2, wait T_rfc (70ns) after each
philpem@2 197 sdram_mode <= M_AutoRefresh;
philpem@2 198 timer <= 32'd1; // wait 2tcy (80ns) ---> TIMER HERE
philpem@2 199 state <= ST_AutoRefresh2_Wait;
philpem@2 200 end
philpem@2 201
philpem@2 202 ST_AutoRefresh2_Wait: begin
philpem@2 203 // Wait for T_rfc
philpem@2 204 sdram_mode <= M_Nop;
philpem@2 205 if (timer == 32'd0) begin
philpem@2 206 // Timer hit zero. Continue
philpem@2 207 state <= ST_LoadModeRegister;
philpem@2 208 end
philpem@2 209 end
philpem@2 210
philpem@2 211 ST_LoadModeRegister: begin
philpem@2 212 // Load Mode Register
philpem@2 213 /**
philpem@2 214 * Mode register:
philpem@2 215 * - BS0,1 = 00 [RFU]
philpem@2 216 * - A11,10 = 00 [RFU]
philpem@2 217 * - A9 = 0 [WBL -- write burst length same as read burst length]
philpem@2 218 * - A8,7 = 00 [Test Mode off]
philpem@2 219 * - A6..4 = 010 [CAS Latency = 2 clocks]
philpem@2 220 * - A3 = 0 [Burst type = sequential]
philpem@2 221 * - A2..0 = 000 [Burst length = 1 word]
philpem@2 222 */
philpem@2 223 sdram_ba <= 2'b00;
philpem@2 224 sdram_addr <= 12'b00_0_00_010_000;
philpem@2 225 sdram_mode <= M_LoadModeRegister;
philpem@2 226
philpem@2 227 // Wait T_mrd (2 clock cycles)
philpem@2 228 timer <= 32'd1; // (2cy)-1 ---> TIMER HERE
philpem@2 229 state <= ST_LoadModeRegister_Wait;
philpem@2 230 end
philpem@2 231
philpem@2 232 ST_LoadModeRegister_Wait: begin
philpem@2 233 // Wait for LMR to complete
philpem@2 234 sdram_mode <= M_Nop;
philpem@2 235 sdram_ba <= 2'd0;
philpem@2 236 sdram_addr <= 12'd0;
philpem@2 237 if (timer == 32'd0) begin
philpem@2 238 // Timer hit zero. Continue
philpem@2 239 state <= ST_Spin;
philpem@2 240 end
philpem@2 241 end
philpem@2 242
philpem@2 243 ST_Spin: begin
philpem@2 244 sdram_mode <= M_Inhibit;
philpem@2 245 state <= ST_Spin;
philpem@0 246 end
philpem@0 247 endcase
philpem@0 248 end
philpem@0 249 end
philpem@0 250
philpem@0 251 endmodule