Industrial manufacturing
Industrial Internet of Things | Industrial materials | Equipment Maintenance and Repair | Industrial programming |
home  MfgRobots >> Industrial manufacturing >  >> Industrial programming >> VHDL

Leveraging Constants and Generic Maps in VHDL for Flexible Module Design

Creating reusable modules is a cornerstone of efficient VHDL design, yet minor variations often demand duplicate code. Generics and generic maps solve this by allowing you to configure a module’s parameters at compile‑time, keeping your code DRY and maintainable.

Constants help avoid hard‑coding the same value repeatedly. They’re ideal for defining signal vector widths or other compile‑time parameters, and can even be mapped to generic constants. Unlike signals or variables, a constant’s value is immutable after elaboration, ensuring consistency across the design.

This article is part of the Basic VHDL Tutorials series.

In our previous tutorial we built a 4‑input multiplexer with an 8‑bit bus width. If you now need a similar MUX with a different width, copying and pasting the entire module isn’t the only option.

Instead, declare a constant that holds the desired bus width, then pass that constant to the module via a generic. The only place you need to change the width is the constant declaration in your testbench.

Below is the syntax for declaring a constant in VHDL:

constant <constant_name> : <type> := <value>;

Constants can appear alongside signals in the declarative part of a file, or with variables inside a process.

To expose a constant to a module, use the generic keyword in the entity declaration:

entity <entity_name> is
    generic(
        <entity_constant_name> : <type> [:= default_value];
        ...
    );
    port(
        <entity_signal_name> : in|out|inout <type>;
        ...
    );
end entity;

Instantiate the generic module elsewhere using a generic map and port map:

<label> : entity <library_name>.<entity_name>(<architecture_name>)
    generic map(
        <entity_constant_name> => <value_or_constant>, ...
    )
    port map(
        <entity_signal_name> => <local_signal_name>, ...
    );

Exercise

In this video tutorial we’ll walk through creating and instantiating a generic 4‑input MUX module in VHDL.

Testbench – Generic MUX

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

entity T16_GenericMapTb is
end entity;

architecture sim of T16_GenericMapTb is
    constant DataWidth : integer := 8;

    signal Sig1 : signed(DataWidth-1 downto 0) := x"AA";
    signal Sig2 : signed(DataWidth-1 downto 0) := x"BB";
    signal Sig3 : signed(DataWidth-1 downto 0) := x"CC";
    signal Sig4 : signed(DataWidth-1 downto 0) := x"DD";

    signal Sel : signed(1 downto 0) := (others => '0');
    signal Output : signed(DataWidth-1 downto 0);

begin
    i_Mux1 : entity work.T16_GenericMux(rtl)
        generic map(DataWidth => DataWidth)
        port map(
            Sel    => Sel,
            Sig1   => Sig1,
            Sig2   => Sig2,
            Sig3   => Sig3,
            Sig4   => Sig4,
            Output => Output
        );

    process is
    begin
        wait for 10 ns;
        Sel <= Sel + 1;
        wait for 10 ns;
        Sel <= Sel + 1;
        wait for 10 ns;
        Sel <= Sel + 1;
        wait for 10 ns;
        Sel <= Sel + 1;
        wait for 10 ns;
        Sel <= "UU";
        wait;
    end process;
end architecture;

Generic MUX Module

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

entity T16_GenericMux is
    generic(DataWidth : integer);
    port(
        -- Inputs
        Sig1 : in signed(DataWidth-1 downto 0);
        Sig2 : in signed(DataWidth-1 downto 0);
        Sig3 : in signed(DataWidth-1 downto 0);
        Sig4 : in signed(DataWidth-1 downto 0);

        Sel  : in signed(1 downto 0);

        -- Output
        Output : out signed(DataWidth-1 downto 0)
    );
end entity;

architecture rtl of T16_GenericMux is
begin
    process(Sel, Sig1, Sig2, Sig3, Sig4) is
    begin
        case Sel is
            when "00" => Output <= Sig1;
            when "01" => Output <= Sig2;
            when "10" => Output <= Sig3;
            when "11" => Output <= Sig4;
            when others => Output <= (others => 'X');
        end case;
    end process;
end architecture;

ModelSim waveform after running the simulation (zoomed to the timeline):

Leveraging Constants and Generic Maps in VHDL for Flexible Module Design

Analysis

By defining DataWidth once in the testbench, we can adapt the same MUX for any bus width without touching the module code. The waveform confirms identical functionality to the hard‑coded version.

Leveraging Constants and Generic Maps in VHDL for Flexible Module Design

Takeaway

Proceed to the next tutorial »

VHDL

  1. Using Impure Functions in VHDL: Enhancing FSM Readability and Maintainability
  2. Mastering VHDL Functions: A Practical Guide to Efficient Design
  3. Using Procedures in VHDL: Simplify Your Design with Reusable Code
  4. Mastering VHDL Port Map Instantiation: A Practical Guide
  5. Mastering the Case-When Statement in VHDL: Efficient Multiplexer Design
  6. Mastering Signed and Unsigned Types in VHDL: A Practical Guide
  7. Mastering VHDL Wait Statements: Wait On, Wait Until, and Combined Usage
  8. Mastering While Loops in VHDL: Dynamic Iteration Control
  9. Mastering For‑Loops in VHDL: A Practical Guide
  10. Mastering Loop and Exit Constructs in VHDL: A Practical Guide