module sdram ( input i_clk, input i_reset, output o_sdram_cs, output o_sdram_ras, output o_sdram_cas, output o_sdram_we, output [1:0] o_sdram_ba, output [12:0] o_sdram_a, input [15:0] i_sdram_dq, output [15:0] o_sdram_dq, output o_sdram_dq_mode, input i_select, input i_read_rq, input i_write_rq, output reg o_ack, input [31:0] i_address, input [31:0] i_data, output reg [31:0] o_data ); reg r_wb_cyc; reg r_wb_stb; wire w_wb_cyc; wire w_wb_stb; wire [31:0] w_wb_addr; wire w_wb_ack; wire w_wb_stall; wire [31:0] w_wb_o_data; assign w_wb_cyc = w_wb_stb || r_wb_cyc; assign w_wb_stb = i_select && !w_wb_stall && (i_read_rq || i_write_rq || r_wb_stb); always @(posedge i_clk or posedge i_reset) begin if (i_reset) begin r_wb_cyc <= 1'b0; end else begin if (w_wb_stb) begin r_wb_cyc <= 1'b1; end else if (w_wb_ack) begin r_wb_cyc <= 1'b0; end end end // FIXME: Ugly solution for 16-bit address read align reg r_unaligned_access; reg r_next_word; assign w_wb_addr = i_address + {r_next_word, 2'b00}; always @(posedge i_clk or posedge i_reset) begin if (i_reset) begin o_ack <= 1'b0; r_wb_stb <= 1'b0; r_unaligned_access <= 1'b0; r_next_word <= 1'b0; end else begin o_ack <= 1'b0; r_wb_stb <= 1'b0; if (i_read_rq) begin if (!i_address[1]) begin r_unaligned_access <= 1'b0; r_next_word <= 1'b0; end else begin r_unaligned_access <= 1'b1; r_next_word <= 1'b0; end end if (w_wb_ack) begin if (!r_unaligned_access) begin o_data <= w_wb_o_data; o_ack <= 1'b1; end else begin if (!r_next_word) begin o_data[31:16] <= w_wb_o_data[15:0]; r_wb_stb <= 1'b1; r_next_word <= 1'b1; end else begin o_ack <= 1'b1; o_data[15:0] <= w_wb_o_data[31:16]; r_unaligned_access <= 1'b0; r_next_word <= 1'b0; end end end end end // Weird shift register required by this module // https://github.com/ZipCPU/arrowzip/blob/master/rtl/arrowzip/toplevel.v#L176 reg [15:0] r_sdram_dq_ext_clk; reg [15:0] r_sdram_dq; always @(posedge i_clk) begin {r_sdram_dq, r_sdram_dq_ext_clk} <= {r_sdram_dq_ext_clk, i_sdram_dq}; end wbsdram wbsdram_inst ( .i_clk(i_clk), .i_wb_cyc(w_wb_cyc), .i_wb_stb(w_wb_stb), // FIXME: Currently strobe can be missed when w_wb_stall is high .i_wb_we(i_write_rq), .i_wb_addr(w_wb_addr[31:2]), .i_wb_data(i_data), .i_wb_sel({4'b1111}), // No need to control this signal .o_wb_ack(w_wb_ack), .o_wb_stall(w_wb_stall), .o_wb_data(w_wb_o_data), .o_ram_cs_n(o_sdram_cs), // .o_ram_cke(), // No connection on PCB .o_ram_ras_n(o_sdram_ras), .o_ram_cas_n(o_sdram_cas), .o_ram_we_n(o_sdram_we), .o_ram_bs(o_sdram_ba), .o_ram_addr(o_sdram_a), .o_ram_dmod(o_sdram_dq_mode), .i_ram_data(r_sdram_dq), .o_ram_data(o_sdram_dq) // .o_ram_dqm(), // No connection on PCB // .o_debug() // No need for this signal ); endmodule