Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial programming >> VHDL

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

Weiter zum nächsten Tutorial »


VHDL

  1. Wie verwenden wir Molybdän?
  2. So erstellen Sie eine Liste von Zeichenfolgen in VHDL
  3. So stoppen Sie die Simulation in einer VHDL-Testbench
  4. So erstellen Sie einen PWM-Controller in VHDL
  5. So generieren Sie Zufallszahlen in VHDL
  6. So verwenden Sie eine Prozedur in einem Prozess in VHDL
  7. So verwenden Sie eine unreine Funktion in VHDL
  8. realloc()-Funktion in der C-Bibliothek:Wie verwenden? Syntax &Beispiel
  9. free()-Funktion in der C-Bibliothek:Wie verwenden? Lernen Sie mit Beispiel
  10. So verwenden Sie einen Cutter Grinder