一,数的表示
首先,将二进制做如下解释:
2的0次方=1
2的1次方=2
2的2次方=4
2的3次方=8
.....
以此类推,那么任何整数,或者说任意一个自然数均可以采用这种方式来表示。
例如,序列10101001,根据上述表示方法,可以很容易推算出序列所表示的数值
2的7次方 * 1 + 2的6次方 * 0 + 2的5次方 * 1+ 2的4次方 * 0 +
2的3次方 * 1 + 2的2次方 * 0 + 2的1次方 * 0 + 2的0次方 * 1 =
128 + 0 + 32 + 0 + 8 + 0 + 0 + 1 = 169
通过这个方法,整个自然数都可用0 和1这两个数字来代替。0与1这两个数字很容易被电子化:有电流就是 1,没有电流就是0。这就是整个现代计算机技术的根本秘密所在。
二,定点数
几乎所有的计算机,以及包括FPGA在内的数字信号处理器件,数字和信号变量都是用二进制数来表示的。数字使用符号0和1来表示, 称为比特(Binary Digit,bit)。其中,二进制数的小数点将数字的整数部分和小数部分分开。为了与十进制数的小数点符号相区别,使用符号∆来表示二进制数的小数点。例如,十进制数11.625的二进制 数表示为1011∆101。二进制数小数点左边的4位1011代表整数部分, 小数点右边的3位101代表数字的小数部分。对于任意一个二进制数来 讲,均可由 B 个整数位和 b 个小数位组成,即
其对应的十进制数大小(假设该二进制数为正数) D 由
给出。每一个的值取1或0。最左端的位 称为最高位(Most Significant Bit ,MSB),最右端的位称为最低位(Least Significant Bit,LSB)
定点数有原码、反码和补码三种表示方法,这三种表示方法在 FPGA设计中使用得十分普遍
(1)原码
原码是「未经更改的码」,指一个二进制数左边加上符号位后所得到的码。
原码表示法是指符号位加绝对值的表示法。符号位通常用0表示正号,用1表示负号。例如,二进制数 ( x )2=0∆110表示+0.75,( x )2=1∆110表示-0.75。
(2)反码
正数的反码与原码相同。负数的反码为原码除了符号位的所有位 取反,即可得到负数的反码。例如,十进制数-0.75的二进制原码表示 为( x )2=1∆110,其反码为1∆001
(3)补码
正数的补码、反码及原码完全相同。
负数的补码与反码之间有一 个简单的换算关系:补码等于反码在最低位加1。
例如,十进制 数-0.75的二进制原码为1∆110,反码为1∆001,其补码为1∆010。
值得 一提的是,在二进制数的运算过程中,补码最重要的特性是减法可以用加法来实现。
原码的优点是乘除运算方便,无论正数还是负数,乘、除运算都 一样,并以符号位决定结果的正负号;若做加法则需要判断两个数符 号是否相同;若做减法,还需要判断两个数绝对值的大小,用大数减小数。
补码的优点是加法运算方便,无论正数还是负数均可直接加, 且符号位同样参与运算,如果符号位发生进位,把进位的1去掉,余下的即结果。
(4)原码与补码的运算对比
由于正数的原码和补码完全相同,因此对于加法运算来讲,原码和补码的运算方式也完全相同。补码的运算优势主要体现在减法上, 我们以一个具体的例子来分析采用补码进行减法运算的优势,在进行分析之前,先要明确的是,在电路中实现比较、加法、减法等运算 时,都需要占用相应的硬件资源,且需要耗费一定的时间。因此,完成相同的运算,所需的运算步骤越少,运算效率就越高。
假设4 bit的数 A 和 B ,其中 A 的值为6,B的值为-5,则其二进制补码分别为 A补(0110)、 B补(1011),按照二进制逢二进一的规则完成加运算,得到10001,舍去最高位1,取低4 bit的数,可得到0001,即十进制数1,结果正确。运算过程如下图:
假设 A 的值为-6, B的值为5,则其二进制补码分别为 A补(1010)、 B补(0101), 按照二进制逢二进一的规则完成加运算,得到1111,(负数补码到原码的转换:除去符号位以外全部取反加1)即(0000 + 1 = 0001),即十进制数-1, 结果正确,运算过程如下图:
从上面的例子可以看出,当采用补码时,无论加法运算还是减法运算,均可通过加法运算来实现,这对电路的设计是十分方便的。
三,FPGA的加减乘除
(1)加减操作
FPGA中的二进制数可以分为定点数和浮点数两种格 式,虽然浮点数的加法和减法运算相对于定点数而言,在运算步聚和 实现难度上都要复杂得多,但浮点数的加法和减法运算仍然是通过将浮点数分解为定点数运算以及移位等步骤来实现的。
例如,对于两个二进制数00101和00110, 当进行加法运算时,Verilog HDL的编译器按二进制规则逐位相加,结果为01011。如果设计者将这两个二进制数看成无符号整数,则表示5+6=11;如果将这两个二进制数的小数点放在最高位与次高位之间, 即0∆0101和0∆0110,则表示0.3125+0.375=0.6875。
需要注意的是,与十进制数运算规则相同,在进行二进制数的加法和减法运算时,参与运算的两个二进制数的小数点位置必须对齐, 且结果的小数点位置也必须相同。
Verilog HDL如何表示负数呢?
例如,二进制数1111,在程序中是表示15还是-1?方法十分简单。
在声明端口或信号时,默认的是无符号数,如果需要将某个数指定为有符号数,则只需在声明时增加关键字signed即可。
例如,“wire signed[7:0] number;”表示将number 声明为8 bit的有符号数,在对其进行运算时自动按照有符号数来处理。
结合二进制数的运算规则可以得出以下几点结论:
- B bit的二进制数,如当成无符号整数,表示的范围为0~;如当成有符号整数,表示的范围为~。
- 如果二进制数的表示范围没有溢出,将运算数据均看成无符号数或有符号数,则运算结果正确。
- 两个B bit的二进制数进行加法和减法运算,若要运算结果 不溢出,则需要 B +1 bit的数存放运算结果。
- 两个二进制数进行加法和减法运算,只要输入数据相同,不 论有符号数还是无符号数,其运算结果的二进制数就完全相同。
虽然在二进制数的加法和减法运算中,不论有符号数还是无符号数,两个二进制数的运算结果的二进制数形式完全相同,
但在Verilog HDL中,仍然有必要根据设计需要采用关键字signed对信号进行声明。 例如,在进行比较运算时,对于无符号数据,1000大于0100;对于有符号数据,1000小于0100。
在实际的工程设计中,经常会遇到多于两个操作数的加法运算 (由于补码的加法和减法运算相同,因此仅讨论加法运算)
在进行FPGA设计中还经常遇到这样一种情况,例如,有3个4 bit 的数参与加法运算,前两个数的加法结果需要用5 bit的数存储,但通过设计能保证最终的运算结果范围为-8~7,即只需用4 bit的数表示,在设计电路时,是否需要采用5 bit的数存储中间运算结果呢?
为了弄清楚这个问题,我们通过2个例子来验证一下。
例子1:
假设3个 4 bit的数进行加法运算: A =7、 B =3、 C =-4, A + B + C =6。
根据二进制数 的运算规则,首先计算 D = A + B =10,如果中间结果也采用4 bit的数表 法,则结果为-6(去掉最高位),即 D 的值为-6,再计算 D + C = E =-10, 由于结果用4 bit的数表示,去掉最高位符位号,值为6,即 E =6,结果正确。上面的运算过程如图所示
例子2:
假设3个 4 bit的数进行加法运算: A =7、 B =9、 C =-4, A + B + C =12。
根据二进制数 的运算规则,首先计算 D = A + B =16,
从运算结果看,如果采用补码进行运算,即使中间运算结果需要用5 bit的数表示,只要最终结果仅需用4 bit的数表示,则在实际电路设计时,中间运算结果仅用4 bit的数运算,也能最终得到正确的结果
得出结论即:当多个数进行加法运算时,如果最终的运算结果需要用 N bit 的数表示,则整个运算过程,包括中间运算结果均用 N bit的数表示, 不需考虑中间变量运算溢出的问题
(2)乘法操作
加法及减法运算在数字电路中实现相对较为简单,在采用综合工 具进行设计综合时,RTL电路图中加法和减法运算会被直接综合成加法器或减法器。乘法运算在其他软件编程语言中实现也十分简单,但用 门电路、加法器、触发器等基本逻辑单元实现乘法运算却不是一件容易的事。、
在采用Xilinx公司FPGA/CPLD进行设计时,如果选用的目标器件(如FPGA)内部集成了专用的乘法器IP核,则Verilog HDL中的乘法运算在综合成电路时将直接综合成乘法器,否则综合成由LUT等基本元件组成的乘法电路。与加法和减法运算相比,乘法器需要占用成倍的硬件资源。当然,在实际FPGA工程设计中,需要用到乘法运算时,可以尽量使用FPGA中的乘法器IP核,这种方法不仅不需要占用硬件资源,还可以达到很高的运算速度。
在FPGA设计中,乘法运算可分为信号与信号的乘法运算,以及常数与信号的乘法运算。对于信号与信号的乘法运算,通常只能使用乘法器IP核来实现;对于常数与信号的乘法运算,可以通过 移位、加法、减法运算来实现。信号 A 与常数的乘法运算如下:
A ×16= A 左移4位
A ×20= A ×16 + A ×4 = A 左移4位 + A 左移2位
A ×27= A ×32 - A ×4 - A = A 左移5位 - A 左移2位 - A
需要注意的是,由于乘法运算结果的位宽比乘数的位宽大,因此 在通过移位、加法和减法运算实现乘法运算前,需要扩展数据位宽, 以免出现数据溢出现象
(3)除法操作
在Verilog HDL编译环境中,除法、指数、求模、求余 等操作均无法在Verilog HDL中直接进行相关运算。实际上,通过基本逻辑单元构建这几种运算也是十分复杂的工作。如果要用Verilog HDL 实现这些运算,一种方法是使用提供的IP核或使用商业IP核; 另一种方法是将这几种运算分解成加法、减法、移位等运算来实现。
Xilinx的FPGA一般都提供除法器IP核。对于信号与信号的除法运算,最好的方法是采用提供的除法器IP核;对于除数是常量的除法运算,则可以采取加法、减法、移位运算来实现除法运算。下面 是一些信号 A 与常数进行除法运算。
A ÷2 ≈ A 右移1位
A ÷3 ≈ A ×(0.25+0.0625+0.0156) ≈ A 右移2位+ A 右移4位+ A 右移6位
A ÷4 ≈ A 右移2位
A ÷5 ≈ A ×(0.125+ 0.0625+0.0156) ≈ A 右移3位+ A 右移4位+ A 右移6位
需要说明的是,与普通乘法运算不同,常数乘法通过左移运算可以得到完全准确的结果,而除数是常数的除法运算却不可避免地存在 运算误差。采用分解方法的除法运算只能得到近似正确的结果,且分解运算的项数越多,精度越高。
参考:杜勇.Xilinx FPGA 数字信号处理设计[M].电子工业出版社:202003.339.