-- **********************************************************
-- **                                                      **
-- **       sram - simulates a 2^16 x 16 sram array        **
-- **              40ns delay                              **
-- **                                                      **
-- **********************************************************


library ieee;  use ieee. std_logic_1164.all;
--version 2.2 last modified 11-14-02

entity sram is
  port (
         nOutputEnable : in  std_logic;
         nWriteEnable  : in  std_logic;
         nChipEnable   : in  std_logic;
         DataBus       : inout  std_logic_vector(15 downto 0);
         Address       : in  std_logic_vector(15 downto 0);
         DumpSignal    : in  std_logic;
         memWait       : out std_logic );

end ;

use work.bv_arithmetic.bv_to_natural,
    work.bv_arithmetic.natural_to_bv,
    std.textio.all;

architecture SixteenBitSram of sram is

  constant mem_size : positive := 65536;

  -- constants followed by an "--" are actually used for timing
  constant read_data_setup     : time := 1  ns;
  constant read_addr_setup     : time := 1  ns;
  constant write_data_setup    : time := 1  ns;
  constant write_addr_setup    : time := 1  ns;
  constant signal_setup    : time := 1  ns;
  

  signal write_access  :  std_logic := '0';
  signal read_access   :  std_logic := '0';

  signal din          : std_logic_vector(15 downto 0); 
  signal dout         : std_logic_vector(15 downto 0); 

  constant high_address : natural := mem_size - 1;

  type memory_array is
   array (natural range 0 to high_address) of bit_vector(15 downto 0);
  type memory_touched_array is
   array (natural range 0 to high_address) of bit_vector(1 downto 0);

  constant load_file_name : string := "mem.init";
  constant dump_file_name : string := "mem.dump";

