Как Verilog ведет себя с отрицательными числами?

Например, скажем, у меня есть reg [7:0] myReg, я присваиваю ему значение -8'D69

Я знаю, что Verilog хранит его как дополнение 2, поэтому его следует хранить как

10111011

Вопрос, который у меня есть сейчас, заключается в том, должен ли я выполнить над ним операцию, скажем, myReg/2

Будет ли он оцениваться как -34? Или он возьмет 10111011 и превратит его в 187, а затем выполнит деление, вернув 93?


person wonton    schedule 13.09.2012    source источник
comment
Вы также должны объявить числа со знаком как таковые. reg signed [7:0] my_reg   -  person Morgan    schedule 13.09.2012
comment
Вы можете использовать ››› 1 для выполнения знакового расширенного деления на 2 (если он объявлен как подписанный тип).   -  person Morgan    schedule 13.09.2012


Ответы (3)


Вы должны помнить, что -8d69 — это всего лишь битовый шаблон. reg — это тип, который содержит битовые комбинации. Это тип переменной, которая указывает / выполнять арифметические действия со знаком или без знака.

Если это для синтеза, не забывайте, что вы хотите попытаться избежать разделителей, вы действительно хотите попытаться избежать подписанных разделителей. Скорее всего, синтез будет меньше с >>> 1

reg [7:0] a;
reg signed [7:0] b;
reg [7:0] c;
reg signed [7:0] d;

initial begin
  a =  -8'd69 ;
  b =  -8'd69 ;
  c =  -8'd69 ;
  d =  -8'd69 ;
  #10ns;
  a = a/2     ;
  b = b/2     ;
  #10ns;
  $display("a      : %8b, %d", a, a);
  $display("b      : %8b, %d", b, b);
  $display("c >>>1 : %8b, %d", c>>>1, c>>>1);
  $display("d >>>1 : %8b, %d", d>>>1, d>>>1);
end

Дает:

a      : 01011101,  93
b      : 11011110,  -34 
c >>>1 : 01011101,  93
d >>>1 : 11011101,  -35

>> x Смещается вправо на x позиций, >>> x Смещается вправо на x позиций, но знак расширяется для подписанных типов.

NB: /2 также округляется в моих примерах, >>> округляется/усекается.

person Morgan    schedule 13.09.2012

Например, скажем, у меня есть reg [7:0] myReg, я присваиваю ему значение -8'D69

На самом деле это не число со знаком, а выражение, состоящее из унарного отрицания, примененного к положительной константе. Если бы выражение было -8'd130, результат переполнился бы. Константы со знаком объявляются как 8'sd69 или просто 69.

Вопрос, который у меня есть сейчас, заключается в том, должен ли я выполнить над ним операцию, скажем, myReg/2

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

//Declare the reg as signed and divide by a signed value
reg signed [7:0] myReg;
assign result = myReg/2;

//Use system functions
assign result = $signed(myReg)/2;

* Полные правила, касающиеся оценки выражения, намного сложнее, но в основном результат любого выражения беззнаковый, если только все операнды не подписаны.

reg signed [7:0] a;
reg [7:0] b;

initial
begin
result = a;            //Signed
result = a * a;        //Signed
result = a * 10;       //Signed
result = $unsigned(a); //Unsigned
result = a[0];         //Unsigned
result = a[7:0];       //Unsigned
result = {a,a};        //Unsigned
result = 10{a};        //Unsigned
result = a + b;        //Unsigned
result = a * b;        //Unsigned
end
person Community    schedule 13.09.2012

Добавлю, что 1. Типы данных bit и reg по умолчанию беззнаковые. 2. Типы данных int, integer, longint, shortint и byte по умолчанию являются знаковыми. 3. Все эти типы данных могут принимать квалификатор со знаком или без знака для изменения значения по умолчанию.

Таким образом, присвоение -8'D69 для myReg приводит к неявному преобразованию в 187. Тогда myReg/2 = 187/2 = 93 без знака. Важно понимать, когда и как SystemVerilog выполняет неявные преобразования типов в выражениях и присваиваниях.

person Steve K    schedule 10.10.2012