Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Industrial programming >> VHDL

Utilisation des fonctions impures en VHDL : Améliorer la lisibilité et la maintenabilité des FSM

En VHDL, une fonction impure peut accéder ou modifier n'importe quel signal dans sa portée lexicale, y compris les signaux qui ne sont pas listés comme paramètres. Cette capacité donne à la fonction des effets de bord - sa valeur de retour peut varier même quand les mêmes arguments sont fournis, et elle peut altérer des signaux externes qui ne sont pas directement retournés.

Alors que les fonctions pures sont confinées à un comportement déterministe, les fonctions impures sont inestimables pour nettoyer la logique complexe de machine d'état en déplaçant les tâches répétitives ou à effets de bord dans un sous-programme unique et bien nommé.

Note : Les fonctions impures sont mieux déclarées à l'intérieur d'un processus. Les déclarer au niveau de l'architecture ou du package n'offre aucun avantage, car la portée de la fonction serait limitée aux signaux qui sont déjà dans la portée au moment de la compilation.

Quand et pourquoi utiliser les fonctions impures

Scénarios typiques :

L'utilisation d'une fonction impure garde la logique principale de la machine d'état lisible tout en préservant le comportement à effets de bord requis par la conception.

Syntaxe

Pour déclarer une fonction impure, il suffit de préfixer le mot-clé impure avant function :

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

Consultez le tutoriel sur les fonctions pour les détails complets de la syntaxe.

Exercice : Refactorisation FSM avec une fonction impure

Précédemment, nous calculions les délais temporels en utilisant une fonction pure CounterVal et réinitialisions manuellement le compteur chaque fois que le minuteur expirait. La fonction impure suivante consolide cette logique :

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
  -- Fréquence d'horloge basse pour accélérer la 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
  -- Instanciation du DUT
  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
    );
    
  -- Génération d'horloge
  Clk <= not Clk after ClockPeriod / 2;
  
  -- Séquence de testbench
  process is
  begin
    wait until rising_edge(Clk);
    wait until rising_edge(Clk);
    -- Relâcher le reset
    nRst <= '1';
    wait;
  end process;
end architecture;

Module Feux Tricolores (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; -- Reset négatif
    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
  -- Fonction pure pour calculer les cycles d'horloge pour un temps donné
  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;
  
  -- Définition d'état FSM
  type t_State is (NorthNext, StartNorth, North, StopNorth, WestNext, StartWest, West, StopWest);
  signal State : t_State;
  
  -- Compteur pour périodes d'horloge, jusqu'à une minute
  signal Counter : integer range 0 to ClockFrequencyHz * 60;
  
begin
  process(Clk) is
    -- Fonction impure qui lit et pilote Counter
    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
        -- État et signaux de reset
        State <= NorthNext;
        Counter <= 0;
        NorthRed <= '1';
        NorthYellow <= '0';
        NorthGreen <= '0';
        WestRed <= '1';
        WestYellow <= '0';
        WestGreen <= '0';
      else
        -- Sorties par défaut
        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;

Analyse de la forme d'onde

Après avoir émis la commande run 5 min dans ModelSim, la simulation montre un comportement identique à la FSM originale - seul le code est devenu plus propre. La logique de réinitialisation du compteur est maintenant encapsulée dans CounterExpired, réduisant la duplication et les erreurs potentielles.

Utilisation des fonctions impures en VHDL : Améliorer la lisibilité et la maintenabilité des FSM

Analyse

La fonction impure transfère la comparaison et la réinitialisation du compteur depuis plusieurs états FSM dans un seul sous-programme. Ce changement améliore la lisibilité : CounterExpired(Seconds => 5) exprime clairement l'intention, alors que Counter = CounterVal(Seconds => 5) est plus verbeux.

Bien que les fonctions impures puissent obscurcir les effets de bord si elles sont trop utilisées, les garder locales à un processus assure que le code environnant reste déterministe et facile à auditer. En pratique, elles sont plus fréquemment employées dans les testbench où la correction est importante mais le risque de bogues subtils est plus faible que dans le RTL synthétisable.

Utilisation des fonctions impures en VHDL : Améliorer la lisibilité et la maintenabilité des FSM

Points clés à retenir

Passez au tutoriel suivant pour explorer des techniques VHDL avancées.

VHDL

  1. Comment le molybdène façonne l'industrie moderne : usages, avantages et dynamiques d'approvisionnement
  2. Créer des listes de chaînes en VHDL : Bonnes pratiques et exemple
  3. Terminer proprement une simulation de banc de test VHDL
  4. Implémenter un contrôleur PWM en VHDL : Conception, simulation et démo FPGA
  5. Générer des nombres aléatoires en VHDL : De l'uniforme à OSVVM
  6. Exploiter les procédures in-process pour un design FSM VHDL plus propre
  7. Utilisation de realloc() en C : Syntaxe, bonnes pratiques et exemple
  8. Maîtriser la fonction free() en C : Guide pratique et exemple
  9. Maîtriser les techniques de la rectifieuse d'outils : guide pratique