So verwenden Sie eine Funktion in VHDL
Funktionen sind Unterprogramme in VHDL, die zur Implementierung häufig verwendeter Algorithmen verwendet werden können. Eine Funktion nimmt null oder mehr Eingabewerte entgegen und gibt immer einen Wert zurück. Neben dem Rückgabewert unterscheidet sich eine Funktion von einer Prozedur dadurch, dass sie keine Wait-Anweisungen enthalten kann. Das bedeutet, dass Funktionen immer null Simulationszeit verbrauchen.
Wenn Sie mit Funktionen oder Methoden aus anderen Programmiersprachen vertraut sind, sollten VHDL-Funktionen leicht zu verstehen sein. In VHDL können wir den Rückgabewert nicht weglassen oder void zurückgeben, eine Funktion muss immer etwas zurückgeben und der Rückgabewert muss etwas zugewiesen werden.
Dieser Blogpost ist Teil der Reihe Basic VHDL Tutorials.
In VHDL gibt es zwei Arten von Funktionen, pure und unrein Funktionen. Dass eine Funktion rein ist, bedeutet, dass sie kein externes Signal ändern oder lesen darf. Wir können sicher sein, dass, wenn wir eine reine Funktion mit bestimmten Argumenten aufrufen, sie immer denselben Wert zurückgibt. Wir sagen, dass die Funktion keine Nebenwirkungen hat .
Die Syntax zum Deklarieren einer Funktion in VHDL lautet:
[pure|impure] function <function_name> (<parameter1_name> : <parameter1_type> := <default_value>;
<parameter2_name> : <parameter2_type> := <default_value>;
... ) return <return_type> is
<constant_or_variable_declaration>
begin
<code_performed_by_the_function>
return <value>
end function;
Das Schlüsselwort pure/impure ist optional, obwohl es standardmäßig rein ist, wenn das Schlüsselwort weggelassen wird. Alle Parameter werden innerhalb der Funktion als Konstanten behandelt. Sie können daher nicht geändert werden. Die Standardwerte sind optional, und die Funktion muss immer bei return
enden Erklärung.
Funktionen haben ihren eigenen deklarativen Bereich zwischen in
und begin
Schlüsselwörter. Hier deklarierte Konstanten, Signale oder Variablen sind nur innerhalb der Funktion selbst gültig und behalten ihre Werte nicht durch nachfolgende Aufrufe der Funktion.
Übung
In diesem Tutorial konzentrieren wir uns auf die reine Funktion, unreine Funktionen werden in einem späteren Tutorial dieser Serie behandelt.
Im vorherigen Tutorial haben wir ein Ampelsteuerungsmodul mit einer endlichen Zustandsmaschine (FSM) erstellt. Wir haben viele der Zeilen, die Timer-Berechnungen enthalten, von einem Zustand in einen anderen kopiert und eingefügt, wobei wir nur eine Konstante geringfügig geändert haben.
Finden Sie heraus, wie Sie den Zustandsmaschinencode vereinfachen können, indem Sie eine Funktion verwenden:
Der endgültige Code für die Funktion 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 -- We are using a low clock frequency to speed up the simulation constant ClockFrequencyHz : integer := 100; -- 100 Hz 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 -- The Device Under Test (DUT) 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); -- 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 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; -- Negative reset 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 -- Enumerated type declaration and state signal declaration type t_State is (NorthNext, StartNorth, North, StopNorth, WestNext, StartWest, West, StopWest); signal State : t_State; -- Calculate the number of clock cycles in minutes/seconds 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; -- Counter for counting clock periods, 1 minute max signal Counter : integer range 0 to CounterVal(Minutes => 1) +1; begin process(Clk) is begin if rising_edge(Clk) then if nRst = '0' then -- Reset values NorthRed <= '1'; NorthYellow <= '0'; NorthGreen <= '0'; WestRed <= '1'; WestYellow <= '0'; WestGreen <= '0'; State <= NorthNext; Counter <= 0; else -- Default values NorthRed <= '0'; NorthYellow <= '0'; NorthGreen <= '0'; WestRed <= '0'; WestYellow <= '0'; WestGreen <= '0'; Counter <= Counter + 1; case State is -- Red light in all directions when NorthNext => NorthRed <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= StartNorth; end if; -- Yellow light in north/south directions when StartNorth => NorthRed <= '1'; NorthYellow <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= North; end if; -- Green light in north/south directions when North => NorthGreen <= '1'; WestRed <= '1'; -- If 1 minute has passed if Counter = CounterVal(Minutes => 1) then Counter <= 0; State <= StopNorth; end if; -- Red and yellow light in north/south direction when StopNorth => NorthYellow <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= WestNext; end if; -- Red light in all directions when WestNext => NorthRed <= '1'; WestRed <= '1'; -- If 5 seconds have passedf if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= StartWest; end if; -- Yellow light in west/east direction when StartWest => NorthRed <= '1'; WestRed <= '1'; WestYellow <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= West; end if; -- Green light in west/east direction when West => NorthRed <= '1'; WestGreen <= '1'; -- If 1 minute has passed if Counter = CounterVal(Minutes => 1) then Counter <= 0; State <= StopWest; end if; -- Red and yellow light in west/east direction when StopWest => NorthRed <= '1'; WestYellow <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= NorthNext; end if; end case; end if; end if; end process; end architecture;
Die Wellenform nachdem wir run 5 min
eingegeben haben Befehl in der ModelSim-Konsole:
Die Wellenform mit hinzugefügten Cursorn an den Übergängen zu und von StartNorth
Zustand:
Analyse
Wir haben die Timer-Berechnungen aus dem vorherigen Tutorial if Counter = ClockFrequencyHz * 5 -1 then
ersetzt mit einem Aufruf an die neue CounterVal
Funktion, die wir erstellt haben:if Counter = CounterVal(Seconds => 5) then
.
Auf dem ersten Wellenform-Screenshot können wir sehen, dass die Funktion des Moduls unverändert ist. Die Verwendung von Funktionen für sich wiederholende Aufgaben ist eine gute Entwurfspraxis. Vor allem, wenn Sie Berechnungen durch besser lesbare Zeilen mit Begriffen wie Minutes
ersetzen können und Seconds
.
Ein weiterer Vorteil der Verwendung von Funktionen besteht darin, dass wir die Implementierung aller Timer auf einmal ändern können, anstatt dies Zeile für Zeile zu tun. Zum Beispiel, wenn wir return TotalSeconds * ClockFrequencyHz;
geschrieben hätten im CounterVal
Funktion hätten alle Timer einen Takt zu lange gedauert. Wir könnten dies dann in return TotalSeconds * ClockFrequencyHz -1;
ändern im CounterVal
Funktion, und alle Timer würden auf einmal fixiert.
Wenn wir den letzten Wellenform-Screenshot untersuchen, können wir sehen, warum wir 1 von dem Timer-Wert subtrahieren müssen, der von CounterVal
zurückgegeben wird Funktion. Diese Wellenform untersucht die Dauer von StartNorth
Zustand, sollte es genau fünf Sekunden dauern. Wenn der State
Signal wechselt auf StartNorth
, die Counter
Der Wert ist 0 und ändert sich erst nach dem nächsten Taktzyklus. Wenn wir also bis zu 500 Taktzyklen gezählt hätten, wäre die StartNorth
Zustand hätte tatsächlich 501 Zyklen gedauert. Wenn unsere Testbench bei 100 Hz läuft, sind 500 Taktzyklen genau fünf Sekunden.
Imbiss
- Funktionen können null oder mehr Parameter annehmen, aber sie geben immer einen Wert zurück
- Funktionen dürfen nicht
wait
enthalten Aussagen - Reine Funktionen können keine Nebeneffekte haben, während unreine Funktionen dies können.
Weiter zum nächsten Tutorial »
VHDL
- 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
- realloc()-Funktion in der C-Bibliothek:Wie verwenden? Syntax &Beispiel
- free()-Funktion in der C-Bibliothek:Wie verwenden? Lernen Sie mit Beispiel
- So verwenden Sie einen Cutter Grinder