明德扬肖老师 发表于 2020-9-7 18:53:00

【FPGA至简设计原理与应用】第一篇第三章硬件描述语言Verilog第5节算术运算符补码由来


本案例的编号为:001500000137,如果有疑问,请按编号在下面贴子查找答案:MDY案例交流【汇总贴】_FPGA-明德扬科教 (mdy-edu.com)
本文为明德扬原创及录用文章,转载请注明出处
大家好,近期我们会连载《FPGA至简设计原理与应用》一书,有兴趣的同学可以学习,也希望大家可以对我们的书提出宝贵的意见和建议。

《FPGA至简设计原理与应用》书籍连载索引目录

http://www.fpgabbs.cn/forum.php?mod=viewthread&tid=989


读过的朋友可积极在贴后留言,书籍正式出版时,我们会从留言者中挑选20位幸运读者,幸运读者可获潘老师亲笔签名书籍一本。

注:手机浏览可能格式会乱,建议用电脑端进行浏览。





[*]补码的由来


本文档编号:001100000061
需要看对应的视频,请点击视频编号:001100000060
1. 本节主要进行组合逻辑的介绍,包括:程序语句(assign语句、always语句),数字进制(二进制、不定态、高阻态),算数运算符(加、减、乘、除运算符),逻辑运算符(逻辑与、或、非运算符),按位逻辑运算符(单目按位与、或、非运算符,双目按位与、或、异或运算符),关系运算符,移位运算符(左移、右移运算符),条件运算符(三目运算符、if语句、case语句、选择语句等),拼接运算符;
2. ALTERA和VIVADO文档



FPGA实现各种算法的时候,首要的就是保证运算结果的正确性,否则一切毫无意义。在分析加加法运算符和减法运算符的时候可以发现保存结果的信号位宽是否合理对正确性与否有很大的影响。例如下面的加法运算:表1.3- 5加法运算结果
运算
十进制
结果运算十进制
结果
1位加法运算,1位保存结果,不保存进位
1’b0+ 1’b0 = 1’b001’b1+ 1’b0 = 1’b11
1’b0+ 1’b1 = 1’b111’b1+ 1’b1 = 1’b00
1位加法运算,2位保存结果,保存进位
1’b0+ 1’b0 = 2’b001’b1+ 1’b0 = 2’b011
1’b0+ 1’b1 = 2’b111’b1+ 1’b1 = 2’b102
1位数 + 2位数,2位保存结果,不保存进位
1’b0+ 2’b00 = 2’b0001’b1+ 2’b00 = 2’b011
1’b0+ 2’b01 = 2’b0111’b1+ 2’b01 = 2’b102
1’b0+ 2’b10 = 2’b1021’b1+ 2’b10 = 2’b113
1’b0+ 2’b11 = 2’b1131’b1+ 2’b11 = 2’b000
1位数 + 2位数,3位保存结果,保存进位
1’b0+ 2’b00 = 3’b00001’b1+ 2’b00 = 3’b0011
1’b0+ 2’b01 = 3’b00111’b1+ 2’b01 = 3’b0102
1’b0+ 2’b10 = 3’b01021’b1+ 2’b10 = 3’b0113
1’b0+ 2’b11 = 3’b01131’b1+ 2’b11 = 3’b1004





从上表可以发现,如果不保留进位,当加法出现进位的时候计算的结果是不正确的,只有保留了进位计算的结果才是正确的。由此可以得出一个结论:使用加法的时候,为了保证结果的正确性,必须保存进位,也就是结果要扩展位宽。例如两个8位的数相加,则结果要扩展一位,将位宽设定为9位。

12345wirea,b;wirec;wired;assign c = a+ b; //结果不正确assign d = a+ b; //结果正确

接着再来分析一下减法运算,如下表所示例子:表1.3- 6减法运算结果
运算十进制结果运算十进制结果
2位减法运算,2位保存结果
2’b00- 2’b00 = 2’b0002’b10- 2’b00 = 2’b102
2’b00- 2’b01 = 2’b1132’b10- 2’b01 = 2’b011
2’b00- 2’b10 = 2’b1022’b10- 2’b10 = 2’b000
2’b00- 2’b11 = 2’b0112’b10- 2’b11 = 2’b113
2’b01- 2’b00 = 2’b0112’b11- 2’b00 = 2’b113
2’b01- 2’b01 = 2’b0002’b11- 2’b01 = 2’b102
2’b01- 2’b10 = 2’b1132’b11- 2’b10 = 2’b011
2’b01- 2’b11 = 2’b1022’b11- 2’b11 = 2’b000

注意表中和2’b00-2’b01,结果是2’b11,对应的十进制值为3,但期望的结果是“-1”。同样的道理,2’b01 - 2’b11,结果是2’b10,对应的十进制值为2,而期望的结果是“-2”,所以上面的结果是不正确的。当期望结果中有正负之分时,可以通过增加一个符号位来区别结果的正负。业内约定的表示方法为,最高位为0时表示正数,最高位值为1表示负数。符号位之后的数值用低2位表示,结果如下表:
表1.3- 7增加符号位的减法运算结果
运算十进制结果运算十进制结果
2位减法运算,3位保存结果,其中最高位是符号位
2’b00- 2’b00 = 3’b000+02’b10- 2’b00 = 3’b010+2
2’b00- 2’b01 = 3’b111-32’b10- 2’b01 = 3’b001+1
2’b00- 2’b10 = 3’b110-22’b10- 2’b10 = 3’b000+0
2’b00- 2’b11 = 3’b101-12’b10- 2’b11 = 3’b111-3
2’b01- 2’b00 = 3’b001+12’b11- 2’b00 = 3’b011+3
2’b01- 2’b01 = 3’b000+02’b11- 2’b01 = 3’b010+2
2’b01- 2’b10 = 3’b111-32’b11- 2’b10 = 3’b001+1
2’b01- 2’b11 = 3’b110-22’b11- 2’b11 = 3’b000+0

