برای تغییر متغییر ها در کد استفاده میشود

Creating modules is a great way to reuse code, but often you need the same module with smaller variations throughout your design. This is what generics and the generic map is for. It allows you to make certain parts of the module configurable at compile-time.

Constants are used when we want to avoid typing the same value over and over again. They can be used for defining bit-widths of signal vectors at compile-time, and they can even be mapped to generic constants as well. Constants can be used in place of signals and variables anywhere in the code, but their values cannot be changed after compile-time.

This blog post is part of the Basic VHDL Tutorials series.

In the previous tutorial, we created a 4-input multiplexer module with a bus width of 8 bits. But what if we also need a similar MUX with a different bus width? Is the only solution to copy-paste the code into a new module, and change the numbers?

Fortunately, no.

It is possible to create constants in VHDL using this syntax:
constant <constant_name> : <type> := <value>;

Constants can be declared along with signals in the declarative part of a VHDL file, or it can be declared along with variables in a process.

Constants can be passed into a module through the entity by using the generic keyword. The syntax for creating an entity for a module which accepts generic constants is:
entity <entity_name> is
generic(
<entity_constant_name> : <type>;
...
);
port(
<entity_signal_name> : in|out|inout <type>;
...
);
end entity;

The syntax for instantiating a generic module in another VHDL file is:
<label> : entity <library_name>.<entity_name>(<architecture_name>)
generic map(
<entity_constant_name> => <value_or_constant>,
...
)
port map(
<entity_signal_name> => <local_signal_name>,
...
);

The final code for the generic MUX testbench:

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

-- An Instance of T16_GenericMux with architecture rtl
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);

-- Testbench process
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;
The final code for the 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);

-- Outputs
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 => -- 'U', 'X', '-', etc.
Output <= (others => 'X');
end case;

end process;

end architecture;

We created a MUX module with a configurable bus width. Now, the bus width is specified in only one place, in the testbench file. We can easily change it to create a MUX with a different bus width.

If we compare the waveform to the one from the previous tutorial, we can see that the behavior is identical. This is because we haven’t changed the behavior of the code at all.

Constants can be used to avoid hard-coding values in multiple places
Generics can be used to make modules more adaptable

We created a MUX module with a configurable bus width. Now, the bus width is specified in only one place, in the testbench file. We can easily change it to create a MUX with a different bus width.

If we compare the waveform to the one from the previous tutorial, we can see that the behavior is identical. This is because we haven’t changed the behavior of the code at all.

Constants can be used to avoid hard-coding values in multiple places
Generics can be used to make modules more adaptable