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

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

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

10111011

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

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

3 ответов


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

если это для синтеза голого в виду, что вы хотите попытаться избежать разделителей, вы действительно хотите попытаться избежать подписанных разделителей. Скорее всего, синтез будет меньше с >>> 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 также округляется в моих примерах,>>> округлит/усечет.


например, скажем, у меня есть 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

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

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