/* This SDRAM controller is for the Mojo's SDRAM shield which uses a 48LC32M8A2-7E SDRAM chip. This module was designed under the assumption that the click rate is 100MHz. Timing values would need to be re-evaluated under different clock rates. This controller features two baisc improvements over the most basic of controllers. It does burst reads and writes of 4 bytes, and it only closes a row when it has to. */ module sdram ( input clk, input rst, // these signals go directly to the IO pins output sdram_clk, output sdram_cle, output sdram_cs, output sdram_cas, output sdram_ras, output sdram_we, output sdram_dqm, output [1:0] sdram_ba, output [12:0] sdram_a, inout [7:0] sdram_dq, // User interface input [22:0] addr, // address to read/write input rw, // 1 = write, 0 = read input [31:0] data_in, // data from a read output [31:0] data_out, // data for a write output busy, // controller is busy when high input in_valid, // pulse high to initiate a read/write output out_valid // pulses high when data from read is valid ); // Commands for the SDRAM localparam CMD_UNSELECTED = 4'b1000; localparam CMD_NOP = 4'b0111; localparam CMD_ACTIVE = 4'b0011; localparam CMD_READ = 4'b0101; localparam CMD_WRITE = 4'b0100; localparam CMD_TERMINATE = 4'b0110; localparam CMD_PRECHARGE = 4'b0010; localparam CMD_REFRESH = 4'b0001; localparam CMD_LOAD_MODE_REG = 4'b0000; localparam STATE_SIZE = 4; localparam INIT = 0, WAIT = 1, PRECHARGE_INIT = 2, REFRESH_INIT_1 = 3, REFRESH_INIT_2 = 4, LOAD_MODE_REG = 5, IDLE = 6, REFRESH = 7, ACTIVATE = 8, READ = 9, READ_RES = 10, WRITE = 11, PRECHARGE = 12; wire sdram_clk_ddr; // This is used to drive the SDRAM clock ODDR2 #( .DDR_ALIGNMENT("NONE"), .INIT(1'b0), .SRTYPE("SYNC") ) ODDR2_inst ( .Q(sdram_clk_ddr), // 1-bit DDR output data .C0(clk), // 1-bit clock input .C1(~clk), // 1-bit clock input .CE(1'b1), // 1-bit clock enable input .D0(1'b0), // 1-bit data input (associated with C0) .D1(1'b1), // 1-bit data input (associated with C1) .R(1'b0), // 1-bit reset input .S(1'b0) // 1-bit set input ); IODELAY2 #( .IDELAY_VALUE(0), .IDELAY_MODE("NORMAL"), .ODELAY_VALUE(100), // value of 100 seems to work at 100MHz .IDELAY_TYPE("FIXED"), .DELAY_SRC("ODATAIN"), .DATA_RATE("SDR") ) IODELAY_inst ( .IDATAIN(1'b0), .T(1'b0), .ODATAIN(sdram_clk_ddr), .CAL(1'b0), .IOCLK0(1'b0), .IOCLK1(1'b0), .CLK(1'b0), .INC(1'b0), .CE(1'b0), .RST(1'b0), .BUSY(), .DATAOUT(), .DATAOUT2(), .TOUT(), .DOUT(sdram_clk) ); // registers for SDRAM signals reg cle_d, dqm_d; reg [3:0] cmd_d; reg [1:0] ba_d; reg [12:0] a_d; reg [7:0] dq_d; reg [7:0] dqi_d; // We want the output/input registers to be embedded in the // IO buffers so we set IOB to "TRUE". This is to ensure all // the signals are sent and received at the same time. (* IOB = "TRUE" *) reg cle_q, dqm_q; (* IOB = "TRUE" *) reg [3:0] cmd_q; (* IOB = "TRUE" *) reg [1:0] ba_q; (* IOB = "TRUE" *) reg [12:0] a_q; (* IOB = "TRUE" *) reg [7:0] dq_q; (* IOB = "TRUE" *) reg [7:0] dqi_q; reg dq_en_d, dq_en_q; // Output assignments assign sdram_cle = cle_q; assign sdram_cs = cmd_q[3]; assign sdram_ras = cmd_q[2]; assign sdram_cas = cmd_q[1]; assign sdram_we = cmd_q[0]; assign sdram_dqm = dqm_q; assign sdram_ba = ba_q; assign sdram_a = a_q; assign sdram_dq = dq_en_q ? dq_q : 8'hZZ; // only drive when dq_en_q is 1 reg [STATE_SIZE-1:0] state_d, state_q = INIT; reg [STATE_SIZE-1:0] next_state_d, next_state_q; reg [22:0] addr_d, addr_q; reg [31:0] data_d, data_q; reg out_valid_d, out_valid_q; assign data_out = data_q; assign busy = !ready_q; assign out_valid = out_valid_q; reg [15:0] delay_ctr_d, delay_ctr_q; reg [1:0] byte_ctr_d, byte_ctr_q; reg [9:0] refresh_ctr_d, refresh_ctr_q; reg refresh_flag_d, refresh_flag_q; reg ready_d, ready_q; reg saved_rw_d, saved_rw_q; reg [22:0] saved_addr_d, saved_addr_q; reg [31:0] saved_data_d, saved_data_q; reg rw_op_d, rw_op_q; reg [3:0] row_open_d, row_open_q; reg [12:0] row_addr_d[3:0], row_addr_q[3:0]; reg [2:0] precharge_bank_d, precharge_bank_q; integer i; always @* begin // Default values dq_d = dq_q; dqi_d = sdram_dq; dq_en_d = 1'b0; // normally keep the bus in high-Z cle_d = cle_q; cmd_d = CMD_NOP; // default to NOP dqm_d = 1'b0; ba_d = 2'd0; a_d = 25'd0; state_d = state_q; next_state_d = next_state_q; delay_ctr_d = delay_ctr_q; addr_d = addr_q; data_d = data_q; out_valid_d = 1'b0; precharge_bank_d = precharge_bank_q; rw_op_d = rw_op_q; byte_ctr_d = 2'd0; row_open_d = row_open_q; // row_addr is a 2d array and must be coppied this way for (i = 0; i < 4; i = i + 1) row_addr_d[i] = row_addr_q[i]; // The data in the SDRAM must be refreshed periodically. // This conter ensures that the data remains intact. refresh_flag_d = refresh_flag_q; refresh_ctr_d = refresh_ctr_q + 1'b1; if (refresh_ctr_q > 10'd750) begin refresh_ctr_d = 10'd0; refresh_flag_d = 1'b1; end saved_rw_d = saved_rw_q; saved_data_d = saved_data_q; saved_addr_d = saved_addr_q; ready_d = ready_q; // This is a queue of 1 for read/write operations. // When the queue is empty we aren't busy and can // accept another request. if (ready_q && in_valid) begin saved_rw_d = rw; saved_data_d = data_in; saved_addr_d = addr; ready_d = 1'b0; end case (state_q) ///// INITALIZATION ///// INIT: begin ready_d = 1'b0; row_open_d = 4'b0; out_valid_d = 1'b0; a_d = 13'b0; ba_d = 2'b0; cle_d = 1'b1; state_d = WAIT; delay_ctr_d = 16'd10100; // wait for 101us next_state_d = PRECHARGE_INIT; dq_en_d = 1'b0; end WAIT: begin delay_ctr_d = delay_ctr_q - 1'b1; if (delay_ctr_q == 13'd0) begin state_d = next_state_q; if (next_state_q == WRITE) begin dq_en_d = 1'b1; // enable the bus early dq_d = data_q[7:0]; end end end PRECHARGE_INIT: begin cmd_d = CMD_PRECHARGE; a_d[10] = 1'b1; // all banks ba_d = 2'd0; state_d = WAIT; next_state_d = REFRESH_INIT_1; delay_ctr_d = 13'd0; end REFRESH_INIT_1: begin cmd_d = CMD_REFRESH; state_d = WAIT; delay_ctr_d = 13'd7; next_state_d = REFRESH_INIT_2; end REFRESH_INIT_2: begin cmd_d = CMD_REFRESH; state_d = WAIT; delay_ctr_d = 13'd7; next_state_d = LOAD_MODE_REG; end LOAD_MODE_REG: begin cmd_d = CMD_LOAD_MODE_REG; ba_d = 2'b0; // Reserved, Burst Access, Standard Op, CAS = 2, Sequential, Burst = 4 a_d = {3'b000, 1'b0, 2'b00, 3'b010, 1'b0, 3'b010}; //010 state_d = WAIT; delay_ctr_d = 13'd1; next_state_d = IDLE; refresh_flag_d = 1'b0; refresh_ctr_d = 10'b1; ready_d = 1'b1; end ///// IDLE STATE ///// IDLE: begin if (refresh_flag_q) begin // we need to do a refresh state_d = PRECHARGE; next_state_d = REFRESH; precharge_bank_d = 3'b100; // all banks refresh_flag_d = 1'b0; // clear the refresh flag end else if (!ready_q) begin // operation waiting ready_d = 1'b1; // clear the queue rw_op_d = saved_rw_q; // save the values we'll need later addr_d = saved_addr_q; if (saved_rw_q) // Write data_d = saved_data_q; // if the row is open we don't have to activate it if (row_open_q[saved_addr_q[9:8]]) begin if (row_addr_q[saved_addr_q[9:8]] == saved_addr_q[22:10]) begin // Row is already open if (saved_rw_q) state_d = WRITE; else state_d = READ; end else begin // A different row in the bank is open state_d = PRECHARGE; // precharge open row precharge_bank_d = {1'b0, saved_addr_q[9:8]}; next_state_d = ACTIVATE; // open current row end end else begin // no rows open state_d = ACTIVATE; // open the row end end end ///// REFRESH ///// REFRESH: begin cmd_d = CMD_REFRESH; state_d = WAIT; delay_ctr_d = 13'd6; // gotta wait 7 clocks (66ns) next_state_d = IDLE; end ///// ACTIVATE ///// ACTIVATE: begin cmd_d = CMD_ACTIVE; a_d = addr_q[22:10]; ba_d = addr_q[9:8]; delay_ctr_d = 13'd0; state_d = WAIT; if (rw_op_q) next_state_d = WRITE; else next_state_d = READ; row_open_d[addr_q[9:8]] = 1'b1; // row is now open row_addr_d[addr_q[9:8]] = addr_q[22:10]; end ///// READ ///// READ: begin cmd_d = CMD_READ; a_d = {2'b0, 1'b0, addr_q[7:0], 2'b0}; ba_d = addr_q[9:8]; state_d = WAIT; delay_ctr_d = 13'd2; // wait for the data to show up next_state_d = READ_RES; end READ_RES: begin byte_ctr_d = byte_ctr_q + 1'b1; // we need to read in 4 bytes data_d = {dqi_q, data_q[31:8]}; // shift the data in if (byte_ctr_q == 2'd3) begin out_valid_d = 1'b1; state_d = IDLE; end end ///// WRITE ///// WRITE: begin byte_ctr_d = byte_ctr_q + 1'b1; // send out 4 bytes if (byte_ctr_q == 2'd0) // first byte send write command cmd_d = CMD_WRITE; dq_d = data_q[7:0]; data_d = {8'h00, data_q[31:8]}; // shift the data out dq_en_d = 1'b1; // enable out bus a_d = {2'b0, 1'b0, addr_q[7:0], 2'b00}; ba_d = addr_q[9:8]; if (byte_ctr_q == 2'd3) begin state_d = IDLE; end end ///// PRECHARGE ///// PRECHARGE: begin cmd_d = CMD_PRECHARGE; a_d[10] = precharge_bank_q[2]; // all banks ba_d = precharge_bank_q[1:0]; state_d = WAIT; delay_ctr_d = 13'd0; if (precharge_bank_q[2]) begin row_open_d = 4'b0000; // closed all rows end else begin row_open_d[precharge_bank_q[1:0]] = 1'b0; // closed one row end end default: state_d = INIT; endcase end always @(posedge clk) begin if(rst) begin cle_q <= 1'b0; dq_en_q <= 1'b0; state_q <= INIT; ready_q <= 1'b0; end else begin cle_q <= cle_d; dq_en_q <= dq_en_d; state_q <= state_d; ready_q <= ready_d; end saved_rw_q <= saved_rw_d; saved_data_q <= saved_data_d; saved_addr_q <= saved_addr_d; cmd_q <= cmd_d; dqm_q <= dqm_d; ba_q <= ba_d; a_q <= a_d; dq_q <= dq_d; dqi_q <= dqi_d; next_state_q <= next_state_d; refresh_flag_q <= refresh_flag_d; refresh_ctr_q <= refresh_ctr_d; data_q <= data_d; addr_q <= addr_d; out_valid_q <= out_valid_d; row_open_q <= row_open_d; for (i = 0; i < 4; i = i + 1) row_addr_q[i] <= row_addr_d[i]; precharge_bank_q <= precharge_bank_d; rw_op_q <= rw_op_d; byte_ctr_q <= byte_ctr_d; delay_ctr_q <= delay_ctr_d; end endmodule