Estoy aprendiendo Verilog y en el proceso tratando de implementar algunos circuitos lógicos simples (y como todos, un SOC simple)
Implementé un UART simple, y funcionó bien durante la simulación y los bancos de prueba, pero después de la síntesis en un FPGA real (un ice40, usando Yosys), me encuentro con problemas en aproximadamente el 2% de los caracteres recibidos. / p>
Usando un analizador lógico, capturé la siguiente traza:
D2sonlosdatosdeRX,D3sonlosdatosdeTX(debenserunecodelosdatosrecibidos),D0sonlospulsosdemuestreodelUART,D1esunaseñalde"recepción de uart".
El problema fue que el UART estaba terminando antes el byte actual ha terminado.
Después de muchas pruebas, me di cuenta de que cuando la transición de Alto a Bajo en el bit de inicio estaba lo suficientemente cerca del reloj FPGA interno, el estado inicial en verilog no estaba configurado en el valor correcto.
El código de verilog era:
always @(posedge clk)
begin
// Main RX processing
if (!rx_active)
begin
if (!rx)
begin
rx_shift <= 0;
rx_state <= 19;
end
end
Cambié el código a:
always @(posedge clk)
begin
// Latches RX signal, prevents glitches
rx_latch <= rx;
// Main RX processing
if (!rx_active)
begin
if (!rx_latch)
begin
rx_shift <= 0;
rx_state <= 19;
end
end
Después de ese cambio, el UART funcionó siempre bien, esto significa que la lógica combinatoria que genera el estado de transición estaba configurando solo algunos de los bits en rx_state, ya que probablemente la señal del reloj no alcanzó todos los FF al mismo tiempo.
Mis preguntas son:
- ¿Es este comportamiento esperado en Verilog?
- ¿Cómo puedo probar si estas condiciones de carrera son posibles en mi código?