-------------------------------------------------------------
-- Filename:  BRAM_DP2.VHD
-- Authors: 
--		Alain Zarembowitch / MSS
-- Version: Rev 0
-- Last modified: 9/8/15

-- Inheritance: 	BRAM_DP.VHD 5/7/15
--
-- description:  synthesizable generic dual port RAM
---------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;

entity BRAM_DP2 is
	 Generic (
		DATA_WIDTHA: integer := 9;
		ADDR_WIDTHA: integer := 11;
		DATA_WIDTHB: integer := 9;
		ADDR_WIDTHB: integer := 11
	);
    Port ( 
			-- chip select, active high
		
	    -- Port A
		CLKA   : in  std_logic;
		CSA: in std_logic;	-- chip select, active high
		WEA    : in  std_logic;	-- write enable, active high
		OEA : in std_logic;	-- output enable, active high
		ADDRA  : in  std_logic_vector(ADDR_WIDTHA-1 downto 0);
		DIA   : in  std_logic_vector(DATA_WIDTHA-1 downto 0);
		DOA  : out std_logic_vector(DATA_WIDTHA-1 downto 0);

		-- Port B
		CLKB   : in  std_logic;
		CSB: in std_logic;	-- chip select, active high
		WEB    : in  std_logic;	-- write enable, active high
		OEB : in std_logic;	-- output enable, active high
		ADDRB  : in  std_logic_vector(ADDR_WIDTHB-1 downto 0);
		DIB   : in  std_logic_vector(DATA_WIDTHB-1 downto 0);
		DOB  : out std_logic_vector(DATA_WIDTHB-1 downto 0)
		);
end entity;

architecture Behavioral of BRAM_DP2 is
--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
-- infered
type mem_type is array ( (2**ADDR_WIDTHA)-1 downto 0 ) of std_logic_vector(DATA_WIDTHA-1 downto 0);
shared variable MEM : mem_type;
signal DOA_local: std_logic_vector(DATA_WIDTHA-1 downto 0);
signal DOB_local: std_logic_vector(DATA_WIDTHA-1 downto 0);

--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin

-- Port A write
process(CLKA)
begin
	if rising_edge(CLKA) then
		if(CSA = '1') and (WEA = '1') then
			mem(conv_integer(ADDRA)) := DIA;
		end if;
	end if;
end process;

-- Port A read
process(CLKA)
begin
	if rising_edge(CLKA) then
		if(CSA = '1') then
			DOA_local <= mem(conv_integer(ADDRA));
		else
			DOA_local <= (others => '0');
		end if;
	end if;
end process;

-- tri-state output
DOA <= DOA_local when (CSA = '1') and (OEA = '1') else (others => 'Z');
 
-- Port B write
process(CLKB)
begin
	if rising_edge(CLKB) then
		if(CSB = '1') and (WEB = '1') then
			mem(conv_integer(ADDRB)) := DIB;
		end if;
	end if;
end process;

-- Port B read
process(CLKB)
begin
	if rising_edge(CLKB) then
		if(CSB = '1') then
			DOB_local <= mem(conv_integer(ADDRB));
		else
			DOB_local <= (others => '0');
		end if;
	end if;
end process;

-- tri-state output
DOB <= DOB_local when (CSB = '1') and (OEB = '1') else (others => 'Z');

end Behavioral;
