小总结一下verilog的位宽与数据转换
时间:10-02
整理:3721RD
点击:
昨天写某verilog的教学实例,又犯了常犯的错误,枉花了不少时间。
总结一下:
如果有以下定义:
wire signed [7:0] a;
wire signed [15:0] b;
wire signed [16:0] sum;
wire signed [23:0] prod;
关于数学运算的位宽:
prod = a * b; 是按24位实现的。
都不会有溢出问题。
简便的解决办法是: prod = (24'sb1 * a * b) >>> 7; 放心综合器不会傻到多实现一个乘法器……
关于赋值:
b = a; 或直接写 b = -8'sd1; b最终都是等于-16'sd1的。
注意如果先有:wire [7:0] c = -8'd1;
在写:b = c; 和 b = -8'd1; 情况是不一样的!
在对c赋值时c已然变为8'd255,理解为 8'd0 - 8'd1(因为“-8'd1”代表的“无符号数-1”是不能理解的),前者是无符号数向长有符号数赋值时,自然是填充0,结果b为16'sd255。
而后者,应理解为一个减法运算后立即赋值,所以减法运算是按16位有符号进行的:16'sd0 - 8'd1,结果b为-16'sd1。
总结一下:
如果有以下定义:
wire signed [7:0] a;
wire signed [15:0] b;
wire signed [16:0] sum;
wire signed [23:0] prod;
关于数学运算的位宽:
- 加乘等数学运算实现的位宽决定于操作数中位宽宽的那个,比如:
- 如果是运算后立即赋值,而被赋值变量较宽,则按被赋值的变量宽度计算,比如:
prod = a * b; 是按24位实现的。
都不会有溢出问题。
- 但这么写,就悲剧了:
- 同样,这样写也是悲剧的:
简便的解决办法是: prod = (24'sb1 * a * b) >>> 7; 放心综合器不会傻到多实现一个乘法器……
关于赋值:
- real常量赋值给整形,是四舍五入的!比如:
- 短有符号数赋值给长数(不管有无符号),是会填充符号位的,保证值的意义尽量不变,比如:
b = a; 或直接写 b = -8'sd1; b最终都是等于-16'sd1的。
注意如果先有:wire [7:0] c = -8'd1;
在写:b = c; 和 b = -8'd1; 情况是不一样的!
在对c赋值时c已然变为8'd255,理解为 8'd0 - 8'd1(因为“-8'd1”代表的“无符号数-1”是不能理解的),前者是无符号数向长有符号数赋值时,自然是填充0,结果b为16'sd255。
而后者,应理解为一个减法运算后立即赋值,所以减法运算是按16位有符号进行的:16'sd0 - 8'd1,结果b为-16'sd1。
好文章
就是好文章!
关于最后一点,个人的理解是:
a作为有符号数,在进行位数展宽时,按有符号数进行扩展,因此最终的b仍是-1,
c作为无符号数,扩展位宽时,按无符号的来,即高位补0,所以b最终为255.