begin

  mem_behavior : process

    variable mem : memory_array;
    variable Touched : memory_touched_array;

    variable word_address : natural;
    variable already_dumped : boolean := FALSE;


    --------------------------------------------------------------------
    --
    --                 LOAD FILE INTO MEMORY ARRAY
    --
    --------------------------------------------------------------------
    procedure load is

      -- file binary_file : text is in load_file_name; --  *** OLD VERSION ***

      file binary_file : text is load_file_name;  -- *** NEW VERSION ***

      variable L : line;
      variable ch : character;
      variable line_number : natural := 0;
      variable addr : natural;
      variable word : bit_vector(15 downto 0);
      ------------------------------------------------------------------
      procedure read_hex_natural ( L : inout line;  n : out natural ) is
        variable result : natural := 0;
      begin
        for i in 1 to 4 loop
          read(L, ch);
          if '0' <= ch and ch <= '9' then
            result := result*16 + character'pos(ch) - character'pos('0');
          elsif 'A' <= ch and ch <= 'F' then
            result := result*16 + character'pos(ch) - character'pos('A') + 10;
          elsif 'a' <= ch and ch <= 'f' then
            result := result*16 + character'pos(ch) - character'pos('a') + 10;
          end if;
        end loop;
        n := result;
      end read_hex_natural;
      ------------------------------------------------------------------
      procedure read_hex_word ( L : inout line;
        word : out bit_vector(15 downto 0)) is
        variable digit : natural;
        variable r : natural := 0;
        variable rr : natural;
      begin
        for i in 1 to 4 loop
          read(L, ch);
          if '0' <= ch and ch <= '9' then
            digit := character'pos(ch) - character'pos('0');
          elsif 'A' <= ch and ch <= 'F' then
            digit := character'pos(ch) - character'pos('A') + 10;
          elsif 'a' <= ch and ch <= 'f' then
            digit := character'pos(ch) - character'pos('a') + 10;
          end if;
          rr := 15 - r;
          word(rr downto rr-3) := natural_to_bv(digit, 4);
          r := r + 4;
        end loop;
      end read_hex_word;
      ------------------------------------------------------------------
    begin
      while not endfile(binary_file) loop
        readline(binary_file, L);
        line_number := line_number + 1;
        read_hex_natural(L, addr);
        read(L, ch);  -- the space character
        read(L, ch);  -- the slash char
        read(L, ch);  -- the space char
        read_hex_word(L, word);
        read(L, ch);  -- the space char
        read(L, ch);  -- the semicolon char
        mem(addr) := word;
        Touched(addr) := "11";
      end loop;
    end load;
    --------------------------------------------------------------------


    --------------------------------------------------------------------
    --
    --                  DUMP MEMORY CONTENTS TO ZERO
    --
    --------------------------------------------------------------------


    procedure do_dump is

       -- file dump : text is out dump_file_name ;    -- *** OLD VERSION ***

       file dump : text open write_mode is dump_file_name; -- *** NEW VERSION ***

      variable outline : line;
    begin
        for i in 0 to high_address loop
          if (Touched(i) = "11") then
            write (outline, i);
            write (outline, string'(" "));
            write (outline, mem(i));
            writeline (dump, outline);
          end if;
        end loop;
    end do_dump;



    --------------------------------------------------------------------
    --
    --                  Do write to memory
    --
    --------------------------------------------------------------------
    procedure do_write is
    begin
          mem(word_address) := to_bitvector(din);
          Touched(word_address) := "11";
    end do_write;
    --------------------------------------------------------------------


    --------------------------------------------------------------------
    --
    --                  Do read from memory
    --
    --------------------------------------------------------------------
    procedure do_read is
    begin
      dout <= To_X01( mem(word_address) ) ;
    end do_read;
    --------------------------------------------------------------------





    --------------------------------------------------------------------
    --
    --                  Memory Actions Procedure
    --
    --------------------------------------------------------------------

    begin

    load;  -- read binary memory image into memory array

      loop
       wait until    (DumpSignal = '1' AND DumpSignal'event)
                  or (read_access = '1' AND read_access'event)
                  or (write_access = '1' AND write_access'event) ;


         word_address := bv_to_natural(To_bitvector(Address)) ;

         if DumpSignal = '1' then
           do_dump;
           already_dumped := TRUE;

         elsif ( write_access = '1') then
           do_write;

         elsif ( read_access = '1') then
           do_read;
         end if;

      end loop;
    end process mem_behavior;



  Make_Stable  : process(nChipEnable'Stable(signal_setup), nWriteEnable'Stable(signal_setup), 
                         nOutputEnable'Stable(signal_setup), nChipEnable, nWriteEnable, nOutputEnable,
                         Address'Stable(write_addr_setup),DataBus'Stable(write_data_setup),
                         Address'Stable(read_addr_setup))

  begin
      if (nChipEnable = '0') then

        if (     (nWriteEnable = '0')
             AND (nOutputEnable = '1')
             AND (nWriteEnable'Stable(signal_setup))
             AND (nOutputEnable'Stable(signal_setup))
             AND (Address'Stable(write_addr_setup))
             AND (DataBus'Stable(write_data_setup)))
        then
           write_access <= '1';
           read_access <= '0';
         
 
        elsif (  (nWriteEnable = '1')
             AND (nOutputEnable = '0')
             AND (nWriteEnable'Stable(signal_setup))
             AND (nOutputEnable'Stable(signal_setup))
             AND (Address'Stable(read_addr_setup)))
        then
           write_access <= '0';
           read_access <= '1';

        else
           read_access <= '0';
           write_access <= '0';
        end if;
      else
        read_access <= '0';
        write_access <= '0';
      end if;

  end process Make_Stable;


  -- Async signals


  din <= DataBus;
  
  DataBus <= dout when (read_access = '1') else "ZZZZZZZZZZZZZZZZ";


--  memWait <= '0'; 

  memWait <= NOT nChipEnable AND (    (NOT read_access AND NOT nOutputEnable)
                                    OR (NOT write_access AND NOT nWriteEnable)    );


end ;







