Я ищу простой способ объявить типы 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