Ошибка в этом модуле обратного отсчета? (верилог)

Мой профессор смотрел на этот код добрых 10 минут, но не смог найти проблему. Итак, я надеюсь, что свежий взгляд увидит то, что мы оба упустили. Как всегда, я буду благодарен за любые подсказки, которые вы можете предоставить.

Контекст: модуль, который считает от FFF до 000, а затем повторяется.

Проблема: только самые низкие 2 отображают уменьшение, пропуская несколько чисел за раз, а затем возвращаясь к FF в, казалось бы, случайной точке.

Предположения: 1. Драйвер SevenSegment работает правильно. Он был проверен вручную и будет отображать присвоенное ему шестнадцатеричное число 2. Модуль ClockDivider работает по назначению. Обратный отсчет уменьшается каждую 1 секунду, как и должно (CLOCK_50 = 50 МГц)

Возможный совет: Verilog предупреждает, что «cd» является предполагаемой защелкой и сохраняет свое значение через один или несколько путей в блоке «always».

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
Как я вижу, основная проблема в том, что у вас есть coutсписок чувствительности, но он никогда не появляется в правой части любого из назначений под ним. Итак, что может сделать инструмент, кроме того, что вы хотите использовать coutв качестве тактового сигнала для блока.
@ThePhoton Спасибо. Таким образом, программа использовала младший значащий бит cout в качестве тактового входа. Рад, что ты поймал его.

Ответы (2)

Лично у меня всегда были проблемы с @(cout) , которые могут быть ненадежными.

Я бы всегда использовал всегда @(posedge CLOCK_50) . На мой взгляд, таким образом вам гарантирован должный результат...

РЕДАКТИРОВАТЬ: добавлен более четкий код для вышеуказанного предложения

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

cout должен изменяться только с положительным фронтом часов в теории (или в коде), но то, что на самом деле происходит, может быть другим. Ваш временной отчет расскажет вам о времени установки и резерве — и это может быть вашей проблемой. измените свою логику на все «синхронные», и я готов поспорить, что это сработает.

Кроме того, рекомендуется избавиться от предполагаемой защелки. все, что для этого потребуется, это оператор else:

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

РЕДАКТИРОВАТЬ: предлагаемый рабочий код

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
johnnymopo, спасибо за ответ. Пересмотренный код по-прежнему вызывал предполагаемую защелку (см. ThePhoton выше). И CLOCK_50 (50 МГц) были бы слишком быстрыми для обратного отсчета. Но благодаря вашему предложению использовать posege мне удалось во всем разобраться. Так что, где бы вы ни были в этом мире, я желаю вам удачи и еще раз спасибо за помощь случайному незнакомцу.
Просто для ясности: добавление else cd <= cd;по-прежнему создает защелку; все, что вы сделали, это сделали это явным, а не неявным. Вообще следует избегать комбинаторных защелок, созданных таким образом.
@dave tweed, как бы вы написали это, чтобы вообще избежать защелки, если вы хотите сделать синхронную логику с общим доменом часов? cd должно быть что-то.... Я спрашиваю, как я это делаю, и, кажется, работает хорошо, по крайней мере до 125 МГц, где я работал. Но у меня нет формального обучения vhdl.
@johnnymopo, я думаю, ваш ответ был бы более ясным, если бы вы включили то, always @(<xxx>)что рекомендуете.
Добавлено предложение кода

Благодаря ThePhoton и johhnymopo я смог найти решение. Решение состояло в том, чтобы ClockDivisor сам действовал как более медленные часы. Код становится:

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

В данном случае это часы с частотой 1 Гц. Затем можно запустить декремент обратного отсчета, используя положение этих более медленных часов:

//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
Рад, что это сработало. Я бы лично попытался заставить все это работать с одними часами. Я считаю, что это будет означать новые часы, а в более крупном дизайне это может затруднить синхронизацию. Не могли бы вы опубликовать точное предполагаемое предупреждение о защелке?
@johnnymopo Точное предупреждение было: «вывод защелки (ов) для переменной« cd », которая хранит свое предыдущее значение в одном или нескольких путях через конструкцию всегда».
Интересно, это происходит из-за того, что slowClock не является новым доменом часов в синтезе? если бы это было так, cdизменения происходили бы один раз в секунду, но по-прежнему основывались бы на тактовой частоте 50 МГц и, следовательно, все еще были бы защелками, но это кажется странным. Я по-прежнему рекомендую использовать общие часы для всей логики, когда это возможно.