Перейти к содержанию
    

Причины неправильного вычисления маски

Есть код:

module tb;

logic one_bit;
logic [3:0] select;
logic [15:0] mask;

assign mask = (~one_bit) << select;

initial
begin
    one_bit = 1'b0;
    select = 3;
    #1;
    $display("mask = %x", mask);
end

endmodule

 

На выходе я получаю:

mask = fff8

А ожидал:

mask = 0008

 

Как исправить знаю (даже несколькими способами), но не понимаю почему оно не работает в таком виде. Не подскажете?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Насколько понимаю, Вы сперва инвертируете one_bit (результат FFFF), а затем сдвигаете на 3 разряда (итог fff8).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Используйте "!" вместо "~"

Это одно из решений. Но не всегда работает. Например, если one_bit будет 2 или больше бит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Действительно странно.

Это как-то связано с неявным приведением типов, потому что если сделать

wire inv_one_bit = ~one_bit;
assign mask = inv_one_bit << select;

то работает как задумывалось.

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно и так:

assign mask = 1'(~one_bit) << select;

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

думал что сначала выполнится инверсия, а уж потом будет приведение типа.

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

Надо стандарт еще раз почитать, наверняка там есть информация про это.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Надо стандарт еще раз почитать, наверняка там есть информация про это.

SystemVerilog IEEE1800-2012

Глава 11.6 Expression bit lengths

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

классная головоломка, ага.

 

Общая идея такая: вы подключаете шину меньшего размера к шине большего размера. Какое значение примут оставшиеся не подключенными проводники?

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

 

Держать все эти особенности стандарта в голове вместе со ссылками на разделы стандарта - это слишком хлопотно.

 

практический вывод из всего этого только один: не стоит экономить на нажатиях клавиш.

Вы сэкономили 10 лишних символов в исходнике, но зато написали не меньше 100 символов сюда, чтобы разобраться, почему не работает. Такая вот простая бухгалтерия.

 

Я не думаю что это то место.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

на самом деле если написать так

 

$unsigned( ((~one_bit) << select) ) старшими будут нолики, а если так

$signed( ((~one_bit) << select) ) старшими будут в зависимости от старшего в ((~one_bit) << select),

 

почему по умолчанию преобразование signed непонятно...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

почему по умолчанию преобразование signed непонятно...

signed тут не причём. Подозреваю, что в случае

$unsigned( ((~one_bit) << select) )

сначала выполняется то что в скобках с приведением типов после уже для расширенного числа (операция <<), а, если $unsigned опустить, то сначала произойдёт приведение типов, а именно расширение разрядности one_bit до разрядности результата, операция ~ при этом даст 1 во всех добавленных битах, простая логическая операция без привязки к signed/unsigned представлению. Вот и знаменитое автоматическое согласование разрядностей верилога :rolleyes:

Изменено пользователем serjj

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

SystemVerilog IEEE1800-2012

Глава 11.6 Expression bit lengths

 

Не, там написано, что результат операции "~" имеет длину аргумента.

По идее, сначала дожно вычисляться (~one_bit) с длиной результата 1 бит, а потом расширение до 16 бит. Но в нашем случае почему-то сначала расширяется one_bit до 16 бит, а потом происходит инверсия.

 

Кстати, можно и без сдвига. Если оставить одну инверсию, получится 0xfff.

 

Изменено пользователем embddr

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...