blob: fe2c518cc941c54a125b3ed512479007fc89c8f2 [file] [log] [blame]
// SDRAM driver from pcpu repo
module sdram (
input wire clk,
// CPU
input wire [23:0] c_addr,
input wire [15:0] c_data_in,
input wire [1:0] c_addr_sel,
output reg [31:0] c_data_out,
input wire c_read_req, c_write_req,
output reg c_busy, c_read_ready, c_cack,
// SDRAM
output reg dr_dqml, dr_dqmh,
output wire dr_cs_n, dr_cas_n, dr_ras_n, dr_we_n, dr_cke,
output reg [1:0] dr_ba,
output reg [12:0] dr_a,
inout [15:0] dr_dq,
input wire srclk
);
localparam CMD_NOP = 3'b111;
localparam CMD_ACTIVE = 3'b011;
localparam CMD_READ = 3'b101;
localparam CMD_WRITE = 3'b100;
localparam CMD_PRECH = 3'b010;
localparam CMD_AREFR = 3'b001;
localparam CMD_LREG = 3'b000;
reg [2:0] ram_cmd = CMD_NOP;
assign {dr_ras_n, dr_cas_n, dr_we_n} = ram_cmd;
assign dr_cke = 1'b1;
assign dr_cs_n = 1'b0;
localparam STATE_INIT_BEGIN = 4'b0000;
localparam STATE_INIT_PRECALL = 4'b0001;
localparam STATE_INIT_AUTOREF1 = 4'b0010;
localparam STATE_INIT_AUTOREF2 = 4'b0011;
localparam STATE_INIT_REGPROG = 4'b0100;
localparam STATE_IDLE = 4'b0101;
localparam STATE_REFR = 4'b0110;
localparam STATE_READ = 4'b0111;
localparam STATE_CASREAD = 4'b1000;
localparam STATE_WRITE = 4'b1001;
localparam STATE_WAIT = 4'b1111;
reg [3:0] state = STATE_INIT_BEGIN;
reg [15:0] wait_reg;
reg [3:0] wait_next_state;
reg [15:0] dr_dq_reg;
reg dr_dq_oe = 1'b0;
assign dr_dq = (dr_dq_oe ? dr_dq_reg : 16'bz);
// refr 7.183 us -> 355 clock -8/10/15 PRECHARGE ALL BEFORE RESET
reg [8:0] autorefr_cnt = 9'd55;
initial c_busy = 1'b1;
initial c_read_ready = 1'b0;
reg [23:0] i_addr;
reg [15:0] i_data_in;
reg [1:0] i_wr_mask;
reg [23:0] c_r_addr, c_w_addr; // to save addr at edge of bus
reg sync_xory_read = 1'b0;
always @(posedge srclk) begin
if(c_read_req & ~c_busy) begin
sync_xory_read <= sync_xory_read^1;
c_r_addr <= c_addr;
end
end
reg sync_x_read_done = 1'b0;
wire pulse_c_read = (sync_xory_read ^ sync_x_read_done) & ~c_read_ready;
reg sync_xory_write = 1'b0;
always @(posedge srclk) begin
if(c_write_req & ~c_busy) begin
sync_xory_write <= sync_xory_write^1;
c_w_addr <= c_addr;
end
end
always @(posedge srclk) begin
c_cack <= 1'b0;
if((c_read_req & ~c_busy) | (c_write_req & ~c_busy)) begin
c_cack <= 1'b1;
end
end
reg sync_x_write_done = 1'b0;
wire pulse_c_write = sync_xory_write ^ sync_x_write_done;
reg prev_srclk = 1'b0;
// 50 Mhz -> 20 ns
// RP 18ns RFC 60ns
always @(posedge clk) begin
//if (state != STATE_WAIT) begin
{dr_dqml, dr_dqmh} <= 2'b00; dr_dq_oe <= 1'b0; dr_a <= 13'b0; dr_ba <= 2'b0;
//end
//prev_srclk <= srclk;
// if((prev_srclk ^ srclk) & srclk)
c_read_ready <= 1'b0;
case (state)
STATE_INIT_BEGIN: begin
ram_cmd <= CMD_NOP;
state <= STATE_WAIT;
wait_next_state <= STATE_INIT_PRECALL;
//wait_reg <= 16'd5000;
wait_reg <= 16'd10;
end
STATE_INIT_PRECALL: begin
ram_cmd <= CMD_PRECH;
dr_a[10] <= 1'b1; // all banks
state <= STATE_WAIT;
wait_next_state <= STATE_INIT_AUTOREF1;
wait_reg <= 16'd1;
end
STATE_INIT_AUTOREF1: begin
ram_cmd <= CMD_AREFR;
state <= STATE_WAIT;
wait_next_state <= STATE_INIT_AUTOREF2;
wait_reg <= 16'd4; // 80 ns
end
STATE_INIT_AUTOREF2: begin
ram_cmd <= CMD_AREFR;
state <= STATE_WAIT;
wait_next_state <= STATE_INIT_REGPROG;
wait_reg <= 16'd4; // 80 ns
end
STATE_INIT_REGPROG: begin
ram_cmd <= CMD_LREG;
dr_a <= 13'b0001000100000;
//dr_a <= 13'b0001000010000;
// CAS 2 BURST R1 W1 SEQ
// CAS 1 CORRECT? DATASHEET
dr_ba <= 2'b00;
state <= STATE_WAIT;
wait_next_state <= STATE_IDLE;
wait_reg <= 16'd4; // 80 ns
end
STATE_IDLE: begin
// c_busy <= 1'b1; //default if not staying in idle
if(c_read_req & ~c_busy/*pulse_c_read*/) begin
ram_cmd <= CMD_ACTIVE; //CHECK IF NOT ACTIVATED ALREADY
//STORE PROG AND DATA IN DIFFERENT BANKS TO NOT PRECHARGE EVERY COMMAND
//8192 rows x 512 col x 16 bit x 4 banks
// 13 b + 9 b + 16 b + 2b
i_addr <= c_addr;
i_data_in <= c_data_in;
dr_ba <= {c_addr[23:22]}; // lower max ram addr and set banks to msb???
dr_a <= c_addr[21:9];
state <= STATE_WAIT;
wait_next_state <= STATE_READ;
wait_reg <= 16'd1;
c_busy <= 1'b1;
sync_x_read_done <= sync_x_read_done^1;
end else if(c_write_req & ~c_busy/*pulse_c_write*/) begin
ram_cmd <= CMD_ACTIVE;
i_addr <= c_addr;
i_data_in <= c_data_in;
i_wr_mask <= ~c_addr_sel;
dr_ba <= {c_addr[23:22]};
dr_a <= c_addr[21:9];
state <= STATE_WAIT;
wait_next_state <= STATE_WRITE;
wait_reg <= 16'd1;
c_busy <= 1'b1;
sync_x_write_done <= sync_x_write_done^1;
end else if(~(|autorefr_cnt)) begin
ram_cmd <= CMD_PRECH;
dr_a[10] <= 1'b1; //ALL BANKS
state <= STATE_WAIT;
wait_next_state <= STATE_REFR;
wait_reg <= 16'd1;
c_busy <= 1'b1;
end else begin
ram_cmd <= CMD_NOP;
state <= STATE_IDLE;
c_busy <= 1'b0;
end
end
STATE_WRITE: begin
ram_cmd <= CMD_WRITE;
{dr_dqmh, dr_dqml} <= i_wr_mask;
dr_ba <= {i_addr[23:22]};
dr_a[8:0] <= i_addr[8:0];
dr_a[9] <= 1'b0; dr_a[12:11] <= 2'b0;
dr_a[10] <= 1'b1; //auto precharge
dr_dq_reg <= i_data_in;
dr_dq_oe <= 1'b1;
state <= STATE_WAIT;
wait_next_state <= STATE_IDLE;
wait_reg <= 16'd1;
end
STATE_REFR: begin
ram_cmd <= CMD_AREFR;
state <= STATE_WAIT;
wait_next_state <= STATE_IDLE;
wait_reg <= 16'd4;
autorefr_cnt <= 9'd355;
end
STATE_READ: begin
ram_cmd <= CMD_READ;
{dr_dqml, dr_dqmh} <= 2'b00;
//don't use burst but two subseq reads for instr
dr_ba <= {i_addr[23:22]};
dr_a[8:0] <= i_addr[8:0];
dr_a[9] <= 1'b0; dr_a[12:11] <= 2'b0;
dr_a[10] <= 1'b1; //auto precharge
state <= STATE_WAIT;
wait_next_state <= STATE_CASREAD;
wait_reg <= 16'd1;
end
STATE_CASREAD: begin
state <= STATE_IDLE; //no wait needed
ram_cmd <= CMD_NOP;
c_data_out <= {16'b0, dr_dq};
c_read_ready <= 1'b1;
c_busy <= 1'b0;
end
default: begin // STATE_WAIT
ram_cmd <= CMD_NOP;
if(wait_reg == 16'b01) begin
state <= wait_next_state;
if (wait_next_state == STATE_IDLE) c_busy <= 1'b0;
else c_busy <= 1'b1;
end
wait_reg <= wait_reg-1;
end
endcase
if(|autorefr_cnt) autorefr_cnt <= autorefr_cnt-1;
end
endmodule