Verilog基础知识(有符号数运算规则,加减运算,乘法运算中的符号位拓展问题)

rule of thumb

  1. The format of the signed type is two’s complement. 有符号数均为补码表示
  2. If any operand in an expression is unsigned the operation is considered to be unsigned. 只有计算表达式右边有无符号数,整个计算式都按照无符号数规则运算
  3. 只有算式右边全为有符号数,运算才会自动补齐所需的bit数,n+n=n+1.n*n=2n
  4. The value -4 represented as a 3bit signed hex value would be specified as -3’sh4. A decimal number is always signed. verilog2001中用’s来特别声明有符号数,十进制的数都是有符号数
  5. Type casting using $unsigned will make the operation unsigned. The operand will be sign extended with 0’s if necessary. $usigned()函数在高位补0
  6. A=$signed(B) will extend using sign bit. $unsigned()函数会在高位补与符号位相同的bit

basic signed addition

两个n bit数相加,得到n+1 bit结果,比如-2(3’sb110)+3(3’sb011)=1(4’sb0011)

//Code Example 1: Addition - Verilog 1995
module add_signed_1995 (
input [2:0] A,
input [2:0] B,
output [3:0] Sum
);
assign Sum = {A[2],A} + {B[2],B};
endmodule // add_signed_1995
//Code Example 2: Addition - Verilog 2001
module add_signed_2001 (
input signed [2:0] A,
input signed [2:0] B,
output signed [3:0] Sum
);
assign Sum = A + B;
endmodule // add_signed_2001

signed + unsigned

如果是两个3bit有符号数+1bit进位。如果在verilog2001中直接用符号位拓展

sum=A+B+carry_in //整个计算式会转换成无符号计算,signed to unsigned conversion occurs
sum=A+B+$signed(carry_in) //就会出现当carry_in=1时候拓展为4'b1111,这时候本来是加1,却变成了减1
sum = A + B + $signed({1'b0,carry_in}) //正确的做法

正确的做法是

// Code Example 3: Add with Carry - Verilog 1995
module add_carry_signed_1995 ( 
input [2:0] A,dsa
input [2:0] B,
input carry_in,
output [3:0] Sum
); 
assign Sum = {A[2],A} + {B[2],B} + carry_in; 
endmodule //add_carry_signed_1995
// Code Example 5: Add with Carry - Correct
module add_carry_signed_final (
input signed [2:0] A,
input signed [2:0] B,
input carry_in,
output signed [3:0] Sum
);
assign Sum = A + B + $signed({1'b0,carry_in});
endmodule // add_carry_signed_final

basic signed multiplication

两个n bit数相乘,得到2n bit结果。如果-3(3’sb101) * 2 (3’sb010) 得到正确结果 -6 (6’sb111010)。但如果乘数是负数,则最高位的乘积需要以减法参与运算,而不是加法。

// Code Example 6: Signed Multiply - Verilog 1995
module mult_signed_1995 (
input [2:0] a,
input [2:0] b,
output [5:0] prod
);
wire [5:0] prod_intermediate0;
wire [5:0] prod_intermediate1;
wire [5:0] prod_intermediate2;
wire [2:0] inv_add1;
assign prod_intermediate0 = b[0] ? {{3{a[2]}}, a} : 6'b0;
assign prod_intermediate1 = b[1] ? {{2{a[2]}}, a, 1'b0} : 6'b0;
// Do the invert and add1 of a.
assign inv_add1 = ~a + 1'b1;
assign prod_intermediate2 = b[2] ? {{1{inv_add1[2]}},
inv_add1, 2'b0} : 6'b0;
assign prod = prod_intermediate0 + prod_intermediate1 +
prod_intermediate2;
endmodule
// Code Example 7: Signed Multiply - Verilog 2001
module mult_signed_2001 (
input signed [2:0] a,
input signed [2:0] b,
output signed [5:0] prod
);
assign prod = a*b;
endmodule

signed * unsigned

prod = a*b; //整个运算变成无符号,-3(3'sb101)*2(3'b010)变成5(6'b000101)*2(6'b000010)=10(6'b001010)
prod = a*$signed(b); //当乘数的MSB=1的时候会出错,-2(3'sb010)*7(3'b111)变成
                     //-2(6'sb000010)*-1(6'sb111111)=2(6'sb110010)
prod = a*$signed({1'b0,b}); //正确做法
// Code Example 11: Signed by Unsigned Multiply
module mult_signed_unsigned_2001 (
input signed [2:0] a,
input [2:0] b,
output signed [5:0] prod
);
assign prod = a*$signed({1'b0,b});
endmodule

signed shift

逻辑移位’>>’, ‘<<’会补零,算术移位’<<<’, ‘>>>’会补符号位

A = 8'sb10100011
A>>3; //8'b00010100 
A>>>3;  //8'b11110100

猜你喜欢

转载自blog.csdn.net/maxwell2ic/article/details/80620991