library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.conv_integer;
use ieee.std_logic_arith.conv_std_logic_vector;
use std.textio.all;
use work.motonesfpga_common.all;

--syncronous rom
entity prg_rom is 
    generic (abus_size : integer := 15; dbus_size : integer := 8);
    port (
            clk             : in std_logic;
            ce_n            : in std_logic;     --active low.
            addr            : in std_logic_vector (abus_size - 1 downto 0);
            data            : out std_logic_vector (dbus_size - 1 downto 0)
        );
end prg_rom;

architecture rtl of prg_rom is

--32k ROM
subtype rom_data is std_logic_vector (dbus_size -1 downto 0);
type rom_array is array (0 to 2**abus_size - 1) of rom_data;

--not used...
constant ROM_TACE : time := 100 ns;      --output enable access time
constant ROM_TOH : time := 10 ns;      --output hold time

--function is called only once at the array initialize.
function rom_fill return rom_array is 
    type binary_file is file of character;
    FILE nes_file : binary_file OPEN read_mode IS "rom-file.nes" ;
    variable read_data : character;
    variable i : integer;
    variable ret : rom_array;
    begin
        --skip first 16 bit data(NES cardridge header part.)
        for i in 0 to 15 loop
            read(nes_file, read_data);
        end loop;

        for i in ret'range loop
            read(nes_file, read_data);
            ret(i) :=
                conv_std_logic_vector(character'pos(read_data), 8);
        end loop;
        d_print("file load success.");
        return ret;
    end rom_fill;

function init_rom
    return rom_array is 
    variable tmp : rom_array := (others => (others => '0'));
    use ieee.numeric_std.to_unsigned;
begin 
    for addr_pos in 0 to 2**abus_size - 1 loop 
        -- Initialize each address with the address itself
        tmp(addr_pos) := std_logic_vector(to_unsigned(addr_pos, dbus_size));
    end loop;
    return tmp;
end init_rom;

-- Declare the ROM signal and specify a default value.	Quartus II
-- will create a memory initialization file (.mif) based on the 
-- default value.

--for GHDL environment
--itinialize with the rom_fill function.
--signal p_rom : rom_array := rom_fill;

--for Quartus II environment
signal p_rom : rom_array;
attribute ram_init_file : string;
attribute ram_init_file of p_rom : signal is "sample1-prg.hex";

signal wk_data  : std_logic_vector (dbus_size - 1 downto 0);

begin

    p : process (clk)
    begin
    if (rising_edge(clk)) then
        if (ce_n = '0') then
            wk_data <= p_rom(conv_integer(addr));
        else
            wk_data <= (others => 'Z');
        end if;
    end if;
    end process;
    
    data <= wk_data when ce_n = '0' else
            (others => 'Z');
end rtl;

