verilog勘误系列之-->算术运算符运算失败

发布时间 2024-01-07 11:20:50作者: 天若手提滑铲

描述

在verilog代码设计时使用算术运算符与乘法搭配使用出现计算错误

原因

由于数据位宽设置不当导致

错误案例

wire	signed	[13:0]	w01;
wire	signed	[23:0]	s01;
reg		signed	[24:0]	m01;
reg		signed 	[25:0]	a1;

// 24 + 14 - 13 = 25
m01 <= (w01 * s01) >>> 13;
m02 <= (w02 * s02) >>> 13;

a1 <= m01 + m02;

仿真

在此处运算时,我们似乎设计好了数据位宽,看起来好像没有错误,但是看仿真结果
image

计算

m01 = (s01 * w01) >>> 13 = (3202 * 68270) >>> 13 = 218600540 >>> 13 = 26684
显然与结果不符合

修改一

将m01的数据位宽与乘法结果位宽匹配. 即m01的位宽应该时w01的位宽加上s01的位宽, 即reg signed [37:0] m01;

仿真

image
此处可以看出仿真结果与手算结果一致

修改二

先使用m01,m02等将结果线先存储起来, 在进行加法运算时将数据算术缩小

// 定义位宽.以及其signed属性
wire	signed	[13:0]	w01;
wire	signed	[23:0]	s01;
reg		signed	[37:0]	m01;
reg		signed	[15:0]	a1;
// 乘法处理
m01 <= w01 * s01;
m02 <= w02 * s02;
// 加法处理, 加完后算术运算符缩小
a1 <= (m01 + m02) >>> 13;

仿真结果

image

验证

m01 = w01 * s01 = 3202 * 68270 = 218,600,540
m02 = w02 * s02 = 3762 * -39900 = -150,103,800
a1 = m01 + m02 = (218,600,540 -150,103,800) >>> 13 = 68,496,740 >>> 13 = 8361

计算结果和仿真结果一致

总结

以上两种修改方法目的在于进行位宽匹配,因此在使用运算符的过程中,需要谨慎位宽,防止数据溢出