module RAM_64KB(
  input clk, resetn,

  input            mem_valid,
  output reg          mem_ready,

  input     [31:0] mem_addr,
  input     [31:0] mem_wdata,
  input     [ 3:0] mem_wstrb,
  output reg   [31:0] mem_rdata
);

  wire [31:0] ram_rdata_0;
  wire [31:0] ram_rdata_1;
  wire [31:0] ram_rdata_2;
  wire [31:0] ram_rdata_3;

  wire [ 3:0] ram_wstrb0_w = (mem_addr[15:14] == 2'b00) ? mem_wstrb : 4'b0;
  wire [ 3:0] ram_wstrb1_w = (mem_addr[15:14] == 2'b01) ? mem_wstrb : 4'b0;
  wire [ 3:0] ram_wstrb2_w = (mem_addr[15:14] == 2'b10) ? mem_wstrb : 4'b0;
  wire [ 3:0] ram_wstrb3_w = (mem_addr[15:14] == 2'b11) ? mem_wstrb : 4'b0;

  reg  [ 3:0] ram_wstrb0;
  reg  [ 3:0] ram_wstrb1;
  reg  [ 3:0] ram_wstrb2;
  reg  [ 3:0] ram_wstrb3;

  reg  [ 3:0] ram_wstrb0_r;
  reg  [ 3:0] ram_wstrb1_r;
  reg  [ 3:0] ram_wstrb2_r;
  reg  [ 3:0] ram_wstrb3_r;

  reg ram_ready1, ram_ready2;
  reg mem_valid_reg;
  reg [31:0] mem_addr_reg0;
  reg [31:0] mem_addr_reg1;

  always @(posedge clk) begin
    ram_wstrb0_r <= ram_wstrb0_w ;
    ram_wstrb1_r <= ram_wstrb1_w ;
    ram_wstrb2_r <= ram_wstrb2_w ;
    ram_wstrb3_r <= ram_wstrb3_w ;
    ram_wstrb0 <= mem_valid_reg ? ram_wstrb0_r : 4'b0000;
    ram_wstrb1 <= mem_valid_reg ? ram_wstrb1_r : 4'b0000;
    ram_wstrb2 <= mem_valid_reg ? ram_wstrb2_r : 4'b0000;
    ram_wstrb3 <= mem_valid_reg ? ram_wstrb3_r : 4'b0000;
  end

  ram_4k_32 _ram_4k_32_0(clk, mem_addr[13:2],
    mem_wdata, ram_rdata_0, 
    ram_wstrb0,
    mem_valid);
  ram_4k_32 _ram_4k_32_1(clk, mem_addr[13:2],
    mem_wdata, ram_rdata_1, 
    ram_wstrb1,
    mem_valid);
  ram_4k_32 _ram_4k_32_2(clk, mem_addr[13:2],
    mem_wdata, ram_rdata_2, 
    ram_wstrb2,
    mem_valid);
  ram_4k_32 _ram_4k_32_3(clk, mem_addr[13:2],
    mem_wdata, ram_rdata_3, 
    ram_wstrb3,
    mem_valid);

  always @(posedge clk) begin
      if (!resetn) begin
        ram_ready2 <= 0;
        ram_ready1 <= 0;
        mem_valid_reg <= 0;
        mem_addr_reg0 <= 0;
        mem_addr_reg1 <= 0;
      end else begin
        if ((mem_valid == 1) && (mem_valid_reg == 0))
          ram_ready1 <= 1;
        if (ram_ready1)
          ram_ready1 <= 0;

        mem_valid_reg <= mem_valid;
        ram_ready2 <= ram_ready1;
        mem_addr_reg0 <= mem_addr;
        mem_addr_reg1 <= mem_addr_reg0;
      end
  end

  wire        mem_ready_w;
  wire [31:0] mem_rdata_w;

  assign mem_ready_w = (|mem_wstrb == 1) ? ram_ready1 : ram_ready2;

  reg [31:0] ram_rdata_0_reg0;
  reg [31:0] ram_rdata_1_reg0;
  reg [31:0] ram_rdata_2_reg0;
  reg [31:0] ram_rdata_3_reg0;

  always @(posedge clk) begin
    ram_rdata_0_reg0 <= ram_rdata_0;
    ram_rdata_1_reg0 <= ram_rdata_1;
    ram_rdata_2_reg0 <= ram_rdata_2;
    ram_rdata_3_reg0 <= ram_rdata_3;
  end

  assign mem_rdata_w =
              (mem_addr_reg1[15:14] == 2'b00) ? ram_rdata_0_reg0 : 
              (mem_addr_reg1[15:14] == 2'b01) ? ram_rdata_1_reg0 : 
              (mem_addr_reg1[15:14] == 2'b10) ? ram_rdata_2_reg0 : 
              (mem_addr_reg1[15:14] == 2'b11) ? ram_rdata_3_reg0 : 32'h 0000_0000 ;

  always @(posedge clk) begin
    mem_rdata <= mem_rdata_w;
    mem_ready <= mem_ready_w;
  end

endmodule