Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Industrial programming >> VHDL

Como usar uma função em VHDL


Funções são subprogramas em VHDL que podem ser usados ​​para implementar algoritmos usados ​​com frequência. Uma função recebe zero ou mais valores de entrada e sempre retorna um valor. Além do valor de retorno, o que diferencia uma função de um procedimento é que ela não pode conter instruções Wait. Isso significa que as funções sempre consomem tempo de simulação zero.

Se você estiver familiarizado com funções ou métodos de outras linguagens de programação, as funções VHDL devem ser fáceis de entender. Em VHDL não podemos omitir o valor de retorno ou retornar void, uma função sempre tem que retornar algo e o valor de retorno tem que ser atribuído a algo.

Esta postagem do blog faz parte da série de tutoriais básicos de VHDL.

Em VHDL, existem dois tipos de funções, puras e impuro funções. O fato de uma função ser pura significa que ela não poderá modificar ou ler nenhum sinal externo. Podemos ter certeza de que quando chamamos uma função pura com certos argumentos, ela sempre retornará o mesmo valor. Dizemos que a função não tem efeitos colaterais .

A sintaxe para declarar uma função em VHDL é:
[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;

A palavra-chave pure/impure é opcional, embora o padrão seja pure se a palavra-chave for omitida. Todos os parâmetros são tratados como constantes dentro da função. Assim, eles não podem ser alterados. Os valores padrão são opcionais e a função deve sempre terminar em um return declaração.

As funções têm sua própria região declarativa entre o in e begin palavras-chave. Constantes, sinais ou variáveis ​​declarados aqui são válidos apenas dentro da própria função e não reterão seus valores por meio de chamadas subsequentes à função.

Exercício


Neste tutorial, vamos nos concentrar na função pura, as funções impuras serão abordadas em um tutorial posterior desta série.

No tutorial anterior, criamos um módulo controlador de semáforos usando uma máquina de estado finito (FSM). Copiamos e colamos muitas das linhas contendo cálculos de temporizador de um estado para outro, alterando apenas uma constante ligeiramente.

Descubra como você pode simplificar o código da máquina de estado usando uma função:




O código final para a função 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;

O código final do módulo do semáforo :
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;

A forma de onda depois de inserirmos o run 5 min comando no console ModelSim:


A forma de onda com cursores adicionados nas transições de e para o StartNorth estado:





Análise


Substituímos os cálculos do temporizador do tutorial anterior if Counter = ClockFrequencyHz * 5 -1 then com uma chamada para o novo CounterVal função que criamos:if Counter = CounterVal(Seconds => 5) then .

Podemos ver na primeira captura de tela da forma de onda que a função do módulo não foi alterada. Usar funções para tarefas repetitivas é uma boa prática de design. Especialmente se você puder substituir cálculos por linhas mais legíveis contendo termos como Minutes e Seconds .

Outra vantagem de usar funções é que podemos alterar a implementação de todos os temporizadores de uma só vez, em vez de fazê-lo linha por linha. Por exemplo, se tivéssemos escrito return TotalSeconds * ClockFrequencyHz; no CounterVal função, todos os temporizadores teriam durado um ciclo de clock muito longo. Poderíamos então mudar isso para return TotalSeconds * ClockFrequencyHz -1; no CounterVal função, e todos os temporizadores seriam fixados de uma só vez.

Se examinarmos a última captura de tela da forma de onda, podemos ver por que precisamos subtrair 1 do valor do temporizador que é retornado do CounterVal função. Esta forma de onda examina a duração do StartNorth estado, deve durar exatamente cinco segundos. Quando o State o sinal muda para StartNorth , o Counter valor é 0, e só muda após o próximo ciclo de clock. Então, se tivéssemos contado até 500 ciclos de clock, o StartNorth estado teria realmente durado 501 ciclos. Com nosso testbench rodando a 100 Hz, 500 ciclos de clock são exatamente cinco segundos.


Retirada


Ir para o próximo tutorial »

VHDL

  1. Como usamos o molibdênio?
  2. Como criar uma lista de strings em VHDL
  3. Como parar a simulação em um testbench VHDL
  4. Como criar um controlador PWM em VHDL
  5. Como gerar números aleatórios em VHDL
  6. Como usar um procedimento em um processo em VHDL
  7. Como usar uma função impura em VHDL
  8. Função realloc() na Biblioteca C:Como usar? Sintaxe e Exemplo
  9. Função free() na biblioteca C:Como usar? Aprenda com o Exemplo
  10. Como usar um moedor de corte