//  $Id: data_memory.v,v 1.1.1.1 2007/04/20 23:07:46 vickery Exp $
/*
 *  Maps first 128Kx32 of CPU memory onto 256Kx16 of SRAM memory.
 *  Ignores CPU address bits 31:19 and 1:0.
 *  Uses 3 FPGA clock cycles per CPU read/write operation.
 *
 *  C. Vickery
 *  April, 2007
 *
 *  $Log: data_memory.v,v $
 *  Revision 1.1.1.1  2007/04/20 23:07:46  vickery
 *  Initial version
 *
 */
module Data_Memory( CPU_read_data,
          sram_upper_byte,
          sram_lower_byte,
          sram_address,
          sram_not_ce,
          sram_not_oe,
          sram_not_we,
          sram_not_ub,
          sram_not_lb,
          CPU_write_data,
          CPU_address,
          CPU_MemRead,
          CPU_MemWrite,
          CPU_Clock,
          FPGA_Clock);
//  State Names
parameter s_idle        = 3'b000;
parameter s_read_lower  = 3'b001;
parameter s_read_upper  = 3'b010;
parameter s_write_lower = 3'b101;
parameter s_write_upper = 3'b110;
parameter s_wait_cpu    = 3'b111;

//  Port Declarations
input[31:0]   CPU_write_data;
input[31:0]   CPU_address;
input         CPU_MemRead, CPU_MemWrite, CPU_Clock, FPGA_Clock;
output[31:0]  CPU_read_data;
reg[31:0]     CPU_read_data;

inout[7:0]    sram_lower_byte;
inout[15:8]   sram_upper_byte;
output[17:0]  sram_address;
output        sram_not_ce, sram_not_oe, sram_not_we, sram_not_ub, sram_not_lb;

reg[17:0]     sram_address;
reg[7:0]      sram_lower_byte;
reg[15:8]     sram_upper_byte;
reg           sram_not_oe, sram_not_we;

reg[15:0]     sram_write_data;

reg [2:0]     curr_state;

//  Chip always enabled; always read/write two bytes at a time
assign sram_not_ce = 0;
assign sram_not_ub = 0;
assign sram_not_lb = 0;

assign {sram_upper_byte,sram_lower_byte} =
                                 sram_not_we ? 16'bZ : sram_write_data;

//  Controller state machine.
/*  For reading, assert OE, set the address on two successive FPGA clock
 *  cycles to capture the two pairs of bytes that make up a CPU word.
 *  For writing, assert WE and write the first pair of bytes, deassert WE
 *  for one FPGA clock, then assert it again to write the second pair.
 *  The wait_cpu state is to be sure the cpu clock goes false before
 *  again checking if it is true; also used to complete the second write
 *  cycle.
 */
  always @(posedge FPGA_Clock)
  begin
    case (curr_state)
      s_idle:
        if (CPU_Clock && CPU_MemRead)
          begin
            sram_address <= {CPU_address[17:2],1'b0};
            sram_not_oe <= 0;
            sram_not_we <= 1;
            curr_state <= s_read_lower;
          end
        else if (CPU_Clock && CPU_MemWrite)
          begin
            sram_address <= {CPU_address[17:2],1'b0};
            sram_not_oe <= 1;
            sram_not_we <= 0;
            sram_write_data = CPU_write_data[15:0];
            curr_state <= s_write_lower;
          end
      s_read_lower:
        begin
          CPU_read_data[15:0] <= {sram_upper_byte,sram_lower_byte};
          sram_address <= {CPU_address[17:2],1'b1};
          curr_state <= s_read_upper;
        end
      s_read_upper:
        begin
          CPU_read_data[31:16] <= {sram_upper_byte,sram_lower_byte};
          sram_not_oe <= 1;
          curr_state <= s_wait_cpu;
        end
      s_write_lower:
        begin
          sram_not_we <= 1;
          curr_state <= s_write_upper;
        end
      s_write_upper:
        begin
          sram_address <= {CPU_address[17:2],1'b1};
          sram_not_we <= 0;
          sram_write_data = CPU_write_data[31:16];
          curr_state <= s_wait_cpu;
        end
      s_wait_cpu:
        begin
          sram_not_we <= 1;
          if ( ! CPU_Clock )
            curr_state <= s_idle;
        end
      default: curr_state <= s_idle;
    endcase
  end
endmodule
