在数字信号处理的应用中,往往会对数据进行截位。在截位的过程中,通过增加四舍五入,能够有效增加运算的准确性。
1. 无符号数
在之前的博客中,有对数制进行过介绍。根据数制的规定,如果被截掉的二进制数最高为1,那么被丢弃的部分一定是大于等于0.5,而如果最高位为0,那么被丢弃部分一定小于0.5。如下代码,如果b是对a的高4位进行截位,那么a的第2bit决定是否要执行进1操作。
wire [7:0] a;
wire [4:0] b;
assign b = a[7:3] + a[2]; //a[2]决定是否进位
这种方式有一个小小的bug,如果当a的高4位都是1,这时的进位会导致a溢出,可以再加入一个防溢出的逻辑。
wire [7:0] a;
wire [4:0] b;
assign b = &a[7:3] ? a[7:3] : a[7:3] + a[2]; //只有当a[7:3]不全为1时,进行四舍五入
2. 有符号数一般方法
当考虑到有符号数时,情况变得复杂起来。当有符号数是正数时,情况和之前讨论的一样。然而,如果是负数的话,是否进位不仅仅取决于被抛弃的数的最高位,也取决于被抛弃的数的其他位。例如补码(1000.100)表示的是-7.5,这时应当直接舍弃后3bit,得到(1000),也就是-8。如果是(1000.101),则表示的是十进制的-7.375,则期望得到的数是-7,也就是(1001),进位为1。
下面是有符号数的代码表示
wire signed [7:0] a;
wire signed [4:0] b;
wire carry_bit;
assign carry_bit = a[7] ? (a[2] & (|a[1:0])) : a[2];
assign b = a[7:3] + $signed({1'b0,carry_bit});
在这基础上加入防溢出逻辑
wire signed [7:0] a;
wire signed [4:0] b;
wire carry_bit;
assign carry_bit = a[7] ? (a[2] & (|a[1:0])) : (~(&a[6:3])) & a[2];
assign b = a[7:3] + $signed({1'b0,carry_bit});