--
-- Copyright (c) 2001 Koay Kah Hoe.  Permission to copy is granted
-- provided that this header remains intact.  This code is provided
-- with no warranties.
--
-- Version : 1.0
--

-------------------------------------------------------------------------------
-- Synthesizable VHDL generated by VHDL Module Generator
--

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use WORK.I8051_LIB.all;

library unisim;
use unisim.VCOMPONENTS.all;

entity I8051_ROM is
	generic (
		Blocks: integer := 3 
	);
	port (rst      : in  STD_LOGIC;
         clk      : in  STD_LOGIC;
         addr     : in  UNSIGNED (11 downto 0);
         data     : out UNSIGNED (7 downto 0);
         rd       : in  STD_LOGIC
	);
	type ENUM_Multiplexer is (TristateBuffers, NormalGates);
	constant Multiplexer: ENUM_Multiplexer := TristateBuffers;
end I8051_ROM;

architecture BHV of I8051_ROM is

	signal WE : STD_LOGIC;
	signal DI : UNSIGNED(7 downto 0);
	signal EN : UNSIGNED(Blocks-1 downto 0);
	type RAMOut_Array is array (0 to Blocks-1) of UNSIGNED(data'range);
	signal RAMOut : RAMOut_Array;
	signal iA,iA2 : integer;
	signal addr_ltched: UNSIGNED(addr'left downto 9);

	component RAMB4_S8
	port (
		DI : in UNSIGNED (7 downto 0);
		EN : in STD_LOGIC;
		WE : in STD_LOGIC;
		RST : in STD_LOGIC;
		CLK : in STD_LOGIC;
		ADDR : in UNSIGNED (8 downto 0);
		DO : out UNSIGNED (7 downto 0)
	);
	end component;

begin

	WE <= '0'; -- Disable write enable
	DI <= CD_8;-- Data input not used

	G1: if Blocks>1 generate

		process (clk)
		begin
			if clk'event and clk='1' then
				if rd = '1' then
					addr_ltched <= addr(addr'left downto 9);
				end if;
			end if;
		end process;

		iA <= CONV_INTEGER(addr(addr'left downto 9));
		iA2 <= CONV_INTEGER(addr_ltched(addr'left downto 9));
		
		-- Convert binary number to one-hot format
		process (iA,rd)
			variable S:UNSIGNED (Blocks-1 downto 0);
		begin
			S := CONV_UNSIGNED(1,Blocks);
			for I in 0 to Blocks-1 loop
				if I < iA then
					S := SHL(S,"1");
				end if;
			end loop;
			if rd = '0' then
				S := (others=>'0');
			end if;
	
			EN <= CONV_UNSIGNED(S,Blocks);
		end process;
	
		G1_1: for I in 0 to Blocks-1 generate
			-- 512 bytes (0x0000~0x01ff)
			U_ROM: RAMB4_S8
				port map (DI, EN(I), WE, rst, clk, addr(8 downto 0), RAMOut(I));
	
			-- Multiplexer using tristate buffers
			G1_1_1: if Multiplexer=TristateBuffers generate
				data <= RAMOut(I) when iA2=I else (others=>'Z');
			end generate;
		end generate;
	
		-- Multiplexer using normal gates
		G1_2: if Multiplexer=NormalGates generate
			process (iA2,RAMOut)
			begin
				data <= RAMOut(0);
				for I in 1 to Blocks-1 loop
					if iA2=I then
						data <= RAMOut(I);
					end if;
				end loop;
			end process;
		end generate;
	end generate;

	G2: if Blocks=1 generate
		U_DEPTH: RAMB4_S8
			port map (DI, rd, WE, rst, clk, addr(8 downto 0), data);
	end generate;

end BHV;

