123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- /*
- * SDRAM controller
- * Custom made for FPGC with l1 cache (one word per cache line), having two W9825G6KH-6 chips:
- * - bus interface to be connected directly to arbiter, so no memory unit in between
- * - no burst, so high latency access to single words
- */
- module SDRAMcontroller(
- // clock/reset inputs
- input clk,
- input reset,
- // signal inputs
- input [23:0] sdc_addr, // bus_addr
- input [31:0] sdc_data, // bus_data
- input sdc_we, // bus_we
- input sdc_start, // bus_start
- // signal outputs
- output reg [31:0] sdc_q = 32'd0, // bus_q
- output reg sdc_done = 1'b0, // bus_done
- // SDRAM signals, initialized for power up
- output SDRAM_CSn, SDRAM_WEn, SDRAM_CASn, SDRAM_RASn,
- output reg SDRAM_CKE = 1'b1,
- output reg [12:0] SDRAM_A = 13'd0,
- output reg [1:0] SDRAM_BA = 2'd0,
- output reg [3:0] SDRAM_DQM = 4'b1111,
- inout [31:0] SDRAM_DQ
- );
- // SDRAM commands
- parameter [3:0] SDRAM_CMD_UNSELECTED= 4'b1000;
- parameter [3:0] SDRAM_CMD_NOP = 4'b0111;
- parameter [3:0] SDRAM_CMD_ACTIVE = 4'b0011;
- parameter [3:0] SDRAM_CMD_READ = 4'b0101;
- parameter [3:0] SDRAM_CMD_WRITE = 4'b0100;
- parameter [3:0] SDRAM_CMD_BURSTSTOP = 4'b0110;
- parameter [3:0] SDRAM_CMD_PRECHARGE = 4'b0010;
- parameter [3:0] SDRAM_CMD_REFRESH = 4'b0001;
- parameter [3:0] SDRAM_CMD_LOADMODE = 4'b0000;
- // Mode register value
- // {3'b reserved, 1'b write mode, 1'b reserved, 1'b test mode, 3'b CAS latency, 1'b addressing mode, 3'b burst length}
- // CAS latency: 010=2, 011=3
- // addressing mode: 0=seq 1=interleave
- // burst length: 000=1, 001=2, 010=4, 011=8, 111=full page
- parameter [12:0] MODE_REG = {3'b0, 1'b0, 1'b0, 1'b0, 3'b010, 1'b0, 3'b000};
- // assign command pins to selected command
- reg [3:0] SDRAM_CMD = SDRAM_CMD_NOP; // default to NOP for power up
- assign {SDRAM_CSn, SDRAM_RASn, SDRAM_CASn, SDRAM_WEn} = SDRAM_CMD;
- // cycles_per_refresh calculation:
- // 25MHz -> 25.000.000 cycles per sec
- // 25.000.000*0.064 -> 1.600.000 cycles per 64ms
- // 1.600.000 / 8192 auto refreshes -> refresh after 196 cycles
- // for 50mhz this should be 196*2 cycles and for 100mhz this should be 196*4 cycles
- parameter cycles_per_refresh = 784;
- reg [9:0] refresh_counter = 10'd0; // cycle counter for refresh command, max 1023
- parameter sdram_startup_cycles = 20000; // 200us @ 100MHz -> 20.000 cycles. Lowered for simulation
- reg [15:0] startup_counter = 16'd0; // cycle counter for startup, max 65.535
- parameter addr_precharge_bit = 10; // address bit that selects which banks are to be precharged (1 == all banks)
- // convert input address into row, column and bank
- wire [12:0] addr_row;
- wire [8:0] addr_col;
- wire [1:0] addr_bank;
- assign addr_col = sdc_addr[8:0]; // 9 bit columns
- assign addr_row = sdc_addr[21:9]; // 13 bit rows
- assign addr_bank = sdc_addr[23:22]; // 2 bit banks
- // DQ port setup
- // write
- reg [31:0] SDRAM_DATA = 32'd0;
- reg SDRAM_DQ_OE = 1'b0;
- assign SDRAM_DQ = SDRAM_DQ_OE ? SDRAM_DATA : 32'hZZZZ;
- // read
- wire [31:0] SDRAM_Q;
- assign SDRAM_Q = SDRAM_DQ;
- // state machine
- parameter s_init = 5'd0;
- parameter s_idle = 5'd1;
- parameter s_open_in_2 = 5'd2;
- parameter s_open_in_1 = 5'd3;
- parameter s_write_1 = 5'd4;
- parameter s_write_2 = 5'd5;
- parameter s_write_3 = 5'd6;
- parameter s_read_1 = 5'd7;
- parameter s_read_2 = 5'd8;
- parameter s_read_3 = 5'd9;
- parameter s_read_4 = 5'd10;
- parameter s_write_precharge = 5'd11;
- parameter s_idle_in_6 = 5'd12;
- parameter s_idle_in_5 = 5'd13;
- parameter s_idle_in_4 = 5'd14;
- parameter s_idle_in_3 = 5'd15;
- parameter s_idle_in_2 = 5'd16;
- parameter s_idle_in_1 = 5'd17;
- parameter s_read_precharge = 5'd18;
- parameter s_read_idle_in_3 = 5'd19;
- reg [4:0] state = s_init;
- // not used, but useful for debugging
- wire refresh = (SDRAM_CMD == SDRAM_CMD_REFRESH);
- reg is_refreshing = 1'b0;
- always @(posedge clk)
- begin
- if (reset)
- begin
- SDRAM_CMD <= SDRAM_CMD_UNSELECTED;
- state <= s_init;
- startup_counter <= 16'd0;
- sdc_done <= 1'b0;
- end
- else
- begin
- // default state
- SDRAM_CMD <= SDRAM_CMD_NOP;
- SDRAM_A <= 13'd0;
- SDRAM_BA <= 2'b00;
- SDRAM_DQM <= 4'b0000;
- sdc_done <= 1'b0;
-
- // update counter for refresh
- refresh_counter <= refresh_counter + 1'b1;
- case(state)
- s_init:
- begin
- // ~200us pause,
- // followed by precharge of all banks,
- // followed by two auto refreshes,
- // followed by mode register init
- SDRAM_CKE <= 1'b1;
- // hold DQM high during initial pause
- if (startup_counter < sdram_startup_cycles - 50)
- begin
- SDRAM_DQM <= 4'b1111;
- end
- case(startup_counter)
- (sdram_startup_cycles-50):
- begin
- // precharge all banks
- SDRAM_CMD <= SDRAM_CMD_PRECHARGE;
- SDRAM_A[addr_precharge_bit] <= 1'b1; // select all banks
- SDRAM_BA <= 2'b00;
- end
- (sdram_startup_cycles-28):
- begin
- SDRAM_CMD <= SDRAM_CMD_REFRESH;
- end
- (sdram_startup_cycles-18):
- begin
- SDRAM_CMD <= SDRAM_CMD_REFRESH;
- end
- (sdram_startup_cycles-7):
- begin
- SDRAM_CMD <= SDRAM_CMD_LOADMODE;
- SDRAM_A <= MODE_REG;
- end
- sdram_startup_cycles:
- begin
- state <= s_idle;
- end
- default:
- begin
- end
- endcase
- startup_counter <= startup_counter + 1'b1;
- end
- s_idle_in_6: state <= s_idle_in_5;
- s_idle_in_5: state <= s_idle_in_4;
- s_idle_in_4: state <= s_idle_in_3;
- s_idle_in_3: state <= s_idle_in_2;
- s_idle_in_2: state <= s_idle_in_1;
- s_idle_in_1: state <= s_idle;
- s_idle:
- begin
- if (refresh_counter > cycles_per_refresh) //refresh has priority!
- begin
- state <= s_idle_in_6;
- is_refreshing <= 1'b1;
- SDRAM_CMD <= SDRAM_CMD_REFRESH;
- refresh_counter <= 0;
- end
- else
- begin
- if (sdc_start)
- begin
- //--------------------------------
- //-- Start the read or write cycle.
- //-- First task is to open the row
- //--------------------------------
- state <= s_open_in_2;
- SDRAM_CMD <= SDRAM_CMD_ACTIVE;
- SDRAM_A <= addr_row;
- SDRAM_BA <= addr_bank;
- end
- else //if nothing happens, just nop
- begin
- SDRAM_DQM <= 2'b00;
- SDRAM_CMD <= SDRAM_CMD_NOP;
- SDRAM_A <= 0;
- end
- end
-
- end
- //--------------------------------------------
- //-- Opening the row ready for reads or writes
- //--------------------------------------------
- s_open_in_2: state <= s_open_in_1;
- s_open_in_1:
- begin
- // if write command
- if (sdc_we)
- begin
- state <= s_write_1;
- SDRAM_DATA <= sdc_data; // already present sdram with data
- SDRAM_DQ_OE <= 1'b1;
- end
- else // if read command
- begin
- state <= s_read_1;
- SDRAM_DQ_OE <= 1'b0;
- end
- end
- s_write_1:
- begin
- state <= s_write_2;
- SDRAM_CMD <= SDRAM_CMD_WRITE;
- SDRAM_A <= addr_col;
- SDRAM_A[addr_precharge_bit] <= 1'b0;
- SDRAM_BA <= addr_bank;
- SDRAM_DQM <= 2'b00;
- SDRAM_DATA <= sdc_data;
- end
- s_write_2:
- begin
- state <= s_write_precharge;
- SDRAM_DQ_OE <= 1'b0;
- sdc_done <= 1'b1; // high for two cycles (this + s_write_precharge)
- end
- s_write_precharge:
- begin
- sdc_done <= 1'b1;
- state <= s_idle_in_3;
- SDRAM_CMD <= SDRAM_CMD_PRECHARGE;
- SDRAM_A[addr_precharge_bit] <= 1'b1;
- end
-
- //----------------------------------
- //-- Processing the read transaction
- //----------------------------------
- s_read_1:
- begin
- state <= s_read_2;
- SDRAM_CMD <= SDRAM_CMD_READ;
- SDRAM_A <= addr_col;
- SDRAM_BA <= addr_bank;
- SDRAM_A[addr_precharge_bit] <= 1'b0;
- SDRAM_DQM <= 2'b00;
- end
- s_read_2:
- begin
- state <= s_read_3;
- end
- s_read_3:
- begin
- state <= s_read_precharge;
- end
- s_read_precharge:
- begin
- sdc_q <= SDRAM_Q;
- sdc_done <= 1'b1; // high for two cycles (this + s_read_idle_in_3)
- state <= s_read_idle_in_3;
- SDRAM_CMD <= SDRAM_CMD_PRECHARGE;
- SDRAM_A[addr_precharge_bit] <= 1'b1;
- end
- s_read_idle_in_3:
- begin
- sdc_done <= 1'b1;
- state <= s_idle_in_2;
- end
-
- default:
- begin
- SDRAM_CMD <= SDRAM_CMD_UNSELECTED;
- state <= s_init;
- startup_counter <= 16'd0;
- end
- endcase
- end
- end
- endmodule
|