Verilog进行饱和与截位操作
一、引言
在利用Verilog写数字信号处理相关算法的过程中往往涉及到对数据的量化以及截位处理。而在实际项目中,一种比较精确的处理方式就是先对截位后的数据进行四舍五入(round),如果在四舍五入的过程中由于进位导致数据溢出,那么我们一般会对信号做饱和(saturation)处理。所谓饱和处理就是如果计算结果超出了要求的数据格式能存储的数据的最大值,那么就用最大值去表示这个数据,如果计算结果超出了要求的数据格式能存储的数据的最最小值,那么就用最小值去表示这个数据。这里先不给例子,下文会详细描述这种情况。
为了叙述方便,本文先做如下规定:如果一个有符号数的总位宽为32位(其中最高位为符号位),小数位宽为16位,那么这个有符号数的数据格式记为
。依次类推,
表示这个数是一个有符号数(最高位为符号位),且总位宽为10位,小数位宽为8位。
表示这个数是一个有符号数(最高位为符号位),且总位宽为16位,小数位宽为13位。总而言之,下文如果定义一个数据为
(
和
均为正整数且
)格式,那么我们可以得到三个重要的信息:
是一个有符号数,最高位为符号位
数据的总位宽为
数据的小数位宽为
二、Verilog中有符号数据的补位与截位
2.1 有符号数与无符号数
顾名思义,有符号数指的就是带有符号位的数据,其中最高位就是符号位(如果最高位为0,那么表示是正数,如果最高位为1,那么表示是负数);无符号数就是不带有符号位的数据。
考虑一个4位的整数
.如果它是一个无符号数据,那么它表示的值为:
。如果它是一个有符号数,那么它表示的值为:
。
所以相同的二进制数把它定义为有符号数和无符号数表示的数值大小有可能是不同的。同时,这里也告诉大家,有符号数和无符号数转化为10进制表示的时候唯一的区别就是最高位的权重不同,拿上例来说,无符号数最高位的权重是23而有符号数最高位的权重是-23。
正因为有符号数和无符号数最高位的权重不同,所以他们所表示的数据范围也是不同的。比如,一个4位的无符号整数的数据范围为
~
,分别对应二进制
~
,而一个4位的有符号整数的数据范围为
~
,分别对应二进制
~
.
扩展到一般情况,一个位宽为m的无符号整数的数据范围为
~
,而一个位宽为m的有符号整数的数据范围为
~
。
2.2 有符号整数的符号位拓展
问题:如何把一个4位的有符号整数扩展成6位的有符号整数。
假设一个4位的有符号整数为
,显然由于最高位为0,所以它是一个正数,如果要把它扩展成6位,那么只需要在最前面加2个0即可,扩展之后的结果为:
。
在看另外一个例子,假设一个4位的有符号整数为
,显然由于最高位为1,所以它是一个负数,如果要把它扩展成6位,那么这里要千万注意了,前面不是添2个0,而是添2个1,扩展之后的结果为:
。为了确保数据扩位以后没有发生错误,这里做一个简单的验证:
显然扩位以后数据大小并未发生变化。
综上得出结论:对一个有符号整数进行扩位的时候为了保证数据大小不发生变化,扩位的时候应该添加的是符号位。
2.3 有符号小数
有了前面两小节的基础以后接下来研究一下有符号小数。前面已经规定了有符号小数的记法。
假设一个有符号小数为
,它的数据格式为
,也就是说它的小数位为2位。那么看看这个数表示的10进制数是多少
显然,小数的计算方法实际上和整数的计算方法是一样的,只不过我们要根据小数点的位置来确定对应的权重。
接下来看看有符号小数的数据范围。就拿
格式的数据来说,它的数据范围为
~
,分别对应二进制
~
。扩展到一般情况,
格式数据的数据范围为
~
。
最后再来看看有符号小数的数据扩展。假设一个有符号小数为
,它的数据格式为
,现在要把这个数据用
格式的数据存储。显然需要把整数部分和小数部分分别扩一位,整数部分采用上一节提到的符号位扩展,小数部分则在最后面添一个0,扩展以后的结果为
,接下来仍然做一个验证
显然,扩位以后数据大小并未发生变化。
总结:有符号小数进行扩位时整数部分进行符号位扩展,小数部分在末尾添0.
2.4 两个有符号数的和
两个有符号数相加,为了保证和不溢出,首先应该把两个数据进行扩展使小数点对齐,然后把扩展后的数据继续进行一位的符号位扩展,这样相加的结果才能保证不溢出。
举例:现在要把
的数据
和
的数据
相加。
由于
的数据小数位只有2位,而
的数据小数点有3位,所以先把
的数据
扩位为
的数据
,使它和
数据的小数点对齐
小数点对齐以后,然后把
的数据
进行符号位扩展成
的数据
两个