Verilog - присвоение значения reg дважды в одном блоке всегда - PullRequest
0 голосов
/ 28 января 2020

Я работаю над счетчиком, который подсчитывает количество бит во входном битовом потоке переменной ширины. Код выглядит следующим образом:

module counter(i_clk, i_arst, i_data, o_done, o_cnt);

    // ---------------------------------------- SIGNALS ---------------------------------------- //
    // Parameters   
    parameter                   OUT_WIDTH;      // Width of the output in bits
    parameter                   IN_WIDTH;       // Number of bits in an input bit stream

    // Input
    input   wire                i_clk;          // Clock
    input   wire                i_arst;         // Active high asynchronous reset
    input   wire                i_data;         // Input data

    // Outputs
    output  reg                 o_done;         // Output done bit
    output  reg[OUT_WIDTH-1:0]  o_cnt;          // WIDTH-bit output counter

    // Internal signals
    integer                     index;          // Bit index for the input
    reg[OUT_WIDTH-1:0]          r_cnt_tmp;      // Temporary counter for assignment


    // ---------------------------------------- LOGIC ---------------------------------------- //
    // Combinational logic
    always @(*) begin
        o_cnt = r_cnt_tmp;
    end


    // Sequential logic
    always @(posedge i_clk or posedge i_arst) begin

        // Reset the counter
        if(i_arst) begin
            r_cnt_tmp   <= {OUT_WIDTH{1'b0}};
            o_done      <= 1'b0;                
            index       <= 0;
        end
        else begin
            // When a new bit stream arrives
            if(index == 0) begin
                r_cnt_tmp   <= {OUT_WIDTH{1'b0}};       // Reset the output data
                o_done      <= 1'b0;                    // Data is now invalid because it is a new bit stream
                                                        // It only happens after a reset or a valid data output 
            end

            // If bit is set
            if(i_data == 1'b1) begin                
                r_cnt_tmp <= r_cnt_tmp + 1; // Count up
            end

            index <= index + 1;             // Increment the index

            if(index == IN_WIDTH) begin     // The input has been completely looped over
                o_done  <= 1'b1;            // Data is now valid for the output
                index   <= 0;               // Reset the index
            end
        end
    end
endmodule

Как только я закончу с текущим битовым потоком, я установлю сигнал o_done, чтобы сообщить, что выходные данные действительны, и я сбросил индекс переменной, чтобы начать с нового битовый поток. Затем на следующем фронте синхронизации я сбрасываю сигнал o_done и значение счетчика и снова начинаю считать.

У меня проблема в том, что мой счетчик не всегда сбрасывается. Поскольку сигнал принимает свое значение только в конце блока, если первый бит потока битов высокий, он не сбрасывается.

Я хотел бы сбросить и снова начать подсчет в том же тактовый цикл, потому что я не хочу больше задержки и у меня есть непрерывные битовые потоки, поступающие на вход

Есть ли решение, чтобы избежать этой проблемы?

Спасибо за вашу помощь.

1 Ответ

1 голос
/ 28 января 2020

Я думаю, что ваша проблема заключается в следующих утверждениях:

           // When a new bit stream arrives
            if(index == 0) begin
                r_cnt_tmp   <= {OUT_WIDTH{1'b0}};       // Reset the output data
                o_done      <= 1'b0;                    // Data is now invalid because it is a new bit stream
                                                        // It only happens after a reset or a valid data output 
            end

            // If bit is set
            if(i_data == 1'b1) begin                
                r_cnt_tmp <= r_cnt_tmp + 1; // Count up
            end

Возможно, у вас есть index == 0 и i_data == 1. Теперь запланировано, что значение r_cnt_tmp станет равным 0 после выполнения блока, поскольку там используется неблокирующее назначение.

Следующий блок попытается увеличить значение, но он будет использовать старое значение счетчика и успешно переопределит ранее запланированное значение сброса. Скорее всего, это не будет «1» или «0».

Один из способов переписать это следующий. В этом примере начальное значение счетчика станет '1', если i_data равен '1', а индекс равен 0.

           // When a new bit stream arrives
            if(index == 0) begin
                r_cnt_tmp   <= i_data;       // Reset the output data to '0' or '1' depending on i_data
                o_done      <= 1'b0;                    // Data is now invalid because it is a new bit stream
                                                        // It only happens after a reset or a valid data output 
            end
            else if(i_data == 1'b1) begin   // you definitely need this 'else'             
                r_cnt_tmp <= r_cnt_tmp + 1; // Count up
            end

Извините, я не проверял его, в частности, когда i_data равен 'x' ,

Возможно, для начального условия могут потребоваться другие требования. Таким образом, вы можете написать это по-своему.

...