`include "inc.h" //******************************************************************************* // S Y N T H E S I Z A B L E S D R A M C O N T R O L L E R C O R E // // This core adheres to the GNU Public License // // This is a synthesizable Synchronous DRAM controller Core. As it stands, // it is ready to work with 8Mbyte SDRAMs, organized as 2M x 32 at 100MHz // and 125MHz. For example: Samsung KM432S2030CT, Fujitsu MB81F643242B. // // The core has been carefully coded so as to be "platform-independent". // It has been successfully compiled and simulated under three separate // FPGA/CPLD platforms: // Xilinx Foundation Base Express V2.1i // Altera Max+PlusII V9.21 // Lattice ispExpert V7.0 // // The interface to the host (i.e. microprocessor, DSP, etc) is synchronous // and supports ony one transfer at a time. That is, burst-mode transfers // are not yet supported. In may ways, the interface to this core is much // like that of a typical SRAM. The hand-shaking between the host and the // SDRAM core is done through the "sdram_busy_l" signal generated by the // core. Whenever this signal is active low, the host must hold the address, // data (if doing a write), size and the controls (cs, rd/wr). // // // Author: Jeung Joon Lee joon.lee@quantum.com, cmosexod@ix.netcom.com // // modified by : Dirk Leinenbach dirkl@wjpserver.cs.uni-sb.de // //******************************************************************************* // // Hierarchy: // // SDRAM.V Top Level Module // HOSTCONT.V Controls the interfacing between the micro and the SDRAM // SDRAMCNT.V This is the SDRAM controller. All data passed to and from // is with the HOSTCONT. // optional // MICRO.V This is the built in SDRAM tester. This module generates // a number of test logics which is used to test the SDRAM // It is basically a Micro bus generator. // /* */ module hostcont ( // system connections sys_rst_l, sys_clk, // microprocessor side connections mp_addx, mp_data_in, mp_data_out, mp_rd_l, mp_wr_l, mp_cs_l, sdram_mode_set_l, sdram_busy_l, mp_mask, // SDRAM side connections sd_addx, sd_data_out0, sd_data_out1, sd_data_out2, sd_data_out3, sd_data_in0, sd_data_in1, sd_data_in2, sd_data_in3, sd_ba, // SDRAMCNT side sd_addx10_mux, sd_addx_mux, sd_rd_ena, do_read, do_write, doing_refresh, do_modeset, modereg_cas_latency, modereg_burst_length, mp_data_mux, decoded_dqm0, decoded_dqm1, decoded_dqm2, decoded_dqm3, do_write_ack, do_read_ack, do_modeset_ack, pwrup, // debug // rd_wr_clk reg_mp_data_mux, reg_mp_addx, reg_sd_data0, reg_sd_data1, reg_sd_data2, reg_sd_data3 // reg_modeset ); // **************************************** // // I/O DEFINITION // // **************************************** // system connections input sys_rst_l; // asynch active low reset input sys_clk; // clock source to the SDRAM // microprocessor side connections input [22:0] mp_addx; // ABW bits for the addx input [63:0] mp_data_in; // DBW bits of data bus input (see INC.H) output [63:0] mp_data_out; // DBW bits of data bus output (see INC.H) input mp_rd_l; // micro bus read , active low input mp_wr_l; // micro bus write, active low input mp_cs_l; input sdram_mode_set_l; // acive low request for SDRAM mode set output sdram_busy_l; // active low busy output input [7:0] mp_mask; // SDRAM side connections output [11:0] sd_addx; // 11 bits of muxed SDRAM addx input [15:0] sd_data_in0; input [15:0] sd_data_in1; input [15:0] sd_data_in2; input [15:0] sd_data_in3; output [15:0] sd_data_out0; output [15:0] sd_data_out1; output [15:0] sd_data_out2; output [15:0] sd_data_out3; output [1:0] sd_ba; // bank select output to the SDRAM input pwrup; // SDRAMCNT side input [1:0] sd_addx10_mux; input [1:0] sd_addx_mux; input sd_rd_ena; output do_write; output do_read; input doing_refresh; output do_modeset; output [2:0] modereg_cas_latency; output [2:0] modereg_burst_length; input mp_data_mux; output [1:0] decoded_dqm0; output [1:0] decoded_dqm1; output [1:0] decoded_dqm2; output [1:0] decoded_dqm3; input do_write_ack; // acknowledge signal from sdramcont state machine // saying that it is now ok to clear 'do_write' signal input do_read_ack; // acknowledge signal from sdramcont state machine // saying that is is now ok to clear 'do_read' signal input do_modeset_ack; //debug //output rd_wr_clk; output [63:0] reg_mp_data_mux; output [22:0] reg_mp_addx; output [15:0] reg_sd_data0; output [15:0] reg_sd_data1; output [15:0] reg_sd_data2; output [15:0] reg_sd_data3; // output [11:0] reg_modeset; // **************************************** // // Memory Elements // // **************************************** // wire [22:0] reg_mp_addx; reg [63:0] reg_mp_data; reg [15:0] reg_sd_data0; reg [15:0] reg_sd_data1; reg [15:0] reg_sd_data2; reg [15:0] reg_sd_data3; reg [1:0] decoded_dqm0; reg [1:0] decoded_dqm1; reg [1:0] decoded_dqm2; reg [1:0] decoded_dqm3; reg [11:0] reg_modeset; reg [11:0] sd_addx; reg do_read; reg do_write; reg [2:0] do_state; reg do_modeset; reg [1:0] sd_ba; reg busy_a_ena; //wire [15:0] sd_data; wire [15:0] sd_data_buff0; wire [15:0] sd_data_buff1; wire [15:0] sd_data_buff2; wire [15:0] sd_data_buff3; wire [63:0] reg_mp_data_mux; reg [63:0] mp_data_out; wire busy_a; wire mp_data_ena; wire do_read_clk; wire do_read_rst_clk; wire do_write_clk; wire do_modeset_clk; wire do_modeset_rst_clk; wire clock_xx; wire modereg_ena; wire read_busy; wire write_busy; wire refresh_busy; wire modeset_busy; wire do_write_rst; wire do_read_rst; wire do_modeset_rst; assign mp_data_ena = ~mp_rd_l; assign modereg_cas_latency = reg_modeset[6:4]; assign modereg_burst_length = reg_modeset[2:0]; assign read_busy = do_read | (~mp_rd_l & busy_a_ena); assign write_busy = do_write | (~mp_wr_l & busy_a_ena); assign modeset_busy = do_modeset; assign refresh_busy = `LO; // SDRAM BUSY SIGNAL GENERATION // // The BUSY signal is NOR'd of READ_BUSY, WRITE_BUSY and DUMB_BUSY. // READ_BUSY is generated while the SDRAM is performing a read. This // does not necessarily have to he synchronous to the micro's read. // The WRITE_BUSY is generated while the SDRAM is performing WRITE. // Again, due to the "dump-n-run" mode (only in SMART_H=1) the micro's // write bus cycle does not necessarily align with SDRAM's write cycle. // DUMB_BUSY is a signal which generates the BUSY at the falling edge of // micro's SDRAM_CS. This is used for those microprocessors which // require a device BUSY as soon as the address is placed on its bus. For // example, most Intel microcontrollers and small processors do have this // requirement. This means that one will fofeit on the dump-n-go feature. // assign sdram_busy_l = ~( read_busy | write_busy | (doing_refresh & ~mp_cs_l)| (modeset_busy & ~mp_cs_l) ); // MP ADDRESS LATCH // Transparent latch // Used to hold the addx from the micro. Latch on the falling edge of // do_write. // BAsed on the way "do_write" is generated, we only need to latch on the writes // since the write can be queued, but since all reads are blocked, the latch // will not latch the addx on reads. assign reg_mp_addx = mp_addx; // // DECODED DQM LATCH // generate the proper DQM[1:0] masks based on mp_mask // always @(do_write or sys_rst_l or mp_addx or mp_mask) begin decoded_dqm0 <= #100 mp_mask[1:0]; decoded_dqm1 <= #100 mp_mask[3:2]; decoded_dqm2 <= #100 mp_mask[5:4]; decoded_dqm3 <= #100 mp_mask[7:6]; end // MP DATA LATCH // Used to hold the data from the micro. Latch on the rising edge // of mp_wr_l // always @(mp_data_in) reg_mp_data <= #100 mp_data_in; // // MODE REG REG // `define default_mode_reg {5'b00000,`default_mode_reg_CAS_LATENCY,`defulat_mode_reg_BURST_TYPE,`default_mode_reg_BURST_LENGHT} always @(posedge sys_clk or negedge sys_rst_l) begin if (~sys_rst_l) reg_modeset <= #100 11'h000; else if (pwrup) reg_modeset <= #100 `default_mode_reg; else if (~sdram_mode_set_l & ~mp_cs_l & ~mp_wr_l) reg_modeset <= #100 mp_data_in[11:0]; end // SD DATA REGISTER // This register holds in the data from the SDRAM // always @(posedge sys_clk or negedge sys_rst_l) if (~sys_rst_l) begin reg_sd_data0 <= #100 16'h0000; reg_sd_data1 <= #100 16'h0000; reg_sd_data2 <= #100 16'h0000; reg_sd_data3 <= #100 16'h0000; end else if (sd_rd_ena) begin reg_sd_data0 <= #100 sd_data_buff0; reg_sd_data1 <= #100 sd_data_buff1; reg_sd_data2 <= #100 sd_data_buff2; reg_sd_data3 <= #100 sd_data_buff3; end // // SD DATA BUS BUFFERS // assign sd_data_out0 = reg_mp_data[15:0]; assign sd_data_out1 = reg_mp_data[31:16]; assign sd_data_out2 = reg_mp_data[47:32]; assign sd_data_out3 = reg_mp_data[63:48]; assign sd_data_buff0 = sd_data_in0; assign sd_data_buff1 = sd_data_in1; assign sd_data_buff2 = sd_data_in2; assign sd_data_buff3 = sd_data_in3; // SDRAM SIDE ADDX always @(sd_addx10_mux or reg_mp_data or reg_mp_addx or reg_modeset) case (sd_addx10_mux) 2'b00: sd_addx[11:10] <= #100 reg_mp_addx[20:19]; // ROW 2'b01: sd_addx[11:10] <= #100 2'b00; // COLUMN 2'b10: sd_addx[11:10] <= #100 reg_modeset[11:10]; // modeset default: sd_addx[11:10] <= #100 2'b00; // I think default should be 0 not 1 endcase always @(sd_addx_mux or reg_modeset or reg_mp_addx) case (sd_addx_mux) 2'b00: sd_addx[9:0] <= #100 reg_mp_addx[18:9]; // ROW 2'b01: sd_addx[9:0] <= #100 {2'b00, reg_mp_addx[8:1]}; // COLUMN 2'b10: begin sd_addx[9:0] <= #100 reg_modeset[9:0]; end default: sd_addx[9:0] <= #100 10'h000; endcase /*always @(sd_addx10_mux or reg_mp_data or reg_mp_addx or reg_modeset or sd_addx_mux) sd_addx[11:0] <= #100 12'b000;*/ // SD_BA always @(sd_addx_mux or reg_mp_addx) case (sd_addx_mux) 2'b00: sd_ba <= #100 reg_mp_addx[22:21]; 2'b01: sd_ba <= #100 reg_mp_addx[22:21]; default: sd_ba <= #100 2'b00; endcase // Micro data mux assign reg_mp_data_mux = mp_data_mux ? 64'h0000000000000000 : reg_mp_data; // MP_DATA_OUT mux always @(reg_sd_data0 or reg_sd_data1 or reg_sd_data2 or reg_sd_data3) begin mp_data_out[15:0] <= #100 reg_sd_data0; mp_data_out[31:16] <= #100 reg_sd_data1; mp_data_out[47:32] <= #100 reg_sd_data2; mp_data_out[63:48] <= #100 reg_sd_data3; end // // DO_READ DO_WRITE DO_MODESET // signal generation // always @(posedge sys_clk or negedge sys_rst_l) if (~sys_rst_l) begin do_read <= #100 `LO; do_write <= #100 `LO; do_modeset <= #100 `LO; do_state <= #100 3'b000; busy_a_ena <= #100 `HI; end else case (do_state) // hang in here until a read or write is requested // (mp_rd_l = 1'b0) or (mp_wr_l = 1'b0) 3'b000: begin // a read request if (~mp_rd_l & ~mp_cs_l) begin do_read <= #100 `HI; do_state <= #100 3'b001; end // a write request else if (~mp_wr_l & ~mp_cs_l & sdram_mode_set_l) begin do_write <= #100 `HI; do_state <= #100 3'b001; end // a mode set request else if (~mp_wr_l & ~mp_cs_l & ~sdram_mode_set_l) begin do_modeset <= #100 `HI; do_state <= #100 3'b001; end else do_state <= #100 3'b000; end // This cycle is dummy cycle. Just to extend 'busy_ena_a' // to a total of 2 cycles 3'b001: begin busy_a_ena <= #100 `LO; // disable busy_a generation if (do_write) do_state <= #100 3'b011; else if (do_read) do_state <= #100 3'b010; else if (do_modeset) do_state <= #100 3'b110; else do_state <= #100 3'b001; end // hang in here until the sdramcnt has acknowledged the // read 3'b010: if (do_read_ack) begin do_read <= #100 `LO; do_state <= #100 3'b100; end else do_state <= #100 3'b010; // hang in here until the sdramcnt has acknowledged the // write 3'b011: if (do_write_ack) begin do_write <= #100 `LO; do_state <= #100 3'b101; end else do_state <= #100 3'b011; // wait in here until the host has read the data // (i.e. has raised its mp_rd_l high) 3'b100: if (mp_rd_l) begin busy_a_ena <= #100 `HI; // re-enable busy_a generation do_state <= #100 3'b000; end else do_state <= #100 3'b100; // wait in here until the host has relinquieshed the write bus // (i.e. has raised its mp_wr_l high) 3'b101: if (mp_wr_l) begin busy_a_ena <= #100 `HI; // re-enable busy_a generation do_state <= #100 3'b000; end else do_state <= #100 3'b101; // hang in here until the sdramcnt has acknowledged the // mode set 3'b110: if (do_modeset_ack) begin do_modeset <= #100 `LO; do_state <= #100 3'b101; end else do_state <= #100 3'b110; endcase endmodule