VHDL-Funktionen meistern: Praktischer Leitfaden für effizientes Design
Funktionen sind Subprogramme in VHDL für häufig verwendete Algorithmen. Sie nehmen null oder mehr Eingabewerte entgegen und geben immer einen Wert zurück. Im Gegensatz zu Prozeduren dürfen sie keine Wait-Statements enthalten – Funktionen verbrauchen also null Simulationszeit.
Wer Funktionen aus anderen Sprachen kennt, versteht VHDL-Funktionen schnell. In VHDL kann der Rückgabewert nicht weggelassen oder void sein; er muss immer zugewiesen werden.
Dieser Beitrag gehört zur Basic VHDL Tutorials Serie.
VHDL unterscheidet pure und impure Funktionen. Pure Funktionen dürfen keine externen Signale lesen/schreiben – bei gleichen Argumenten liefern sie immer denselben Wert (keine Seiteneffekte).
Syntax
[pure|impure] function <name> (
<param1> : <type> := <default>;
<param2> : <type> := <default>;
...
) return <return_type> is
<lokale Deklarationen>
begin
<Code>
return <Wert>
end function;
pure/impure ist optional (Default: pure). Alle Parameter sind Konstanten im Funktionskörper. Defaultwerte optional. Funktion muss an return enden. Eigener deklarativer Bereich zwischen is und begin – lokale Objekte gelten nur innerhalb des Aufrufs.
Übung
Fokus auf pure Funktionen; impure Functions folgen später.
Im vorherigen Tutorial bauten wir einen Ampel-Controller mit FSM. Viele Timer-Berechnungen wurden per Copy-Paste dupliziert. Erfahren Sie, wie eine Funktion den Code vereinfacht:
Testbench
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T21_FunctionTb is
end entity;
architecture sim of T21_FunctionTb is
constant ClockFrequencyHz : integer := 100;
constant ClockPeriod : time := 1000 ms / ClockFrequencyHz;
signal Clk : std_logic := '1';
signal nRst : std_logic := '0';
signal NorthRed : std_logic;
signal NorthYellow : std_logic;
signal NorthGreen : std_logic;
signal WestRed : std_logic;
signal WestYellow : std_logic;
signal WestGreen : std_logic;
begin
i_TrafficLights : entity work.T21_TrafficLights(rtl)
generic map(ClockFrequencyHz => ClockFrequencyHz)
port map (
Clk => Clk, nRst => nRst,
NorthRed => NorthRed, NorthYellow => NorthYellow, NorthGreen => NorthGreen,
WestRed => WestRed, WestYellow => WestYellow, WestGreen => WestGreen
);
Clk <= not Clk after ClockPeriod / 2;
process is
begin
wait until rising_edge(Clk);
wait until rising_edge(Clk);
nRst <= '1';
wait;
end process;
end architecture;
Ampel-Modul
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T21_TrafficLights is
generic(ClockFrequencyHz : natural);
port(
Clk : in std_logic;
nRst : in std_logic;
NorthRed : out std_logic;
NorthYellow : out std_logic;
NorthGreen : out std_logic;
WestRed : out std_logic;
WestYellow : out std_logic;
WestGreen : out std_logic
);
end entity;
architecture rtl of T21_TrafficLights is
type t_State is (NorthNext, StartNorth, North, StopNorth, WestNext, StartWest, West, StopWest);
signal State : t_State;
function CounterVal(Minutes : integer := 0; Seconds : integer := 0) return integer is
variable TotalSeconds : integer;
begin
TotalSeconds := Seconds + Minutes * 60;
return TotalSeconds * ClockFrequencyHz - 1;
end function;
signal Counter : integer range 0 to CounterVal(Minutes => 1) + 1;
process(Clk) is
begin
if rising_edge(Clk) then
if nRst = '0' then
NorthRed <= '1'; NorthYellow <= '0'; NorthGreen <= '0';
WestRed <= '1'; WestYellow <= '0'; WestGreen <= '0';
State <= NorthNext; Counter <= 0;
else
NorthRed <= '0'; NorthYellow <= '0'; NorthGreen <= '0';
WestRed <= '0'; WestYellow <= '0'; WestGreen <= '0';
Counter <= Counter + 1;
case State is
when NorthNext =>
NorthRed <= '1'; WestRed <= '1';
if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= StartNorth; end if;
when StartNorth =>
NorthRed <= '1'; NorthYellow <= '1'; WestRed <= '1';
if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= North; end if;
when North =>
NorthGreen <= '1'; WestRed <= '1';
if Counter = CounterVal(Minutes => 1) then Counter <= 0; State <= StopNorth; end if;
when StopNorth =>
NorthYellow <= '1'; WestRed <= '1';
if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= WestNext; end if;
when WestNext =>
NorthRed <= '1'; WestRed <= '1';
if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= StartWest; end if;
when StartWest =>
NorthRed <= '1'; WestRed <= '1'; WestYellow <= '1';
if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= West; end if;
when West =>
NorthRed <= '1'; WestGreen <= '1';
if Counter = CounterVal(Minutes => 1) then Counter <= 0; State <= StopWest; end if;
when StopWest =>
NorthRed <= '1'; WestYellow <= '1';
if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= NorthNext; end if;
end case;
end if;
end if;
end process;
end architecture;
Wellenform
Nach run 5 min in ModelSim: Modulverhalten unverändert.
Zoom auf Übergänge zu/von StartNorth:
Analyse
Timer-Berechnungen if Counter = ClockFrequencyHz * 5 -1 then ersetzt durch if Counter = CounterVal(Seconds => 5) then.
- Funktionen für repetitive Aufgaben = guter Stil. Ersetzt kryptische Formeln durch sprechende Begriffe (
Minutes,Seconds). - Zentrale Änderung: Hätte
CounterValreturn TotalSeconds * ClockFrequencyHz;geliefert, wären alle Timer um einen Takt zu lang. Korrektur an einer Stelle fixiert alle Timer.
Warum -1? Bei Zustandswechsel auf StartNorth ist Counter = 0; er inkrementiert erst im nächsten Takt. Zählte man bis 500 (bei 100 Hz = 5 s), dauerte der Zustand 501 Takte. Mit -1 exakt 500 Takte = 5 s.
Merksätze
- Funktionen nehmen 0+ Parameter, geben immer Wert zurück.
- Keine
waitStatements erlaubt. - Pure Funktionen = keine Seiteneffekte; Impure Functions = Seiteneffekte erlaubt.
Nächstes Tutorial »
VHDL
- Wie Molybdän die moderne Industrie formt: Nutzung, Vorteile und Versorgungsdynamik
- String-Listen in VHDL erstellen: Best Practices & Beispiel
- VHDL-Testbench-Simulation sauber beenden
- PWM-Controller in VHDL implementieren: Design, Simulation & FPGA-Demo
- Zufallszahlen in VHDL generieren: Von Uniform zu OSVVM
- In-Prozess-Prozeduren für saubere VHDL-FSM-Entwürfe nutzen
- Impure Functions in VHDL nutzen: FSM-Lesbarkeit und Wartbarkeit steigern
- realloc() in C: Syntax, Best Practices & Beispiel
- C's free() Funktion meistern: Praktischer Leitfaden & Beispiel
- Schleiftechniken für Werkzeugschleifmaschinen meistern: Praktischer Leitfaden