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

Impure Functions in VHDL nutzen: FSM-Lesbarkeit und Wartbarkeit steigern

Eine impure function in VHDL kann auf jedes Signal in ihrem lexikalischen Gültigkeitsbereich zugreifen oder es verändern – auch Signale, die nicht als Parameter übergeben werden. Das verleiht der Funktion Seiteneffekte: Ihr Rückgabewert kann bei gleichen Argumenten variieren, und sie kann externe Signale modifizieren.

Während reine Funktionen deterministisches Verhalten garantieren, sind impure Functions unentbehrlich, um komplexe Zustandsmaschinen-Logik aufzuräumen, indem repetitive oder nebenwirkende Aufgaben in ein einzelnes, gut benanntes Subprogramm ausgelagert werden.

Hinweis: Impure Functions sollten innerhalb eines Prozesses deklariert werden. Auf Architektur- oder Package-Ebene bieten sie keinen Vorteil, da ihr Gültigkeitsbereich auf zur Compile-Zeit sichtbare Signale beschränkt bleibt.

Wann und warum impure Functions einsetzen?

Die Kern-FSM-Logik bleibt lesbar, während das nebenwirkende Verhalten erhalten bleibt.

Syntax

Einfach impure vor function setzen:

impure function CounterExpired(Minutes : integer := 0; Seconds : integer := 0) return boolean;

Details zur Funktionssyntax im Function Tutorial.

Übung: FSM-Refactoring mit impure Function

Bisher wurden Zeitverzögerungen mit reiner Funktion CounterVal berechnet und der Zähler manuell zurückgesetzt. Die folgende impure Funktion bündelt diese Logik:

Testbench (T22_ImpureFunctionTb)

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity T22_ImpureFunctionTb is
end entity;

architecture sim of T22_ImpureFunctionTb is
  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
  i_TrafficLights : entity work.T22_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 (T22_TrafficLights)

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity T22_TrafficLights is
  generic(ClockFrequencyHz : integer);
  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 T22_TrafficLights is
  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;

  type t_State is (NorthNext, StartNorth, North, StopNorth, WestNext, StartWest, West, StopWest);
  signal State : t_State;
  signal Counter : integer range 0 to ClockFrequencyHz * 60;

  process(Clk) is
    impure function CounterExpired(Minutes : integer := 0; Seconds : integer := 0) return boolean is
    begin
      if Counter = CounterVal(Minutes, Seconds) then
        Counter <= 0;
        return true;
      else
        return false;
      end if;
    end function;
  begin
    if rising_edge(Clk) then
      if nRst = '0' then
        State <= NorthNext; Counter <= 0;
        NorthRed <= '1'; NorthYellow <= '0'; NorthGreen <= '0';
        WestRed <= '1'; WestYellow <= '0'; WestGreen <= '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 CounterExpired(Seconds => 5) then State <= StartNorth; end if;
          when StartNorth =>
            NorthRed <= '1'; NorthYellow <= '1'; WestRed <= '1';
            if CounterExpired(Seconds => 5) then State <= North; end if;
          when North =>
            NorthGreen <= '1'; WestRed <= '1';
            if CounterExpired(Minutes => 1) then State <= StopNorth; end if;
          when StopNorth =>
            NorthYellow <= '1'; WestRed <= '1';
            if CounterExpired(Seconds => 5) then State <= WestNext; end if;
          when WestNext =>
            NorthRed <= '1'; WestRed <= '1';
            if CounterExpired(Seconds => 5) then State <= StartWest; end if;
          when StartWest =>
            NorthRed <= '1'; WestRed <= '1'; WestYellow <= '1';
            if CounterExpired(Seconds => 5) then State <= West; end if;
          when West =>
            NorthRed <= '1'; WestGreen <= '1';
            if CounterExpired(Minutes => 1) then State <= StopWest; end if;
          when StopWest =>
            NorthRed <= '1'; WestYellow <= '1';
            if CounterExpired(Seconds => 5) then State <= NorthNext; end if;
        end case;
      end if;
    end if;
  end process;
end architecture;

Wellenform-Analyse

Nach run 5 min in ModelSim zeigt die Simulation identisches Verhalten wie der ursprüngliche FSM – nur der Code ist sauberer. Die Zähler-Reset-Logik ist nun in CounterExpired gekapselt, was Duplikation und Fehlerpotenzial reduziert.

Impure Functions in VHDL nutzen: FSM-Lesbarkeit und Wartbarkeit steigern

Analyse

Die impure Funktion verlagert Zählervergleich und -reset aus mehreren FSM-Zuständen in ein einziges Subprogramm. CounterExpired(Seconds => 5) drückt die Absicht klarer aus als Counter = CounterVal(Seconds => 5).

Impure Functions können Seiteneffekte verschleiern, wenn sie übermäßig genutzt werden. Lokale Deklaration im Prozess hält den umgebenden Code deterministisch und auditierbar. In der Praxis häufiger in Testbenches eingesetzt, wo Korrektheit wichtig, aber Risiko subtiler Bugs geringer als in synthetisierbarem RTL ist.

Impure Functions in VHDL nutzen: FSM-Lesbarkeit und Wartbarkeit steigern

Kernpunkte

Nächstes Tutorial: Fortgeschrittene VHDL-Techniken.

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. VHDL-Funktionen meistern: Praktischer Leitfaden für effizientes Design
  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