Почему встраивание арифметики Verilog c превращает ее в логическую? - PullRequest
3 голосов
/ 21 февраля 2020

Я прочитал несколько вопросов о том, как реализовать арифметический c сдвиг в Verilog. Все предлагают использовать $signed(…) >>> ….

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

  • reg[2:0] a = $signed(3'b100) >>> 1 ; производит 3'b110
  • reg[2:0] a = 1'b1 ? $signed(3'b100) >>> 1 : 3'b000; производит 3'b010

Исправление, по-видимому, заключается в переносе вычисления в $unsigned:

  • reg[2:0] a = $unsigned($signed(3'b100) >>> 1) ; производит 3'b110
  • reg[2:0] a = 1'b1 ? $unsigned($signed(3'b100) >>> 1) : 3'b000; производит 3'b110

Почему встраивание arithmeti c сдвиг заставляет его действовать как логический, и почему добавление $unsigned вокруг него решает проблему?

Вот минимальный рабочий пример:

module puzzle();
   reg [2:0] a_u = 3'b100 >>> 1; // 3'b010
   reg [2:0] a_s = $signed(3'b100) >>> 1; // 3'b110
   reg [2:0] a_mux = 1'b1 ? $signed(3'b100) >>> 1 : 3'b000; // 3'b010

   reg [2:0] b_u = $unsigned(3'b100 >>> 1); // 3'b010
   reg [2:0] b_s = $unsigned($signed(3'b100) >>> 1); // 3'b110
   reg [2:0] b_mux = 1'b1 ? $unsigned($signed(3'b100) >>> 1) : 3'b000; // 3'b110

   initial begin
      $display("a_u = 3'b%3b", a_u);
      $display("a_s = 3'b%3b", a_s);
      $display("a_mux = 3'b%3b", a_mux);

      $display("b_u = 3'b%3b", b_u);
      $display("b_s = 3'b%3b", b_s);
      $display("b_mux = 3'b%3b", b_mux);
   end
endmodule

Вывод:

a_u = 3'b010
a_s = 3'b110
a_mux = 3'b010
b_u = 3'b010
b_s = 3'b110
b_mux = 3'b110

Ответы [ 2 ]

4 голосов
/ 22 февраля 2020

Здесь действуют два правила выражения Verilog:

  • Контекстно-зависимые и самоопределенные выражения
  • В контексте смешивание операнда со знаком и без знака приводит ко всему без знака

Если у вас есть выражение

C ? A : B

Операнды A и B находятся в контексте друг с другом. Каждый операнд будет изменен на самый большой операнд, и оба должны быть подписаны, чтобы остаться подписанным. Это происходит до применения оператора во время компиляции. S самоопределяется - ничто, кроме C, не влияет на его размер или подпись. Кроме того, C не влияет на контекст A и B

Аналогично, когда у вас есть выражение

A >>> S

A определяется контекстом и S самоопределяется

Теперь, если мы объединим два выражения в одно:

C ? A >>> S : B

Поскольку A и B находятся в одном контексте, а B не подписано, A конвертируется в без знака. Как только вы заключаете A>>>S в вызов функции (любой вызов функции работает одинаково), каждый входной аргумент функции имеет свой собственный контекст, независимый от остальной части выражения, частью которого он является. Возвращаемое значение будет обрабатываться в контексте с остальной частью выражения.

1 голос
/ 21 февраля 2020

Я не знаю причину, но кажется, что преобразование 3'b000 в 3'sb000 также решает вашу проблему.

reg [2:0] a_mux = 1'b1 ? $signed(3'b100) >>> 1 : 3'sb000;

Кроме того, использование $signed() вместо $unsigned() также работает:

reg [2:0] b_mux = 1'b1 ? $signed($signed(3'b100) >>> 1) : 3'b000;
...