0
0
VhdlHow-ToBeginner · 4 min read

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_vector addresses to integers properly with to_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

SignalDescription
clkClock signal for synchronous operations
weWrite enable; '1' to write data_in to RAM
addrAddress input to select memory location
data_inData input to write into RAM
data_outData 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.