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

Usando Funções Impuras em VHDL: Melhorando Legibilidade e Manutenibilidade de FSM

Em VHDL, uma função impura pode acessar ou modificar qualquer sinal dentro de seu escopo léxico, incluindo sinais que não estão listados como parâmetros. Esta capacidade dá à função efeitos colaterais — seu valor de retorno pode variar mesmo quando os mesmos argumentos são fornecidos, e ela pode alterar sinais externos que não são diretamente retornados.

Enquanto funções puras são confinadas a comportamento determinístico, funções impuras são inestimáveis para limpar lógica complexa de máquina de estado movendo tarefas repetitivas ou com efeitos colaterais para um único subprograma bem nomeado.

Nota: Funções impuras são melhor declaradas dentro de um processo. Declará-las no nível de arquitetura ou pacote não oferece vantagem, pois o escopo da função seria limitado aos sinais que já estão no escopo em tempo de compilação.

Quando e Por Que Usar Funções Impuras

Cenários típicos incluem:

Usar uma função impura mantém a lógica principal da máquina de estado legível enquanto preserva o comportamento com efeitos colaterais exigido pelo design.

Sintaxe

Para declarar uma função impura, simplesmente anteponha a palavra-chave impure antes de function:

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

Consulte o tutorial de funções para detalhes completos de sintaxe.

Exercício: Refatoração de FSM com Função Impura

Anteriormente, calculávamos atrasos de tempo usando uma função pura CounterVal e resetávamos manualmente o contador sempre que o temporizador expirava. A seguinte função impura consolida esta lógica:

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 -- Frequência de clock baixa para acelerar simulação 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 -- Instanciação do 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); -- Geração de clock Clk <= not Clk after ClockPeriod / 2; -- Sequência do testbench process is begin wait until rising_edge(Clk); wait until rising_edge(Clk); -- Liberar reset nRst <= '1'; wait; end process; end architecture; 

Módulo Semáforos (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 negativo 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 -- Função pura para calcular ciclos de clock para um tempo dado 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; -- Definição de estado do FSM type t_State is (NorthNext, StartNorth, North, StopNorth, WestNext, StartWest, West, StopWest); signal State : t_State; -- Contador para períodos de clock, até um minuto signal Counter : integer range 0 to ClockFrequencyHz * 60; begin process(Clk) is -- Função impura que lê e conduz 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 -- Reset estado e sinais State <= NorthNext; Counter <= 0; NorthRed <= '1'; NorthYellow <= '0'; NorthGreen <= '0'; WestRed <= '1'; WestYellow <= '0'; WestGreen <= '0'; else -- Saídas padrão 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; 

Visão da Forma de Onda

Após emitir o comando run 5 min no ModelSim, a simulação mostra comportamento idêntico ao FSM original — apenas o código se tornou mais limpo. A lógica de reset do contador agora está encapsulada dentro de CounterExpired, reduzindo duplicação e potenciais erros.

Usando Funções Impuras em VHDL: Melhorando Legibilidade e Manutenibilidade de FSM

Análise

A função impura transfere a comparação e reset do contador de múltiplos estados do FSM para um único subprograma. Esta mudança melhora a legibilidade: CounterExpired(Seconds => 5) transmite claramente a intenção, enquanto Counter = CounterVal(Seconds => 5) é mais verboso.

Embora funções impuras possam obscurecer efeitos colaterais se usadas em excesso, mantê-las locais a um processo garante que o código circundante permaneça determinístico e fácil de auditar. Na prática, elas são mais frequentemente empregadas em testbenches onde a correção é importante, mas o risco de bugs sutis é menor que em RTL sintetizável.

Usando Funções Impuras em VHDL: Melhorando Legibilidade e Manutenibilidade de FSM

Principais Conclusões

Prossiga para o próximo tutorial para explorar técnicas avançadas de VHDL.

VHDL

  1. Como o Molibdênio Molda a Indústria Moderna: Usos, Benefícios e Dinâmica de Fornecimento
  2. Criando Listas de Strings em VHDL: Boas Práticas e Exemplo
  3. Finalizando Graciosamente uma Simulação de Testbench VHDL
  4. Implementando um Controlador PWM em VHDL: Projeto, Simulação e Demo em FPGA
  5. Gerando Números Aleatórios em VHDL: De Uniforme a OSVVM
  6. Aproveitando Procedimentos In-Process para Design de FSM em VHDL Mais Limpo
  7. Dominando Funções VHDL: Guia Prático para Design Eficiente
  8. Usando realloc() em C: Sintaxe, Boas Práticas e Exemplo
  9. Dominando a Função free() em C: Guia Prático e Exemplo
  10. Dominando Técnicas de Retificadora de Ferramentas e Cortadores: Guia Prático