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

Comment utiliser une fonction en VHDL

Les fonctions sont des sous-programmes en VHDL qui peuvent être utilisés pour implémenter des algorithmes fréquemment utilisés. Une fonction prend zéro ou plusieurs valeurs d'entrée et renvoie toujours une valeur. En plus de la valeur de retour, ce qui distingue une fonction d'une procédure, c'est qu'elle ne peut pas contenir d'instructions Wait. Cela signifie que les fonctions consomment toujours zéro temps de simulation.

Si vous connaissez les fonctions ou les méthodes d'autres langages de programmation, les fonctions VHDL devraient être faciles à comprendre. En VHDL, nous ne pouvons pas omettre la valeur de retour ou renvoyer void, une fonction doit toujours retourner quelque chose et la valeur de retour doit être affectée à quelque chose.

Cet article de blog fait partie de la série de didacticiels VHDL de base.

En VHDL, il existe deux types de fonctions, pures et impur les fonctions. Qu'une fonction soit pure signifie qu'elle ne sera pas autorisée à modifier ou à lire un signal externe. Nous pouvons être certains que lorsque nous appelons une fonction pure avec certains arguments, elle renverra toujours la même valeur. Nous disons que la fonction n'a pas d'effets secondaires .

La syntaxe pour déclarer une fonction en VHDL est :

[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;

Le mot-clé pur/impur est facultatif, bien qu'il soit par défaut pur si le mot-clé est omis. Tous les paramètres sont traités comme des constantes à l'intérieur de la fonction. Ainsi, ils ne peuvent pas être modifiés. Les valeurs par défaut sont facultatives et la fonction doit toujours se terminer à un return déclaration.

Les fonctions ont leur propre région déclarative entre le in et begin mots clés. Les constantes, signaux ou variables déclarés ici ne sont valides qu'au sein de la fonction elle-même, et ils ne conserveront pas leurs valeurs lors d'appels ultérieurs à la fonction.

Exercice

Dans ce didacticiel, nous allons nous concentrer sur la fonction pure, les fonctions impures seront couvertes dans un didacticiel ultérieur de cette série.

Dans le didacticiel précédent, nous avons créé un module de contrôleur de feux de circulation à l'aide d'une machine à états finis (FSM). Nous avons copié-collé de nombreuses lignes contenant des calculs de minuterie d'un état à un autre, en ne modifiant que légèrement une constante.

Découvrez comment simplifier le code de la machine d'état à l'aide d'une fonction :

Le code final pour la fonction 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;

Le code final pour le module des feux de circulation :

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;

La forme d'onde après avoir saisi le run 5 min commande dans la console ModelSim :

La forme d'onde avec des curseurs ajoutés aux transitions vers et depuis le StartNorth état :

Analyse

Nous avons remplacé les calculs de minuterie du tutoriel précédent if Counter = ClockFrequencyHz * 5 -1 then avec un appel au nouveau CounterVal fonction que nous avons créée :if Counter = CounterVal(Seconds => 5) then .

Nous pouvons voir sur la première capture d'écran de la forme d'onde que la fonction du module est inchangée. L'utilisation de fonctions pour des tâches répétitives est une bonne pratique de conception. Surtout si vous pouvez remplacer les calculs par des lignes plus lisibles contenant des termes comme Minutes et Seconds .

Un autre avantage de l'utilisation des fonctions est que nous pouvons modifier l'implémentation de tous les temporisateurs à la fois, au lieu de le faire ligne par ligne. Par exemple, si nous avions écrit return TotalSeconds * ClockFrequencyHz; dans le CounterVal fonction, tous les temporisateurs auraient duré un cycle d'horloge de trop. Nous pourrions alors changer cela en return TotalSeconds * ClockFrequencyHz -1; dans le CounterVal fonction, et toutes les minuteries seraient fixées à la fois.

Si nous examinons la dernière capture d'écran de la forme d'onde, nous pouvons voir pourquoi nous devons soustraire 1 de la valeur de la minuterie renvoyée par le CounterVal fonction. Cette forme d'onde examine la durée du StartNorth état, il devrait durer exactement cinq secondes. Lorsque le State le signal passe à StartNorth , le Counter la valeur est 0 et ne change qu'après le cycle d'horloge suivant. Donc, si nous avions compté jusqu'à 500 cycles d'horloge, le StartNorth l'état aurait en fait duré 501 cycles. Avec notre banc d'essai fonctionnant à 100 Hz, 500 cycles d'horloge correspondent exactement à cinq secondes.

À emporter

Aller au tutoriel suivant »


VHDL

  1. Comment utilisons-nous le molybdène?
  2. Comment créer une liste de chaînes en VHDL
  3. Comment arrêter la simulation dans un testbench VHDL
  4. Comment créer un contrôleur PWM en VHDL
  5. Comment générer des nombres aléatoires en VHDL
  6. Comment utiliser une procédure dans un processus en VHDL
  7. Fonction realloc() dans la bibliothèque C :comment l'utiliser ? Syntaxe et exemple
  8. Fonction free() dans la bibliothèque C :comment l'utiliser ? Apprendre avec l'exemple
  9. Comment utiliser une meuleuse de coupe