// ----------------------------------------------------------------------- // // 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 aligned 4-byte accesses with byte enables. // Port 2 does aligned 8-byte accesses, write only, with no byte // enables; it supports streaming from a FIFO. // // All signals are in the sdram clock domain. // // [rw]ack is asserted at the beginning of a read- or write cycle and // deasserted afterwards; rready 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 // log2(burst length) ) ( // Reset and clock input rst_n, input clk, input out_clk, // Phase shifted external clock // 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 rready0, // 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, output reg [31:0] rd1, input rrq1, output reg rack1, output reg rready1, input [31:0] wd1, input [3:0] wstrb1, output reg wack1, // Port 2 input [24:1] a2, input [15:0] wd2, input [1:0] wrq2, output reg wacc2 // Data accepted, advance data & addr ); `include "functions.sv" // For modelsim wire wrq1 = |wstrb1; // 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]; assign sr_cke = 1'b1; `ifdef SD_CLK_USE_DDIO // 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. // // This buffer is driven by a separate PLL output, so that // the phase shift between the clock and the outputs/inputs // can be tuned. ddio_out sr_clk_out ( .aclr ( 1'b0 ), .datain_h ( 1'b1 ), .datain_l ( 1'b0 ), .outclock ( out_clk ), .dataout ( sr_clk ) ); `else // !`ifdef SD_CLK_USE_DDIO // Dedicated clock pin assign sr_clk = out_clk; `endif // SDRAM output signal registers 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; // 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 // 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_rfsh, // Refresh cycles during initialization st_init_mrd, // MRD register write during initialization st_idle, // Idle state: all banks precharged st_rfsh, st_rd_wr, // Port 0/1 transaction st_pre_idle, st_wr2 // Port 2 write (burstable) } state_t; state_t state = st_reset; reg is_write; always @(posedge clk or negedge rst_n) if (~rst_n) begin rfsh_ctr <= 1'b0; rfsh_prio <= 2'b00; init_ctr <= 1'b0; 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) reg [3:0] op_cycle; // Cycle into the current operation reg op_zero; // op_cycle wrap around reg [1:0] init_op_ctr; // op_cycle extension for init states reg [31:0] wdata_q; reg [ 3:0] be_q; reg [ 9:0] col_addr; reg wrq2_more; // // 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. This affects read timing. // // Note that rready starts out as 1. This allows a 0->1 detection // on the rready line to be used as cycle termination signal. // always @(posedge clk or negedge rst_n) if (~rst_n) begin 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 <= 4'h0; op_zero <= 1'b0; init_op_ctr <= 2'b00; state <= st_reset; is_write <= 1'bx; rack0 <= 1'b0; rready0 <= 1'b1; wack0 <= 1'b0; rack1 <= 1'b0; rready1 <= 1'b1; wack1 <= 1'b0; wacc2 <= 1'b0; wrq2_more <= 1'bx; wdata_q <= 32'hxxxx_xxxx; be_q <= 4'bxxxx; col_addr <= 10'hxxx; end else begin // Default values // Note: dram_ba are preserved dram_a <= 13'hxxxx; dram_dqm <= 2'b00; dram_d <= 16'haaaa; dram_cmd <= cmd_nop; dram_d_en <= 1'b1; // Don't float except during read if (state != st_rd_wr) begin rack0 <= 1'b0; wack0 <= 1'b0; rack1 <= 1'b0; wack1 <= 1'b0; end wacc2 <= 1'b0; if (state == st_reset || state == st_idle) op_cycle <= 1'b0; else op_cycle <= op_cycle + 1'b1; op_zero <= |op_cycle; if (|op_cycle) init_op_ctr <= init_op_ctr + 1'b1; case (state) st_reset: begin dram_a[10] <= 1'b1; // Precharge all banks dram_cmd <= cmd_nop; if (init_ctr[t_p_lg2]) begin dram_cmd <= cmd_pre; state <= st_init_rfsh; end end st_init_rfsh: begin if (op_zero) begin dram_cmd <= cmd_ref; if (init_op_ctr == 2'b11) state <= st_init_mrd; end end st_init_mrd: begin dram_a <= mrd_val; dram_ba <= 2'b00; if (op_zero) if (init_op_ctr[0]) state <= st_idle; else dram_cmd <= cmd_mrd; end st_idle: begin is_write <= 1'bx; be_q <= 4'bxxxx; wdata_q <= 32'hxxxx_xxxx; // 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. dram_a <= 13'h1bb; dram_ba <= 2'bxx; dram_d <= 16'hbbbb; casez ( {rrq0|wrq0, rrq1|wrq1, wrq2[0], rfsh_prio} ) 5'b1????: begin // Begin port 0 transaction dram_cmd <= cmd_act; dram_a <= a0[24:12]; dram_ba <= a0[11:10]; col_addr <= a0[9:0]; if ( wrq0 ) begin state <= st_rd_wr; wack0 <= 1'b1; wdata_q <= {16'hxxxx, wd0, wd0}; be_q <= {2'b00, a0[0], ~a0[0]}; is_write <= 1'b1; end else begin state <= st_rd_wr; rack0 <= 1'b1; rready0 <= 1'b0; is_write <= 1'b0; end end 5'b01?0?: begin // Begin port 1 transaction dram_cmd <= cmd_act; dram_a <= a1[24:12]; dram_ba <= a1[11:10]; col_addr <= { a1[9:2], 2'b00 }; if ( wrq1 ) begin state <= st_rd_wr; wack1 <= 1'b1; wdata_q <= wd1; be_q <= wstrb1; is_write <= 1'b1; end else begin state <= st_rd_wr; rack1 <= 1'b1; rready1 <= 1'b0; is_write <= 1'b0; end end 5'b0??1?, 5'b00?01: begin // Begin refresh transaction dram_cmd <= cmd_ref; state <= st_rfsh; end 5'b00100: begin // Begin port 2 write dram_cmd <= cmd_act; dram_a <= a2[24:12]; dram_ba <= a2[11:10]; state <= st_wr2; end default: begin dram_cmd <= cmd_desl; state <= st_idle; end endcase // casez ( {rrq0|wrq0, rrq1|wrq1, rfsh_prio} ) end // case: st_idle st_rfsh: begin if (op_cycle == t_rfc-2) state <= st_idle; end st_rd_wr: begin dram_d_en <= is_write; dram_dqm <= {2{is_write}}; dram_d <= 16'hcccc; // Commands // // This assumes: // tRCD = 3 // rRRD = 2 // CL = 3 // tRC = 10 // tRAS = 7 // tWR = 2 // tRP = 3 // case (op_cycle) 2: begin dram_a[10] <= 1'b0; // No auto precharge dram_a[8:0] <= col_addr[9:1]; dram_cmd <= is_write ? cmd_wr : cmd_rd; dram_d <= wdata_q[15:0]; dram_dqm <= {2{is_write}} & ~be_q[1:0]; wdata_q <= { 16'hdddd, wdata_q[31:16] }; be_q <= { 2'hxx, be_q[3:2] }; end 3: begin dram_d <= wdata_q[15:0]; dram_dqm <= {2{is_write}} & ~be_q[1:0]; wdata_q <= { 16'heeee, wdata_q[31:16] }; be_q <= 4'bxxxx; end 6: begin // Earliest legal cycle to precharge // It seems auto precharge violates tRAS(?) // so do it explicitly. dram_a[10] <= 1'b1; // One bank dram_cmd <= cmd_pre; end // CL+2 cycles after the read command // The +2 accounts for internal and I/O delays 7: begin if (rack0) rd0 <= col_addr[0] ? sr_dq[15:8] : sr_dq[7:0]; rready0 <= rready0 | rack0; if (rack1) rd1[15:0] <= sr_dq; end 8: begin if (rack1) rd1[31:16] <= sr_dq; rready1 <= rready1 | rack1; state <= st_pre_idle; end endcase // case (op_cycle) end // case: st_rd_wr st_pre_idle: begin // Last cycle before tRC is a separate state // so that rack/wack will be cleared dram_d_en <= is_write; dram_dqm <= {2{is_write}}; state <= st_idle; end st_wr2: begin // Streamable write from flash ROM dram_d <= wd2; dram_a[10] <= 1'b0; // No auto precharge/precharge one bank dram_a[8:0] <= a2[9:1]; case (op_cycle) 0: begin wacc2 <= 1'b1; end 1: begin wacc2 <= 1'b1; end 2: begin dram_cmd <= cmd_wr; wacc2 <= 1'b1; wrq2_more <= wrq2[1]; end 3: begin wacc2 <= 1'b1; end 4: begin dram_cmd <= cmd_wr; if (wrq2_more & ~(rrq0|wrq0|rrq1|wrq1|(|rfsh_prio)|(&dram_a[8:2]))) begin // Burst can continue wacc2 <= 1'b1; op_cycle <= 1; end end // case: 4 6: begin dram_dqm <= 2'b11; // This shouldn't be necessary?! end 7: begin // tWR completed dram_cmd <= cmd_pre; dram_dqm <= 2'b11; end 8: begin dram_dqm <= 2'b11; end 9: begin // tRP will be complete in the next cycle dram_dqm <= 2'b11; state <= st_idle; end endcase // case (op_cycle) end // case: st_wr2 endcase // case(state) end // else: !if(~rst_n) endmodule // dram