diff --git a/modules/genrams/altera/Manifest.py b/modules/genrams/altera/Manifest.py index d6297cad34ca5e91e2e430a4d3c01d3e1ce4d01e..c86aa8ff89d004160f519e2199c41c586acb25a3 100644 --- a/modules/genrams/altera/Manifest.py +++ b/modules/genrams/altera/Manifest.py @@ -1,5 +1,6 @@ files = [ "generic_async_fifo.vhd", +"generic_simple_dpram.vhd", "generic_dpram.vhd", "generic_spram.vhd", "generic_sync_fifo.vhd"] diff --git a/modules/genrams/altera/generic_dpram.vhd b/modules/genrams/altera/generic_dpram.vhd index 1df91c324a3e3b44e5efac06e518e6c048276ea5..294015358f8fe58ca72dccc2dbad25d72948e222 100644 --- a/modules/genrams/altera/generic_dpram.vhd +++ b/modules/genrams/altera/generic_dpram.vhd @@ -3,25 +3,25 @@ -- Project : Generics RAMs and FIFOs collection ------------------------------------------------------------------------------- -- File : generic_dpram.vhd --- Author : Tomasz Wlostowski --- Company : CERN BE-CO-HT +-- Author : Wesley W. Terpstra +-- Company : GSI -- Created : 2011-01-25 --- Last update: 2012-01-20 +-- Last update: 2013-03-04 -- Platform : -- Standard : VHDL'93 ------------------------------------------------------------------------------- -- Description: True dual-port synchronous RAM for Altera 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 ------------------------------------------------------------------------------- -- Copyright (c) 2011 CERN +-- Copyright (c) 2013 GSI ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2011-01-25 1.0 twlostow Created -- 2012-03-13 1.1 wterpstra Added initial value as array +-- 2013-03-04 2.0 wterpstra Rewrote using altsyncram ------------------------------------------------------------------------------- @@ -31,23 +31,20 @@ use ieee.numeric_std.all; library work; use work.genram_pkg.all; -use work.memory_loader_pkg.all; -entity generic_dpram is +library altera_mf; +use altera_mf.altera_mf_components.all; - generic ( +entity generic_dpram is + generic( -- standard parameters g_data_width : natural; g_size : natural; g_with_byte_enable : boolean := false; - g_addr_conflict_resolution : string := "read_first"; - g_init_file : string := ""; - g_init_value : t_generic_ram_init := c_generic_ram_nothing; - g_dual_clock : boolean := true; - g_fail_if_file_not_found : boolean := true - ); - - port ( + g_addr_conflict_resolution : string := "dont_care"; + g_init_file : string := "none"; + g_dual_clock : boolean := true); + port( rst_n_i : in std_logic := '1'; -- synchronous reset, active LO -- Port A @@ -57,8 +54,8 @@ entity generic_dpram is 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; @@ -71,203 +68,237 @@ end generic_dpram; architecture syn of generic_dpram is - constant c_num_bytes : integer := g_data_width/8; - - type t_ram_type is array(0 to g_size-1) of std_logic_vector(g_data_width-1 downto 0); - type t_ram_word_bs is array (0 to 7) of std_logic_vector(7 downto 0); - type t_ram_type_bs is array (0 to g_size - 1) of t_ram_word_bs; - - function f_memarray_to_ramtype(arr : t_meminit_array) return t_ram_type is - variable tmp : t_ram_type := (others => (others => '0')); - variable n, pos : integer; + function f_sameport_order(x : string) return string is 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; - end loop; - return tmp; - end f_memarray_to_ramtype; - - function f_memarray_to_ramtype_bs(arr : t_meminit_array) return t_ram_type_bs is - variable tmp : t_ram_type_bs := (others => (others => (others => '0'))); - variable n, pos : integer; + if x = "read_first" then + return "OLD_DATA"; + elsif x = "write_first" then + --return "NEW_DATA_NO_NBE_READ"; -- unwritten bytes='X' + return "NEW_DATA_WITH_NBE_READ"; -- unwritten bytes=OLD_DATA (ie: whole result = NEW_DATA) + elsif x = "dont_care" then + return "DONT_CARE"; + else + assert (false) report "generic_dpram: g_addr_conflict_resolution must be: read_first, write_first, dont_care" severity failure; + end if; + end f_sameport_order; + + function f_diffport_order(x : string) return string is 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/8)(i mod 8) := arr(pos, i); - end loop; -- i - n := n+1; - pos := pos + 1; - end loop; - end loop; - return tmp; - end f_memarray_to_ramtype_bs; - - function f_file_contents return t_meminit_array is + if x = "read_first" then + return "OLD_DATA"; + elsif x = "write_first" then + return "DONT_CARE"; -- "NEW_DATA" is unsupported; we use a bypass MUX in this case + elsif x = "dont_care" then + return "DONT_CARE"; + else + assert (false) report "generic_dpram: g_addr_conflict_resolution must be: read_first, write_first, dont_care" severity failure; + end if; + end f_diffport_order; + + function f_filename(x : string) return string is begin - if g_init_value'length > 0 then - return g_init_value; + if x'length = 0 or x = "none" then + return "UNUSED"; else - return f_load_mem_from_file(g_init_file, g_size, g_data_width, g_fail_if_file_not_found); + return x; end if; - end f_file_contents; + end f_filename; - signal ram : t_ram_type := f_memarray_to_ramtype (f_file_contents); - signal ram_bs : t_ram_type_bs := f_memarray_to_ramtype_bs(f_file_contents); + constant c_num_bytes : integer := (g_data_width+7)/8; + constant c_addr_width : integer := f_log2_size(g_size); + constant sameport_order : string := f_sameport_order(g_addr_conflict_resolution); + constant diffport_order : string := f_diffport_order(g_addr_conflict_resolution); + constant c_init_file : string := f_filename(g_init_file); - signal q_local_a : t_ram_word_bs; - signal q_local_b : t_ram_word_bs; - - signal bwe_int_a : std_logic_vector(7 downto 0); - signal bwe_int_b : std_logic_vector(7 downto 0); - - signal clka_int : std_logic; - signal clkb_int : std_logic; + signal qa : std_logic_vector(g_data_width-1 downto 0); + signal qb : std_logic_vector(g_data_width-1 downto 0); + signal da : std_logic_vector(g_data_width-1 downto 0); + signal db : std_logic_vector(g_data_width-1 downto 0); + signal nba : boolean; + signal nbb : boolean; begin - assert (g_addr_conflict_resolution = "read_first") - report "generic_dpram: Altera template supports only read-first mode." severity failure; - assert (((g_data_width / 8) * 8) = g_data_width) or (g_with_byte_enable = false) - report "generic_dpram: in byte-enabled mode the data width must be a multiple of 8" severity failure; - assert(g_data_width <= 64 or g_with_byte_enable = false) - report "generic_dpram: byte-selectable memories can be have 64-bit data width due to synthesis tool limitation" severity failure; - - - - --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; - - - - gen_with_byte_enable : if(g_with_byte_enable = true) generate - bwe_int_a <= std_logic_vector(to_unsigned(0, 8-bwea_i'length)) & bwea_i; - bwe_int_b <= std_logic_vector(to_unsigned(0, 8-bweb_i'length)) & bweb_i; - unpack : for i in 0 to c_num_bytes - 1 generate - qa_o(8*(i+1) - 1 downto 8*i) <= q_local_a(i); - qb_o(8*(i+1) - 1 downto 8*i) <= q_local_b(i); - end generate unpack; - - process(clka_i) - begin - if(rising_edge(clka_i)) then - if(wea_i = '1') then - --- I know the code below is stupid, but it's the only way to make Quartus --- recongnize it as a memory block - if(bwe_int_a(0) = '1' and g_data_width >= 8) then - ram_bs(to_integer(unsigned(aa_i)))(0) <= da_i(7 downto 0); - end if; - if(bwe_int_a(1) = '1' and g_data_width >= 16) then - ram_bs(to_integer(unsigned(aa_i)))(1) <= da_i(15 downto 8); - end if; - if(bwe_int_a(2) = '1' and g_data_width >= 24) then - ram_bs(to_integer(unsigned(aa_i)))(2) <= da_i(23 downto 16); - end if; - if(bwe_int_a(3) = '1' and g_data_width >= 32) then - ram_bs(to_integer(unsigned(aa_i)))(3) <= da_i(31 downto 24); - end if; - if(bwe_int_a(4) = '1' and g_data_width >= 40) then - ram_bs(to_integer(unsigned(aa_i)))(4) <= da_i(39 downto 32); - end if; - if(bwe_int_a(5) = '1' and g_data_width >= 48) then - ram_bs(to_integer(unsigned(aa_i)))(5) <= da_i(47 downto 40); - end if; - if(bwe_int_a(6) = '1' and g_data_width >= 56) then - ram_bs(to_integer(unsigned(aa_i)))(6) <= da_i(55 downto 48); - end if; - if(bwe_int_a(7) = '1' and g_data_width = 64) then - ram_bs(to_integer(unsigned(aa_i)))(7) <= da_i(64 downto 57); - end if; - end if; - q_local_a <= ram_bs(to_integer(unsigned(aa_i))); - end if; - end process; - - process(clkb_i) - begin - if(rising_edge(clkb_i)) then - if(web_i = '1') then - --- I know the code below is stupid, but it's the only way to make Quartus --- recongnize it as a memory block - if(bwe_int_b(0) = '1' and g_data_width >= 8) then - ram_bs(to_integer(unsigned(ab_i)))(0) <= db_i(7 downto 0); - end if; - if(bwe_int_b(1) = '1' and g_data_width >= 16) then - ram_bs(to_integer(unsigned(ab_i)))(1) <= db_i(15 downto 8); - end if; - if(bwe_int_b(2) = '1' and g_data_width >= 24) then - ram_bs(to_integer(unsigned(ab_i)))(2) <= db_i(23 downto 16); - end if; - if(bwe_int_b(3) = '1' and g_data_width >= 32) then - ram_bs(to_integer(unsigned(ab_i)))(3) <= db_i(31 downto 24); - end if; - if(bwe_int_b(4) = '1' and g_data_width >= 40) then - ram_bs(to_integer(unsigned(ab_i)))(4) <= db_i(39 downto 32); - end if; - if(bwe_int_b(5) = '1' and g_data_width >= 48) then - ram_bs(to_integer(unsigned(ab_i)))(5) <= db_i(47 downto 40); - end if; - if(bwe_int_b(6) = '1' and g_data_width >= 56) then - ram_bs(to_integer(unsigned(ab_i)))(6) <= db_i(55 downto 48); - end if; - if(bwe_int_b(7) = '1' and g_data_width = 64) then - ram_bs(to_integer(unsigned(ab_i)))(7) <= db_i(64 downto 57); - end if; - end if; - q_local_b <= ram_bs(to_integer(unsigned(ab_i))); - end if; - end process; - - - end generate gen_with_byte_enable; - - - gen_without_byte_enable_readfirst : if(g_with_byte_enable = false) generate - process(clka_i) + assert (g_addr_conflict_resolution /= "write_first" or (g_dual_clock = false and g_with_byte_enable = false)) + report "generic_dpram: write_first is only possible when dual_clock and g_with_byte_enable are false" + severity failure; + + assert (g_addr_conflict_resolution /= "read_first" or g_dual_clock = false) + report "generic_dpram: read_first is only possible when dual_clock is false" + severity failure; + + assert (g_addr_conflict_resolution /= "write_first") + report "generic_dpram: write_first requires a bypass MUX" + severity note; + + case_qb_raw : if (g_addr_conflict_resolution /= "write_first") generate + qa_o <= qa; + qb_o <= qb; + end generate; + + case_qb_bypass : if (g_addr_conflict_resolution = "write_first") generate + qa_o <= qa when nba else db; + qb_o <= qb when nbb else da; + + memoize : process(clka_i) is begin if rising_edge(clka_i) then - if(wea_i = '1') then - ram(to_integer(unsigned(aa_i))) <= da_i; - qa_o <= da_i; -- Arria5 must have "new data" for a port RW conflict - else - qa_o <= ram(to_integer(unsigned(aa_i))); - end if; + nba <= aa_i /= ab_i or web_i = '0'; + nbb <= aa_i /= ab_i or wea_i = '0'; + da <= da_i; + db <= db_i; end if; end process; - - process(clkb_i) - begin - if rising_edge(clkb_i) then - if(web_i = '1') then - ram(to_integer(unsigned(ab_i))) <= db_i; - qb_o <= db_i; -- Arria5 must have "new data" for a port RW conflict - else - qb_o <= ram(to_integer(unsigned(ab_i))); - end if; - end if; - end process; - end generate gen_without_byte_enable_readfirst; + end generate; - + case_be_dual : if (g_with_byte_enable = true and g_dual_clock = true) generate + memory : altsyncram + generic map( + byte_size => 8, + numwords_a => g_size, + numwords_b => g_size, + widthad_a => c_addr_width, + widthad_b => c_addr_width, + width_a => g_data_width, + width_b => g_data_width, + width_byteena_a => c_num_bytes, + width_byteena_b => c_num_bytes, + operation_mode => "BIDIR_DUAL_PORT", + read_during_write_mode_mixed_ports => diffport_order, + read_during_write_mode_port_a => sameport_order, + read_during_write_mode_port_b => sameport_order, + outdata_reg_a => "UNREGISTERED", + outdata_reg_b => "UNREGISTERED", + address_reg_b => "CLOCK1", + wrcontrol_wraddress_reg_b => "CLOCK1", + byteena_reg_b => "CLOCK1", + indata_reg_b => "CLOCK1", + rdcontrol_reg_b => "CLOCK1", + init_file => c_init_file) + port map( + clock0 => clka_i, + wren_a => wea_i, + address_a => aa_i, + data_a => da_i, + byteena_a => bwea_i, + q_a => qa, + + clock1 => clkb_i, + wren_b => web_i, + address_b => ab_i, + data_b => db_i, + byteena_b => bweb_i, + q_b => qb); + end generate; + + case_be_single : if (g_with_byte_enable = true and g_dual_clock = false) generate + memory : altsyncram + generic map( + byte_size => 8, + numwords_a => g_size, + numwords_b => g_size, + widthad_a => c_addr_width, + widthad_b => c_addr_width, + width_a => g_data_width, + width_b => g_data_width, + width_byteena_a => c_num_bytes, + width_byteena_b => c_num_bytes, + operation_mode => "BIDIR_DUAL_PORT", + read_during_write_mode_mixed_ports => diffport_order, + read_during_write_mode_port_a => sameport_order, + read_during_write_mode_port_b => sameport_order, + outdata_reg_a => "UNREGISTERED", + outdata_reg_b => "UNREGISTERED", + address_reg_b => "CLOCK0", + wrcontrol_wraddress_reg_b => "CLOCK0", + byteena_reg_b => "CLOCK0", + indata_reg_b => "CLOCK0", + rdcontrol_reg_b => "CLOCK0", + init_file => c_init_file) + port map( + clock0 => clka_i, + wren_a => wea_i, + address_a => aa_i, + data_a => da_i, + byteena_a => bwea_i, + q_a => qa, + + wren_b => web_i, + address_b => ab_i, + data_b => db_i, + byteena_b => bweb_i, + q_b => qb); + end generate; + + case_nobe_dual : if (g_with_byte_enable = false and g_dual_clock = true) generate + memory : altsyncram + generic map( + byte_size => 8, + numwords_a => g_size, + numwords_b => g_size, + widthad_a => c_addr_width, + widthad_b => c_addr_width, + width_a => g_data_width, + width_b => g_data_width, + operation_mode => "BIDIR_DUAL_PORT", + read_during_write_mode_mixed_ports => diffport_order, + read_during_write_mode_port_a => sameport_order, + read_during_write_mode_port_b => sameport_order, + outdata_reg_a => "UNREGISTERED", + outdata_reg_b => "UNREGISTERED", + address_reg_b => "CLOCK1", + wrcontrol_wraddress_reg_b => "CLOCK1", + byteena_reg_b => "CLOCK1", + indata_reg_b => "CLOCK1", + rdcontrol_reg_b => "CLOCK1", + init_file => c_init_file) + port map( + clock0 => clka_i, + wren_a => wea_i, + address_a => aa_i, + data_a => da_i, + q_a => qa, + + clock1 => clkb_i, + wren_b => web_i, + address_b => ab_i, + data_b => db_i, + q_b => qb); + end generate; + + case_nobe_single : if (g_with_byte_enable = false and g_dual_clock = false) generate + memory : altsyncram + generic map( + byte_size => 8, + numwords_a => g_size, + numwords_b => g_size, + widthad_a => c_addr_width, + widthad_b => c_addr_width, + width_a => g_data_width, + width_b => g_data_width, + operation_mode => "BIDIR_DUAL_PORT", + read_during_write_mode_mixed_ports => diffport_order, + read_during_write_mode_port_a => sameport_order, + read_during_write_mode_port_b => sameport_order, + outdata_reg_a => "UNREGISTERED", + outdata_reg_b => "UNREGISTERED", + address_reg_b => "CLOCK0", + wrcontrol_wraddress_reg_b => "CLOCK0", + byteena_reg_b => "CLOCK0", + indata_reg_b => "CLOCK0", + rdcontrol_reg_b => "CLOCK0", + init_file => c_init_file) + port map( + clock0 => clka_i, + wren_a => wea_i, + address_a => aa_i, + data_a => da_i, + q_a => qa, + + wren_b => web_i, + address_b => ab_i, + data_b => db_i, + q_b => qb); + end generate; + end syn; diff --git a/modules/genrams/altera/generic_simple_dpram.vhd b/modules/genrams/altera/generic_simple_dpram.vhd new file mode 100644 index 0000000000000000000000000000000000000000..f89efa136e4f68c9ec0efe9f69848c5e55d65621 --- /dev/null +++ b/modules/genrams/altera/generic_simple_dpram.vhd @@ -0,0 +1,249 @@ +------------------------------------------------------------------------------- +-- Title : Parametrizable dual-port synchronous RAM (Altera version) +-- Project : Generics RAMs and FIFOs collection +------------------------------------------------------------------------------- +-- File : generic_simple_dpram.vhd +-- Author : Wesley W. Terpstra +-- Company : GSI +-- Created : 2013-03-04 +-- Last update: 2013-03-04 +-- Platform : +-- Standard : VHDL'93 +------------------------------------------------------------------------------- +-- Description: Simple dual-port synchronous RAM for Altera FPGAs with: +-- - configurable address and data bus width +-- - byte-addressing mode (data bus width restricted to multiple of 8 bits) +------------------------------------------------------------------------------- +-- Copyright (c) 2013 GSI +------------------------------------------------------------------------------- +-- Revisions : +-- Date Version Author Description +-- 2013-03-04 1.0 wterpstra Adapted from generic_dpram.vhd +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.genram_pkg.all; + +library altera_mf; +use altera_mf.altera_mf_components.all; + +entity generic_simple_dpram is + generic( + g_data_width : natural; + g_size : natural; + g_with_byte_enable : boolean := false; + g_addr_conflict_resolution : string := "dont_care"; + g_init_file : string := "none"; + g_dual_clock : 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); + + -- Port B + clkb_i : in std_logic; + ab_i : in std_logic_vector(f_log2_size(g_size)-1 downto 0); + qb_o : out std_logic_vector(g_data_width-1 downto 0) + ); + +end generic_simple_dpram; + +architecture syn of generic_simple_dpram is + + function f_diffport_order(x : string) return string is + begin + if x = "read_first" then + return "OLD_DATA"; + elsif x = "write_first" then + return "DONT_CARE"; -- "NEW_DATA" is unsupported; we use a bypass MUX in this case + elsif x = "dont_care" then + return "DONT_CARE"; + else + assert (false) report "generic_simple_dpram: g_addr_conflict_resolution must be: read_first, write_first, dont_care" severity failure; + end if; + end f_diffport_order; + + function f_filename(x : string) return string is + begin + if x'length = 0 or x = "none" then + return "UNUSED"; + else + return x; + end if; + end f_filename; + + constant c_num_bytes : integer := (g_data_width+7)/8; + constant c_addr_width : integer := f_log2_size(g_size); + constant diffport_order : string := f_diffport_order(g_addr_conflict_resolution); + constant c_init_file : string := f_filename(g_init_file); + + signal qb : std_logic_vector(g_data_width-1 downto 0); + signal da : std_logic_vector(g_data_width-1 downto 0); + signal nbb : boolean; + +begin + + assert (g_addr_conflict_resolution /= "write_first" or (g_dual_clock = false and g_with_byte_enable = false)) + report "generic_simple_dpram: write_first is only possible when dual_clock and g_with_byte_enable are false" + severity failure; + + assert (g_addr_conflict_resolution /= "read_first" or g_dual_clock = false) + report "generic_simple_dpram: read_first is only possible when dual_clock is false" + severity failure; + + assert (g_addr_conflict_resolution /= "write_first") + report "generic_simple_dpram: write_first requires a bypass MUX" + severity note; + + case_qb_raw : if (g_addr_conflict_resolution /= "write_first") generate + qb_o <= qb; + end generate; + + case_qb_bypass : if (g_addr_conflict_resolution = "write_first") generate + qb_o <= qb when nbb else da; + + memoize : process(clka_i) is + begin + if rising_edge(clka_i) then + nbb <= aa_i /= ab_i or wea_i = '0'; + da <= da_i; + end if; + end process; + end generate; + + case_be_dual : if (g_with_byte_enable = true and g_dual_clock = true) generate + memory : altsyncram + generic map( + byte_size => 8, + numwords_a => g_size, + numwords_b => g_size, + widthad_a => c_addr_width, + widthad_b => c_addr_width, + width_a => g_data_width, + width_b => g_data_width, + width_byteena_a => c_num_bytes, + operation_mode => "DUAL_PORT", + read_during_write_mode_mixed_ports => diffport_order, + outdata_reg_a => "UNREGISTERED", + outdata_reg_b => "UNREGISTERED", + address_reg_b => "CLOCK1", + wrcontrol_wraddress_reg_b => "CLOCK1", + byteena_reg_b => "CLOCK1", + indata_reg_b => "CLOCK1", + rdcontrol_reg_b => "CLOCK1", + init_file => c_init_file) + port map( + clock0 => clka_i, + wren_a => wea_i, + address_a => aa_i, + data_a => da_i, + byteena_a => bwea_i, + + clock1 => clkb_i, + address_b => ab_i, + q_b => qb); + end generate; + + case_be_single : if (g_with_byte_enable = true and g_dual_clock = false) generate + memory : altsyncram + generic map( + byte_size => 8, + numwords_a => g_size, + numwords_b => g_size, + widthad_a => c_addr_width, + widthad_b => c_addr_width, + width_a => g_data_width, + width_b => g_data_width, + width_byteena_a => c_num_bytes, + operation_mode => "DUAL_PORT", + read_during_write_mode_mixed_ports => diffport_order, + outdata_reg_a => "UNREGISTERED", + outdata_reg_b => "UNREGISTERED", + address_reg_b => "CLOCK0", + wrcontrol_wraddress_reg_b => "CLOCK0", + byteena_reg_b => "CLOCK0", + indata_reg_b => "CLOCK0", + rdcontrol_reg_b => "CLOCK0", + init_file => c_init_file) + port map( + clock0 => clka_i, + wren_a => wea_i, + address_a => aa_i, + data_a => da_i, + byteena_a => bwea_i, + + address_b => ab_i, + q_b => qb); + end generate; + + case_nobe_dual : if (g_with_byte_enable = false and g_dual_clock = true) generate + memory : altsyncram + generic map( + byte_size => 8, + numwords_a => g_size, + numwords_b => g_size, + widthad_a => c_addr_width, + widthad_b => c_addr_width, + width_a => g_data_width, + width_b => g_data_width, + operation_mode => "DUAL_PORT", + read_during_write_mode_mixed_ports => diffport_order, + outdata_reg_a => "UNREGISTERED", + outdata_reg_b => "UNREGISTERED", + address_reg_b => "CLOCK1", + wrcontrol_wraddress_reg_b => "CLOCK1", + byteena_reg_b => "CLOCK1", + indata_reg_b => "CLOCK1", + rdcontrol_reg_b => "CLOCK1", + init_file => c_init_file) + port map( + clock0 => clka_i, + wren_a => wea_i, + address_a => aa_i, + data_a => da_i, + + clock1 => clkb_i, + address_b => ab_i, + q_b => qb); + end generate; + + case_nobe_single : if (g_with_byte_enable = false and g_dual_clock = false) generate + memory : altsyncram + generic map( + byte_size => 8, + numwords_a => g_size, + numwords_b => g_size, + widthad_a => c_addr_width, + widthad_b => c_addr_width, + width_a => g_data_width, + width_b => g_data_width, + operation_mode => "DUAL_PORT", + read_during_write_mode_mixed_ports => diffport_order, + outdata_reg_a => "UNREGISTERED", + outdata_reg_b => "UNREGISTERED", + address_reg_b => "CLOCK0", + wrcontrol_wraddress_reg_b => "CLOCK0", + byteena_reg_b => "CLOCK0", + indata_reg_b => "CLOCK0", + rdcontrol_reg_b => "CLOCK0", + init_file => c_init_file) + port map( + clock0 => clka_i, + wren_a => wea_i, + address_a => aa_i, + data_a => da_i, + + address_b => ab_i, + q_b => qb); + end generate; + +end syn; diff --git a/modules/genrams/altera/generic_spram.vhd b/modules/genrams/altera/generic_spram.vhd index 8bc1875dec41b44dda509f1c8970d9fac7e33371..1df90af25bd52ff17a87a290d376a15a90daa7a7 100644 --- a/modules/genrams/altera/generic_spram.vhd +++ b/modules/genrams/altera/generic_spram.vhd @@ -3,24 +3,23 @@ -- Project : Generics RAMs and FIFOs collection ------------------------------------------------------------------------------- -- File : generic_spram.vhd --- Author : Tomasz Wlostowski --- Company : CERN BE-Co-HT +-- Author : Wesley W. Terpstra +-- Company : GSI -- Created : 2011-01-25 --- Last update: 2011-01-25 +-- Last update: 2013-03-04 -- Platform : -- Standard : VHDL'93 ------------------------------------------------------------------------------- -- Description: Single-port synchronous RAM for Altera 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 ------------------------------------------------------------------------------- -- Copyright (c) 2011 CERN ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2011-01-25 1.0 twlostow Created +-- 2013-03-04 2.0 wterpstra Rewrote using altsyncram ------------------------------------------------------------------------------- @@ -31,122 +30,96 @@ use ieee.numeric_std.all; library work; use work.genram_pkg.all; -entity generic_spram is +library altera_mf; +use altera_mf.altera_mf_components.all; - generic ( - -- standard parameters +entity generic_spram is + generic( g_data_width : natural := 32; g_size : natural := 1024; g_with_byte_enable : boolean := false; - g_addr_conflict_resolution : string := "read_first"; - g_init_file : string := "" - ); - - port ( - rst_n_i : in std_logic := '1'; -- synchronous reset, active LO - clk_i : in std_logic; -- clock input - - -- byte write enable, actiwe when g_with_byte_enable == true - bwe_i : in std_logic_vector((g_data_width+7)/8-1 downto 0); - - -- global write enable (masked by bwe_i if g_with_byte_enable = true) - we_i : in std_logic; - - -- address input - a_i : in std_logic_vector(f_log2_size(g_size)-1 downto 0); - - -- data input - d_i : in std_logic_vector(g_data_width-1 downto 0); - - -- data output - q_o : out std_logic_vector(g_data_width-1 downto 0) - ); - + g_addr_conflict_resolution : string := "dont_care"; + g_init_file : string := ""); + port( + rst_n_i : in std_logic := '1'; + clk_i : in std_logic; + bwe_i : in std_logic_vector((g_data_width+7)/8-1 downto 0); + we_i : in std_logic; + a_i : in std_logic_vector(f_log2_size(g_size)-1 downto 0); + d_i : in std_logic_vector(g_data_width-1 downto 0); + q_o : out std_logic_vector(g_data_width-1 downto 0)); end generic_spram; - - architecture syn of generic_spram is - - constant c_num_bytes : integer := g_data_width/8; - - type t_ram_type is array(0 to g_size-1) of std_logic_vector(g_data_width-1 downto 0); - type t_ram_word_bs is array (0 to 7) of std_logic_vector(7 downto 0); - type t_ram_type_bs is array (0 to g_size - 1) of t_ram_word_bs; - - signal ram : t_ram_type := (others => (others => '0')); - signal ram_bs : t_ram_type_bs := (others => (others => (others => '0'))); - signal q_local : t_ram_word_bs; - - signal bwe_int : std_logic_vector(7 downto 0); + function f_sameport_order(x : string) return string is + begin + if x = "read_first" then + return "OLD_DATA"; + elsif x = "write_first" then + --return "NEW_DATA_NO_NBE_READ"; -- unwritten bytes='X' + return "NEW_DATA_WITH_NBE_READ"; -- unwritten bytes=OLD_DATA (ie: whole result = NEW_DATA) + elsif x = "dont_care" then + return "DONT_CARE"; + else + assert (false) report "generic_spram: g_addr_conflict_resolution must be: read_first, write_first, dont_care" severity failure; + end if; + end f_sameport_order; -begin - assert (g_init_file = "") report "generic_spram: Memory initialization files not supported yet. Sorry :(" severity failure; - assert (g_addr_conflict_resolution = "read_first") report "generic_spram: Altera template supports only read-first mode." severity failure; - assert (((g_data_width / 8) * 8) = g_data_width) or (g_with_byte_enable = false) report "generic_spram: in byte-enabled mode the data width must be a multiple of 8" severity failure; - assert(g_data_width <= 64 or g_with_byte_enable = false) report "generic_spram: byte-selectable memories can be have 64-bit data width due to synthesis tool limitation" severity failure; - - bwe_int <= std_logic_vector(to_unsigned(0, 8-bwe_i'length)) & bwe_i; - - - gen_with_byte_enable : if(g_with_byte_enable = true) generate - - unpack : for i in 0 to c_num_bytes - 1 generate - q_o(8*(i+1) - 1 downto 8*i) <= q_local(i); - end generate unpack; - - process(clk_i) - begin - if(rising_edge(clk_i)) then - if(we_i = '1') then - --- I know the code below is stupid, but it's the only way to make Quartus --- recongnize it as a memory block - if(bwe_int(0) = '1' and g_data_width >= 8) then - ram_bs(to_integer(unsigned(a_i)))(0) <= d_i(7 downto 0); - end if; - if(bwe_int(1) = '1' and g_data_width >= 16) then - ram_bs(to_integer(unsigned(a_i)))(1) <= d_i(15 downto 8); - end if; - if(bwe_int(2) = '1' and g_data_width >= 24) then - ram_bs(to_integer(unsigned(a_i)))(2) <= d_i(23 downto 16); - end if; - if(bwe_int(3) = '1' and g_data_width >= 32) then - ram_bs(to_integer(unsigned(a_i)))(3) <= d_i(31 downto 24); - end if; - if(bwe_int(4) = '1' and g_data_width >= 40) then - ram_bs(to_integer(unsigned(a_i)))(4) <= d_i(39 downto 32); - end if; - if(bwe_int(5) = '1' and g_data_width >= 48) then - ram_bs(to_integer(unsigned(a_i)))(5) <= d_i(47 downto 40); - end if; - if(bwe_int(6) = '1' and g_data_width >= 56) then - ram_bs(to_integer(unsigned(a_i)))(6) <= d_i(55 downto 48); - end if; - if(bwe_int(7) = '1' and g_data_width >= 64) then - ram_bs(to_integer(unsigned(a_i)))(7) <= d_i(64 downto 57); - end if; - - - end if; - q_local <= ram_bs(to_integer(unsigned(a_i))); - end if; - end process; - end generate gen_with_byte_enable; - - - gen_without_byte_enable_readfirst : if(g_with_byte_enable = false) generate - process(clk_i) - begin - if rising_edge(clk_i) then - if(we_i = '1') then - ram(to_integer(unsigned(a_i))) <= d_i; - end if; - q_o <= ram(to_integer(unsigned(a_i))); - end if; - end process; - end generate gen_without_byte_enable_readfirst; + function f_filename(x : string) return string is + begin + if x'length = 0 or x = "none" then + return "UNUSED"; + else + return x; + end if; + end f_filename; + + constant c_num_bytes : integer := (g_data_width+7)/8; + constant c_addr_width : integer := f_log2_size(g_size); + constant sameport_order : string := f_sameport_order(g_addr_conflict_resolution); + constant c_init_file : string := f_filename(g_init_file); +begin + case_be : if (g_with_byte_enable = true) generate + memory : altsyncram + generic map( + byte_size => 8, + numwords_a => g_size, + widthad_a => c_addr_width, + width_a => g_data_width, + width_byteena_a => c_num_bytes, + operation_mode => "SINGLE_PORT", + read_during_write_mode_port_a => sameport_order, + outdata_reg_a => "UNREGISTERED", + init_file => c_init_file) + port map( + clock0 => clk_i, + wren_a => we_i, + address_a => a_i, + data_a => d_i, + byteena_a => bwe_i, + q_a => q_o); + end generate; + + case_nobe : if (g_with_byte_enable = false) generate + memory : altsyncram + generic map( + byte_size => 8, + numwords_a => g_size, + widthad_a => c_addr_width, + width_a => g_data_width, + operation_mode => "SINGLE_PORT", + read_during_write_mode_port_a => sameport_order, + outdata_reg_a => "UNREGISTERED", + init_file => c_init_file) + port map( + clock0 => clk_i, + wren_a => we_i, + address_a => a_i, + data_a => d_i, + q_a => q_o); + end generate; + end syn;