Расширить значение единицами

Вопрос или проблема

Когда вы присваиваете узкий битовый вектор более широкому в SystemVerilog вот так:

logic [3:0] narrow;
logic [7:0] wide;
assign wide = narrow;

он будет расширен нулями narrow. Есть ли хороший способ сделать единичное расширение вместо этого? Я не имею в виду знаковое расширение, и не хочу явно указывать размер. Я думаю о чем-то вроде этого:

assign wide = { '1, narrow };

Но это не работает, поскольку в конкатенации не допускаются несформатированные значения. Есть ли хорошее решение для этого?

Вы можете использовать $bits для вычисления размера и использовать оператор повторенной конкатенации:

assign wide = { {($bits(wide) - $bits(narrow)){1'b1}}, narrow };

Ссылайтесь на стандарт IEEE Std 1800-2023 раздел 20.6.2 Функция системного размера выражений.

Если бы вы использовали параметры в объявлении сигналов, то вы могли бы сделать расчет с использованием параметров вместо $bits.

Хорошо, я нашел удобный способ:

assign wide = ~{~narrow};

Если вы просто сделаете это:

assign wide = ~narrow;

то, весьма не интуитивно, SV будет расширять narrow до ширины wide перед инверсией. Боже мой, нам нужен разумный заменитель SV. В любом случае, в этом случае мы можем использовать этот факт. Конкатенация {...} защищает ~narrow внутри нее от аналогичного расширения. Так что это эквивалентно (в более разумном языке):

wide = ~(zero_extend(~(narrow)));

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

Также уровень “WTF SV?” довольно высок, так что если вы действительно используете это, обязательно добавьте комментарий, объясняющий это!

Ответ или решение

Расширение значения с единицами в SystemVerilog

При работе с системами проектирования на основе SystemVerilog разработчики часто сталкиваются с задачей расширения битовых векторов. В данной статье мы обсудим, как можно эффективно расширить узкий битовый вектор, заполняя его единицами, в отличие от стандартного ноль-расширения, которое применяется по умолчанию.

Пример кода

Рассмотрим следующий код, где мы объявляем узкий и широкий битовые векторы:

logic [3:0] narrow;
logic [7:0] wide;
assign wide = narrow;

В приведенном примере произойдет ноль-расширение значения narrow при присвоении его wide. Таким образом, narrow будет расширен нулями до ширины wide. Однако в некоторых случаях может потребоваться заполнение расширенной части единицами, что часто называют "расширением единиц".

Решение с использованием функции $bits

Первый способ решения данной задачи заключается в использовании функции $bits, которая позволяет вычислить размер битового вектора. Затем можно воспользоваться оператором конкатенации с повторением:

assign wide = { {($bits(wide) - $bits(narrow)){1'b1}}, narrow };

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

Альтернативный способ с инвертированием

Другой интересный способ расширения narrow единицами – это использование операции инверсии:

assign wide = ~{~narrow};

На первый взгляд, такой код может показаться непонятным. Принимаем во внимание, что если использовать простое ~narrow, то произойдет ноль-расширение narrow перед инверсией. Тем не менее, использование фигурных скобок {...} позволяет сохранить оригинальное значение narrow, а затем инвертировать его.

В этом случае:

wide = ~(zero_extend(~(narrow)));

Таким образом, мы достигаем той же цели, что и в первом случае, но с меньшим количеством явного кода. Следует отметить, что два инвертора можно оптимизировать на уровне компиляции, если оптимизатор поддерживает такой функционал.

Рекомендации

Хотя оба подхода работают корректно, рекомендуется всегда добавлять комментарии к коду, если вы используете нестандартные методы, особенно такие, как инверсия в данном контексте. Это поможет другим разработчикам лучше понять вашу логику и избежать путаницы.

Заключение

Расширение битовых векторов с единицами в SystemVerilog может быть выполнено различными способами. Использование $bits и операторов конкатенации является стандартным и безопасным методом, тогда как инверсия предоставляет более изящное, хоть и менее очевидное, решение. Выбор подхода должен основываться на специфике вашего проекта и предпочтениях команды разработки.

Оцените материал
Добавить комментарий

Капча загружается...