Минимальная битовая ширина Verilog - PullRequest
0 голосов
/ 21 июня 2020

Я ищу простой способ объявить типы Verilog / SystemVerilog с параметризованной разрядностью. Это то, что у меня есть до сих пор, и я задавался вопросом, есть ли лучший способ сделать это. Я просмотрел системные функции в LRM 1800-2009 и -2017. Ближайшее, что я смог найти, - это $bits, но мне бы хотелось что-то вроде $minbits. Я что-то упустил?

В VHDL для этого нужно просто указать range:

    signal counter: integer range 0 to MAX_COUNT;

... и компилятор вычислит минимальную ширину в битах для хранения этого range.

Для значений параметров 20 нс и 125 мс счетчик должен быть 23 бита с MAX_COUNT равным 6,250,000.

module Debounce
#(
    parameter CLOCK_PERIOD_ns    = 20,  // nanoseconds.
    parameter DEBOUNCE_PERIOD_ms = 125  // milliseconds.
)
. . .
    function int MinBitWidth([1023:0] value);
        begin
            for (MinBitWidth = 0; value > 0; MinBitWidth = MinBitWidth + 1)
            begin
                value = value >> 1;
            end
        end
    endfunction

    localparam MAX_COUNT_32BITS = DEBOUNCE_PERIOD_ms * 1_000_000 / CLOCK_PERIOD_ns;  // Default type of 32-bits.

    localparam COUNTER_BITS = MinBitWidth(MAX_COUNT_32BITS);  // Calculate actual bit width needed.
    typedef logic [COUNTER_BITS - 1 : 0] TCounter;
    localparam TCounter MAX_COUNT = MAX_COUNT_32BITS;  // Assign to a type of the actual bit width (truncation warning from Quartus).
    localparam TCounter ONE = 1;
    TCounter counter;
. . .
    always @(posedge clock)
    begin
. . .
        if (counter == MAX_COUNT_32BITS - 1)  // Synthesises a 32-bit comparer no matter how many bits are needed with unused bits tied to ground.
. . .
        if (counter == MAX_COUNT - ONE)       // Synthesises a 23-bit comparer as expected.
. . .
            counter <= counter + 1;           // Synthesises a 23-bit counter as expected.
. . .
            counter <= counter + ONE;         // Synthesises a 23-bit counter as expected.

Неправильный алгоритм

Я рассмотрел $clog2, что является правильным способом получения адреса ширины шины из ОЗУ глубины параметра . Однако это не то же самое, что минимальная разрядность значения. Позвольте мне объяснить ...

Рассмотрим значение 4, которое равно 100 base-2 (3 бита).

Алгоритм $clog2 вычисляет значение 2, что неверно. Это должно быть 3. Причина этого просчета заключается в том, что $clog2 вычитает 1 из значения перед тем, как начинает вычислять количество битов, т.е. 4 становится 3, затем вычисляется минимальная разрядность значения 3, давая 2 бита. . Хотя это математически правильно для потолка бревенчатой ​​базы-2 , это не битовая ширина оригинала значение.

Вот алгоритм clogb2 из LRM:

function integer clogb2;
    input [31:0] value;
    begin
        value = value - 1;  // GOTCHA!
        for (clogb2 = 0; value > 0; clogb2 = clogb2 + 1) begin
            value = value >> 1;
        end
    end
endfunction

Правильный алгоритм

Правильный алгоритм - вычислить минимальную разрядность значение исходное , которое является алгоритмом, указанным @ jonathan-mayer в его первом ответе перед его редактированием .

Вот правильный алгоритм как функция:

function integer MinBitWidth;
    input [1023:0] value;
    begin
        for (MinBitWidth = 0; value > 0; MinBitWidth = MinBitWidth + 1)
        begin
            value = value >> 1;
        end
    end
endfunction

Ответы [ 2 ]

1 голос
/ 21 июня 2020

Просто сделайте +1, чтобы получить правильные значения для степеней 2.

$clog2(MAX_COUNT_32BITS + 1);

0 голосов
/ 21 июня 2020

$clog2 из IEEE Std 1800-2017, раздел 20.8.1 Целочисленные математические функции :

Системная функция $clog2 должна возвращать верхний предел базы журнала 2 аргумента (журнал округляется до целого числа).

module tb;

    parameter CLOCK_PERIOD_ns    =  20;  // nanoseconds.
    parameter DEBOUNCE_PERIOD_ms = 125;  // milliseconds.
    localparam MAX_COUNT_32BITS = DEBOUNCE_PERIOD_ms * 1_000_000 / CLOCK_PERIOD_ns;  // Default type of 32-bits.
    localparam COUNTER_BITS = $clog2(MAX_COUNT_32BITS);  // Calculate actual bit width needed.

initial begin
    $display("MAX_COUNT_32BITS = %0d, COUNTER_BITS = %0d", MAX_COUNT_32BITS, COUNTER_BITS);
end

endmodule

Вывод:

MAX_COUNT_32BITS = 6250000, COUNTER_BITS = 23
...