Constants en generic maps in VHDL benutten voor flexibele modulontwerpen
Herbruikbare modules maken is een hoeksteen van efficiënt VHDL-ontwerp, maar kleine variaties vereisen vaak gedupliceerde code. Generics en generic maps lossen dit op door je een module's parameters te laten configureren tijdens compilatie, wat je code DRY en onderhoudbaar houdt.
Constanten helpen herhaarde hardcoded waarden te vermijden. Ze zijn ideaal voor het definiëren van signaalvectorbreedtes of andere compile-time parameters, en kunnen zelfs aan generieke constanten gemapt worden. In tegenstelling tot signalen of variabelen is de waarde van een constant na elaboratie onveranderlijk, wat consistentie door het ontwerp garandeert.
Dit artikel is onderdeel van de Basic VHDL Tutorials-reeks.
In onze vorige tutorial bouwden we een 4-input multiplexer met een 8-bits busbreedte. Als je nu een vergelijkbare MUX met een andere breedte nodig hebt, is kopiëren en plakken van de hele module niet de enige optie.
In plaats daarvan declareren we een constant die de gewenste busbreedte bevat, en geven we die constant door aan de module via een generic. De enige plek waar je de breedte hoeft te wijzigen is de constant-declaratie in je testbench.
Hieronder staat de syntax voor het declareren van een constant in VHDL:
constant <constant_name> : <type> := <value>;
Constanten mogen naast signalen in het declaratieve deel van een bestand verschijnen, of met variabelen binnen een proces.
Om een constant aan een module bloot te leggen, gebruik je het generic-sleutelwoord in de entity-declaratie:
entity <entity_name> is generic( <entity_constant_name> : <type> [:= default_value]; ... ); port( <entity_signal_name> : in|out|inout <type>; ... ); end entity;
Instantieer de generieke module ergens anders met een generic map en 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>, ... );
Oefening
In deze videotutorial lopen we door het maken en instantieren van een generieke 4-input MUX-module in VHDL.
Testbench – Generieke 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;
Generieke 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-golfform na het draaien van de simulatie (ingezoomd op de tijdlijn):

Analyse
Door DataWidth één keer in de testbench te definiëren, kunnen we dezelfde MUX voor elke busbreedte aanpassen zonder de modulecode aan te raken. De golfform bevestigt identieke functionaliteit als de hardcoded versie.

Kernpunten
- Constanten elimineren herhaalde hardcoded waarden, wat leesbaarheid verbetert en fouten vermindert.
- Generics maken hoogst configureerbare modules mogelijk, wat hergebruik over een ontwerp vergroot.
Ga door naar de volgende tutorial »
VHDL
- PIC18-microcontrollers: kenmerken, prestaties en hoe u ze gebruikt
- In-process procedures benutten voor schonere VHDL FSM-ontwerpen
- Impure functies in VHDL gebruiken: FSM-leesbaarheid en onderhoudbaarheid verbeteren
- VHDL-functies onder de knie krijgen: een praktische gids voor efficiënt ontwerp
- Procedures in VHDL gebruiken: je ontwerp vereenvoudigen met herbruikbare code
- Constants en generic maps in VHDL benutten voor flexibele modulontwerpen
- VHDL port map instantiation onder de knie krijgen: een praktische gids
- De Case-When-statement in VHDL onder de knie krijgen: efficiënte multiplexer-ontwerpen
- Signed en unsigned types in VHDL onder de knie krijgen: een praktische gids
- Conditionele logica in VHDL: If-Then-Elsif-Else uitgelegd
- Gratis VHDL-simulator & editor setup: Een studentengids