乘法器和除法器 引言本篇文章主要是关于《计算机组成原理》的乘法和除法运算的底层进行细节展开相比于考研的内容底层的实现可能会更加全面一些。乘法器两个数相乘我们在小学的时候就利用竖式进行计算所以在我们无符号数的时候我们的计算方式也是一样的。但是对于计算机底层的实现并不是和我们人的想法一样。我们的乘数的当前这一位如果是1那么我们就把被乘数抄过去如果是0那么就全部补0但是我们还必须要实现这个错位的加法这个其实就是将被乘数左移这个样子就多了一个0那我们应该怎么取出乘数的最低一位呢其实也是比较简单的将乘数左移以为然后和1进行按位与这个样子就可以取出来了。我们看一下完整的操作过程。这里我们先不考虑符号的问题我们先讨论无符号数的乘法。我们在最原始的版本里面有三个寄存器这三个寄存器分别存储被乘数乘数乘积。我们整个操作的循环一共是m次乘数的位数。在一开始我们必须要进行初始化操作乘积全部初始化为0我们先取出乘数的第一位然后进入控制测试如果这个值是0我们的被乘数左移一位目的是错位对齐乘数向右移动一位目的是取出下一位然后进行下一轮。如果这个乘数的最低位取出来的是1那么进入控制测试之后就会被传递到ALU中然后被乘数也会被传送到ALU中与乘积进行加法运算算完的结果直接写入乘积里面这个步骤的前提是把写使能拉高方便下一次的运算然后将被乘数向左移动一位乘数向右移动一位。这个就是一个完整的乘法器过程。接下来我们需要讨论一下原码的乘法运算这个也比较的简单我们发现同号为0异号为1那不就是异或嘛~~~所以我们单独计算符号那一位剩余的数值位我们还是和之前一样计算。但是这个底层的模型并不是最好的我们还可以减少寄存器的使用我们的被乘数利用一个寄存器而乘积和乘数使用同一个寄存器但是这个寄存器是64位的这个样子才可以同时存下乘积和乘数。这个模型里面乘数不需要向左移动我们之前被乘数之所以需要向左移动是因为我们需要在末尾补0从而实现错位的相加这个最后体现在的是乘积结果上而我们这一次不移动被乘数而是向右移动乘积可以理解为一个相对运动相当于把最后的结果加在了正确的位置。我们的乘积是分成两个部分左边的32位是乘积右边的32位是乘数而且每一次我们取相应的部分都只取对应的32位即使是经过了移动因为我们移动过去的部分之后不会参与运算当循环结束之后在乘积里面的数就是我们需要的数。然后我们要考虑补码的运算在补码的运算里面我们所有的运算数都要转化为补码符号位也需要参与运算在运算过程中需要考虑符号位乘上被乘数之后的部分积是正数还是负数最后我们得到的结果也是补码。所以有4种情况正数 * 正数 和无符号一样正数 * 负数乘数是负数那么我们一定要注意乘数的符号位是1那么这个时候要进行符号扩展用1负数 * 正数因为被乘数是负数所以这一次我们符号扩展的时候无论如何都是补1负数 * 负数我们之前一直都强调的是乘数的符号位参与运算才会补1所以只有在乘数的符号位最后参与运算的时候才会负负得正也就是补0其他的情况下还是要符号扩展1除法器我们依然按照之前小学的方法进行除法运算但是如果是计算机怎么模拟这一个过程呢这一整个过程循环 被除数位数 - 除数位数 1次。首先是除数和被除数的位数对齐然后我们每一次是否上1取决于被除数和除数的大小计算机在判断大小的时候做的是减法运算如果结果大于0那么我们就记录下减后的余数这个余数会参与下一次的运算商 1如果结果小于0那么我们就把这个数重新加回去商 0。这一个过程结束之后我们的商向左移动一位除数向右移动一位那我们这里会担心会不会除数向右移动导致除数的1被移除了。这个不用担心因为我们一开始进行了对齐的操作也就是相当于给除数扩大了2^n倍而在左移的过程中也就是把这些扩大的位数全部移除了而扩大多少倍这个和循环的次数一样也是m - n 1倍。其实比较难理解的就是除数对齐和右移这个可能和我们人类运算的方式有些不一样因为计算机的计算底层就是比较所以我们必须要从最高位开始比较那为什么可以保证不会把除数的有效的1移出去呢原因就是当执行到最后一位的时候如果这个时候商0说明余数比真实没有扩大的除数已经要小了所以这也就是我们得到的余数而如果商1那剩下的那个余数一定比我们的除数要小。那么我们的内部实现还是这一个图首先除数和商还有余数分别用一个寄存器存储在上面的过程中我们也发现了被除数其实就是余数在开始之前我们需要初始化每一个寄存器然后我们每一轮先把余数寄存器里面的内容和除数寄存器里面的内容放在ALU里面相减然后放在余数寄存器里面如果次数余数寄存器里面的数大于0进入控制测试让商 1然后左移一位除数右移一位如果小于0进入控制测试让商 0然后左移同时将余数加回去除数右移一位最后重复 m - n 1次。当然除法器可以进行进一步的优化余数和商可以放在同一个寄存器里面因为我们的余数其实最高位每一次经过运算之后就不再有用了当左移的时候被丢弃不会影响结果反而因为相对的运动除数不需要向右移动了。有符号原码运算和乘法一样符号位通过异或的操作可以确定。补码的运算相对于比较的难其中难点主要在于相减的操作因为涉及到了正数和负数的减法。因为我们判断商是不是1其实方法是统一的就是看两个数的绝对值谁大所以我们这里就需要调整比较的方法了符号参与运算除数和被除数余数和商均用补码表示。符号拓展。如果是正数除以正数这个和刚才说明的一模一样如果是正数除以负数15/-9我们在相减的时候应该抛弃符号的影响因为我们需要知道的是15和9谁更大这里到底商是不是1所以我们这里计算的是15 -9如果结果是0那么就说明商是1如果不是就商是0。如果是负数除以正数相当于是-15 9如果结果是正数说明不够减除数更大如果是负数说明被除数更大商是1。如果是负数除以负数相当于是-15- -9如果结果是正数说明是不够减如果是负数说明够减。总的来说无论是变成加法还是减法我们最后的结果只要和被除数同号那么就可以商1因为证明的是被除数更大。但是在计算的过程里面我们一定要注意的我们的余数和商并不是都是补码如果是异号相除那么我们得到的其实是原码因为我们初始化的时候全部初始化为0但是异号相除结果一定是负数所以我们最后的结果还需要求其补码否则得到的就是原码。总结本篇文章到这里就结束了希望可以帮助大家理解~~~~