Como muchos de ustedes, el Manual de metodología de reutilización describe una máquina de estado en VHDL como un par de procesos: se ha explorado un proceso combinatorio para calcular el siguiente estado a partir de las entradas y el estado actual, y un proceso secuencial para actualizar ese estado. . Estado actual y próximo estado.
Como muchos de ustedes, el Manual de metodología de reutilización describe una máquina de estado en VHDL como un par de procesos: se ha explorado un proceso combinatorio para calcular el siguiente estado a partir de las entradas y el estado actual, y un proceso secuencial para actualizar ese estado. . Estado actual y próximo estado.
Aquí hay un ejemplo simple de su formato: una máquina de estado que simplemente incrementa una variable de estado de contador cada vez que se afirma su entrada de habilitación:
comb: process(cnt_r, en_i) begin if en_i = '1' then cnt_x <= cnt_r + 1; else cnt_x <= cnt_r; end if; end process; seq: process(clk_i) begin if rising_edge(clk_i) then cnt_r <= cnt_x; end if; end process;
A pesar de mi respeto por el formato de dos estados, hay algunas cosas que no me gustan.
Demasiadas señales:
Se deben definir dos señales para cada variable de estado. Uno para almacenar el estado actual y el otro para contener el siguiente valor de estado. Además, si su proceso de máquina de estado tiene una gran cantidad de indicadores, contadores y registros, tendrá el doble de señales.
Larga lista confidencial:
La señal de estado actual y todas las entradas deben incluirse en la lista de sensibilidad del proceso combinatorio. A medida que agrega y elimina señales, debe actualizar la lista de sensibilidad de los procesos combinatorios que las utilizan. De lo contrario, el sintetizador le avisará.
Pestillo inferido:
Si no asigna un valor a la siguiente señal de estado para cada camino posible a través del proceso combinatorio, obtiene un bloqueo inferido. Por ejemplo, la señal cnt_x se convierte en un pestillo si escribe incorrectamente un proceso combinatorio de la siguiente manera:
bad_comb: process(cnt_r, en_i) begin if en_i = '1' then cnt_x <= cnt_r + 1; end if; end process;
Cuando no se activa enable, cnt_x no tiene una asignación explícita, por lo que el sintetizador lo convierte en un pestillo. Por lo general, eso no es lo que desea, especialmente en lo que parece ser un proceso combinatorio. Para evitar bloqueos, suelo colocar las asignaciones predeterminadas para cada variable de estado en la parte superior del proceso combinatorio.
default_comb: process(cnt_r, en_i) begin cnt_x <= cnt_r; -- Default assignment keeps the boogy-man away! if en_i = '1' then cnt_x <= cnt_r + 1; end if; end process;
La asignación predeterminada deja el contador en su valor actual. Si se confirma la habilitación, esto se anula con el siguiente código. De cualquier manera, las variables de estado siempre tienen asignaciones explícitas, evitando los latches inferidos.
Demasiado código:
Dos procesos, el doble de señales, una larga lista de confidencialidad y asignaciones predeterminadas ayudan a aumentar la cantidad de código que necesita para escribir, depurar, mantener y documentar. Además, más código significa menos diseño general que se ajuste a la pantalla de su monitor, lo que dificulta “leer el diseño en su cabeza” y es más probable que introduzca errores.
Debido al problema de la “inflación de código”, en estos días escribimos máquinas de estado como procesos únicos.
process(clk_i) begin if rising_edge(clk_i) then if en_i = '1' then cnt_r <= cnt_r + 1; end if; end if; end process;
El uso del formato de un solo proceso ofrece las siguientes ventajas:
- Solo se requiere una señal por variable de estado.
- La lista de sensibilidad solo debe contener señales de reloj (a menos que también se requiera un reinicio asíncrono).
- No hay forma de crear un pestillo inferido.
- Cometerá menos errores porque tendrá mucho menos código.
- Si la variable de estado no se usa fuera del proceso, se puede definir dentro del proceso como una variable VHDL en lugar de una señal. También puede contener definiciones de tipo para variables de estado enumeradas. Esto proporciona una mejor encapsulación de la máquina de estado para el resto del diseño.
Nos referimos a estos como beneficios blandos porque solo lo ayudan a crear y comprender su máquina de estado y en realidad no mejoran su rendimiento (es decir, el tamaño del circuito sintetizado o la frecuencia máxima del reloj). Aún así, cuando se considera el costo del diseño y el tiempo de depuración, los beneficios suaves pagan beneficios reales.
Sin embargo, el formato de un estado causa problemas cuando las máquinas de estado se comunican entre sí. Digamos que la máquina de estado A quiere que la máquina de estado B realice alguna operación. B ve que su señal do_it se afirma en el borde 1 del reloj y comienza la operación. Si la operación de B toma solo un ciclo, B afirma la señal done_it después del flanco 2 del reloj. Sin embargo, A no puede reaccionar a la señal de finalización anulando la señal de solicitud hasta poco después del flanco 3 del reloj. , B ya ha visto do_it alto en el flanco 3 del reloj y ha iniciado otra operación (posiblemente indeseable).
Este problema se puede resolver mediante un apretón de manos como este:
- A eleva la señal do_it.
- B realiza la operación y genera la señal done_it.
- Al ver que se eleva la señal done_it, A baja la señal do_it.
- Cuando desaparece la señal do_it, B baja la señal done_it y luego comienza a escuchar otra solicitud.
Un protocolo de protocolo de enlace resuelve el problema de múltiples disparadores, pero ralentiza la comunicación entre las máquinas de estado. Además, si A realmente quiere que B realice una operación repetidamente, no solo debe afirmar y mantener la señal de solicitud, sino realizar un protocolo de enlace de varios ciclos para iniciar cada operación.
Una máquina de estado de dos procesos proporciona una mejor solución en este caso. El proceso combinatorio de A puede responder inmediatamente a la señal done_it de B y reducir su señal do_it antes del siguiente borde del reloj. A también puede seguir afirmando la señal do_it continuamente si desea que B realice múltiples operaciones.
Finalmente, ¿qué tipo de máquina de estado debe usar? Usamos máquinas de estado de 1 proceso cuando es posible, y tipos de 2 procesos cuando necesitamos más control para lograr el rendimiento. Sé que no se adhiere a las pautas respaldadas por RMM, pero soy ingeniero, por lo que soy libre de usar mi propio criterio y dejar que los robots manejen el enfoque del libro de cocina.
[Aside: If you want to see an even more heretical way to code state machines, check out the inferred state machines Martin Thompson talks about in his blog.]