随笔记录 — 关于DEBUG和饱和处理(saturation)与四舍五入(Round)处理方式

关于DEBUG和饱和处理

DEBUG

DEBUG也就是平时所说的调试,我最近发现有一些刚开始学习FPGA或者Verilog的人完全不懂的如何去DEBUG,所以在这里写一下一个DEBUG的思路。

首先代码是肯定写完了之后才会有DEBUG的,为什么要DEBUG?因为你发现你的仿真跟你所预期或者需要的波形不一样。Windows的话,可以在EDA或者仿真软件上看到错误的地方,但是在Linux下的话,可能就是下图这样:
在这里插入图片描述
会有一些提示,无论是Windows还是Linux,这里提供一个做DEBUG的思路:

首先分析错误所在的输入输出,是输入错误还是输出错误?
然后分析错误形成的原因,是数据处理有问题?还是信号传输通道不对?或者是别的什么原因……
然后找到出问题的这个模块(根据顶层报错的路径),可能这个模块里面还有很多个小模块,那么这个时候报错的信息就很关键了。找到报错的这个信号或者数据,然后通过查找信号名称去追这个信号在哪里出现过,做一个简单分析。
做了一个简单分析之后呢,跟你预期或者需求文档进行对比,你基本就可以开始尝试去做DEBUG了,一直修改直到你的仿真波形正确。

饱和处理

提到饱和处理,经常有一个跟他相关的叫做Round的模块也会被提到。所谓饱和处理就是如果计算结果超出了要求的数据格式能存储的数据的最大值,那么就用最大值去表示这个数据,如果计算结果超出了要求的数据格式能存储的数据的最最小值,那么就用最小值去表示这个数据。

在利用Verilog写数字信号处理相关算法的过程中往往涉及到对数据的量化以及截位处理。而在实际项目中,一种比较精确的处理方式就是先对截位后的数据进行四舍五入(round),如果在四舍五入的过程中由于进位导致数据溢出,那么我们一般会对信号做饱和(saturation)处理。所谓饱和处理就是如果计算结果超出了要求的数据格式能存储的数据的最大值,那么就用最大值去表示这个数据,如果计算结果超出了要求的数据格式能存储的数据的最最小值,那么就用最小值去表示这个数据。

先说明一下符号位:有符号数指的就是带有符号位的数据,其中最高位就是符号位(如果最高位为0,那么表示是正数,如果最高位为1,那么表示是负数);无符号数就是不带有符号位的数据。

所谓饱和处理就是如果计算结果超出了要求的数据格式能存储的数据的最大值,那么就用最大值去表示这个数据,如果计算结果超出了要求的数据格式能存储的数据的最最小值,那么就用最小值去表示这个数据。

例1:有一个6Q3的数据为6’b011.111,现在要求用4Q2格式的数据去存储它,显然6’b011.111转化为10进制如下:

6’b011.111 = 121+120+12-1+12-2+1*2-3 = 3.875

而4Q2格式的数据能表示的数据的最大值为4’b01.11,转化为10进制为1.75,因此4Q2格式的数据根本无法准确的存放3.875这个数据,这样就是所谓的饱和情况。在这种情况下,饱和处理就是把超过了1.75的所有数据全部用1.75来表示,也就是说,6Q3的数据为6’b011.111如果非要用4Q2格式的数据来存储的话,在进行饱和处理的情况下最终的存储结果为:4’b01.11。

例2:有一个6Q3的数据为6’b100.111,现在要求用4Q2格式的数据去存储它,显然6’b100.111转化为10进制如下:

6’b100.111 = 1*(-22)+12-1+12-2+1*2-3 = -4 + 0.5 + 0.25 + 0.125 = -3.125

而4Q2格式的数据能表示的数据的最小值为4’b10.00,转化为10进制为-2,因此4Q2格式的数据根本无法准确的存放-3.125这个数据,这是另一种饱和情况。在这种情况下,饱和处理就是把小于-2的所有数据全部用-2来表示,也就是说,6Q3的数据为6’b100.111如果非要用4Q2格式的数据来存储的话,在进行饱和处理的情况下最终的存储结果为:4’b10.00。

Round

假设一个9Q6格式的数据为:9’b011.101101,现在只想保留3位小数位,显然必须把最后三位小数位截掉,但是不能直接把数据截成6’b011.101,这样是不精确的,工程上一般也不允许这么做,正确的做法是先看这个数据是正数还是负数,因为9’b011.101101的最高位为0,所以它是一个正数,然后再看截掉部分(此例中截掉部分是最末尾的101)的最高位是0还是1,在数据是正数的情况下,如果截掉部分的最高位为1,那么是需要产生进位的,所以,最终9’b011.101101应该被截成6’b011.110.

如果是负数则正好相反。假设一个9Q6格式的数据为:9’b100.101101,由于最高位是1,所以这个数是一个负数,然后再看截断部分的最高位以及除最高位的其他位是否有1,此例中截断部分(截断部分为末尾的101)的最高位为1,而且除最高位以外的其他位也有为1的情况,由于负数最高位的权重是(-22),所以对于这种情况是不需要进位的,与正数不同的是,负数不进位是需要加1的。因此最终9’b100.101101应该被截成6’b100.110。

假设a是一个9Q6格式的数据,要求把小数位截成3位。下面是Verilog代码:

assign carry_bit = a[8] ? ( a[2] & ( |a[1:0] ) ) : a[2] ;

assign a_round = {a[8], a[8:3]} + carry_bit ;

上面的代码第一行是通过判断符号位a[8]和截断部分数据特征来确定是否需要进位,如果a[8]是0,计算得到的carry_bit为1,则表示是a是正数,且截断是需要进位;如果a[8]是1,计算得到的carry_bit为1,则表示是a是负数,且截断是不需要进位的,负数不进位需要加1。代码第二行为了保证进位后数据不溢出,所以扩展了一位符号位。

处理方式可看: Verilog对数据进行四舍五入(round)与饱和(saturation)截位.

猜你喜欢

转载自blog.csdn.net/Hennys/article/details/119680692