Aprovechando constantes y generic maps en VHDL para diseño de módulos flexibles
Crear módulos reutilizables es una piedra angular del diseño VHDL eficiente, sin embargo, variaciones menores a menudo demandan código duplicado. Los genéricos y generic maps resuelven esto permitiéndole configurar los parámetros de un módulo en tiempo de compilación, manteniendo su código DRY y mantenible.
Las constantes ayudan a evitar codificar duro el mismo valor repetidamente. Son ideales para definir anchos de bus de señales u otros parámetros en tiempo de compilación, e incluso pueden mapearse a constantes genéricas. A diferencia de señales o variables, el valor de una constante es inmutable después de la elaboración, asegurando consistencia a lo largo del diseño.
Este artículo es parte de la serie Tutoriales Básicos de VHDL.
En nuestro tutorial anterior construimos un multiplexor de 4 entradas con ancho de bus de 8 bits. Si ahora necesita un MUX similar con un ancho diferente, copiar y pegar el módulo entero no es la única opción.
En su lugar, declare una constante que contenga el ancho de bus deseado, luego pase esa constante al módulo a través de un genérico. El único lugar donde necesita cambiar el ancho es la declaración de constante en su testbench.
A continuación se muestra la sintaxis para declarar una constante en VHDL:
constant <constant_name> : <type> := <value>;
Las constantes pueden aparecer junto a señales en la parte declarativa de un archivo, o con variables dentro de un proceso.
Para exponer una constante a un módulo, use la palabra clave generic en la declaración de entidad:
entity <entity_name> is
generic(
<entity_constant_name> : <type> [:= default_value];
...
);
port(
<entity_signal_name> : in|out|inout <type>;
...
);
end entity;
Instancie el módulo genérico en otro lugar usando un generic map y 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>,
...
);
Ejercicio
En este tutorial en video recorreremos la creación e instanciación de un módulo MUX 4-a-1 genérico en VHDL.
Testbench – MUX Genérico
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;
Módulo MUX Genérico
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T16_GenericMux is
generic(DataWidth : integer);
port(
-- Entradas
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);
-- Salida
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;
Forma de onda de ModelSim después de ejecutar la simulación (zoom en la línea de tiempo):

Análisis
Al definir DataWidth una vez en el testbench, podemos adaptar el mismo MUX para cualquier ancho de bus sin tocar el código del módulo. La forma de onda confirma funcionalidad idéntica a la versión con ancho fijo.

Conclusión
- Las constantes eliminan valores codificados duro repetitivos, aumentando legibilidad y reduciendo errores.
- Los genéricos hacen módulos altamente configurables, mejorando la reutilización a lo largo de un diseño.
Proceda al siguiente tutorial »
VHDL
- Microcontroladores PIC18: Características, Rendimiento y Cómo Usarlos
- Aprovechando procedimientos en-proceso para diseños FSM más limpios en VHDL
- Uso de funciones impuras en VHDL: Mejorando legibilidad y mantenibilidad de FSM
- Dominando funciones VHDL: Guía práctica para diseño eficiente
- Uso de procedimientos en VHDL: Simplifique su diseño con código reutilizable
- Aprovechando constantes y generic maps en VHDL para diseño de módulos flexibles
- Dominando la instanciación con port map en VHDL: Guía práctica
- Dominando la sentencia Case-When en VHDL: Diseño eficiente de multiplexores
- Dominando tipos Signed y Unsigned en VHDL: Guía práctica
- Dominando lógica condicional en VHDL: If-Then-Elsif-Else explicado
- Configuración gratis de simulador y editor VHDL: Guía para estudiantes