Memories: RAM, ROM, FIFOs
Synthesis tools infer block RAM / distributed RAM when you follow standard templates.
Synthesis tools infer block RAM / distributed RAM when you follow standard templates.
22.1 Single-port RAM (synchronous read → block RAM)
Read-during-write modes: read-first, write-first, no-change. Asynchronous reads (dout <= ram(addr) outside the clocked process) infer distributed/LUT RAM.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity spram is
generic (ADDR_W : positive := 10; DATA_W : positive := 8);
port (
clk : in std_logic;
we : in std_logic;
addr : in std_logic_vector(ADDR_W-1 downto 0);
din : in std_logic_vector(DATA_W-1 downto 0);
dout : out std_logic_vector(DATA_W-1 downto 0));
end entity;
architecture rtl of spram is
type ram_t is array (0 to 2**ADDR_W - 1) of std_logic_vector(DATA_W-1 downto 0);
signal ram : ram_t := (others => (others => '0'));
begin
process (clk)
begin
if rising_edge(clk) then
if we = '1' then
ram(to_integer(unsigned(addr))) <= din;
end if;
dout <= ram(to_integer(unsigned(addr))); -- read-first behavior
end if;
end process;
end architecture;22.2 Simple dual-port & true dual-port RAM
For true dual-port RAM with two clocks and two writers, use a shared variable of the RAM type (tool templates) or vendor IP (XPM macros: xpm_memory_tdpram).
process (clk) -- write port A
begin
if rising_edge(clk) then
if we_a = '1' then ram(to_integer(unsigned(addr_a))) <= din_a; end if;
end if;
end process;
process (clk_b) -- read port B (may be a different clock)
begin
if rising_edge(clk_b) then
dout_b <= ram(to_integer(unsigned(addr_b)));
end if;
end process;22.3 ROM
Generate tables with functions (math_real.sin in a constant function) or load from files (§19).
type rom_t is array (0 to 15) of std_logic_vector(7 downto 0);
constant SINE_ROM : rom_t := (x"80", x"B0", x"DA", x"F5", x"FF", x"F5", x"DA", x"B0",
x"80", x"4F", x"25", x"0A", x"00", x"0A", x"25", x"4F");
process (clk)
begin
if rising_edge(clk) then
data <= SINE_ROM(to_integer(unsigned(addr)));
end if;
end process;22.4 Synchronous FIFO
Extensions: almost-full/almost-empty flags, first-word-fall-through (FWFT), data count, asynchronous (dual-clock) FIFOs with Gray-coded pointers (§27).
entity sync_fifo is
generic (DATA_W : positive := 8; DEPTH_LOG2 : positive := 4);
port (
clk, rst : in std_logic;
wr_en : in std_logic;
din : in std_logic_vector(DATA_W-1 downto 0);
full : out std_logic;
rd_en : in std_logic;
dout : out std_logic_vector(DATA_W-1 downto 0);
empty : out std_logic);
end entity;
architecture rtl of sync_fifo is
constant DEPTH : positive := 2**DEPTH_LOG2;
type mem_t is array (0 to DEPTH-1) of std_logic_vector(DATA_W-1 downto 0);
signal mem : mem_t;
signal wr_ptr, rd_ptr : unsigned(DEPTH_LOG2 downto 0) := (others => '0'); -- extra MSB for full/empty
begin
full <= '1' when (wr_ptr(DEPTH_LOG2) /= rd_ptr(DEPTH_LOG2)) and
(wr_ptr(DEPTH_LOG2-1 downto 0) = rd_ptr(DEPTH_LOG2-1 downto 0)) else '0';
empty <= '1' when wr_ptr = rd_ptr else '0';
process (clk)
begin
if rising_edge(clk) then
if rst = '1' then
wr_ptr <= (others => '0'); rd_ptr <= (others => '0');
else
if wr_en = '1' and full = '0' then
mem(to_integer(wr_ptr(DEPTH_LOG2-1 downto 0))) <= din;
wr_ptr <= wr_ptr + 1;
end if;
…