从上表中可以看出增加符号位后还是会存在部分运算结果与预期不符合的问题。例如表中的2’b00-2’b01,结果是3’b111,对应的十进制值为-3,但期望的结果是“-1”。所以上面的结果仍然是不正确的。
现在,重新对二进制数“000~111”进行如下转换:a.       正数:保持不变b.      负数:符号位保持不变,数值取反加1。
也就是说,如果是正数“+1”,之前是用“001”表示,现在仍然是用“001”表示。如果是负数“-1”,之前是用“101”表示,现在则是用“111”表示。负数“-3”,之前是用“111”表示,现在则是用“101”表示。这种表示方式就是补码表示方式。改为用补码来表示后,再来分析下结果:表1.3- 8补码表示减法运算结果
运算补码结果运算补码结果
2位减法运算,3位保存结果,其中最高位是符号位
2’b00- 2’b00 = 3’b000+02’b10- 2’b00 = 3’b010+2
2’b00- 2’b01 = 3’b111-12’b10- 2’b01 = 3’b001+1
2’b00- 2’b10 = 3’b110-22’b10- 2’b10 = 3’b000+0
2’b00- 2’b11 = 3’b101-32’b10- 2’b11 = 3’b111-1
2’b01- 2’b00 = 3’b001+12’b11- 2’b00 = 3’b011+3
2’b01- 2’b01 = 3’b000+02’b11- 2’b01 = 3’b010+2
2’b01- 2’b10 = 3’b111-12’b11- 2’b10 = 3’b001+1
2’b01- 2’b11 = 3’b110-22’b11- 2’b11 = 3’b000+0

可以看到上表的结果全部都是正确的,与预期全部一致。这一过程虽然完全没有对代码进行任何改变,但通过更改数据的定义就实现了正确的结果。
在之前的讨论中,加数、被加数、减数和被减数的运算过程都没有使用有符号数。现在使用有符号数的补码重新对其进行表示。假设加数、被加数、减数和被减数都是2位(范围为-2~1),考虑到进位和借位原因,结果用3位来表示(范围为-4~3)。因为结果位宽变为3位,所以减数和被减数都扩展成用3位表示,列出下表:表1.3- 9补码表示运算结果
十进制运算二进制补码表示补码结果
0-03’b000- 3’b000 = 3’b000+0
0-13’b000- 3’b001 = 3’b111-1
0-(-2)3’b000- 3’b110 = 3’b010+2
0-(-1)3’b000-3’b111 = 3’b001+1
1-03’b001- 3’b000 = 3’b001+1
1-13’b001- 3’b001 = 3’b000+0
1-(-2)3’b001- 3’b110 = 3’b011+3
1-(-1)3’b001- 3’b111 = 3’b010+2
-2-03’b110- 3’b000 = 3’b110-2
-2-13’b110- 3’b001 = 3’b101-3
-2-(-2)3’b110- 3’b110 = 3’b000+0
-2-(-1)3’b110- 3’b111 = 3’b111-1
-1-03’b111- 3’b000 = 3’b111-1
-1-13’b111- 3’b001 = 3’b110-2
-1-(-2)3’b111- 3’b110 = 3’b001+1
-1-(-1)3’b111- 3’b111 = 3’b000+0
0+03’b000+ 3’b000 = 3’b000+0
0+13’b000+ 3’b001 = 3’b001+1
0+(-2)3’b000+ 3’b110 = 3’b110-2
0+(-1)3’b000+ 3’b111 = 3’b111-1
1+03’b001 + 3’b000 = 3’b001+1
1+13’b001+ 3’b001 = 3’b010+2
1+(-2)3’b001+ 3’b110 = 3’b111-1
1+(-1)3’b001+ 3’b111 = 3’b000+0
-2+03’b110+ 3’b000 = 3’b110-2
-2+13’b110+ 3’b001 = 3’b111-1
-2+(-2)3’b110+ 3’b110 = 3’b100-4
-2+(-1)3’b110+ 3’b111 = 3’b101-3
-1+03’b111+ 3’b000 = 3’b111-1
-1+13’b111+ 3’b001 = 3’b000+0
-1+(-2)3’b111+ 3’b110 = 3’b101-3
-1+(-1)3’b111+ 3’b111 = 3’b110-2

总结运算步骤如下:1. 根据“人的常识”,预计结果的最大最小值,从而确定结果的信号位宽。2. 将加数、减数等数据,位宽扩展成结果位宽一致。3. 按二进制加减法进行计算。
通过以上方式,得到的就是补码的结果。事实上,在FPGA甚至计算机系统中,所有数据的保存的方式都是补码的形式。如果读者想要了解更多关于补码的内容可以参阅相关资料。




页: [1]
查看完整版本: 【FPGA至简设计原理与应用】第一篇第三章硬件描述语言Verilog第5节算术运算符补码由来