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

VHDL-Funktionen meistern: Praktischer Leitfaden für effizientes Design

Funktionen sind Subprogramme in VHDL für häufig verwendete Algorithmen. Sie nehmen null oder mehr Eingabewerte entgegen und geben immer einen Wert zurück. Im Gegensatz zu Prozeduren dürfen sie keine Wait-Statements enthalten – Funktionen verbrauchen also null Simulationszeit.

Wer Funktionen aus anderen Sprachen kennt, versteht VHDL-Funktionen schnell. In VHDL kann der Rückgabewert nicht weggelassen oder void sein; er muss immer zugewiesen werden.

Dieser Beitrag gehört zur Basic VHDL Tutorials Serie.

VHDL unterscheidet pure und impure Funktionen. Pure Funktionen dürfen keine externen Signale lesen/schreiben – bei gleichen Argumenten liefern sie immer denselben Wert (keine Seiteneffekte).

Syntax

[pure|impure] function <name> (
  <param1> : <type> := <default>;
  <param2> : <type> := <default>;
  ...
) return <return_type> is
  <lokale Deklarationen>
begin
  <Code>
  return <Wert>
end function;

pure/impure ist optional (Default: pure). Alle Parameter sind Konstanten im Funktionskörper. Defaultwerte optional. Funktion muss an return enden. Eigener deklarativer Bereich zwischen is und begin – lokale Objekte gelten nur innerhalb des Aufrufs.

Übung

Fokus auf pure Funktionen; impure Functions folgen später.

Im vorherigen Tutorial bauten wir einen Ampel-Controller mit FSM. Viele Timer-Berechnungen wurden per Copy-Paste dupliziert. Erfahren Sie, wie eine Funktion den Code vereinfacht:

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
  constant ClockFrequencyHz : integer := 100;
  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
  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
    );

  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;

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;
    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
  type t_State is (NorthNext, StartNorth, North, StopNorth, WestNext, StartWest, West, StopWest);
  signal State : t_State;

  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;

  signal Counter : integer range 0 to CounterVal(Minutes => 1) + 1;

  process(Clk) is
  begin
    if rising_edge(Clk) then
      if nRst = '0' then
        NorthRed <= '1'; NorthYellow <= '0'; NorthGreen <= '0';
        WestRed <= '1'; WestYellow <= '0'; WestGreen <= '0';
        State <= NorthNext; Counter <= 0;
      else
        NorthRed <= '0'; NorthYellow <= '0'; NorthGreen <= '0';
        WestRed <= '0'; WestYellow <= '0'; WestGreen <= '0';
        Counter <= Counter + 1;
        case State is
          when NorthNext =>
            NorthRed <= '1'; WestRed <= '1';
            if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= StartNorth; end if;
          when StartNorth =>
            NorthRed <= '1'; NorthYellow <= '1'; WestRed <= '1';
            if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= North; end if;
          when North =>
            NorthGreen <= '1'; WestRed <= '1';
            if Counter = CounterVal(Minutes => 1) then Counter <= 0; State <= StopNorth; end if;
          when StopNorth =>
            NorthYellow <= '1'; WestRed <= '1';
            if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= WestNext; end if;
          when WestNext =>
            NorthRed <= '1'; WestRed <= '1';
            if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= StartWest; end if;
          when StartWest =>
            NorthRed <= '1'; WestRed <= '1'; WestYellow <= '1';
            if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= West; end if;
          when West =>
            NorthRed <= '1'; WestGreen <= '1';
            if Counter = CounterVal(Minutes => 1) then Counter <= 0; State <= StopWest; end if;
          when StopWest =>
            NorthRed <= '1'; WestYellow <= '1';
            if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= NorthNext; end if;
        end case;
      end if;
    end if;
  end process;
end architecture;

Wellenform

Nach run 5 min in ModelSim: Modulverhalten unverändert.

VHDL-Funktionen meistern: Praktischer Leitfaden für effizientes Design

Zoom auf Übergänge zu/von StartNorth:

VHDL-Funktionen meistern: Praktischer Leitfaden für effizientes Design

Analyse

Timer-Berechnungen if Counter = ClockFrequencyHz * 5 -1 then ersetzt durch if Counter = CounterVal(Seconds => 5) then.

Warum -1? Bei Zustandswechsel auf StartNorth ist Counter = 0; er inkrementiert erst im nächsten Takt. Zählte man bis 500 (bei 100 Hz = 5 s), dauerte der Zustand 501 Takte. Mit -1 exakt 500 Takte = 5 s.

VHDL-Funktionen meistern: Praktischer Leitfaden für effizientes Design

Merksätze

Nächstes Tutorial »

VHDL

  1. Wie Molybdän die moderne Industrie formt: Nutzung, Vorteile und Versorgungsdynamik
  2. String-Listen in VHDL erstellen: Best Practices & Beispiel
  3. VHDL-Testbench-Simulation sauber beenden
  4. PWM-Controller in VHDL implementieren: Design, Simulation & FPGA-Demo
  5. Zufallszahlen in VHDL generieren: Von Uniform zu OSVVM
  6. In-Prozess-Prozeduren für saubere VHDL-FSM-Entwürfe nutzen
  7. Impure Functions in VHDL nutzen: FSM-Lesbarkeit und Wartbarkeit steigern
  8. realloc() in C: Syntax, Best Practices & Beispiel
  9. C's free() Funktion meistern: Praktischer Leitfaden & Beispiel
  10. Schleiftechniken für Werkzeugschleifmaschinen meistern: Praktischer Leitfaden