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
waitenthalten 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