Significa que alguien no ha pensado mucho en cómo escribir sus máquinas de estado.
Esto no es un bucle, es un estado en una máquina de estados. Es de suponer que hay muchos estados que hacen cosas similares, con pequeñas variaciones, y es demasiado fácil perder de vista los detalles.
En cada ciclo de reloj, una máquina de estado ejecuta las acciones predeterminadas (cosas que haces en cada ciclo) y el código para el estado específico en el que se encuentra ahora. Por lo tanto, debe realizar un seguimiento de su estado y, si es necesario, cambiar a otro estado.
Así que una máquina de estado de un solo proceso típica se parece a
process(reset,clk) is -- and nothing else in the sensitivity list!
begin
if reset = '1' then
state <= Idle;
elsif rising_edge(clk) then
-- default actions
ID_START <= '0';
if Counter /= 0 then
Counter <= Counter - 1;
end if;
-- state machine proper
case state is
when WAIT_ST =>
-- state actions
...
when others =>
state <= Idle;
end case;
end if;
end process;
Esperamos que puedas encontrar esta estructura básica y cada uno de sus componentes en la tuya. (También hay máquinas de estado de 2 procesos y 3 procesos que traen problemas adicionales y ninguna ventaja real, los ignoraré).
Varias herramientas para mejorar una máquina de estado:
(1) Usa acciones predeterminadas.
Aquí, asumo que su señal ID_START
se establece en '0' en todos los estados excepto uno, probablemente etiquetado como START_ST
. Si ese es el caso, puedes agregar una acción predeterminada, ID_START <= '0';
como lo he hecho anteriormente. Luego, puede anular esta acción en uno (o pocos) estado (s) que necesitan cualquier otro valor, como
when START_ST =>
ID_START <= '1';
y puede eliminar todas las otras asignaciones de ID_START <= '0';
en otros estados. Un poco menos de desorden ...
Sin embargo, si ID_START
se establece en un estado, se borra en otro y no se asigna (mantiene su valor) en todos los demás estados, entonces no puede hacer esto. Así que usa el juicio, como siempre, al refactorizar.
(2) Use constantes con nombre en lugar de números mágicos.
¿Qué registro es la dirección X "01" y qué le hace X "00"?
CPU_CAN_DATA <= NOP;
CPU_CAN_ADDR <= Control_Reg;
(3) Use registros para agrupar señales asociadas.
(Puede ponerlos en un paquete y reutilizarlos donde lo necesite)
type CPU_CAN is record
WE : std_logic;
DATA : std_logic_vector(7 downto 0);
ADDR : unsigned(7 downto 0)
end record;
signal CPU_CAN_BUS : CPU_CAN;
Las direcciones NB suelen ser números naturales, por lo tanto, sin firmar. Los datos pueden ser cualquier cosa, no necesariamente un número, por lo tanto, std_logic_vector.
Y ahora puede asignar señales relacionadas en una sola declaración:
CPU_CAN_BUS <= ( WE=> '0', ADDR => Ctrl_Reg, DATA => NOP);
Probablemente puedas hacer lo mismo con CAN_CS, can_init_start, can_read_start.
(4) Use procedimientos y funciones para simplificar operaciones repetitivas.
(5) Use un contador de retardo programable.
Si WAIT_ST es el único estado que necesita un contador de retardo, el enfoque actual es correcto. Sin embargo, si necesita varios retrasos, pueden compartir un contador, que cuenta como una de las acciones predeterminadas anteriores. Como cuenta atrás, solo necesita compararlo con 0 (ahorrando un poco de hardware) y está programado cuando salta a un estado como WAIT_ST
if something then
Counter <= WAIT_FOR;
state_n <= WAIT_ST;
end if;
(6) detente antes de hacer las cosas más complicadas! es decir, si mux_sel
no se ajusta lógicamente a ninguno de los anteriores, déjelo en paz ...
El resultado final de estos cambios es algo así como
when WAIT_ST =>
-- CAN_CS, can_init_start, can_read_start, ID_START are defaults
mux_sel <= "00";
CPU_CAN_BUS <= ( WE=> '0', ADDR => Ctrl_Reg, DATA => NOP);
INST <= Frame_Type & Sub_Frame_Type;
if Counter = 0 then then
state_n <= IDLE_ST;
end if; -- else we stay in WAIT_ST
¿Mejor?