sdram.sv (11761B)
1 // Copyright 2020, Brian Swetland <swetland@frotz.net> 2 // Licensed under the Apache License, Version 2.0. 3 4 `default_nettype none 5 6 // tRCD (RAS# to CAS# Delay Time) 7 // Min clocks betwen ACTIVE of a bank and a READ or WRITE of that bank 8 // 9 // tRC (RAS# Cycle Time) 10 // Min clocks between ACTIVE of one row in a bank and ACTIVE of a 11 // different row in the /same/ bank. PRECHARGE must happen in between. 12 // 13 // tRRD (Row Activate to Row Activate Delay) 14 // Min time between ACTIVE of a row in one bank and the ACTIVE of 15 // a row in a /different/ bank. 16 // 17 // tRP (Precharge to Refresh/Activate) 18 // Min time between PREFRESH of a bank and REFRESH or ACTIVE of it 19 // 20 // tWR (Write Recovery Time) 21 // Min clocks between the last word of a write and PRECHARGE of that bank 22 23 module sdram #( 24 // Memory Geometry 25 parameter BANKBITS = 1, // 2^BANKBITS banks of 26 parameter ROWBITS = 11, // 2^ROWBITS rows by 27 parameter COLBITS = 8, // 2^COLBITS columns of 28 parameter DWIDTH = 16, // DWIDTH bit wide words 29 30 // Memory Timing 31 parameter T_RI = 1900, // Refresh Interval 32 parameter T_RC = 8, // RAS# Cycle Time 33 parameter T_RCD = 3, // RAS# CAS# Delay 34 parameter T_RRD = 3, // Row Row Delay 35 parameter T_RP = 3, // Precharge to Refresh/Activate 36 parameter T_WR = 2, // Write Recovery TimeA 37 parameter T_MRD = 3, // Mode Register Delay 38 parameter T_PWR_UP = 25000, // Power on delay 39 40 // Fine TuningA 41 parameter CLK_SHIFT = 0, // 1 = delay clock by 1/2 cycle (if 1) 42 parameter CLK_DELAY = 0 // 1..128 = delay clock by N x 25pS (ECP5) 43 ) ( 44 input wire clk, 45 input wire reset, 46 output wire pin_clk, 47 output wire pin_ras_n, 48 output wire pin_cas_n, 49 output wire pin_we_n, 50 inout wire [DWIDTH-1:0]pin_data, 51 output wire [AWIDTH-1:0]pin_addr, 52 53 input wire [XWIDTH-1:0]rd_addr, 54 input wire [3:0]rd_len, 55 input wire rd_req, 56 output reg rd_ack = 0, 57 58 output reg [DWIDTH-1:0]rd_data, 59 output reg rd_rdy = 0, 60 61 input wire [XWIDTH-1:0]wr_addr, 62 input wire [DWIDTH-1:0]wr_data, 63 input wire [3:0]wr_len, 64 input wire wr_req, 65 output reg wr_ack = 0 66 ); 67 68 // sdram addr is wide enough for row + bank 69 localparam AWIDTH = (ROWBITS + BANKBITS); 70 71 // full addr is rowbits + bankbits + colbits wide 72 localparam XWIDTH = (ROWBITS + BANKBITS + COLBITS); 73 74 localparam BANKCOUNT = (1 << BANKBITS); 75 76 // validate T_RCD and adjust MODE bits and read latency configuration 77 if ((T_RCD != 2) && (T_RCD != 3)) 78 $error("T_RCD must be 2 or 3"); 79 80 localparam PMSB = T_RCD; 81 localparam [1:0]SDRAM_CL = T_RCD; 82 localparam [9:0]SDRAM_MODE = { 4'b000, SDRAM_CL, 4'b0000 }; 83 84 integer i; // used by various for loops 85 86 // split input address into bank, row, col 87 wire [BANKBITS-1:0]wr_bank; 88 wire [ROWBITS-1:0]wr_row; 89 wire [COLBITS-1:0]wr_col; 90 assign {wr_row, wr_bank, wr_col} = wr_addr; 91 92 // split input address into bank, row, col 93 wire [BANKBITS-1:0]rd_bank; 94 wire [ROWBITS-1:0]rd_row; 95 wire [COLBITS-1:0]rd_col; 96 assign {rd_row, rd_bank, rd_col} = rd_addr; 97 98 // sdram io address management 99 reg [XWIDTH-1:0]io_addr = 0; 100 reg [XWIDTH-1:0]io_addr_next; 101 102 wire [COLBITS-1:0]io_col; 103 wire [BANKBITS-1:0]io_bank; 104 wire [ROWBITS-1:0]io_row; 105 assign {io_row, io_bank, io_col} = io_addr; 106 wire [COLBITS-1:0]io_col_add1 = io_col + {{COLBITS-1{1'b0}},1'b1}; 107 108 reg [DWIDTH-1:0]rd_data_next; 109 reg rd_ack_next; 110 reg rd_rdy_next; 111 reg wr_ack_next; 112 113 // signals to sdram_glue module 114 wire ras_n; 115 wire cas_n; 116 wire we_n; 117 wire [AWIDTH-1:0]addr; 118 wire [DWIDTH-1:0]data_i; 119 reg [DWIDTH-1:0]data_o = 0; 120 reg data_oe = 0; 121 122 reg [DWIDTH-1:0]data_o_next; 123 reg data_oe_next; 124 125 reg [2:0]cmd = 3'b111; 126 reg [2:0]cmd_next; 127 128 // next refresh down counter 129 reg [15:0]refresh = T_PWR_UP; 130 reg [15:0]refresh_next; 131 wire [15:0]refresh_sub1 = refresh - 16'd1; 132 wire refresh_done = refresh[15]; 133 134 // sdram bank state 135 reg bank_active[0:BANKCOUNT-1]; 136 reg bank_active_next[0:BANKCOUNT-1]; 137 reg [ROWBITS-1:0]bank_row[0:BANKCOUNT-1]; 138 reg [ROWBITS-1:0]bank_row_next[0:BANKCOUNT-1]; 139 140 // state machine state 141 localparam START = 4'd0; 142 localparam IDLE = 4'd1; 143 localparam INIT0 = 4'd2; 144 localparam INIT1 = 4'd3; 145 localparam INIT2 = 4'd4; 146 localparam REFRESH = 4'd5; 147 localparam ACTIVE = 4'd6; 148 localparam READ = 4'd7; 149 localparam WRITE = 4'd8; 150 localparam START_READ = 4'd9; 151 localparam START_WRITE = 4'd10; 152 153 reg [3:0]state = START; 154 reg [3:0]state_next; 155 156 // sdram commands 157 localparam CMD_SET_MODE = 3'b000; // A0-9 mode, A10+ SBZ 158 localparam CMD_REFRESH = 3'b001; 159 localparam CMD_PRECHARGE = 3'b010; // BA*=bankno, A10=ALL 160 localparam CMD_ACTIVE = 3'b011; // BA*=bankno, A*=ROW 161 localparam CMD_WRITE = 3'b100; // BA*=bankno, A10=AP, COLADDR 162 localparam CMD_READ = 3'b101; // BA*=bankno, A10=AP, COLADDR 163 localparam CMD_STOP = 3'b110; 164 localparam CMD_NOP = 3'b111; 165 166 reg [PMSB:0]rd_pipe_rdy = 0; 167 reg [PMSB:0]rd_pipe_bsy = 0; 168 reg [PMSB:0]rd_pipe_rdy_next; 169 reg [PMSB:0]rd_pipe_bsy_next; 170 171 reg [3:0]burst = 0; 172 reg [3:0]burst_next; 173 wire [3:0]burst_sub1; 174 wire burst_done; 175 assign { burst_done, burst_sub1 } = { 1'b0, burst } - 5'd1; 176 177 reg io_sel_a10 = 0; 178 reg io_sel_a10_next; 179 reg io_sel_row = 0; 180 reg io_sel_row_next; 181 182 // general purpose down counter 183 //reg [4:0]count = 0; 184 //reg [4:0]count_next; 185 //wire [4:0]count_sub1 = count - 5'd1; 186 //wire count_done = count[4]; 187 188 reg [8:0]count = 0; 189 reg [8:0]count_next; 190 reg count_done = 1; 191 reg count_done_next; 192 193 reg io_do_rd = 0; 194 reg io_do_rd_next; 195 196 always_comb begin 197 state_next = state; 198 // count_next = count_done ? count : count_sub1; 199 refresh_next = refresh_done ? refresh : refresh_sub1; 200 cmd_next = CMD_NOP; 201 data_o_next = data_o; 202 data_oe_next = 0; 203 wr_ack_next = 0; 204 rd_rdy_next = 0; 205 rd_ack_next = 0; 206 rd_data_next = rd_data; 207 burst_next = burst; 208 io_addr_next = io_addr; 209 io_do_rd_next = io_do_rd; 210 io_sel_a10_next = io_sel_a10; 211 io_sel_row_next = io_sel_row; 212 213 count_done_next = count_done | count[0]; 214 count_next = { 1'b0, count[8:1] }; 215 216 for (i = 0; i < BANKCOUNT; i++) begin 217 bank_active_next[i] = bank_active[i]; 218 bank_row_next[i] = bank_row[i]; 219 end 220 221 // read pipe regs track inbound read data (rdy) 222 // and hold off writes (bsy) to avoid bus conflict 223 rd_pipe_rdy_next = { 1'b0, rd_pipe_rdy[PMSB:1] }; 224 rd_pipe_bsy_next = { 1'b0, rd_pipe_bsy[PMSB:1] }; 225 226 if (rd_pipe_rdy[0]) begin 227 rd_rdy_next = 1; 228 rd_data_next = data_i; 229 end 230 231 if (count_done) // state can only advance if counter is 0 232 case (state) 233 START: begin 234 refresh_next = T_PWR_UP; 235 state_next = INIT0; 236 end 237 IDLE: begin 238 if (refresh_done) begin 239 // refresh counter has expired, precharge all and refresh 240 state_next = REFRESH; 241 cmd_next = CMD_PRECHARGE; 242 io_sel_row_next = 0; 243 io_sel_a10_next = 1; // ALL BANKS 244 //count_next = T_RP - 2; 245 count_next[T_RP-2] = 1; count_done_next = 0; 246 end else 247 if (rd_req) begin 248 io_do_rd_next = 1; 249 io_addr_next = rd_addr; 250 burst_next = rd_len; 251 state_next = START_READ; 252 rd_ack_next = 1; 253 end else if (wr_req) begin 254 io_do_rd_next = 0; 255 io_addr_next = wr_addr; 256 data_o_next = wr_data; 257 burst_next = wr_len; 258 state_next = START_WRITE; 259 wr_ack_next = 1; 260 end 261 end 262 START_READ: begin 263 if (!bank_active[io_bank] || (bank_row[io_bank] != io_row)) begin 264 state_next = ACTIVE; 265 cmd_next = CMD_PRECHARGE; 266 io_sel_row_next = 0; // column addr 267 io_sel_a10_next = 0; // one bank only 268 //count_next = T_RP - 2; 269 count_next[T_RP-2] = 1; count_done_next = 0; 270 end else begin 271 cmd_next = CMD_READ; 272 io_sel_row_next = 0; // column addr 273 io_sel_a10_next = 0; // no auto precharge 274 rd_pipe_rdy_next = { 1'b1, rd_pipe_rdy[PMSB:1] }; 275 rd_pipe_bsy_next = { PMSB + 1 { 1'b1 } }; 276 if (burst == 4'd0) begin 277 state_next = IDLE; 278 end else begin 279 state_next = READ; 280 burst_next = burst_sub1; 281 end 282 end 283 end 284 START_WRITE: if (!rd_pipe_bsy[0]) begin 285 if (!bank_active[io_bank] || (bank_row[io_bank] != io_row)) begin 286 state_next = ACTIVE; 287 // precharge one bank (a10=0) 288 cmd_next = CMD_PRECHARGE; 289 io_sel_row_next = 0; // column addr 290 io_sel_a10_next = 0; // one bank only 291 //count_next = T_RP - 2; 292 count_next[T_RP-2] = 1; count_done_next = 0; 293 end else begin 294 cmd_next = CMD_WRITE; 295 io_sel_row_next = 0; // column addr 296 io_sel_a10_next = 0; // no auto precharge 297 data_oe_next = 1; 298 if (burst == 4'd0) begin 299 state_next = IDLE; 300 burst_next = burst_sub1; 301 count_next[2] = 1; count_done_next = 0; // WR? 302 end else begin 303 state_next = WRITE; 304 end 305 end 306 end 307 ACTIVE: begin 308 state_next = io_do_rd ? START_READ : START_WRITE; 309 //count_next = T_RCD - 2; 310 count_next[T_RCD-2] = 1; count_done_next = 0; 311 cmd_next = CMD_ACTIVE; 312 io_sel_row_next = 1; // row address 313 bank_active_next[io_bank] = 1; 314 bank_row_next[io_bank] = io_row; 315 end 316 READ: begin 317 if (burst == 4'd0) begin 318 state_next = IDLE; 319 end else begin 320 burst_next = burst_sub1; 321 end 322 // column addressing pre-selected from initial read 323 io_addr_next[COLBITS-1:0] = io_col_add1; 324 cmd_next = CMD_READ; 325 rd_pipe_rdy_next = { 1'b1, rd_pipe_rdy[PMSB:1] }; 326 rd_pipe_bsy_next = { PMSB + 1 { 1'b1 } }; 327 end 328 WRITE: begin 329 if (burst == 4'd0) begin 330 state_next = IDLE; 331 count_next[2] = 1; count_done_next = 0; // WR? 332 end else begin 333 burst_next = burst_sub1; 334 end 335 // column addressing pre-selected from initial write 336 io_addr_next[COLBITS-1:0] = io_col_add1; 337 cmd_next = CMD_WRITE; 338 data_o_next = wr_data; // handshake? 339 data_oe_next = 1; 340 end 341 INIT0: if (refresh_done) begin 342 state_next = INIT1; 343 //count_next = 2; 344 count_next[2] = 1; count_done_next = 0; 345 cmd_next = CMD_PRECHARGE; 346 io_sel_row_next = 0; // column addressing 347 io_sel_a10_next = 1; // ALL BANKS 348 end 349 INIT1: begin 350 state_next = INIT2; 351 cmd_next = CMD_SET_MODE; 352 //count_next = T_MRD - 2; 353 count_next[T_MRD-2] = 1; count_done_next = 0; 354 io_addr_next[XWIDTH-1:COLBITS] = 355 { {ROWBITS-10{1'b0}}, SDRAM_MODE, {BANKBITS{1'b0}} }; 356 io_sel_row_next = 1; // row addressing 357 end 358 INIT2: begin 359 state_next = REFRESH; 360 cmd_next = CMD_REFRESH; 361 //count_next = T_RC - 2; 362 count_next[T_RC-2] = 1; count_done_next = 0; 363 end 364 REFRESH: begin 365 state_next = IDLE; 366 cmd_next = CMD_REFRESH; 367 //count_next = T_RC - 2; 368 count_next[T_RC-2] = 1; count_done_next = 0; 369 refresh_next = T_RI - 1; 370 371 // we got here after a precharge all 372 for (i = 0; i < BANKCOUNT; i++) 373 bank_active_next[i] = 0; 374 end 375 default: begin 376 //state_next = START; 377 end 378 endcase 379 end 380 381 always_ff @(posedge clk) begin 382 state <= reset ? START : state_next; 383 count <= count_next; 384 count_done <= count_done_next; 385 burst <= burst_next; 386 refresh <= refresh_next; 387 cmd <= cmd_next; 388 io_do_rd <= io_do_rd_next; 389 io_sel_a10 <= io_sel_a10_next; 390 io_sel_row <= io_sel_row_next; 391 io_addr <= io_addr_next; 392 data_o <= data_o_next; 393 data_oe <= data_oe_next; 394 wr_ack <= wr_ack_next; 395 rd_ack <= rd_ack_next; 396 rd_rdy <= rd_rdy_next; 397 rd_data <= rd_data_next; 398 for (i = 0; i < BANKCOUNT; i++) begin 399 bank_active[i] <= bank_active_next[i]; 400 bank_row[i] <= bank_row_next[i]; 401 end 402 rd_pipe_rdy <= rd_pipe_rdy_next; 403 rd_pipe_bsy <= rd_pipe_bsy_next; 404 end 405 406 assign { ras_n, cas_n, we_n } = cmd; 407 408 wire [(ROWBITS-COLBITS)-1:0]io_misc = {{ROWBITS-10-1{1'b0}}, io_sel_a10, {10-COLBITS{1'b0}}}; 409 wire [ROWBITS-1:0]io_low = io_sel_row ? io_row : { io_misc, io_col }; 410 assign addr = { io_bank, io_low }; 411 412 `ifdef verilator 413 assign pin_clk = clk; 414 assign pin_ras_n = ras_n; 415 assign pin_cas_n = cas_n; 416 assign pin_we_n = we_n; 417 assign pin_addr = addr; 418 419 // TODO: fix me 420 assign pin_data = data_o; 421 assign data_i = pin_data; 422 423 `else 424 sdram_glue #( 425 .AWIDTH(AWIDTH), 426 .DWIDTH(DWIDTH), 427 .CLK_SHIFT(CLK_SHIFT), 428 .CLK_DELAY(CLK_DELAY) 429 ) glue ( 430 .clk(clk), 431 .pin_clk(pin_clk), 432 .pin_ras_n(pin_ras_n), 433 .pin_cas_n(pin_cas_n), 434 .pin_we_n(pin_we_n), 435 .pin_addr(pin_addr), 436 .pin_data(pin_data), 437 .ras_n(ras_n), 438 .cas_n(cas_n), 439 .we_n(we_n), 440 .addr(addr), 441 .data_i(data_i), 442 .data_o(data_o), 443 .data_oe(data_oe) 444 ); 445 `endif 446 447 endmodule 448