Prozeduren in VHDL: Wiederverwendbaren Code für einfachere Designs
In VHDL sind Prozeduren Subprogramme, die wiederkehrende Codeblöcke vermeiden. Wenn dieselbe Operation an mehreren Stellen benötigt wird, ist ein vollständiges Modul oft überdimensioniert. Eine Prozedur bietet eine leichte, wiederverwendbare Lösung.
Prozeduren können in jedem deklarativen Bereich stehen – Architektur, Package, Prozess – und ihr Gültigkeitsbereich ist auf diesen Bereich beschränkt. Beim Aufruf wird der Prozedurkörper ausgeführt, als stünde der Code an der Aufrufstelle – Modularität ohne Komponenten-Overhead.
Im Gegensatz zu Funktionen geben Prozeduren keinen direkten Rückgabewert. Aber über out oder inout Parameter können Werte zurückgegeben werden – die Prozedur verhält sich wie ein Mini-Modul mit Ein- und Ausgängen.
Teil der Basic VHDL Tutorials Serie.
Syntax
procedure <name> ( signal|variable|constant <name1> : in|out|inout <type>; signal|variable|constant <name2> : in|out|inout <type>; ... ) is <lokale Deklarationen> begin <Prozedurcode> end procedure;
Parameterliste definiert Ein-/Ausgänge wie ein Mini-Modul. Parameter können Signals, Variablen, Konstanten sein. Lokale Objekte (Konstanten, Variablen, Typen, Subtypen, Aliases) erlaubt; Signale nicht. Da Prozeduren wait Statements enthalten dürfen, eignen sie sich ideal für Testbenches (BFM-Treiber, DUT-Ausgabeprüfung).
Übung
Im vorherigen Tutorial wurde ein Timer mit tief verschachtelten if-then-else Blöcken gebaut. Jede Verschachtelung erhöhte Komplexität und verringerte Lesbarkeit, obwohl dieselbe Operation auf verschiedenen Signalen ausgeführt wurde. Besser: Wiederkehrende Logik in Prozedur kapseln.
Video-Tutorial zur VHDL-Prozedur:
Beispiel: Prozedur-basierter Timer
Testbench unverändert, außer Prozeduraufruf für DUT:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T19_ProcedureTb is
end entity;
architecture sim of T19_ProcedureTb is
constant ClockFrequencyHz : integer := 10;
constant ClockPeriod : time := 1000 ms / ClockFrequencyHz;
signal Clk : std_logic := '1';
signal nRst : std_logic := '0';
signal Seconds : integer;
signal Minutes : integer;
signal Hours : integer;
begin
i_Timer : entity work.T19_Timer(rtl)
generic map(ClockFrequencyHz => ClockFrequencyHz)
port map (Clk => Clk, nRst => nRst, Seconds => Seconds, Minutes => Minutes, Hours => Hours);
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;
Timer-Modul nutzt Prozedur für Zähler-Inkrement:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T19_Timer is
generic(ClockFrequencyHz : integer);
port(
Clk : in std_logic;
nRst : in std_logic;
Seconds : inout integer;
Minutes : inout integer;
Hours : inout integer
);
end entity;
architecture rtl of T19_Timer is
signal Ticks : integer;
procedure IncrementWrap(
signal Counter : inout integer;
constant WrapValue : in integer;
constant Enable : in boolean;
variable Wrapped : out boolean
) is
begin
Wrapped := false;
if Enable then
if Counter = WrapValue - 1 then
Wrapped := true;
Counter <= 0;
else
Counter <= Counter + 1;
end if;
end if;
end procedure;
begin
process(Clk) is
variable Wrap : boolean;
begin
if rising_edge(Clk) then
if nRst = '0' then
Ticks <= 0; Seconds <= 0; Minutes <= 0; Hours <= 0;
else
IncrementWrap(Ticks, ClockFrequencyHz, true, Wrap);
IncrementWrap(Seconds, 60, Wrap, Wrap);
IncrementWrap(Minutes, 60, Wrap, Wrap);
IncrementWrap(Hours, 24, Wrap, Wrap);
end if;
end if;
end process;
end architecture;
Wellenform bestätigt: Minuten-Zähler wrappt korrekt bei 60 Minuten.
Analyse
Verhalten identisch zum ursprünglichen verschachtelten if-Ansatz – nur strukturelle Änderung.
- Erster Parameter
CounteralsinoutSignal – Prozedur liest und aktualisiert. - Zweiter/Dritter Parameter
WrapValue,Enableals Konstanten – im Prozedurkörper als Compile-Time-Konstanten behandelt. - Letzter Parameter
Wrappedalsvariablemitout– Pseudo-Rückgabewert, ob Wrap erfolgte.
Im Hauptprozess vier aufeinanderfolgende IncrementWrap-Aufrufe kaskadieren die Zähler. Wrap-Variable des vorherigen Aufrufs speist Enable des nächsten. Variable essenziell, da Signal-Updates erst nach Prozess-Suspend sichtbar; Variable liefert sofortigen Datenfluss.
Merksätze
- Prozeduren als wiederverwendbare Subprogramme eliminieren Duplicate Code.
- Parameter können Signals, Variablen, Konstanten sein – hohe Flexibilität.
- Im Gegensatz zu Funktionen dürfen Prozeduren
waitStatements enthalten – ideal für Testbench-Treiber.
Nächstes Tutorial »
VHDL
- VHDL Procedure Beispiel: Inkrementieren eines Standard Logic Vectors
- 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
- VHDL-Funktionen meistern: Praktischer Leitfaden für effizientes Design
- Schleiftechniken für Werkzeugschleifmaschinen meistern: Praktischer Leitfaden