3.加减运算
数据的表示与存放问题解决了。这些数据要参与运算,冯诺依曼计算机的特征是所有信息都是二进制编码,所以运算也是基于01完成的,这部分研究如何构建运算电路。
3.1 布尔代数和基本逻辑电路
3.1.1
关于01的一套数学运算体系起源于1850年前后英国数学家乔治布尔,所以就叫做布尔代数了。
最基本的逻辑运算:与或非,任一逻辑表达式都可以写成这种关系,比如异或也是常用的逻辑运算。
基本的门电路与或非门,其他的门电路可以用这三种基本门电路实现。
对于n位逻辑运算,重复来n个相同逻辑门就行,实现按位与或非。
组合逻辑电路无存储功能,输出取决于当前输入。时序逻辑电路有存储功能,除了当前输入,也受到存储单元状态的影响。
可以使用基本逻辑门组成有特定功能的组合逻辑部件,如译码器、编码器、多路选择器、加法器。
可以使用基本的数字电路设计方法实现出组合逻辑部件
真值表描述功能部件的输入和输出关系
根据真值表确定逻辑表达式
根据逻辑表达式实现逻辑电路
比如多路选择器,最基本的是二选一,很容易实现。选择端的位数是和输入端的个数相关的。
3.1.2 加法器
一位加法器,全加器,两个加数AB,低位进位Cin,和为F,向高位进位为Cout
实现出来之后封装好,就是一个模块化的全加器。
1bit加法器可以实现nbit加法器,进位串起来就可以。
加法实现以后,其他所有算术运算部件都可以基于加法器和逻辑运算来实现,因此所有的算术运算都可以基于01以及逻辑运算实现。这是个计算机设计时很重要的基础
n位的无符号数加法器无法用于带符号数想加,无法判断溢出,比较大小也无法实现。比较通常通过做减法来实现,减法用补码采用加法器实现。
因此加法器除了基本功能,还需要输出一些标志信息。
OF溢出,Cn异或Cn-1
SF符号标志,最高位就行
ZF全为0,或非
CF进位借位标志,Cout异或Cin
至此我们可以把这个东西叫做ALU了,功能比较基础
3.1.3 整数加减和ALU
来分析以下变量的机器数。
要能实现这些东西,要求机器的硬件可以实现补码的表示,以及和的补码和差的补码的实现。
根据这个定义,可以推导一些补码运算的公式。
分析到此,在电路上,需要多设计一个取反电路,二路选择器实现原码还是补码,
在上面的基础上,就构造了一个可以实现整数加减法的运算部件。在此基础上,再加上寄存器,移位器,就可以实现ALU乘除运算等功能了。
ALU叫做算术逻辑部件,里面的核心部件就是整数加减运算。
ALU输出的结果,由ALUop控制端控制,控制端的位数由ALU可以做的操作的个数决定。比如8种操作就需要3bit的op控制线,ALUop的编码对应了不同的操作。
ALU是CPU里的器件,CPU里的控制器送来的就是ALU的控制编码,输出端获得结果以及标志位
3.2 C表达式到逻辑电路
C基础:基本数据类型;基本运算类型+-*/%<>==,位操作,逻辑运算,移位,扩展和截断
高级语言的运算表达式距离机器还有些距离,来看看是怎么实现的。
比如y = (x>>2) + k如何在计算机里实现。
任何高级语言的表达式,都要转换为指令序列。
上面这个式子
sarw $2, %ax ;x>>2 值在ax寄存器里 addw %bx, %ax ;k的值在bx
计算机直接执行指令来完成运算,控制器对指令移码,产生控制信号送运算电路。
操作数在运算电路里运算
sarw $2, %ax 将操作数2和R[ax]送移位器运算 addw 把两个寄存器送整数加法器中运算
可以看出,高级语言表达式到最终逻辑门电路中间是通过指令作为媒介。高级语言转换成指令,指令能直接在硬件上执行,指令最终靠逻辑门实现。
因此高级语言里的运算一定要由相应的指令来实现。
3.3 C语言里的运算
算术运算
无符号数
带符号整数
浮点数的+-*/%
位运算
用来对位串实现掩码操作或相应的其他处理
操作
|
&
~
^
移位运算
用来提取信息,扩大缩小特殊倍
<< >>
语法层次上未设计逻辑移位还是算术移位,在指令层次上有区别,由数据类型确定
比如从数据y中提取低位字节,使用&实现掩码操作:y&0x00ff,就得到了低字节。
移位会有数据丢失或溢出的问题。
逻辑运算
用于关系表达式的运算
||
&&
!
区别按位操作。
还有一类没有运算符的运算,通常在类型转换嗯时候用到,位扩展和位截断运算,没有专门的操作运算符,都是隐含操作。
位扩展,char转int
位截断,int赋值给char
3.4 加减运算的实现
3.4.1 整数加减运算
按照前面ALU的思路,最核心的是加法器。加减法运算都用加法来处理,加法器加上额外的电路能实现减法运算。
加法器本身并不知道是否是带符号数,只管加,并且也不判断对错,只是给低n位作为结果,生成标志信息。至于结果是否正确,是靠软件实现的。
运算时候的条件码(标志位)专门记录到寄存器里,状态字寄存器,或者标志寄存器,如IA32里的EFLAGS寄存器。
这些标志可以在if语句里用作条件转移的判断。
在做加法运算时,主要判断是否溢出,无符号加溢出条件CF=1,带符号数溢出条件OF=1
如果是做减法,
3.4.2 整数减法举例
一个简单的C语言程序,加法部件假定位数为8。
控制台输出结果:
c语言里=赋值运算符是直接把机器码等过去。
从这个例子可以看出来,ALU只是机械的对机器码作运算,并不管结果的对错,结果对错需要程序判断。这些程序上运算结果的异常背后都是数字电路上的实现逻辑。
程序里的x-y运算,送到了ALU这边,有个问题是怎么求一个数负数的补码,直接全部(符号位也取反)按位取反就可以轻松转换成加法,sub指令相当于数据选择器选择原来的数据输出还是说取反输出,顺手输入到Cin即按位取反再加1,这个硬件上的设计还是挺有意思的。
有了这些基础,再来看看如何用程序判断一个无符号数相加有无溢出
最后更新于