0
0
VhdlHow-ToBeginner · 4 min read

VHDL Code for Dual Port RAM: Syntax and Example

A dual port RAM in VHDL is a memory block with two independent ports for simultaneous read/write operations. It typically uses two sets of address, data, and control signals. You can implement it using a process block with separate read/write logic for each port.
📐

Syntax

The basic syntax for a dual port RAM in VHDL includes defining a type for memory, signals for two ports (A and B), and a process that handles read and write operations independently for each port.

  • entity: Declares inputs and outputs for two ports.
  • architecture: Contains the memory array and the process.
  • process: Handles clocked read/write for both ports.
vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity dual_port_ram is
    generic (
        DATA_WIDTH : integer := 8;
        ADDR_WIDTH : integer := 4
    );
    port (
        clk   : in  std_logic;
        -- Port A
        addr_a : in  std_logic_vector(ADDR_WIDTH-1 downto 0);
        data_in_a  : in  std_logic_vector(DATA_WIDTH-1 downto 0);
        we_a   : in  std_logic;
        data_out_a : out std_logic_vector(DATA_WIDTH-1 downto 0);
        -- Port B
        addr_b : in  std_logic_vector(ADDR_WIDTH-1 downto 0);
        data_in_b  : in  std_logic_vector(DATA_WIDTH-1 downto 0);
        we_b   : in  std_logic;
        data_out_b : out std_logic_vector(DATA_WIDTH-1 downto 0)
    );
end dual_port_ram;

architecture Behavioral of dual_port_ram is
    type ram_type is array (0 to 2**ADDR_WIDTH-1) of std_logic_vector(DATA_WIDTH-1 downto 0);
    signal ram : ram_type := (others => (others => '0'));
begin
    process(clk)
    begin
        if rising_edge(clk) then
            -- Port A write
            if we_a = '1' then
                ram(to_integer(unsigned(addr_a))) <= data_in_a;
            end if;
            -- Port A read
            data_out_a <= ram(to_integer(unsigned(addr_a)));

            -- Port B write
            if we_b = '1' then
                ram(to_integer(unsigned(addr_b))) <= data_in_b;
            end if;
            -- Port B read
            data_out_b <= ram(to_integer(unsigned(addr_b)));
        end if;
    end process;
end Behavioral;
💻

Example

This example shows a dual port RAM with 8-bit data and 4-bit address width. It supports independent read and write on both ports A and B on the rising clock edge.

vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity dual_port_ram is
    generic (
        DATA_WIDTH : integer := 8;
        ADDR_WIDTH : integer := 4
    );
    port (
        clk   : in  std_logic;
        addr_a : in  std_logic_vector(ADDR_WIDTH-1 downto 0);
        data_in_a  : in  std_logic_vector(DATA_WIDTH-1 downto 0);
        we_a   : in  std_logic;
        data_out_a : out std_logic_vector(DATA_WIDTH-1 downto 0);
        addr_b : in  std_logic_vector(ADDR_WIDTH-1 downto 0);
        data_in_b  : in  std_logic_vector(DATA_WIDTH-1 downto 0);
        we_b   : in  std_logic;
        data_out_b : out std_logic_vector(DATA_WIDTH-1 downto 0)
    );
end dual_port_ram;

architecture Behavioral of dual_port_ram is
    type ram_type is array (0 to 2**ADDR_WIDTH-1) of std_logic_vector(DATA_WIDTH-1 downto 0);
    signal ram : ram_type := (others => (others => '0'));
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if we_a = '1' then
                ram(to_integer(unsigned(addr_a))) <= data_in_a;
            end if;
            data_out_a <= ram(to_integer(unsigned(addr_a)));

            if we_b = '1' then
                ram(to_integer(unsigned(addr_b))) <= data_in_b;
            end if;
            data_out_b <= ram(to_integer(unsigned(addr_b)));
        end if;
    end process;
end Behavioral;
Output
No direct console output; the RAM stores and outputs data on ports A and B as per clock and control signals.
⚠️

Common Pitfalls

  • Simultaneous write to the same address: Writing to the same address from both ports at the same time can cause undefined behavior.
  • Read-before-write timing: Reading and writing the same address in the same clock cycle may return old or new data depending on synthesis.
  • Incorrect address conversion: Forgetting to convert std_logic_vector to integer using to_integer(unsigned()) causes errors.
  • Missing clock edge condition: Always use if rising_edge(clk) to synchronize memory operations.
vhdl
wrong: data_out_a <= ram(addr_a); -- addr_a is std_logic_vector, needs conversion

right: data_out_a <= ram(to_integer(unsigned(addr_a)));
📊

Quick Reference

  • Use std_logic_vector for addresses and data ports.
  • Convert addresses to integer with to_integer(unsigned(addr)) before indexing.
  • Use separate write enable signals for each port.
  • Synchronize all operations on the rising clock edge.
  • Be cautious with simultaneous writes to the same address.

Key Takeaways

Dual port RAM allows simultaneous read/write on two independent ports using separate address and control signals.
Always synchronize RAM operations with a clock edge using a process block.
Convert address signals from std_logic_vector to integer before accessing the memory array.
Avoid writing to the same address from both ports at the same time to prevent conflicts.
Use separate write enable signals for each port to control memory writes independently.