// ----------------------------------------------------------------------- // // Copyright 2010-2021 H. Peter Anvin - All Rights Reserved // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, // Boston MA 02110-1301, USA; either version 2 of the License, or // (at your option) any later version; incorporated herein by reference. // // ----------------------------------------------------------------------- // // Simple SDRAM controller // // Very simple non-parallelizing SDRAM controller. // // // Two ports are provided: port 0 is single byte per transaction, // and has highest priority; it is intended for transactions from the // ABC-bus. Port 1 does 4-byte accesses with arbitrary alignment and // byte enables. // // All signals are in the sdram clock domain. // // [rw]ack is asserted at the beginning of a read- or write cycle and // deasserted afterwards; rvalid is asserted once all data is read and // the read data (rdX port) is valid; it remains asserted after the // transaction is complete and rack is deasserted. // module sdram #( parameter // Timing parameters // The parameters are hardcoded for Micron MT48LC16M16A2-6A, // per datasheet: // 100 MHz 167 MHz // ---------------------------------------------------------- // CL 2 3 READ to data out // tRCD 18 ns 2 3 ACTIVE to READ/WRITE // tRFC 60 ns 6 10 REFRESH to ACTIVE // tRP 18 ns 2 3 PRECHARGE to ACTIVE/REFRESH // tRAS 42 ns 5 7 ACTIVE to PRECHARGE // tRC 60 ns 6 10 ACTIVE to ACTIVE (same bank) // tRRD 12 ns 2 2 ACTICE to ACTIVE (different bank) // tWR 12 ns 2 2 Last write data to PRECHARGE // tMRD 2 2 MODE REGISTER to ACTIVE/REFRESH // // These parameters are set by power of 2: // tREFi 64/8192 ms 781 1302 Refresh time per row (max) // tP 100 us 10000 16667 Time until first command (min) t_cl = 3, t_rcd = 3, t_rfc = 10, t_rp = 3, t_ras = 7, t_rc = 10, t_rrd = 2, t_wr = 2, t_mrd = 2, t_refi_lg2 = 10, // 1024 cycles t_p_lg2 = 15, // 32768 cycles burst_lg2 = 1 // Burst length on port 1 ) ( // Reset and clock input rst_n, input clk, // SDRAM hardware interface output sr_clk, // SDRAM clock output buffer output sr_cke, // SDRAM clock enable output sr_cs_n, // SDRAM CS# output sr_ras_n, // SDRAM RAS# output sr_cas_n, // SDRAM CAS# output sr_we_n, // SDRAM WE# output [1:0] sr_dqm, // SDRAM DQM (per byte) output [1:0] sr_ba, // SDRAM bank selects output [12:0] sr_a, // SDRAM address bus inout [15:0] sr_dq, // SDRAM data bus // Port 0: single byte, high priority input [24:0] a0, // Address, must be stable until ack output reg [7:0] rd0, // Data from SDRAM input rrq0, // Read request output reg rack0, // Read ack (transaction started) output reg rvalid0, // Read data valid input [7:0] wd0, // Data to SDRAM input wrq0, // Write request output reg wack0, // Write ack (data latched) // Port 1 input [24:2] a1, input [7:0] be1, // Write byte enable output reg [31:0] rd1, input rrq1, output reg rack1, output reg rvalid1, input [31:0] wd1, input wrq1, output reg wack1 ); // Mode register data wire mrd_wburst = 1'b1; // Write bursts enabled wire [2:0] mrd_cl = t_cl; wire [2:0] mrd_burst = burst_lg2; wire mrd_interleave = 1'b0; // Interleaved bursts wire [12:0] mrd_val = { 3'b000, // Reserved ~mrd_wburst, // Write burst disable 2'b00, // Normal operation mrd_cl, // CAS latency mrd_interleave, // Interleaved bursts mrd_burst }; // Burst length // Where to issue a PRECHARGE when we only want to read one word // (terminate the burst as soon as possible, but no sooner...) localparam t_pre_rd_when = max(t_ras, t_rcd + 1); // Where to issue a PRECHARGE when we only want to write one word // (terminate the burst as soon as possible, but no sooner...) localparam t_pre_wr_when = max(t_ras, t_rcd + t_wr); // Actual burst length (2^burst_lg2) localparam burst_n = 1 << burst_lg2; // Command opcodes and attributes (is_rfsh, CS#, RAS#, CAS#, WE#) localparam cmd_desl = 5'b0_1111; // Deselect (= NOP) localparam cmd_nop = 5'b0_0111; // NO OPERATION localparam cmd_bst = 5'b0_0110; // BURST TERMINATE localparam cmd_rd = 5'b0_0101; // READ localparam cmd_wr = 5'b0_0100; // WRITE localparam cmd_act = 5'b0_0011; // ACTIVE localparam cmd_pre = 5'b0_0010; // PRECHARGE localparam cmd_ref = 5'b1_0001; // AUTO REFRESH localparam cmd_mrd = 5'b0_0000; // LOAD MODE REGISTER reg [4:0] dram_cmd; wire is_rfsh = dram_cmd[4]; assign sr_cs_n = dram_cmd[3]; assign sr_ras_n = dram_cmd[2]; assign sr_cas_n = dram_cmd[1]; assign sr_we_n = dram_cmd[0]; // SDRAM output clock buffer. The SDRAM output clock is // inverted with respect to our internal clock, so that // the SDRAM sees the positive clock edge in the middle of // our clocks. // // Use a DDIO buffer for best performance // For EP4CE15 only could use a secondary PLL here, but it // isn't clear it buys us a whole lot. ddio_out sr_clk_out ( .aclr ( 1'b0 ), .datain_h ( 1'b0 ), .datain_l ( 1'b1 ), .outclock ( clk ), .dataout ( sr_clk ) ); // SDRAM output signal registers reg dram_cke; assign sr_cke = dram_cke; reg [12:0] dram_a; assign sr_a = dram_a; reg [1:0] dram_ba; assign sr_ba = dram_ba; reg [1:0] dram_dqm; assign sr_dqm = dram_dqm; reg [15:0] dram_d; // Data to DRAM reg dram_d_en; // Drive data out assign sr_dq = dram_d_en ? dram_d : 16'hzzzz; // I/O cell input register for SDRAM data reg [15:0] dram_q; always @(posedge clk) dram_q <= sr_dq; // State machine and counters reg [t_refi_lg2-2:0] rfsh_ctr; // Refresh timer wire rfsh_ctr_msb = rfsh_ctr[t_refi_lg2-2]; reg rfsh_ctr_last_msb; wire rfsh_tick = rfsh_ctr_last_msb & ~rfsh_ctr_msb; reg [t_p_lg2:t_refi_lg2-1] init_ctr; // Reset to init counter reg [1:0] rfsh_prio; // Refresh priority // Bit 0 - refresh if opportune // Bit 1 - refresh urgent reg [3:0] op_cycle; // Cycles into the current operation // The actual values are unimportant; the compiler will optimize // the state machine implementation. typedef enum logic [2:0] { st_reset, // Reset until init timer expires st_init, // 1st refresh during initialization st_idle, // Idle state: all banks precharged st_rfsh, st_rd, st_wr } state_t; state_t state = st_reset; always @(posedge clk or negedge rst_n) if (~rst_n) begin rfsh_ctr <= 1'b0; init_ctr <= 1'b0; rfsh_prio <= 2'b00; end else begin rfsh_ctr <= rfsh_ctr + 1'b1; rfsh_ctr_last_msb <= rfsh_ctr_msb; // Refresh priority management if (is_rfsh) rfsh_prio <= 2'b00; // This is a refresh cycle else if (rfsh_tick) rfsh_prio <= { rfsh_prio[0], 1'b1 }; // The refresh counter is also used as a prescaler // for the initialization counter. // Note that means init_ctr is two cycles "behind" // rfsh_ctr; this is totally fine. init_ctr <= init_ctr + rfsh_tick; end // else: !if(~rst_n) // Handle bank wraparound reg last_dword; // This is the last dword in this bank reg [14:0] next_bank; // Row:bank for the next bank reg [11:2] col_addr; // Current bank:column always @(posedge clk) begin if (op_cycle == 0) begin next_bank <= { dram_a, dram_ba } + 1'b1; last_dword <= &col_addr[9:2]; // last dword in bank? end end // else: !if(~rst_n) reg [31:0] wdata_q; reg [ 7:0] be_q; // // Careful with the timing here... there is one cycle between // registers and wires, and the DRAM observes the clock 1/2 // cycle from the internal logic. // always @(posedge clk or negedge rst_n) if (~rst_n) begin dram_cke <= 1'b0; dram_cmd <= cmd_desl; dram_a <= 13'hxxxx; dram_ba <= 2'bxx; dram_dqm <= 2'b00; dram_d <= 16'hxxxx; dram_d_en <= 1'b1; // Don't float except during read op_cycle <= 1'b0; state <= st_reset; rack0 <= 1'b0; rvalid0 <= 1'b0; wack0 <= 1'b0; rack1 <= 1'b0; rvalid1 <= 1'b0; wack1 <= 1'b0; wdata_q <= 32'hxxxx_xxxx; be_q <= 8'hxx; end else begin dram_cke <= 1'b1; // Always true once out of reset // Default values dram_ba <= 2'bxx; dram_dqm <= 2'b00; dram_d <= 16'hxxxx; dram_cmd <= cmd_nop; dram_d_en <= 1'b1; // Don't float except during read rack0 <= 1'b0; wack0 <= 1'b0; rack1 <= 1'b0; wack1 <= 1'b0; if (state == st_reset || state == st_idle) op_cycle <= 1'b0; else op_cycle <= op_cycle + 1'b1; case (state) st_reset: begin dram_cmd <= cmd_desl; if (init_ctr[t_p_lg2]) begin dram_cmd <= cmd_pre; dram_a[10] <= 1'b1; // Precharge All Banks state <= st_init; end end st_init: begin // Add 3 to the count to account for skew between rfsh_ctr // and init_ctr if ( rfsh_ctr[4:0] == t_rp+3 || rfsh_ctr[4:0] == t_rp+t_rfc+3 ) begin dram_cmd <= cmd_ref; end if ( rfsh_ctr[4:0] == t_rp+t_rfc*2+3 ) begin dram_cmd <= cmd_mrd; dram_a <= mrd_val; end if ( rfsh_ctr[4:0] >= t_rp+t_rfc*2+t_mrd-1+3 ) state <= st_idle; end // case: st_init st_idle: begin // A data transaction starts with ACTIVE command; // a refresh transaction starts with REFRESH. // Port 0 has the highest priority, then // refresh, then port 1; a refresh transaction // is started opportunistically if nothing is // pending and the refresh counter is no less than // half expired. casez ( {rrq0|wrq0, rrq1|wrq1, rfsh_prio} ) 4'b1???: begin // Begin port 0 transaction dram_cmd <= cmd_act; dram_a <= a0[24:12]; dram_ba <= a0[11:10]; col_addr <= a0[11:2]; be_q <= 1'b1 << a0[1:0]; if ( wrq0 ) begin state <= st_wr; wack0 <= 1'b1; wdata_q <= {4{wd0}}; end else begin state <= st_rd; rack0 <= 1'b1; rvalid0 <= 1'b0; end end 4'b010?: begin // Begin port 1 transaction dram_cmd <= cmd_act; dram_a <= a1[24:12]; dram_ba <= a1[11:10]; col_addr <= a1[11:2]; be_q <= be1; if ( wrq1 ) begin state <= st_wr; wack1 <= 1'b1; wdata_q <= wd1; end else begin state <= st_rd; rack1 <= 1'b1; rvalid1 <= 1'b0; end end 4'b0?1?, 4'b0001: begin // Begin refresh transaction dram_cmd <= cmd_ref; state <= st_rfsh; end default: begin dram_cmd <= cmd_desl; state <= st_idle; end endcase // casez ( {rrq0|wrq0, rrq1|wrq1, rfsh_ctr[t_ref:t_ref-1]} ) end // case: st_idle st_rfsh: begin if (op_cycle == t_rfc-2) state <= st_idle; end st_rd: begin rack0 <= rack0; rack1 <= rack1; dram_d_en <= 1'b0; // Tristate data bus // Commands // // This assumes: // tRCD = 3 // rRRD = 2 // CL = 3 // tRC = 10 case (op_cycle) 1: begin dram_a <= next_bank[14:2]; dram_ba <= next_bank[1:0]; dram_cmd <= last_dword ? cmd_act : cmd_nop; end 2, 4: begin dram_a[12:9] <= 4'b0000; dram_a[8:1] <= col_addr[9:2]; dram_a[0] <= 1'b0; dram_cmd <= cmd_rd; col_addr <= col_addr + 1'b1; end 8: begin // Precharge all banks dram_a[12:9] <= 4'b0010; dram_cmd <= cmd_pre; end 10: begin state <= st_idle; rack0 <= 1'b0; rack1 <= 1'b0; end endcase // case (op_cycle) // +2 for bus turnaround latencies // Assert rvalid in the same cycle the last requested // data byte (as given by byte enables) is latched. if (op_cycle >= 2+t_cl+2) begin if (rack0) begin rvalid0 <= ~|be_q[7:2]; if (be_q[0]) rd0 <= dram_q[7:0]; if (be_q[1]) rd0 <= dram_q[15:8]; end if (rack1) begin rvalid1 <= ~|be_q[7:2]; if (op_cycle[0] ^ ((2+t_cl+2) & 1'b1)) begin // Odd word if (be_q[0]) rd1[23:16] <= dram_q[ 7:0]; if (be_q[1]) rd1[31:24] <= dram_q[15:8]; end else begin // Even word if (be_q[0]) rd1[ 7:0] <= dram_q[ 7:0]; if (be_q[1]) rd1[15:8] <= dram_q[15:8]; end // else: !if(op_cycle[0] ^ ((t_rcd-1+t_cl+2) & 1'b1)) end // if (rack1) be_q <= be_q >> 2; end // if (op_cycle >= 2+t_cl+2) end // case: st_rd st_wr: begin wack0 <= wack0; wack1 <= wack1; dram_dqm <= 2'b11; // Mask data bytes unless we mean it // Commands // // This assumes: // tRCD = 3 // tRRD = 2 // CL = 3 // tRC = 10 // tWR = 2 // tRP = 3 case (op_cycle) 1: begin dram_a <= next_bank[14:2]; dram_ba <= next_bank[1:0]; dram_cmd <= last_dword ? cmd_act : cmd_nop; end 2, 4: begin dram_a[12:9] <= 4'b0000; dram_a[8:1] <= col_addr[9:2]; dram_a[0] <= 1'b0; dram_cmd <= cmd_wr; col_addr <= col_addr + 1'b1; end 7: begin // Precharge all banks dram_a[12:9] <= 4'b0010; dram_cmd <= cmd_pre; end 10: begin state <= st_idle; wack0 <= 1'b0; wack1 <= 1'b0; end endcase // case (op_cycle) if (op_cycle >= 2) begin dram_d <= wdata_q[15:0]; // Flip data between odd and even words wdata_q <= { wdata_q[15:0], wdata_q[31:16] }; dram_dqm <= ~be_q[1:0]; be_q <= be_q >> 2; end end // case: st_wr endcase // case(state) end // else: !if(~rst_n) endmodule // dram