;********************************************************************************* ; di2659.txt ; ; LISTING 1 - FIFO CONTROLLER ; ; "SDRAM interface slashes pin count," EDN, March 29, 2001, pg 132 ; http://www.ednmag.com/ednmag/reg/2001/03292001/designideas.htm#07di4 ;********************************************************************************* `timescale 1 ns / 1 ns /* ** Minimal-pin SDRAM controller with FIFO address counters. This ** has a simple do_write/wr_ok, do_read/rd_ok handshake for data input & ** output. The 'rst_fifo' signal syncronously resets the fifo ** ** Author: Tim Hellman, M&M Consulting */ module sdctl(clk, reset_, rst_fifo, do_write, do_read, wr_data_in, /* Fifo I/O */ wr_ok, rd_ok, rd_data_out, sd_ras_, sd_cas_, sd_we_, sd_dqm, sd_bank, /* SDRAM signals */ sd_addr_hi, sd_data ); input clk, reset_, do_write, do_read, rst_fifo; input [7:0] wr_data_in; output wr_ok, rd_ok, sd_ras_, sd_cas_, sd_we_, sd_dqm; output [7:0] rd_data_out; output [1:0] sd_bank; output [11:8] sd_addr_hi; inout [7:0] sd_data; /* ** States */ parameter StIdle = 0, StActive = 1, StRdWr = 2, StData1 = 3, StData2 = 4, StData3 = 5, StRdPrech = 6, StWrPrech = 7; reg [2:0] State; reg [13:0] RdRow, WrRow; reg [8:2] RdCol, WrCol; reg sd_data_ena, doing_write; always @(posedge clk or negedge reset_) if (!reset_) begin RdRow <= 0; WrRow <= 0; RdCol <= 0; WrCol <= 7'h7f; sd_data_ena <= 0; State <= StIdle; doing_write <= 0; end else begin /* ** State machine. Once kicked off, run through all states */ if (State == StIdle && (do_write | do_read)) begin doing_write <= #1 do_write; State <= #1 State + 1; end else if (State != StIdle) State <= #1 State + 1; /* ** Read/write counters (note that write col counter starts ** one behind read). The Write row also increments when ** WrCol == '7e (because WrCol is always one behind) */ if (rst_fifo) {RdRow,RdCol} <= #1 0; else if (State == StWrPrech && !doing_write) {RdRow,RdCol} <= #1 {RdRow,RdCol} + 1; if (rst_fifo) WrCol <= #1 7'h7f; else if (State == StWrPrech && doing_write) WrCol <= #1 WrCol + 1; if (rst_fifo) WrRow <= #1 0; else if (State == StWrPrech && doing_write && WrCol == 7'h7e) WrRow <= #1 WrRow + 1; if (State == StIdle && (do_read | do_write)) sd_data_ena <= #1 1; else if (doing_write && (State == StRdPrech) || !doing_write && (State == StRdWr)) sd_data_ena <= #1 0; end /* ** Generate the SDRAM 'command' bits (combinatorially) */ reg [2:0] SdCmd; always @(State or doing_write) begin case (State) StActive: SdCmd = 3; StRdWr: SdCmd = doing_write ? 4 : 5; StRdPrech: SdCmd = doing_write ? 7 : 2; StWrPrech: SdCmd = doing_write ? 2 : 7; default: SdCmd = 7; // NOP endcase end assign {sd_ras_, sd_cas_, sd_we_} = SdCmd; /* ** Data output is either address or data */ wire [8:0] ColAddr = doing_write ? {WrCol, 2'b11} : {RdCol, 2'b00}; wire [13:0] RowAddr = doing_write ? WrRow : RdRow; assign wr_ok = (State >= StData1 && State <= StRdPrech) & doing_write; assign rd_ok = (State >= StData2 && State <= StWrPrech) & !doing_write; /* Upper bits of column. address must equal 0 */ wire [11:0] MuxAddr = (State == StActive) ? RowAddr : {3'b0,ColAddr}; assign sd_bank = RowAddr[13:12]; assign sd_addr_hi = MuxAddr[11:8]; wire [7:0] DataOut = (State == StActive || State == StRdWr) ? MuxAddr[7:0] : wr_data_in; assign sd_data = sd_data_ena ? DataOut : 'hz; assign rd_data_out = sd_data; assign sd_dqm = doing_write ? (State == StRdWr | State == StWrPrech) : (State == StRdPrech); endmodule