So verwenden Sie eine Prozedur in VHDL
Eine Prozedur ist eine Art Unterprogramm in VHDL, das uns dabei helfen kann, die Wiederholung von Code zu vermeiden. Manchmal besteht die Notwendigkeit, identische Operationen an mehreren Stellen im Design durchzuführen. Während das Erstellen eines Moduls für kleinere Operationen übertrieben sein kann, ist eine Prozedur oft das, was Sie wollen.
Prozeduren können innerhalb jeder deklarativen Region deklariert werden. Der Geltungsbereich der Prozedur wird auf die deklarierte Architektur, das Paket oder den Prozess beschränkt. Wann immer Sie die Prozedur aufrufen, verhält sie sich so, als wäre der Code der Prozedur dort eingefügt worden, wo sie aufgerufen wurde.
Eine Prozedur gibt keinen Wert zurück wie eine Funktion, aber Sie können Werte zurückgeben, indem Sie out
deklarieren oder inout
Signale in der Parameterliste.
Dieser Blogpost ist Teil der Reihe Basic VHDL Tutorials.
Die grundlegende Syntax zum Erstellen einer Prozedur lautet:procedure <procedure_name> (signal|variable|constant <name1> : in|out|inout <type>;
signal|variable|constant <name2> : in|out|inout <type>;
... ) is
<declarations_for_use_within_the_procedure>
begin
<code_performed_by_the_procedure_here>
end procedure;
Die Parameterliste einer Prozedur definiert ihre Ein- und Ausgänge, ähnlich wie bei einem Mini-Modul. Es kann ein Signal oder eine Konstante sein, aber im Gegensatz zu einem Modul kann es auch eine Variable sein. Sie können Objekte zwischen den Schlüsselwörtern „is“ und „begin“ deklarieren, die nur innerhalb der Prozedur gültig sind. Dazu können Konstanten, Variablen, Typen, Untertypen und Aliase gehören, aber keine Signale.
Im Gegensatz zu Funktionen können Prozeduren Warteanweisungen enthalten. Daher werden sie häufig in Prüfständen wie einfache BFMs zur Simulation von Schnittstellen oder zur Überprüfung der Ausgabe des zu testenden Geräts (DUT) verwendet.
Übung
Im vorherigen Tutorial haben wir ein Timer-Modul mit verschachtelten If-Then-Else-Anweisungen erstellt. Jede Ebene von If-Then-Else innerhalb einer anderen If-Then-Else fügt dem Design Komplexität hinzu und es wird weniger lesbar. Auf jeder Logikebene führen wir im Grunde die gleiche Operation mit einem anderen Satz von Signalen durch. Gibt es dafür keinen besseren Weg?
In diesem Video-Tutorial lernen wir, wie man eine Prozedur in VHDL erstellt:
Der endgültige Code für die Prozedur testbench :
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 -- We're slowing down the clock to speed up simulation time constant ClockFrequencyHz : integer := 10; -- 10 Hz 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 -- The Device Under Test (DUT) i_Timer : entity work.T19_Timer(rtl) generic map(ClockFrequencyHz => ClockFrequencyHz) port map ( Clk => Clk, nRst => nRst, Seconds => Seconds, Minutes => Minutes, Hours => Hours); -- Process for generating clock Clk <= not Clk after ClockPeriod / 2; -- Testbench sequence process is begin wait until rising_edge(Clk); wait until rising_edge(Clk); -- Take the DUT out of reset nRst <= '1'; wait; end process; end architecture;
Der endgültige Code für das Timer-Modul mit einer Prozedur:
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; -- Negative reset Seconds : inout integer; Minutes : inout integer; Hours : inout integer); end entity; architecture rtl of T19_Timer is -- Signal for counting clock periods 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 the negative reset signal is active if nRst = '0' then Ticks <= 0; Seconds <= 0; Minutes <= 0; Hours <= 0; else -- Cascade counters 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;
Das Wellenformfenster in ModelSim, vergrößert auf der Zeitachse, wo Minutes
Signal wird umgebrochen:
Analyse
Wir können aus der Wellenform ersehen, dass das Wrapping von Signalen immer noch so funktioniert wie im vorherigen Tutorial. Das liegt daran, dass wir die Funktion des Moduls nicht wirklich geändert haben, sondern nur die Art und Weise, wie sie implementiert ist.
Das erste Element in der Parameterliste für IncrementWrap
Prozedur ist die Counter
Signal. Es wird mit der Richtung inout
deklariert damit die Prozedur ihren Wert sowohl lesen als auch setzen kann.
Das zweite und dritte Element in der Parameterliste sind Konstanten. Das bedeutet, dass die Werte, die Sie hier eingeben, als Konstanten innerhalb erscheinen des Verfahrens. Die WrapValue
zusammen mit dem Enable
eingeben input bestimmt, ob der Counter
Signal wird inkrementiert oder umgebrochen.
Das letzte Element in der Parameterliste ist eine Variable mit der Richtung out
. Der Zweck dieser Ausgabe besteht darin, den Aufrufer über die Prozedur zu informieren, die der Zähler umbrochen hat. Wir verwenden es hier wie einen Rückgabewert.
Im Hauptprozess haben wir vier Aufrufe an die IncrementWrap
Verfahren. Jeder der nachfolgenden Aufrufe verwendet den Wrap
Variable, um die Zählung zu aktivieren. Es hätte nicht funktioniert, wenn wir anstelle einer Variablen ein Signal verwendet hätten, da Signalwerte nur aktualisiert werden, wenn ein Prozess schlafen geht. Wir brauchen den Ausgabewert eines Prozeduraufrufs, der als Eingabe für einen Aufruf in der nächsten Zeile verwendet werden soll. Es muss also eine Variable sein.
Imbiss
- Prozeduren können als Minimodule verwendet werden, um das Kopieren und Einfügen von Code zu vermeiden
- Parameter (Ein-/Ausgänge) einer Prozedur können Signale, Variablen oder Konstanten sein
- Im Gegensatz zu Funktionen können Prozeduren Warteanweisungen enthalten
Weiter zum nächsten Tutorial »
VHDL
- Prozeduranweisung – VHDL-Beispiel
- Wie verwenden wir Molybdän?
- So erstellen Sie eine Liste von Zeichenfolgen in VHDL
- So stoppen Sie die Simulation in einer VHDL-Testbench
- So erstellen Sie einen PWM-Controller in VHDL
- So generieren Sie Zufallszahlen in VHDL
- So verwenden Sie eine Prozedur in einem Prozess in VHDL
- So verwenden Sie eine unreine Funktion in VHDL
- So verwenden Sie eine Funktion in VHDL
- So verwenden Sie einen Cutter Grinder