Cómo crear una máquina de estados finitos en VHDL
Una máquina de estados finitos (FSM) es un mecanismo cuya salida depende no solo del estado actual de la entrada, sino también de valores pasados de entrada y salida.
Siempre que necesite crear algún tipo de algoritmo dependiente del tiempo en VHDL, o si se enfrenta al problema de implementar un programa de computadora en un FPGA, generalmente se puede resolver usando un FSM.
Las máquinas de estado en VHDL son procesos cronometrados cuyas salidas están controladas por el valor de una señal de estado. La señal de estado sirve como memoria interna de lo que sucedió en la iteración anterior.
Esta publicación de blog es parte de la serie Tutoriales básicos de VHDL.
Considere los estados de los semáforos en esta intersección:
Los semáforos tienen un número finito de estados, a los que les hemos dado nombres identificables. Nuestra máquina de estado de ejemplo no tiene entradas de control, la salida es el estado de las luces en las direcciones norte/sur y oeste/este. Es el tiempo transcurrido y el estado anterior de las salidas lo que hace avanzar esta máquina de estados.
Podemos representar estados en VHDL usando un tipo enumerado . Estos son tipos de datos como signed
o unsigned
, pero en lugar de números enteros, podemos proporcionar una lista personalizada de valores posibles. De hecho, si echa un vistazo al paquete std_logic_1164, encontrará que el std_ulogic
type no es más que un tipo enumerado con los valores 'U'
, 'X'
, '0'
, '1'
, 'Z'
, 'W'
, 'L'
, 'H'
y '-'
enumerados como valores de enumeración.
Una vez que tengamos nuestro tipo enumerado, podemos declarar una señal del nuevo tipo que se puede usar para realizar un seguimiento del estado actual del FSM.
La sintaxis para declarar una señal con un tipo enumerado en VHDL es:type <type_name> is (<state_name1>, <state_name2>, ...);
signal <signal_name> : <type_name>;
Usando la señal de estado, la máquina de estados finitos se puede implementar en un proceso con una declaración Case. La sentencia Case contiene una sentencia When para cada uno de los estados posibles, lo que hace que el programa tome caminos diferentes para cada estado. La declaración When también puede contener código que debe ejecutarse mientras se encuentra en ese estado en particular. Por lo general, el estado cambiará cuando se cumpla una condición predefinida.
Esta es una plantilla para una máquina de estado de un proceso:process(Clk) is
begin
if rising_edge(Clk) then
if nRst = '0' then
State <= <reset_state>;
else
case State is
when <state_name> =>
<set_outputs_for_this_state_here>
if <state_change_condition_is_true> then
State <= <next_state_name>;
end if;
...
end case;
end if;
end if;
end process;
Nota:
Hay varias formas de crear un FSM en VHDL. Lea acerca de los diferentes estilos aquí:
Máquina de estado de un proceso, dos procesos y tres procesos
Ejercicio
En este videotutorial aprenderemos a crear una máquina de estados finitos en VHDL:
El código final para la máquina de estado testbench :
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T20_FiniteStateMachineTb is end entity; architecture sim of T20_FiniteStateMachineTb 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.T20_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 la máquina de estado :
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T20_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 T20_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 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'; -- If 5 seconds have passed if Counter = ClockFrequencyHz * 5 -1 then Counter <= 0; State <= StartNorth; end if; -- Red and yellow in north/south direction when StartNorth => NorthRed <= '1'; NorthYellow <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = ClockFrequencyHz * 5 -1 then Counter <= 0; State <= North; end if; -- Green in north/south direction when North => NorthGreen <= '1'; WestRed <= '1'; -- If 1 minute has passed if Counter = ClockFrequencyHz * 60 -1 then Counter <= 0; State <= StopNorth; end if; -- Yellow in north/south direction when StopNorth => NorthYellow <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = ClockFrequencyHz * 5 -1 then Counter <= 0; State <= WestNext; end if; -- Red in all directions when WestNext => NorthRed <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = ClockFrequencyHz * 5 -1 then Counter <= 0; State <= StartWest; end if; -- Red and yellow in west/east direction when StartWest => NorthRed <= '1'; WestRed <= '1'; WestYellow <= '1'; -- If 5 seconds have passed if Counter = ClockFrequencyHz * 5 -1 then Counter <= 0; State <= West; end if; -- Green in west/east direction when West => NorthRed <= '1'; WestGreen <= '1'; -- If 1 minute has passed if Counter = ClockFrequencyHz * 60 -1 then Counter <= 0; State <= StopWest; end if; -- Yellow in west/east direction when StopWest => NorthRed <= '1'; WestYellow <= '1'; -- If 5 seconds have passed if Counter = ClockFrequencyHz * 5 -1 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:
Análisis
Declaramos un tipo enumerado con los ocho estados diferentes de nuestros semáforos. Luego, declaramos un state
señal de este nuevo tipo que creamos. Esto significa que la señal solo puede tener uno de los ocho valores de estado nombrados y ningún otro valor.
El FSM se implementó utilizando una declaración de caso dentro de un proceso cronometrado. En cada flanco ascendente del reloj, el proceso se despierta y el state
se evalúa la señal. El código dentro de exactamente uno de los when
Las opciones (ramas) pueden ejecutarse, dependiendo del estado actual.
En nuestro código, es el valor del Counter
Señal que desencadena cambios de estado. Cuando el Contador alcanza un valor predefinido, que representa 5 segundos o 1 minuto, se asigna una nueva codificación de estado al State
señal. Luego, cuando el proceso se despierta en el siguiente flanco ascendente del reloj después de que se haya actualizado el valor del estado, el FSM se encuentra en un estado diferente.
Tenga en cuenta que no estamos asignando '0'
a cualquier señal en cualquiera de los when
opciones Esto se debe a que le hemos dado a todas las señales de salida un valor predeterminado de '0'
al inicio del proceso. Puede recordar de un tutorial anterior que es el último valor que se asigna a una señal que se vuelve efectivo. Las asignaciones de señales se hacen efectivas solo después de que finaliza el proceso. Si asignamos '0'
a la señal al comienzo del proceso, y luego '1'
en uno de los when
opciones, la señal obtendrá el valor '1'
.
Podemos ver en la forma de onda que el State
la señal recorre los ocho estados. Los estados verdes fijos duran un minuto, por lo que la imagen de la forma de onda se ha cortado en el North
y West
estados.
Para llevar
- Los algoritmos generalmente se implementan como máquinas de estado finito (FSM)
- Se puede implementar una FSM mediante el uso de una declaración de caso en un proceso cronometrado
- Los estados FSM se pueden implementar en un tipo enumerado
Ir al siguiente tutorial »
VHDL
- Máquina de estado finito
- Cómo garantizar el mejor rendimiento de la máquina de estado Qt
- Cómo crear una lista de cadenas en VHDL
- Cómo crear un banco de pruebas controlado por Tcl para un módulo de bloqueo de código VHDL
- Cómo detener la simulación en un banco de pruebas VHDL
- Cómo crear un controlador PWM en VHDL
- Cómo generar números aleatorios en VHDL
- Cómo crear un FIFO de búfer de anillo en VHDL
- Cómo crear un banco de pruebas de autocomprobación
- Cómo crear una lista enlazada en VHDL
- ¿Cómo la máquina láser CNC OMNI crea regalos de Navidad personalizados?