¿Por qué mi contador de segundos está en el comportamiento de valores de salto de verilog?

Estoy implementando un contador de segundos en la placa educativa Altera DE-1 alimentado por el antiguo Cyclone 2 FPGA. Mi plan es hacer un 'reductor de reloj' que tome el reloj integrado de 50 MHz y produzca una señal de reloj de 1 Hz (denominada 'pulso'), que luego se usará para impulsar el contador normal. El módulo down clocker es el siguiente:

module downClockerTest(pulse, clk, reset);
    output reg pulse;
    reg [25:0] count;
    input clk, reset;

    always @(posedge clk or negedge reset) begin
        if(~reset) begin
            count <= 26'h0;
            pulse <= 1'd0;
        end
        else if(count == 26'd49999999)
            count <= 26'd0;
        else begin
            count <= count + 26'h1;
            pulse <= (count > 26'd24999999);
        end
    end
endmodule

Con el siguiente RTL:RTL del contador descendente con un registro al final

Observe que el 'pulso' de salida está registrado. Este diseño funciona bien; el contador cuenta como debería. Sin embargo, si trato de eliminar el registro al final intentando impulsar la salida de 'pulso' con una sola declaración de asignación, el contador de segundos parece comenzar a saltar 1 y luego 4 en 1 segundo, lo que indica 5 pos-bordes desde el down-clocker, donde solo debería haber uno.

El down-clocker ligeramente modificado es el siguiente:

module downClockerTest(pulse, clk, reset);
    output pulse;
    reg [25:0] count;
    input clk, reset;

    assign pulse = (count > 26'd24999999);  // The counter seems to increment by 1 and then 4 in quick succession (1 second).

    always @(posedge clk or negedge reset) begin
        if(~reset) begin
            count <= 26'h0;
        end
        else if(count == 26'd49999999)
            count <= 26'd0;
        else begin
            count <= count + 26'h1;
        end
    end
endmodule

El RTL modificado sin el registro es:RTL de down-clocker sin registro

¿Por qué el down-clocker solo funciona bien cuando hay un registro al final? ¿El registro está realizando algún tipo de 'antirrebote'? ¿El 'rebote' ocurre también en circuitos de conmutación no mecánicos? ¿Cuál podría ser la posible razón desde un punto de vista electrónico?

Puede ser prudente agregar que el análisis de tiempo de TimeQuest falla en ambos casos con una advertencia crítica: "No se cumplen los requisitos de tiempo". Pero aún así, uno funciona donde otro no.

Supongo que este extraño comportamiento tiene que ver con una condición de carrera causada cuando una secuencia de bits cambia drásticamente sus 1 y 0 después de un incremento. Por ejemplo, 110111 se convierte en 111000 después de incrementarse en 1. Dado que no se sabe cuál de los flip-flops, que almacena las posiciones de bits individuales en la secuencia, actualizará sus valores primero, el número (léase: secuencia de bits) puede fluctuar por un instante antes de alcanzar un valor estable. Puede haber números (secuencias de bits) que, mientras tienden hacia sus valores estables, fluctúan a través del valor que se compara (24999999, en nuestro caso) y hacen que el comparador emita Logic-HI. Un registro al final sin duda resolvería este problema. Sin embargo, todo esto son conjeturas, con bases en poca experimentación. Cualquier opinión sabida será bienvenida.

Respuestas (3)

Cuando utilice la asignación asíncrona para el pulso, verá la influencia de retrasos desiguales en el comparador como fallas en la salida. El registro de la señal de comparación oculta esto, lo que permite que todo se estabilice antes del siguiente borde del reloj. (Esto está garantizado por la herramienta place-route si dice que la ruta cumple con el tiempo).

Si, en el futuro, tiene alguna razón por la que necesita decodificar asíncronamente un conjunto de salidas de contador, y desea que esté libre de fallas , hay una respuesta: use el conteo de código Gray . Los códigos grises garantizan que solo una señal a la vez cambia de estado, por lo que evita la condición de carrera de múltiples rutas que conduce a la falla.

Sí, hay "rebote", pero en este contexto, los llamamos "problemas técnicos". El comparador (count > 26'd24999999)representa una cantidad bastante grande de lógica combinatoria, y no hay posibilidad de que todas las rutas a través de esta lógica (y la interconexión FPGA asociada) tengan exactamente el mismo retraso. Por lo tanto, la salida pulseexperimentará una o más fallas antes de que se estabilice.

Si está utilizando pulsedirectamente como un reloj para otra lógica, esa lógica experimentará flancos de reloj adicionales.

Los comparadores son una lógica relativamente compleja, con largas cadenas de transporte.

Yo recomendaría algo como esto:

module downClockerTest(pulse, clk, reset);
    output reg pulse;
    reg [24:0] count;
    input clk, reset;

    always @(posedge clk or negedge reset) begin
        if(~reset) begin
            count <= 25'h0;
            pulse <= 1'd0;
        end
        else if(count == 25'd24999999) begin
            count <= 25'd0;
            pulse <= ~pulse;
        end
        else begin
            count <= count + 1;
        end
    end
endmodule

En lugar de contar hasta 50 000 000 y usar un comparador para establecer el pulsevalor, solo cuento hasta 25 000 000 y alterno pulsecada vez que llego al conteo completo.

Esta es ciertamente una solución mejor (y mi muy inicial). Sin embargo, la intención de mi pregunta es averiguar "por qué" ocurre el problema, no cuál es la mejor solución.
@Kraken, creo que Dave dio una muy buena respuesta a esa parte de la pregunta.