计算机组成
5 乘法器和除法器
5.7 除法器的优化
咱们如今的这个除法器已经能够正常的工做了。可是距离实用还有至关大的距离,必需要通过优化,不过除法的优化就比较复杂。所以,在这一节,咱们只是对它的优化方法和优化的方向作一个很是基本的探讨。性能优化
这是咱们已经有了的这一版除法器,咱们不妨称之为初版的实现。在这个除法器当中,有一个64位的余数寄存器;一个64位的除数寄存器;一个32位的商寄存器和一个64位的ALU。框架
那咱们首先来考虑面积方面的优化,咱们先来看看在哪些地方存在着浪费。性能
首先,咱们的除数是只有32位的,而咱们的除数寄存器使用了64位的,实际只使用了其中的一半,这是第一个能够优化的点。优化
第二,商寄存器在初始化的时候是空的,每执行完一轮会产生移位,从右向左逐位填满。因此,这里也存在着浪费的状况。spa
第三,余数寄存器初始时是满的,也就是最开始的被除数。可是,在不断进行和除数的减法以后这个余数会变得愈来愈小,它有实际意义的位从左往右在逐渐地减小。因此,越日后,余数寄存器当中浪费的位就会越多。blog
那咱们就尝试从这三个方面进行面积上的优化。图片
那咱们把通过面积优化的除法器称为第二版,咱们就来看一看第二版的除法器是什么样的。为了方便对比,咱们把优化方案和原来结构的描述放在一块儿。工作流
首先,原先有一个64位的除数寄存器,如今咱们将除数寄存器缩小为32位,由于除数原本就是32位的,因此这样除数寄存器就没有了浪费的状况。可是咱们要注意,除数寄存器是在整个运算过程当中一直要使用的,它的移位只是为了和余数寄存器进行对齐,以方便运算。因此,原先才准备了一个64位的寄存器,以便于除数在移位的过程当中也不会丢失。那如今将它缩小为32位了,就不能再有移位的功能,不然其中有效位就会丢失了。所以,这个除数寄存器也就不用再支持移位功能。那么在运算中须要将除数和余数进行对齐的这项功能,就得放到别的地方来完成了。class
第二,咱们知道原来有一个32位的商寄存器,它一开始是空的,在运算的过程当中逐位填满。那既然它一开始没有用,因此咱们干脆先取消这个寄存器,再看一看可不能够在别的地方实现相似的功能。并行
第三,原来有一个64位的ALU。而咱们知道,实际参与运算的其中一个操做数是除数,另外一个操做数则是余数寄存器当中和除数对应的一些位,实际上只有32位。因此,咱们就将这个64位的ALU缩小为32位,也就是说只要让其中有效位数参与运算。
那么对于余数寄存器,或者说一开始是被除数的这个寄存器,它在和除数进行减法运算时,最开始只有最高的32位参与运算,以后才逐次地往低位移动。因此,咱们先规定这个余数寄存器只有高32位参与这个加减法运算,咱们也在这个余数寄存器当中画一条半透明的线做为标记,而整个余数寄存器仍然保留为64位,其中的高32位被链接到ALU的一个输入,而ALU的输出也链接到了余数寄存器的高32位。
可是,原来除数寄存器是带有右移的功能,从而实现了余数寄存器中参与运算的数逐渐向低位移动这样一个状况,那如今除数寄存器已经不能右移了。与之相对,余数寄存器那就得支持一个左移的功能,并且咱们再去回顾除法的运算过程能够发现,余数或者说被除数的高位一旦退出了运算,就再也不会有机会从新参与运算了。因此,把余数寄存器的高位向左移位,并将移出的位丢弃,是不会对运算的过程形成影响的。因此,咱们将余数寄存器加上左移的功能。而实际上咱们发现,如今这个余数寄存器不只支持左移,还支持右移的功能。为何支持左移?刚才我已经介绍了;而为何支持右移呢?就留给你们本身来思考。
固然,何时进行移位须要由控制逻辑进行控制。因此,在余数寄存器上也须要有相应的控制输入。那如今咱们要注意的是,余数寄存器的浪费问题仍然没有解决。随着运算的进行,每一轮余数寄存器都会向左移位一次,它的右边则会多空出一位来,并且空出的位会愈来愈多。那么咱们回头来看一看,其中咱们还须要一个32位的商寄存器,并且这个商在运算的一开始是不须要占据任何空间的,只须要每一轮采用左移的方式,给它多分配一个比特就能够了。那就正好是余数寄存器如今所浪费的状况,咱们就能够很天然地将商寄存器合并到余数寄存器当中。让每一轮产生的商,从余数寄存器的右端逐个移入。这样当运算结束时,商就占据了余数寄存器的低32位,而余数寄存器的高32位,则是最后真正的余数。这样再连上对应的控制逻辑以后,咱们就有了一个通过面积优化的除法器。
那么在实现了面积优化以后,咱们就要考虑在性能上是否能够进行优化。
想进行除法器的性能优化,咱们就要先来回顾乘法是如何进行优化的。其实如今的乘法器能够作到很是好的优化,这和乘法运算自身的特色是分不开的。
咱们来看以前提到过的例子,仔细分析就能够发现,虽然乘法和除法都要产生不少中间的结果,也都须要经过移位等操做进行对齐,再进行最后的运算。可是很大的不一样在于,乘法的每个中间结果都是独立的,每个中间结果,要么和被乘数相等,要么是0,并且它到底是哪种?只由乘数当中固定的一位决定,不受其它位的影响。因此,若是咱们人工进行乘法的计算,当咱们有了被乘数和乘数以后,能够交给不少人来协做运算。每一个人只计算其中一个中间结果,而后再由一些人将这些中间结果加起来,这样就能够经过并行的计算大幅度地提升性能。
而咱们来看除法的这个工做流程,中间有一个检查余数的工做,并且当余数小于0时,还须要回退第一步的操做。这实际上就是由于除法的这些中间结果并非各个独立的。那咱们可能会想到,乘法的那个流程图当中,不也有一个要进行检查的分支操做吗?看上去和除法这个流程图是很是类似的。那么,不妨把乘法的这个流程图找出来仔细地看一看。
的确。在开始的这个地方确实有一个检查乘数寄存器的最低位的操做,而且根据检查结果的不一样会走向两个不一样的分支。可是,咱们仔细分析就会发现,这个分支其实是不存在的。由于当最低位为1时,会执行将被乘数寄存器和乘积寄存器相加,这样一个操做。那么咱们不妨能够理解为,将被乘数寄存器的内容和乘数寄存器的最低位进行一个”与操做“,而后再和乘积寄存器相加,由于如今乘数寄存器的最低位是1,任何数和1进行”与操做“,结果仍是这个数自己,因此,这样的改动并不会影响这里的操做;而对于这一边,当最低位为0时,若是咱们也作一样的操做,也就是将乘数寄存器的最低位和被乘数寄存器先进行”与操做“,而后再和乘积寄存器相加,由于任何数和0进行”与操做“,结果都是0,0再和乘积寄存器相加,那就至关于没有执行加法操做,乘积寄存器的内容并无改变。因此,实际上咱们能够将这个分支取消,在每轮的最开始都直接将乘数寄存器的最低位和被乘数寄存器进行”与操做”,而后和乘积寄存器相加。这样不管最低位是1,仍是0,都能完成这个工做流程图所表达的工做。
那即便对于这个优化后的工做流程,效果也是同样的。由于第一步的检查以后,2和3这两步操做都会执行,惟一的区别在于1a这个操做。因此,采用刚才所描述的那种修改(前一个图片提供的修改方案,引入“与操做”),也能够达到一样的效果。所以,对于这个工做流程来讲,在实际的实现当中也能够不存在这个分支的操做。
然而对于除法的这个工做流程,这一次减法的运算结果是事先没法预知的。所以,没法预知下一步将执行哪个分支,并且其中一种分支还须要将这个减法操做进行回退。因此,也没有办法将两个分支进行合并。所以,在这个除法运算流程的大框架之下,是很难进行进一步的性能优化了。
正是因为除法的优化很是的困难,于是也引来了不少人对除法进行深刻的研究,也产生了不少颇有趣的,快速除法的实现方法。若是你对此有兴趣,能够进一步深刻地探索。