0
0
VhdlHow-ToBeginner · 4 min read

VHDL Code for Cache Memory: Syntax and Example

A simple cache memory in VHDL can be implemented using an array to store data blocks and logic to handle read/write operations. The entity defines inputs like address and data, while the architecture implements the cache behavior with signals and processes.
📐

Syntax

The basic syntax for a cache memory in VHDL includes an entity that defines the interface with inputs and outputs, and an architecture that contains the internal signals and logic.

  • entity: Declares ports such as address, data input/output, read/write control, and clock.
  • architecture: Implements the cache storage (usually an array), and processes for reading and writing data.
  • signals: Used to hold cache lines and status bits like valid flags.
vhdl
entity CacheMemory is
    Port (
        clk       : in  std_logic;
        rst       : in  std_logic;
        addr      : in  std_logic_vector(3 downto 0); -- 4-bit address
        data_in   : in  std_logic_vector(7 downto 0); -- 8-bit data input
        data_out  : out std_logic_vector(7 downto 0); -- 8-bit data output
        read_en   : in  std_logic;
        write_en  : in  std_logic
    );
end CacheMemory;

architecture Behavioral of CacheMemory is
    type cache_array is array (0 to 15) of std_logic_vector(7 downto 0);
    signal cache : cache_array := (others => (others => '0'));
    signal valid : std_logic_vector(15 downto 0) := (others => '0');
begin
    process(clk, rst)
    begin
        if rst = '1' then
            cache <= (others => (others => '0'));
            valid <= (others => '0');
            data_out <= (others => '0');
        elsif rising_edge(clk) then
            if write_en = '1' then
                cache(to_integer(unsigned(addr))) <= data_in;
                valid(to_integer(unsigned(addr))) <= '1';
            elsif read_en = '1' then
                if valid(to_integer(unsigned(addr))) = '1' then
                    data_out <= cache(to_integer(unsigned(addr)));
                else
                    data_out <= (others => '0'); -- cache miss returns zero
                end if;
            end if;
        end if;
    end process;
end Behavioral;
💻

Example

This example shows a simple 16-entry cache memory with 8-bit data and 4-bit address. It supports synchronous read and write operations controlled by read_en and write_en signals. The cache uses a valid bit to indicate if data at an address is valid.

vhdl
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity CacheMemory is
    Port (
        clk       : in  std_logic;
        rst       : in  std_logic;
        addr      : in  std_logic_vector(3 downto 0);
        data_in   : in  std_logic_vector(7 downto 0);
        data_out  : out std_logic_vector(7 downto 0);
        read_en   : in  std_logic;
        write_en  : in  std_logic
    );
end CacheMemory;

architecture Behavioral of CacheMemory is
    type cache_array is array (0 to 15) of std_logic_vector(7 downto 0);
    signal cache : cache_array := (others => (others => '0'));
    signal valid : std_logic_vector(15 downto 0) := (others => '0');
begin
    process(clk, rst)
    begin
        if rst = '1' then
            cache <= (others => (others => '0'));
            valid <= (others => '0');
            data_out <= (others => '0');
        elsif rising_edge(clk) then
            if write_en = '1' then
                cache(to_integer(unsigned(addr))) <= data_in;
                valid(to_integer(unsigned(addr))) <= '1';
            elsif read_en = '1' then
                if valid(to_integer(unsigned(addr))) = '1' then
                    data_out <= cache(to_integer(unsigned(addr)));
                else
                    data_out <= (others => '0');
                end if;
            end if;
        end if;
    end process;
end Behavioral;
⚠️

Common Pitfalls

Common mistakes when coding cache memory in VHDL include:

  • Not initializing the valid bits, causing incorrect cache hits.
  • Using asynchronous resets improperly, which can cause glitches.
  • Mixing combinational and sequential logic inside the same process, leading to simulation mismatches.
  • Forgetting to convert std_logic_vector addresses to integers before indexing arrays.

Always use synchronous reset and proper type conversions.

vhdl
Wrong example (missing valid initialization and wrong indexing):

process(clk)
begin
    if rising_edge(clk) then
        if write_en = '1' then
            cache(to_integer(unsigned(addr))) <= data_in; -- addr is std_logic_vector, needs conversion
            valid(to_integer(unsigned(addr))) <= '1'; -- same issue
        end if;
    end if;
end process;

Corrected example:

process(clk, rst)
begin
    if rst = '1' then
        valid <= (others => '0');
    elsif rising_edge(clk) then
        if write_en = '1' then
            cache(to_integer(unsigned(addr))) <= data_in;
            valid(to_integer(unsigned(addr))) <= '1';
        end if;
    end if;
end process;
📊

Quick Reference

Remember these tips when writing VHDL cache memory code:

  • Use std_logic_vector for addresses and data, convert addresses to integer for array indexing.
  • Initialize cache and valid bits on reset.
  • Separate read and write logic clearly inside clocked processes.
  • Use synchronous reset for predictable behavior.

Key Takeaways

Define cache memory with an entity and implement storage using arrays in architecture.
Always convert address signals from std_logic_vector to integer for array indexing.
Initialize valid bits and cache contents on reset to avoid incorrect data reads.
Use synchronous reset and separate read/write logic inside clocked processes.
Check for cache hits using valid bits before outputting data to avoid stale data.