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 um procedimento em um processo em VHDL


É possível conduzir sinais externos de um procedimento. Desde que o sinal esteja dentro do escopo do procedimento, ele pode ser acessado para leitura ou escrita, mesmo que não esteja listado na lista de parâmetros.

Os procedimentos que são declarados na região declarativa da arquitetura não podem conduzir nenhum sinal externo. Isso ocorre simplesmente porque não há sinais em seu escopo em tempo de compilação. Um procedimento declarado dentro de um processo, por outro lado, terá acesso a todos os sinais que o processo pode ver.

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

Tais procedimentos podem ser usados ​​para organizar algoritmos em processos onde as mesmas operações ocorrem várias vezes. Poderíamos usar um procedimento normal onde todas as entradas e saídas são atribuídas a sinais locais quando você os chama, mas esse não é o ponto. Ao omitir os sinais de entrada e saída da chamada do procedimento, devemos digitar menos e, mais importante, tornar o código mais legível.

Imagine um processo implementando um protocolo de comunicação complexo. Seria muito mais fácil entender o fluxo de execução do algoritmo principal se algumas operações fossem substituídas por chamadas de procedimento como RequestToSend() ou SendAutorizationHeader() . Você saberia o que essas linhas faziam apenas olhando os nomes dos procedimentos.

Exercício


No tutorial anterior, simplificamos nosso código de máquina de estado finito (FSM) usando uma função impura. Estávamos dirigindo o Counter sinal da função impura e usamos o valor de retorno para determinar quando mudar de estado. Mas e se quisermos mover a atribuição do State sinal na função também e ignorar o valor de retorno?

Não é possível chamar uma função sem atribuir o valor de retorno a algo em VHDL. Se tentarmos fazer isso, o ModelSim produzirá o erro de compilação: Nenhuma entrada viável para o subprograma “CounterExpired”.

Em vez disso, podemos usar um procedimento para isso. Um procedimento declarado dentro de um processo pode acessar qualquer sinal dentro do escopo desse processo. Isso é semelhante à função impura, mas como é um procedimento, não há valor de retorno.

Neste tutorial em vídeo vamos simplificar o código FSM usando um procedimento declarado em um processo:



O código final para o procedimento em processo testbench :
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity T23_ProcedureInProcessTb is
end entity;

architecture sim of T23_ProcedureInProcessTb 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.T23_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 para o módulo de semáforos :
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

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

    -- Counter for counting clock periods, 1 minute max
    signal Counter : integer range 0 to ClockFrequencyHz * 60;

begin

    process(Clk) is

        -- Procedure for changing state after a given time
        procedure ChangeState(ToState : t_State;
                              Minutes : integer := 0;
                              Seconds : integer := 0) is
            variable TotalSeconds : integer;
            variable ClockCycles  : integer;
        begin
            TotalSeconds := Seconds + Minutes * 60;
            ClockCycles  := TotalSeconds * ClockFrequencyHz -1;
            if Counter = ClockCycles then
                Counter <= 0;
                State   <= ToState;
            end if;
        end procedure;

    begin
        if rising_edge(Clk) then
            if nRst = '0' then
                -- Reset values
                State   <= NorthNext;
                Counter <= 0;
                NorthRed    <= '1';
                NorthYellow <= '0';
                NorthGreen  <= '0';
                WestRed     <= '1';
                WestYellow  <= '0';
                WestGreen   <= '0';

            else
                -- Default values
                NorthRed    <= '0';
                NorthYellow <= '0';
                NorthGreen  <= '0';
                WestRed     <= '0';
                WestYellow  <= '0';
                WestGreen   <= '0';

                Counter <= Counter + 1;

                case State is

                    -- Red in all directions
                    when NorthNext =>
                        NorthRed <= '1';
                        WestRed  <= '1';
                        ChangeState(StartNorth, Seconds => 5);

                    -- Red and yellow in north/south direction
                    when StartNorth =>
                        NorthRed    <= '1';
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        ChangeState(North, Seconds => 5);

                    -- Green in north/south direction
                    when North =>
                        NorthGreen <= '1';
                        WestRed    <= '1';
                        ChangeState(StopNorth, Minutes => 1);

                    -- Yellow in north/south direction
                    when StopNorth =>
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        ChangeState(WestNext, Seconds => 5);

                    -- Red in all directions
                    when WestNext =>
                        NorthRed <= '1';
                        WestRed  <= '1';
                        ChangeState(StartWest, Seconds => 5);

                    -- Red and yellow in west/east direction
                    when StartWest =>
                        NorthRed   <= '1';
                        WestRed    <= '1';
                        WestYellow <= '1';
                        ChangeState(West, Seconds => 5);

                    -- Green in west/east direction
                    when West =>
                        NorthRed  <= '1';
                        WestGreen <= '1';
                        ChangeState(StopWest, Minutes => 1);

                    -- Yellow in west/east direction
                    when StopWest =>
                        NorthRed   <= '1';
                        WestYellow <= '1';
                        ChangeState(NorthNext, Seconds => 5);

                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:





Análise


Não alteramos o comportamento do módulo e podemos ver que a forma de onda permanece inalterada.

Comparado com o código do tutorial onde criamos inicialmente o módulo de semáforos, o código FSM está muito mais legível agora. Você pode facilmente seguir o algoritmo que ele implementa lendo o código. Ter o temporizador e a lógica de mudança de estado em um único procedimento é benéfico porque garante que seja implementado igualmente em todos os lugares em que for usado.


Retirada


VHDL

  1. Tutorial - Introdução ao VHDL
  2. Declaração de Procedimento - Exemplo de VHDL
  3. Como usamos o molibdênio?
  4. Como criar uma lista de strings em VHDL
  5. Como usar uma função impura em VHDL
  6. Como usar uma função em VHDL
  7. Como usar um procedimento em VHDL
  8. Como criar um temporizador em VHDL
  9. Como criar um processo cronometrado em VHDL
  10. Como usar um moedor de corte