How to Use Block RAM in FPGA with VHDL: Syntax and Example
To use
block RAM in FPGA with VHDL, you define a RAM entity with memory arrays and synchronous read/write processes. You instantiate this RAM in your design and connect address, data, and control signals. FPGA tools map this code to physical block RAM resources automatically.Syntax
Block RAM in VHDL is typically described using a RAM entity with signals for address, data_in, data_out, write_enable, and clock. The memory is modeled as an array of std_logic_vector. A synchronous process handles reading and writing on clock edges.
Key parts:
- address: selects memory location
- data_in: data to write
- data_out: data read from RAM
- write_enable: controls writing
- clock: synchronizes operations
vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity block_ram is
Port (
clk : in std_logic;
we : in std_logic;
addr : in std_logic_vector(7 downto 0);
data_in : in std_logic_vector(15 downto 0);
data_out : out std_logic_vector(15 downto 0)
);
end block_ram;
architecture Behavioral of block_ram is
type ram_type is array (0 to 255) of std_logic_vector(15 downto 0);
signal ram : ram_type := (others => (others => '0'));
begin
process(clk)
begin
if rising_edge(clk) then
if we = '1' then
ram(to_integer(unsigned(addr))) <= data_in;
end if;
data_out <= ram(to_integer(unsigned(addr)));
end if;
end process;
end Behavioral;Example
This example shows a simple block RAM with 256 locations of 16-bit width. It writes data when we is high and reads data every clock cycle. This code can be synthesized on FPGA and will use block RAM resources.
vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity block_ram is
Port (
clk : in std_logic;
we : in std_logic;
addr : in std_logic_vector(7 downto 0);
data_in : in std_logic_vector(15 downto 0);
data_out : out std_logic_vector(15 downto 0)
);
end block_ram;
architecture Behavioral of block_ram is
type ram_type is array (0 to 255) of std_logic_vector(15 downto 0);
signal ram : ram_type := (others => (others => '0'));
begin
process(clk)
begin
if rising_edge(clk) then
if we = '1' then
ram(to_integer(unsigned(addr))) <= data_in;
end if;
data_out <= ram(to_integer(unsigned(addr)));
end if;
end process;
end Behavioral;Output
No console output; synthesized hardware reads/writes memory as expected.
Common Pitfalls
Common mistakes when using block RAM in VHDL include:
- Using asynchronous read/write instead of synchronous (clocked) processes, which FPGA block RAMs require.
- Not converting
std_logic_vectoraddresses to integers properly withto_integer(unsigned(addr)). - Writing and reading the same address in the same clock cycle without understanding read-first or write-first behavior of the RAM.
- Forgetting to initialize RAM if needed, which can cause unknown startup values.
vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
-- Wrong: asynchronous read
entity bad_ram is
Port (
clk : in std_logic;
we : in std_logic;
addr : in std_logic_vector(7 downto 0);
data_in : in std_logic_vector(15 downto 0);
data_out : out std_logic_vector(15 downto 0)
);
end bad_ram;
architecture Bad of bad_ram is
type ram_type is array (0 to 255) of std_logic_vector(15 downto 0);
signal ram : ram_type := (others => (others => '0'));
begin
process(clk)
begin
if rising_edge(clk) then
if we = '1' then
ram(to_integer(unsigned(addr))) <= data_in;
end if;
end if;
end process;
data_out <= ram(to_integer(unsigned(addr))); -- asynchronous read
end Bad;
-- Correct: synchronous read
architecture Good of bad_ram is
type ram_type is array (0 to 255) of std_logic_vector(15 downto 0);
signal ram : ram_type := (others => (others => '0'));
begin
process(clk)
begin
if rising_edge(clk) then
if we = '1' then
ram(to_integer(unsigned(addr))) <= data_in;
end if;
data_out <= ram(to_integer(unsigned(addr))); -- synchronous read
end if;
end process;
end Good;Quick Reference
| Signal | Description |
|---|---|
| clk | Clock signal for synchronous operations |
| we | Write enable; '1' to write data_in to RAM |
| addr | Address input to select memory location |
| data_in | Data input to write into RAM |
| data_out | Data output read from RAM |
Key Takeaways
Use synchronous processes with clock edges to model block RAM in VHDL.
Convert address signals from std_logic_vector to integer using to_integer(unsigned(addr)).
Write and read operations happen on the same clock edge; understand FPGA RAM behavior.
Initialize RAM if your design requires known startup values.
FPGA tools automatically map properly coded RAM to physical block RAM resources.