黄金法则是:所有操作数都必须是有符号(signed)的。
Verilog 似乎非常偏向于无符号(unsigned)数。以下任何一种情况都会产生 无符号 值:
- 对两个操作数进行的任何操作,除非 两个操作数都是有符号的。
- 带有显式进制(base)的数(例如 12'd10),除非使用了显式的 “s” 修饰符。
- 位选择(bit-select)的结果。
- 部分选择(part-select)的结果。
- 拼接(concatenation)的结果。
所以归根结底,要么使用 $signed 系统函数,要么定义有符号的 wire 和有符号的 reg。
例如,要把一个有符号的 reg 变量与一个无符号的 reg 变量相乘,并(当然)把结果当作有符号值来处理,可以像下面这样写:
reg [15:0] a; // Unsigned
reg signed [15:0] b;
wire signed [16:0] signed_a;
wire signed [31:0] a_mult_b;
assign signed_a = a; // Convert to signed
assign a_mult_b = signed_a * b
注意,signed_a 比 a 宽 1 位,因此有空间存放符号位(sign bit),而这个符号位始终为 0。如果没有这一位,a 的最高有效位(MSb,most significant bit)在 signed_a 中就会被当作符号位。
有人可能会误以为,必须用 {1'b0, a} 这样的写法来显式指定 signed_a 的 MSb,而不是直接写 a。但 Verilog 标准明确指出:一个数是有符号还是无符号,只由表达式本身决定。赋值左侧(left-hand side)对此没有任何影响。因此,a 被当作无符号值处理,并因此用 0 扩展。