¿Error en este módulo de cuenta atrás? (Verilog)

3

Mi profesor miró este código durante unos buenos 10 minutos, pero no pudo encontrar el problema. Entonces, espero que un par de ojos nuevos vean algo que ambos extrañamos. Como siempre, estaré agradecido por cualquier sugerencia que pueda proporcionar.

Contexto: un módulo que cuenta de FFF a 000 y luego se repite.

Problema: Solo las 2 más bajas muestran una disminución, saltándose varios números a la vez y luego saltan nuevamente a FF en un punto aparentemente aleatorio.

Supuestos: 1. El controlador SevenSegment funciona correctamente. Se ha verificado manualmente y mostrará el número hexadecimal que se le ha dado. 2. El módulo ClockDivider funciona según lo previsto. La cuenta regresiva disminuye cada 1 segundo como debería (CLOCK_50 = 50 MHz)

Posible sugerencia: Verilog advierte que "cd" es un retén inferido y retiene su valor a través de una o más rutas en el bloque "siempre"

module ClockDivider( input CLOCK_50, output reg[ 31:0] count );
parameter clockDivisor = 50_000_000;

always @( posedge CLOCK_50 )
    if ( count == 0)
        count <= clockDivisor;
        else
            count <= count - 1;
endmodule


module Test (

    //////////// CLOCK //////////
    input                       CLOCK_50,
    //////////// SEG7 //////////
    output           [6:0]      HEX0,
    output           [6:0]      HEX1,
    output           [6:0]      HEX2
);

//ClockDivider Output
wire                [31:0]          cout;

reg                 [11:0]            cd;

ClockDivider a( CLOCK_50, cout);

always @(cout)
begin

if (cout == 32'h0)
        if (cd == 12'h0)
                cd <= 12'hFFF;
        else
                cd <= (cd - 12'h001);

end

SevenSegment    C2( cd[11:8],  1'b0, HEX2 ); 
SevenSegment    C1( cd[7:4],   1'b0, HEX1 );
SevenSegment    C0( cd[3:0],   1'b0, HEX0 );

endmodule
    
pregunta Meridian

2 respuestas

4

Personalmente, he tenido problemas con always @ (cout) que pueden ser erróneos.

Siempre usaría siempre @ (posedge CLOCK_50) . En mi opinión, tienes garantizados resultados adecuados de esta manera ...

EDITAR: se agregó un código más claro para la sugerencia anterior

always @(cout) -> always @(posedge CLOCK_50)

cout debería cambiar solo con la ventaja positiva del reloj en teoría (o código), pero lo que realmente está sucediendo puede ser diferente. Su informe de tiempo le informará sobre el tiempo de instalación y la holgura, y este puede ser su problema. cambia tu lógica a "sincrónica" y te apuesto a que funciona.

también, deshágase del cierre inferido como buena práctica. todo lo que tomaría es una declaración else:

if (cout == 32'h0)
    if (cd == 12'h0)
        cd <= 12'hFFF;
    else
        cd <= (cd - 12'h001);
else
    cd <= cd;

EDITAR: código de trabajo sugerido

module ClockDivider(input CLOCK_50, 
                    output reg[ 0:0] en 
                   );
    parameter clockDivisor = 50_000_000;
    reg [31:0] i;

    always @( posedge CLOCK_50 ) begin
            if ( i == clockDivisor ) begin
                    en <= 1;
                    i <= 0;
            end
            else begin
                    en <= 0;
                    i <= i + 32'b1;
            end
    end
endmodule

//1Hz clock output
wire                [0:0]           en;
//Holds the countdown value FFF-000
reg                 [11:0]              cd;

ClockDivider CLOCK_1Hz( CLOCK_50, en);

always @(posedge CLOCK_50)
    if (en) begin
        if (cd == 12'h0)
            cd <= 12'hFFF;
        else
            cd <= (cd - 12'h001);
    end 
    else 
        cd <= cd;
end
    
respondido por el johnnymopo
2

Gracias a ThePhoton y johhnymopo pude encontrar la solución. La solución fue hacer que ClockDivisor actuara como un reloj más lento. El código se convierte en:

module ClockDivider( input CLOCK_50, output reg[ 0:0] count );
    parameter clockDivisor = 50_000_000;
    reg [31:0] i;

always @( posedge CLOCK_50 )
    begin
            i <= i + 32'b1;
            if ( i == clockDivisor )
                    begin
                    count <= 1;
                    i <= 0;
                    end
            else
                    count <= 0;
    end

endmodule

En este caso, este es un reloj de 1Hz. El decremento de la cuenta regresiva se puede activar mediante el posicionamiento de ese reloj más lento:

//1Hz clock output
wire                [0:0]           slowClock;

//Holds the countdown value FFF-000
reg                 [11:0]              cd;

ClockDivider CLOCK_1Hz( CLOCK_50, slowClock);

always @(posedge slowClock)
begin

if (cd == 12'h0)
    cd <= 12'hFFF;
else
    cd <= (cd - 12'h001);

end
    
respondido por el Meridian

Lea otras preguntas en las etiquetas