Lección Teach
Lógica digital en la DE1-SoC (5/6): máquinas de estados finitos
El alumnado diseña una máquina de estados finitos para una salida tipo semáforo, la sintetiza y verifica transiciones en la DE1-SoC.
Resultados de aprendizaje
Explicar qué es una máquina de estados finitos en términos de estados, transiciones y salidas.
Distinguir máquinas Moore (salidas desde el estado) de máquinas Mealy (salidas desde estado e inputs).
Leer y modificar una FSM Verilog de dos o tres bloques: registro de estado, lógica de siguiente estado y lógica de salida.
Construir un controlador de semáforo y un detector de secuencia en la DE1-SoC real.
Explicar por qué se enclava una salida de pulso breve para que una cámara remota pueda verla.
Vista previa de la actividad del estudiante
Contenido de la actividad
Solo vista previa. En una sesión de clase, los estudiantes pueden completar respuestas y entregar su trabajo al docente.
Qué es una máquina de estados finitos
10 min
Ya construiste circuitos que recuerdan: un biestable guarda un bit, un registro guarda varios y un contador guarda su cuenta actual. Una máquina de estados finitos (FSM) organiza esa memoria en *situaciones con significado*. En cada instante la máquina está en exactamente uno de un conjunto pequeño y fijo de estados. Para un semáforo, los estados podrían ser VERDE, AMARILLO y ROJO. El número de estados es finito, y la máquina siempre está en uno y solo uno de ellos.
Una FSM se define por tres cosas:
- Estados: el conjunto finito de situaciones posibles. Un estado especial es el estado de reset, donde empieza la máquina.
- Transiciones: las reglas para pasar de un estado a otro. En cada flanco de reloj, la máquina mira su estado actual y sus entradas, y decide cuál será el siguiente estado. La transición VERDE -> AMARILLO significa "si estás en VERDE y se cumple la condición, en el próximo flanco irás a AMARILLO".
- Salidas: lo que la máquina controla en sus salidas (aquí, los LED) en cada situación.
Toda la máquina avanza con el reloj: en cada flanco puede cambiar a un nuevo estado según el estado actual y las entradas actuales, y mantiene ese estado hasta el siguiente flanco. Entre flancos no hace más que esperar: el mismo comportamiento de muestreo y retención que viste con los biestables, ahora usado para recorrer una secuencia de estados.
Moore frente a Mealy. Las FSM se escriben en dos estilos que solo difieren en *de dónde salen las salidas*:
- En una máquina Moore, las salidas dependen solo del estado actual. Si conoces el estado, conoces las salidas; las entradas no aparecen en la ecuación de salida. El semáforo es Moore: cuando el estado es ROJO, el LED rojo está encendido, punto.
- En una máquina Mealy, las salidas dependen del estado actual y de las entradas actuales. El mismo estado puede producir salidas distintas según lo que esté haciendo la entrada en ese instante. El detector de secuencia es Mealy: activa "detectado" en un estado concreto *solo si el bit entrante también tiene el valor correcto*.
Las salidas Moore son estables mientras permaneces en un estado. Las salidas Mealy pueden cambiar en cuanto cambia una entrada, incluso sin salir del estado; eso las hace rápidas, pero también potencialmente breves o sensibles a glitches, algo importante cuando observas por cámara.
Forma típica de una FSM en Verilog. Casi todas las FSM de este curso usan dos o tres bloques:
1. Un registro de estado: bloque con reloj (always @(posedge clock ...)) que guarda el estado actual y copia el siguiente estado en cada flanco. Es el único bloque con memoria.
2. Un bloque de siguiente estado: bloque combinacional (always @(*)) que calcula cuál debe ser el siguiente estado a partir del estado actual y las entradas. Debe incluir un default (un valor de respaldo para next_state y un default: en el case) para que *todos* los caminos asignen un valor; si falta, se puede inferir un latch no deseado.
3. Lógica de salida: assign o parte de un bloque combinacional que produce las salidas desde el estado (Moore) o desde estado y entradas (Mealy).
Los dos diseños de esta lección siguen exactamente esta forma: registro de estado con reloj, bloque always @(*) de siguiente estado con default y lógica de salida.
Una máquina expendedora recuerda cuánto dinero se ha insertado y entrega un producto cuando se alcanza el precio. Si la modelas como una FSM, qué representa mejor el estado?
Un circuito enciende un LED cuando está en el estado BUSY y la entrada go vale 1 en ese momento. Esa salida es Moore o Mealy? Explícalo en una frase.
Nota obligatoria: reset asíncrono en estas FSM
7 min
Antes de construir nada, hay un cambio deliberado respecto a lecciones anteriores.
En las Lecciones 2 y 3, tus biestables y registros usaban reset síncrono: el reset se comprobaba *dentro* del bloque con reloj, por ejemplo if (!KEY[0]) Q <= 0; dentro de always @(posedge CLOCK_50). Como esa prueba solo se evalúa en un flanco de reloj, un reset síncrono actúa solo en el siguiente flanco de subida. Si el reloj es lento, el reset espera.
Las FSM de esta lección usan un reset asíncrono activo en bajo. Mira la lista de sensibilidad del registro de estado:
always @(posedge slow_clk or negedge KEY[0]) begin
if (!KEY[0]) state <= GREEN; // asincrono: actua en cuanto KEY[0] baja
else state <= next_state;
end
Añadir or negedge KEY[0] significa que el bloque también despierta en el instante en que KEY[0] baja (cuando pulsas el botón), no solo en un flanco de slow_clk. Así, al pulsar KEY[0], la máquina fuerza su estado conocido de inmediato, sin esperar al reloj lento.
La diferencia, de forma clara:
- Reset síncrono (Lecciones 2-3): actúa solo en un flanco de reloj. Es limpio y predecible, pero con un reloj lento tienes que esperar al flanco.
- Reset asíncrono (Lecciones 5-6): actúa de inmediato, en cuanto se activa el reset, independientemente del reloj.
Por qué cambiar aquí? Estas FSM se mueven con un slow_clk dividido cuyos flancos están separados por segundos. Si el reset fuera síncrono, podrías pulsar KEY[0] y no ver nada durante más de un segundo hasta el siguiente flanco lento; justo cuando una máquina se atasca quieres una salida instantánea. Un reset asíncrono te da ese "volver al inicio" inmediato y fiable en la placa real. KEY es activo en bajo, así que negedge KEY[0] es el momento en que pulsas el botón y !KEY[0] es verdadero mientras lo mantienes pulsado.
Pulsas KEY[0] cuando falta casi un segundo para el siguiente flanco de slow_clk. Con el reset asíncrono de estas FSM, cuándo salta la máquina a su estado de reset? Cuándo habría saltado con un reset síncrono?
El registro de estado está escrito como always @(posedge slow_clk or negedge KEY[0]). Qué añade la parte or negedge KEY[0], y cómo se comportaría el reset si la borraras (dejando solo always @(posedge slow_clk))?
Ejercicio 3-A: semáforo (FSM Moore)
10 min
Tu primera FSM es un controlador de semáforo. Tiene tres estados y pasa por ellos en un ciclo fijo, manteniendo cada luz durante cierto número de ticks:
VERDE -> AMARILLO -> ROJO -> VERDE -> ...
Conexiones: LEDR[0] = verde, LEDR[1] = amarillo, LEDR[2] = rojo, y KEY[0] = reset (activo en bajo), que devuelve la máquina a VERDE. La máquina usa un slow_clk dividido: cada flanco de slow_clk es un tick, de unos 0,33 s con este divisor.
Es una máquina Moore. La lógica de salida al final es:
assign LEDR[0] = (state == GREEN);
assign LEDR[1] = (state == YELLOW);
assign LEDR[2] = (state == RED);
Cada LED es función solo del estado: no aparece ninguna entrada. Conocer el estado te dice exactamente qué luz está encendida. Esa es la propiedad que define una máquina Moore.
Dos registros distintos hacen dos trabajos distintos. Lee con cuidado el registro de estado, porque contiene *dos* memorias fáciles de confundir:
- state (un reg [1:0]) guarda qué luz está encendida ahora: GREEN, YELLOW o RED. Ese es el estado de la FSM.
- timer (un reg [2:0]) es un contador de permanencia que cuenta cuántos ticks quedan en la luz actual. Mientras timer sea mayor que cero, simplemente decrementa (timer <= timer - 1) y el estado no cambia. Solo cuando timer llega a 0 la máquina avanza a next_state y recarga timer para la nueva luz.
Así que state guarda *cuál* luz está encendida, y timer cuenta *cuánto tiempo* permanece. Son registros diferentes con objetivos diferentes; timer es lo que hace que cada luz dure varios ticks en vez de pasar en un solo tick.
Tiempos reales del código. Cuando la máquina entra en cada estado, recarga timer, y contar desde el valor cargado hasta 0 inclusive da el número de ticks:
- GREEN carga timer = 3 y cuenta 3, 2, 1, 0 -> 4 ticks (aprox. 1,33 s).
- YELLOW carga timer = 1 y cuenta 1, 0 -> 2 ticks (aprox. 0,67 s).
- RED carga timer = 3 -> 4 ticks (aprox. 1,33 s).
Un ciclo completo dura entonces 4 + 2 + 4 = 10 ticks, aproximadamente 10 x 0,33 s = 3,3 s.
El semáforo como máquina Moore de tres estados: GREEN -> YELLOW -> RED -> GREEN, con un temporizador que mantiene cada estado un número fijo de ticks (GREEN 4, YELLOW 2, RED 4; un tick dura unos 0,33 s). Cada estado enciende exactamente un LED, así que las salidas dependen solo del estado. KEY[0] resetea la máquina a GREEN.
Módulo completo. El divisor produce slow_clk; el registro de estado, con reset asíncrono, avanza la luz cuando expira el temporizador; el bloque always @(*) calcula la siguiente luz; y las tres líneas assign son la lógica de salida Moore.
// Lección 5 - Ejercicio 3-A: controlador de semáforo (FSM Moore)
// KEY[0]=reset (activo en bajo, vuelve a GREEN). LEDR[0]=verde, LEDR[1]=amarillo, LEDR[2]=rojo.
// Tiempos: GREEN = 4 ticks, YELLOW = 2 ticks, RED = 4 ticks (un tick = flanco slow_clk, ~0.33 s).
// Esta FSM usa reset ASINCRONO activo en bajo para que KEY[0] fuerce GREEN inmediatamente.
module leds_mirror(CLOCK_50, KEY, LEDR);
input CLOCK_50;
input [3:0] KEY; // KEY[0] = reset_n
output [9:0] LEDR;
localparam GREEN = 2'd0, YELLOW = 2'd1, RED = 2'd2;
localparam [24:0] DIV = 25'd16_666_666; // flanco slow_clk cada ~0.33 s
reg [24:0] div;
reg slow_clk;
always @(posedge CLOCK_50) begin
if (!KEY[0]) begin div <= 0; slow_clk <= 0; end
else if (div == DIV) begin div <= 0; slow_clk <= ~slow_clk; end
else div <= div + 1'b1;
end
reg [1:0] state, next_state;
reg [2:0] timer;
always @(posedge slow_clk or negedge KEY[0]) begin
if (!KEY[0]) begin state <= GREEN; timer <= 3'd3; end
else if (timer == 3'd0) begin
state <= next_state;
case (next_state)
GREEN: timer <= 3'd3; // 4 ticks (3,2,1,0)
YELLOW: timer <= 3'd1; // 2 ticks
RED: timer <= 3'd3; // 4 ticks
default: timer <= 3'd3;
endcase
end else timer <= timer - 1'b1;
end
always @(*) begin
case (state)
GREEN: next_state = YELLOW;
YELLOW: next_state = RED;
RED: next_state = GREEN;
default: next_state = GREEN;
endcase
end
assign LEDR[0] = (state == GREEN);
assign LEDR[1] = (state == YELLOW);
assign LEDR[2] = (state == RED);
assign LEDR[9:3] = 7'b0;
endmoduleLas salidas del semáforo son assign LEDR[0] = (state == GREEN); y similares. Si quisieras convertir una de esas salidas en Mealy en vez de Moore, qué tipo de término tendrías que añadir a su expresión que ahora no aparece?
Ejercicio 3-A en la placa: observar, modificar, ampliar
14 min
Ahora construye el semáforo en la DE1-SoC real, mide cada fase y modifícalo.
Abre el laboratorio Verilog de la DE1-SoC. El editor muestra
leds_mirror.v.Selecciona todo el contenido de
leds_mirror.vy reemplázalo por el módulo del semáforo. Mantén el nombreleds_mirrory conservainput CLOCK_50;.Pulsa Sintetizar. Si una guía tapa el botón, ciérrala o sáltala primero. Espera a que termine (aprox. 1-3 minutos). Los errores más comunes son olvidar
CLOCK_50en la lista de puertos o un punto y coma; corrige y vuelve a sintetizar. Continúa solo cuando el estado final diga 0 errores.Pulsa Enviar a la FPGA y espera a la placa y la cámara.
Observa el ciclo. Mira cómo
LEDR[0](verde),LEDR[1](amarillo) yLEDR[2](rojo) se turnan. Cuenta cuántos segundos o ticks dura cada luz y regístralo. Compara con el código: GREEN 4 ticks, YELLOW 2, RED 4.Pulsa reset. Mientras esté encendido YELLOW o RED, pulsa y suelta
KEY[0]. La máquina debe volver directamente a GREEN de inmediato. Estás viendo el reset asíncrono.
Observa el ciclo del semáforo en la cámara. Registra la duración observada de cada fase (en segundos o ticks de unos 0.33 s) y comparala con los ticks esperados del código: GREEN 4, YELLOW 2, RED 4.
| Fase (LED encendido) | Ticks esperados (código) | Duración observada (s o ticks) |
|---|---|---|
Sube tu evidencia. Espera la fase YELLOW, captura una imagen de la cámara cuando LEDR[1] esté encendido y LEDR[0] y LEDR[2] estén apagados, y adjúntala abajo.
Ahora haz dos cambios.
(Modificar) Cambia los tiempos de permanencia. Edita los valores de recarga de timer para que el ciclo sea GREEN = 6 ticks, YELLOW = 2 ticks, RED = 6 ticks. Recuerda que el temporizador cuenta desde el valor cargado hasta 0 inclusive, así que N ticks significa cargar N - 1: carga 5 para GREEN, 1 para YELLOW y 5 para RED (en el case dentro del registro de estado y también en la línea de reset si cambia el valor inicial de ese estado). Sintetiza, carga y confirma los nuevos tiempos en la cámara. Después calcula la nueva longitud total del ciclo en ticks.
(Añadir) Un estado de rojo intermitente. Añade un cuarto estado, FLASH_RED, al que la máquina entra después de RED. El ciclo será GREEN -> YELLOW -> RED -> FLASH_RED -> GREEN. En FLASH_RED, el LED rojo debe parpadear durante algunos ticks, por ejemplo 4, y después volver a GREEN. Pistas: amplía state/next_state para que puedan representar un cuarto valor, añade FLASH_RED a la lista localparam y al case de siguiente estado, dale una duración en el case del temporizador, y en FLASH_RED controla LEDR[2] con un bit que cambie en cada tick (por ejemplo, el bit bajo de timer) en vez de dejarlo fijo a 1. Sintetiza, carga y confirma que el LED rojo parpadea en la nueva fase antes de volver a verde.
Para hacer que YELLOW dure el doble, qué registro cambiarías (state o timer), dónde exactamente en el código, y qué registro dejarías completamente intacto?
Con tus tiempos modificados (GREEN = 6, YELLOW = 2, RED = 6 ticks), cuánto dura un ciclo completo en ticks? Muestra la suma.
Usando el código y lo que observaste, justifica en dos o tres frases que este semáforo es una máquina Moore. Identifica la lógica de salida y explica por qué los LED son función solo del estado, no de ninguna entrada.
Ejercicio 3-B: detector de la secuencia '1011' (FSM Mealy)
11 min
Tu segunda FSM observa una corriente de bits que llega uno por tick en SW[0] y enciende un LED cuando acaba de ver el patrón 1011. Es una máquina Mealy: activa "detectado" en un estado concreto *solo cuando el bit entrante también es correcto*, así que la salida depende de estado y entrada juntos.
Conexiones: SW[0] = bit serial de entrada, KEY[0] = reset (activo en bajo), LEDR[0] = detectado, y LEDR[4:1] = estado actual en formato one-hot (un LED por estado) para depurar. La máquina usa un slow_clk dividido cuyo flanco de subida, un tick, ocurre aproximadamente cada 1,33 s.
Estados. El detector recuerda cuánto del patrón 1011 ha visto hasta ahora:
- S0: nada coincide todavía (estado de reset).
- S1: el último bit fue 1 (coincide 1).
- S2: coincide 10.
- S3: coincide 101.
- S4: coincide el patrón completo 1011. Desde aquí la máquina todavía puede empezar una nueva detección, lo que permite detecciones solapadas.
En cada tick, el bloque de siguiente estado mira el estado actual y el bit de SW[0]. La salida detect se activa dentro de S3 solo cuando el bit entrante es 1, porque 101 seguido de 1 completa 1011. Esa es la salida Mealy: depende de estado y entrada.
Por qué enclavamos la salida: léelo con cuidado. La señal Mealy cruda detect está alta solo durante un tick. Con un reloj rápido sería invisible; incluso con este reloj lento, un destello de ~1,33 s es fácil de perder en una cámara remota si parpadeas o si el fotograma cae mal. Por eso este diseño no conecta detect directamente al LED. En su lugar enclava la detección: un registro separado detected_latch se pone a 1 cuando detect se dispara y permanece a 1 hasta que pulses reset. LEDR[0] muestra ese latch, así que una vez detectado 1011, el LED se enciende y *se queda encendido* hasta KEY[0]. Es una decisión deliberada para observación remota: convertimos un evento breve en una indicación estable.
Detector 1011 como máquina Mealy de cinco estados. Los estados S0..S4 indican cuánto del patrón se ha reconocido. La salida detect se activa desde estado S3 y entrada 1 juntos, por eso es Mealy. La regla de solapamiento mantiene la máquina lista para nuevas coincidencias. El pulso de un tick se enclava en LEDR[0] para que permanezca encendido hasta reset.
Módulo completo. Observa la forma de dos bloques: un always @(*) combinacional calcula next_state y la salida Mealy detect, y un always @(posedge slow_clk or negedge KEY[0]) guarda el estado y el latch, con reset asíncrono.
// Lección 5 - Ejercicio 3-B: detector de secuencia "1011" (FSM Mealy) con LED detectado enclavado
// SW[0]=bit serial. KEY[0]=reset (activo en bajo). LEDR[0]=detectado (ENCLAVADO hasta reset).
// LEDR[4:1]=estado actual (one-hot) para depurar.
// Para introducir un bit: coloca SW[0], espera un tick de slow_clk (~1.33 s), cambia SW[0], espera otra vez...
// El pulso Mealy "detectado" dura un tick, así que lo enclavamos en LEDR[0] para la cámara remota.
module leds_mirror(CLOCK_50, KEY, SW, LEDR);
input CLOCK_50;
input [3:0] KEY; // KEY[0] = reset_n
input [9:0] SW; // SW[0] = entrada serial
output [9:0] LEDR;
localparam [26:0] DIV = 27'd33_333_333;
reg [26:0] div;
reg slow_clk;
always @(posedge CLOCK_50) begin
if (!KEY[0]) begin div <= 0; slow_clk <= 0; end
else if (div == DIV) begin div <= 0; slow_clk <= ~slow_clk; end
else div <= div + 1'b1;
end
localparam S0=3'd0, S1=3'd1, S2=3'd2, S3=3'd3, S4=3'd4;
reg [2:0] state, next_state;
reg detect;
always @(*) begin
next_state = S0;
detect = 1'b0;
case (state)
S0: next_state = SW[0] ? S1 : S0;
S1: next_state = SW[0] ? S1 : S2; // unos extra mantienen "visto 1"
S2: next_state = SW[0] ? S3 : S0;
S3: if (SW[0]) begin next_state = S4; detect = 1'b1; end // 1011 completo (salida Mealy)
else next_state = S2; // solape: se ha visto "...10" otra vez
S4: next_state = SW[0] ? S1 : S0;
default: next_state = S0;
endcase
end
reg detected_latch;
always @(posedge slow_clk or negedge KEY[0]) begin
if (!KEY[0]) begin state <= S0; detected_latch <= 1'b0; end
else begin
state <= next_state;
if (detect) detected_latch <= 1'b1; // queda encendido hasta reset
end
end
assign LEDR[0] = detected_latch;
assign LEDR[4:1] = (state==S0) ? 4'b0001 :
(state==S1) ? 4'b0010 :
(state==S2) ? 4'b0100 :
(state==S3) ? 4'b1000 : 4'b0000; // S4 se muestra como 0000
assign LEDR[9:5] = 5'b0;
endmodulePodrías predecir exactamente cuándo se dispara detect mirando solo los LED de estado LEDR[4:1], *sin* conocer SW[0]? Usa tu respuesta para explicar por qué es una salida Mealy y no Moore.
Ejercicio 3-B en la placa: introducir bits, recuperar, modificar
14 min
Ahora construye el detector e introduce bits a mano. Cómo introducir un bit: coloca SW[0] con el valor del bit, espera un tick completo de slow_clk (unos 1,33 s) para que la máquina lo muestree en el siguiente flanco de subida, y después cambia SW[0] al siguiente bit y vuelve a esperar. Mira LEDR[4:1] para seguir el estado.
En
leds_mirror.v, reemplaza todo el contenido por el detector1011de arriba. Mantén el nombreleds_mirroryinput CLOCK_50;.Pulsa Sintetizar, espera a que termine correctamente y pulsa Enviar a la FPGA.
Resetea primero. Pulsa y suelta
KEY[0].LEDR[0](detectado) debe estar apagado yLEDR[4:1]debe mostrar S0 (0001).Introduce
1, 0, 1, 1. PonSW[0] = 1, espera ~1,33 s; ponSW[0] = 0, espera; ponSW[0] = 1, espera; ponSW[0] = 1, espera. Después del último1,LEDR[0]debe enclavarse encendido y quedarse así. Registra los LED de estado tras cada bit.Resetea, y después introduce
1, 0, 1, 0, 1, 1(un bit incorrecto en medio). Introduce cada bit igual. La máquina no debe dispararse falsamente con el bit malo, debe recuperarse y debe detectar el1011del final (LEDR[0]se enclava). Esto muestra que la FSM se recupera de un bit incorrecto en vez de quedarse atascada.Resetea cuando quieras empezar una secuencia nueva; reset es lo único que apaga el
LEDR[0]enclavado.
Introduce la secuencia 1,0,1,1, un bit por tick de slow_clk (aprox. 1.33 s cada uno). Después de cada bit, lee el estado en LEDR[4:1] (one-hot: 0001=S0, 0010=S1, 0100=S2, 1000=S3, 0000=S4) y si LEDR[0] se ha enclavado. La detección debe enclavarse tras el último 1.
| Bit introducido (SW[0]) | LEDR[4:1] observado (one-hot) | LEDR[0] detectado? (on/off) |
|---|---|---|
Sube tu evidencia. Después de introducir 1, 0, 1, 1, LEDR[0] se enclava encendido y permanece así hasta reset. Captura una imagen de la cámara mostrando LEDR[0] encendido y adjúntala abajo.
Ahora modifica el detector.
(Modificar) Detectar 101 en vez de 1011. Primero dibuja el nuevo diagrama de estados en papel: necesitas estados para "nada coincide", "coincide 1" y "coincide 10", y la salida detect debe dispararse cuando, estando en "coincide 10", el siguiente bit sea 1 (completando 101). Piensa en el solape: después de detectar 101, el último 1 puede ser el inicio del siguiente 101. Luego edita el Verilog: puedes quitar S4, redirigir transiciones para que detect se active en el paso 10-luego-1, y mantener el latch y la visualización one-hot. Sintetiza, carga y confirma que introducir 1, 0, 1 enclava LEDR[0].
La salida Mealy cruda detect está registrada (guardada en un biestable) o es combinacional (calculada directamente desde estado y entrada)? Qué problema temporal puede causar una salida Mealy combinacional, y cómo se conecta eso con que hayamos enclavado LEDR[0]?
Supón que conectaras el pulso crudo de un tick detect directamente a LEDR[0] en vez de enclavarlo. Con el reloj lento de ~1,33 s, qué verías probablemente en la cámara al detectar 1011, y por qué sería poco fiable capturarlo?
En el paso 5 introdujiste 1, 0, 1, 0, 1, 1 y aun así la máquina detectó 1011 al final. Explica brevemente cómo la FSM se recuperó del bit incorrecto sin quedarse atascada ni dispararse falsamente.
Qué construiste
4 min
Construiste dos máquinas de estados finitos en la DE1-SoC real: un semáforo Moore, cuyas salidas dependen solo del estado y que avanza GREEN -> YELLOW -> RED con un temporizador, y un detector Mealy de 1011, cuya salida detect depende del estado y de la entrada. Usaste la forma típica de FSM: registro de estado con reloj, bloque combinacional de siguiente estado con default y lógica de salida, además de un reset asíncrono activo en bajo que fuerza un estado conocido de inmediato. También viste por qué una salida de un tick se enclava para que una cámara remota pueda capturarla.
Qué secuencia coincide con lo que hiciste en cada ejercicio de esta lección?
En cuatro o cinco frases: explica por qué el semáforo es Moore y el detector es Mealy (cita la lógica de salida de cada uno), diferencia el registro state y el registro timer del semáforo, explica por qué LEDR[0] del detector se enclavó, y nombra un momento donde importó la polaridad activa en bajo de KEY o el reset asíncrono.