Commit 7348be7e authored by Wesley W. Terpstra's avatar Wesley W. Terpstra

genrams: rewrote altera variants using altsyncram

By using altsyncram directly, we get the follow benefits:
  * clear control of read-write resolution behaviour
  * can specify a mif file for initialization
  * eliminates warnings about dual-port clock inference timings
parent 94230c7c
files = [
"generic_async_fifo.vhd",
"generic_simple_dpram.vhd",
"generic_dpram.vhd",
"generic_spram.vhd",
"generic_sync_fifo.vhd"]
This diff is collapsed.
-------------------------------------------------------------------------------
-- 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;
......@@ -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;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment