------------------------------------------------------------------------------- -- Title : Parametrizable dual-port synchronous RAM (Xilinx version) -- Project : Generics RAMs and FIFOs collection ------------------------------------------------------------------------------- -- File : generic_dpram.vhd -- Author : Tomasz Wlostowski -- Company : CERN BE-CO-HT -- Created : 2011-01-25 -- Last update: 2011-10-05 -- Platform : -- Standard : VHDL'93 ------------------------------------------------------------------------------- -- Description: True dual-port synchronous RAM for Xilinx FPGAs with: -- - configurable address and data bus width -- - byte-addressing mode (data bus width restricted to multiple of 8 bits) -- Todo: -- - loading initial contents from file -- - add support for read-first/write-first address conflict resulution (only -- supported by Xilinx in VHDL templates) ------------------------------------------------------------------------------- -- Copyright (c) 2011 CERN ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2011-01-25 1.0 twlostow Created ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use std.textio.all; library work; use work.genram_pkg.all; use work.memory_loader_pkg.all; entity generic_dpram is generic ( -- standard parameters --G g_data_width : natural; --G g_size : natural; g_data_width : natural := 32; g_size : natural := 16384; g_with_byte_enable : boolean := false; g_addr_conflict_resolution : string := "read_first"; g_init_file : string := ""; g_dual_clock : boolean := true; g_fail_if_file_not_found : boolean := true ); port ( rst_n_i : in std_logic := '1'; -- synchronous reset, active LO -- Port A clka_i : in std_logic; bwea_i : in std_logic_vector((g_data_width+7)/8-1 downto 0); wea_i : in std_logic; aa_i : in std_logic_vector(f_log2_size(g_size)-1 downto 0); da_i : in std_logic_vector(g_data_width-1 downto 0); qa_o : out std_logic_vector(g_data_width-1 downto 0); -- Port B clkb_i : in std_logic; bweb_i : in std_logic_vector((g_data_width+7)/8-1 downto 0); web_i : in std_logic; ab_i : in std_logic_vector(f_log2_size(g_size)-1 downto 0); db_i : in std_logic_vector(g_data_width-1 downto 0); qb_o : out std_logic_vector(g_data_width-1 downto 0) ); end generic_dpram; architecture syn of generic_dpram is constant c_num_bytes : integer := (g_data_width+7)/8; type t_ram_type is array(0 to g_size-1) of std_logic_vector(g_data_width-1 downto 0); function f_memarray_to_ramtype(arr : t_meminit_array) return t_ram_type is variable tmp : t_ram_type; variable n, pos : integer; begin pos := 0; while(pos < g_size)loop n := 0; -- avoid ISE loop iteration limit while (pos < g_size and n < 4096) loop for i in 0 to g_data_width-1 loop tmp(pos)(i) := arr(pos, i); end loop; -- i n := n+1; pos := pos + 1; end loop; pos := pos + 1; end loop; return tmp; end f_memarray_to_ramtype; shared variable ram : t_ram_type := f_memarray_to_ramtype( f_load_mem_from_file(g_init_file, g_size, g_data_width, g_fail_if_file_not_found)); signal s_we_a : std_logic_vector(c_num_bytes-1 downto 0); signal s_ram_in_a : std_logic_vector(g_data_width-1 downto 0); signal s_we_b : std_logic_vector(c_num_bytes-1 downto 0); signal s_ram_in_b : std_logic_vector(g_data_width-1 downto 0); signal clka_int : std_logic; signal clkb_int : std_logic; signal wea_rep, web_rep : std_logic_vector(c_num_bytes-1 downto 0); begin gen_single_clock : if(g_dual_clock = false) generate clka_int <= clka_i after 1ns; clkb_int <= clka_i after 1ns; end generate gen_single_clock; gen_dual_clock : if(g_dual_clock = true) generate clka_int <= clka_i after 1ns; clkb_int <= clkb_i after 1ns; end generate gen_dual_clock; wea_rep <= (others => wea_i); web_rep <= (others => web_i); s_we_a <= bwea_i; s_we_b <= bweb_i; gen_with_byte_enable_readfirst : if(g_with_byte_enable = true and g_addr_conflict_resolution = "read_first") generate process (clka_int) begin if rising_edge(clka_int) then qa_o <= ram(to_integer(unsigned(aa_i))); for i in 0 to c_num_bytes-1 loop if s_we_a(i) = '1' then ram(to_integer(unsigned(aa_i)))((i+1)*8-1 downto i*8) := da_i((i+1)*8-1 downto i*8); end if; end loop; end if; end process; process (clkb_int) begin if rising_edge(clkb_int) then qb_o <= ram(to_integer(unsigned(ab_i))); for i in 0 to c_num_bytes-1 loop if s_we_b(i) = '1' then ram(to_integer(unsigned(ab_i)))((i+1)*8-1 downto i*8) := db_i((i+1)*8-1 downto i*8); end if; end loop; end if; end process; end generate gen_with_byte_enable_readfirst; gen_without_byte_enable_readfirst : if(g_with_byte_enable = false and g_addr_conflict_resolution = "read_first") generate process(clka_int) begin if rising_edge(clka_int) then qa_o <= ram(to_integer(unsigned(aa_i))); if(wea_i = '1') then ram(to_integer(unsigned(aa_i))) := da_i; end if; end if; end process; process(clkb_int) begin if rising_edge(clkb_int) then qb_o <= ram(to_integer(unsigned(ab_i))); if(web_i = '1') then ram(to_integer(unsigned(ab_i))) := db_i; end if; end if; end process; end generate gen_without_byte_enable_readfirst; gen_without_byte_enable_writefirst : if(g_with_byte_enable = false and g_addr_conflict_resolution = "write_first") generate process(clka_int) begin if rising_edge(clka_int) then if(wea_i = '1') then ram(to_integer(unsigned(aa_i))) := da_i; qa_o <= da_i; else qa_o <= ram(to_integer(unsigned(aa_i))); end if; end if; end process; process(clkb_int) begin if rising_edge(clkb_int) then if(web_i = '1') then ram(to_integer(unsigned(ab_i))) := db_i; qb_o <= db_i; else qb_o <= ram(to_integer(unsigned(ab_i))); end if; end if; end process; end generate gen_without_byte_enable_writefirst; end syn;