Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Industrial programming >> VHDL

Cómo usar una función en VHDL

Las funciones son subprogramas en VHDL que se pueden usar para implementar algoritmos de uso frecuente. Una función toma cero o más valores de entrada y siempre devuelve un valor. Además del valor devuelto, lo que distingue a una función de un procedimiento es que no puede contener declaraciones de espera. Esto significa que las funciones siempre consumen tiempo de simulación cero.

Si está familiarizado con funciones o métodos de otros lenguajes de programación, las funciones VHDL deberían ser fáciles de entender. En VHDL no podemos omitir el valor devuelto ni devolver vacío, una función siempre tiene que devolver algo y el valor devuelto tiene que asignarse a algo.

Esta publicación de blog es parte de la serie Tutoriales básicos de VHDL.

En VHDL, hay dos tipos de funciones, puras e impuro funciones Que una función sea pura significa que no se le permitirá modificar ni leer ninguna señal externa. Podemos estar seguros de que cuando llamamos a una función pura con ciertos argumentos, siempre devolverá el mismo valor. Decimos que la función no tiene efectos secundarios .

La sintaxis para declarar una función en VHDL es:

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

La palabra clave puro/impuro es opcional, aunque por defecto será puro si se omite la palabra clave. Todos los parámetros se tratan como constantes dentro de la función. Por lo tanto, no se pueden cambiar. Los valores predeterminados son opcionales y la función siempre debe terminar en un return declaración.

Las funciones tienen su propia región declarativa entre el in y begin palabras clave Las constantes, señales o variables declaradas aquí son válidas solo dentro de la función misma y no conservarán sus valores a través de llamadas posteriores a la función.

Ejercicio

En este tutorial, nos centraremos en la función pura, las funciones impuras se tratarán en un tutorial posterior de esta serie.

En el tutorial anterior, creamos un módulo controlador de semáforos usando una máquina de estado finito (FSM). Copiamos y pegamos muchas de las líneas que contenían cálculos de temporizador de un estado a otro, cambiando solo una constante ligeramente.

Descubra cómo puede simplificar el código de la máquina de estado usando una función:

El código final para la función 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;

El código final para el módulo de semáforos :

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 forma de onda después de que ingresamos el run 5 min comando en la consola de ModelSim:

La forma de onda con cursores agregados en las transiciones hacia y desde el StartNorth estado:

Análisis

Reemplazamos los cálculos del temporizador del tutorial anterior if Counter = ClockFrequencyHz * 5 -1 then con una llamada al nuevo CounterVal función que creamos:if Counter = CounterVal(Seconds => 5) then .

Podemos ver en la primera captura de pantalla de forma de onda que la función del módulo no ha cambiado. El uso de funciones para tareas repetitivas es una buena práctica de diseño. Especialmente si puede reemplazar los cálculos con líneas más legibles que contengan términos como Minutes y Seconds .

Otra ventaja de usar funciones es que podemos cambiar la implementación de todos los temporizadores a la vez, en lugar de hacerlo línea por línea. Por ejemplo, si hubiéramos escrito return TotalSeconds * ClockFrequencyHz; en el CounterVal función, todos los temporizadores habrían durado un ciclo de reloj demasiado tiempo. Entonces podríamos cambiar esto a return TotalSeconds * ClockFrequencyHz -1; en el CounterVal y todos los temporizadores se arreglarían a la vez.

Si examinamos la captura de pantalla de la última forma de onda, podemos ver por qué necesitamos restar 1 del valor del temporizador que se devuelve del CounterVal función. Esta forma de onda examina la duración del StartNorth estado, debería durar exactamente cinco segundos. Cuando el State la señal cambia a StartNorth , el Counter el valor es 0, y solo cambia después del próximo ciclo de reloj. Entonces, si hubiéramos contado hasta 500 ciclos de reloj, el StartNorth estado hubiera durado realmente 501 ciclos. Con nuestro banco de pruebas funcionando a 100 Hz, 500 ciclos de reloj son exactamente cinco segundos.

Para llevar

Ir al siguiente tutorial »


VHDL

  1. ¿Cómo utilizamos el molibdeno?
  2. Cómo crear una lista de cadenas en VHDL
  3. Cómo detener la simulación en un banco de pruebas VHDL
  4. Cómo crear un controlador PWM en VHDL
  5. Cómo generar números aleatorios en VHDL
  6. Cómo usar un procedimiento en un proceso en VHDL
  7. Cómo usar una función impura en VHDL
  8. Cómo crear una máquina de estados finitos en VHDL
  9. Realloc () Función en la biblioteca C:¿Cómo usar? Sintaxis y ejemplo
  10. Función free () en la biblioteca C:¿Cómo usar? Aprende con el Ejemplo
  11. Cómo usar una amoladora cortadora