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

Aprovechando procedimientos en-proceso para diseños FSM más limpios en VHDL

En VHDL, un procedimiento puede conducir señales externas siempre que la señal permanezca en su ámbito. Mientras que un procedimiento declarado en una arquitectura no tiene acceso a señales externas —porque esas señales no son visibles en tiempo de compilación— un procedimiento definido dentro de un proceso puede leer y escribir libremente cualquier señal que el proceso pueda ver.

Usar procedimientos en-proceso es una forma efectiva de desenredar lógica repetitiva en máquinas de estados o protocolos complejos. Al encapsular acciones comunes —como una transición de estado temporizada— dentro de un procedimiento, reduce código boilerplate, mejora la legibilidad y hace que la intención de cada paso sea cristalina.

Por ejemplo, en un controlador de semáforo, renombrar operaciones a ChangeState(ToState, Minutes, Seconds) dice al lector exactamente qué está haciendo el código sin sumergirse en las asignaciones de variables subyacentes.

Ejercicio práctico

En un tutorial anterior, usamos una función impura para conducir una señal Counter y determinar cambios de estado. Sin embargo, no pudimos mover la asignación de State a esa función porque VHDL requiere un valor de retorno para cada llamada a función. En su lugar, un procedimiento —desprovisto de valor de retorno— encaja perfectamente para este caso de uso.

A continuación se muestra el testbench y módulo completos que demuestran una FSM de semáforo conducida por un procedimiento en-proceso.

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
  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
  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
    );
  Clk <= not Clk after ClockPeriod / 2;
  
  process is
  begin
    wait until rising_edge(Clk);
    wait until rising_edge(Clk);
    nRst <= '1';
    wait;
  end process;
end architecture;

Módulo de semáforo

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;
    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
  type t_State is (NorthNext, StartNorth, North, StopNorth, WestNext, StartWest, West, StopWest);
  signal State : t_State;
  signal Counter : integer range 0 to ClockFrequencyHz * 60;
  
begin
  process(Clk) is
    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
        State      <= NorthNext;
        Counter    <= 0;
        NorthRed   <= '1';
        NorthYellow<= '0';
        NorthGreen <= '0';
        WestRed    <= '1';
        WestYellow <= '0';
        WestGreen  <= '0';
      else
        NorthRed   <= '0';
        NorthYellow<= '0';
        NorthGreen <= '0';
        WestRed    <= '0';
        WestYellow <= '0';
        WestGreen  <= '0';
        Counter    <= Counter + 1;
        
        case State is
          when NorthNext =>
            NorthRed <= '1';
            WestRed  <= '1';
            ChangeState(StartNorth, Seconds => 5);
          when StartNorth =>
            NorthRed   <= '1';
            NorthYellow<= '1';
            WestRed    <= '1';
            ChangeState(North, Seconds => 5);
          when North =>
            NorthGreen <= '1';
            WestRed    <= '1';
            ChangeState(StopNorth, Minutes => 1);
          when StopNorth =>
            NorthYellow<= '1';
            WestRed    <= '1';
            ChangeState(WestNext, Seconds => 5);
          when WestNext =>
            NorthRed <= '1';
            WestRed  <= '1';
            ChangeState(StartWest, Seconds => 5);
          when StartWest =>
            NorthRed   <= '1';
            WestRed    <= '1';
            WestYellow <= '1';
            ChangeState(West, Seconds => 5);
          when West =>
            NorthRed  <= '1';
            WestGreen <= '1';
            ChangeState(StopWest, Minutes => 1);
          when StopWest =>
            NorthRed   <= '1';
            WestYellow <= '1';
            ChangeState(NorthNext, Seconds => 5);
        end case;
      end if;
    end if;
  end process;
end architecture;

Forma de onda

La simulación permanece idéntica a la FSM original —solo el código se ha vuelto más mantenible y fácil de entender.

Análisis

Al mover la lógica de temporización y cambio de estado a un solo procedimiento, preservamos el comportamiento del módulo mientras mejoramos dramáticamente la legibilidad. El procedimiento asegura una implementación consistente donde sea que se llame.

Conclusiones clave

VHDL

  1. Dominando las Técnicas de Afiladora de Herramientas: Guía Práctica
  2. Cómo el molibdeno moldea la industria moderna: usos, beneficios y dinámica de suministro
  3. Introducción a VHDL: Construyendo tu primera compuerta AND
  4. Ejemplo de procedimiento VHDL: Incrementando un vector Standard Logic
  5. Creación de listas de cadenas en VHDL: Buenas prácticas y ejemplo
  6. Uso de funciones impuras en VHDL: Mejorando legibilidad y mantenibilidad de FSM
  7. Dominando funciones VHDL: Guía práctica para diseño eficiente
  8. Uso de procedimientos en VHDL: Simplifique su diseño con código reutilizable
  9. Construya un temporizador fiable en VHDL: Contar ciclos de reloj hasta horas
  10. Construcción de un proceso activado por reloj en VHDL: Guía práctica
  11. Dominando la instanciación con port map en VHDL: Guía práctica