402-乘法器的实现
# 402-乘法器的实现
如果希望 CPU 支持某一种运算,我们就需要用硬件电路来实现对应的功能部件。现在呢我们现在已经有了一种乘法运算的方法,适合硬件来进行实现。而且,我们还掌握了一些硬件电路的基本知识。我们就可以一起来尝试如何构建一个硬件的乘法器。
现在我们来看乘法器是怎么实现的。 我们用一个简单的二进制乘法作为例子,1000 乘以 1001, 这是两个四位的二进制数相乘, 那么为此我们要实现一个四位的乘法器, 首先我们需要一个寄存器来保存被乘数, 被乘数寄存器是一个八位的寄存器。而且带有左移的功能。 它有一个左移的控制信号输入,当外部的控制逻辑将这个信号视为有效时,在下一个时钟顺延到来的时候,被乘数寄存器当中的内容就会向左移动一位。 第二个寄存器是乘积寄存器,这也是一个八位的寄存器。 用来保存运算的结果。 被乘数寄存器当中的内容和乘积寄存器当中的内容需要进行加法运算, 这里我们就需要进行一个八位的加法器。 它会将被乘数寄存器当中的内容和乘积寄存器当中的内容进行相加,并将结果再送到乘积寄存器当中。
另外,我们还需要一个寄存器来保存乘数。 这个寄存器只要四位就可以了。但有一点比较特殊,乘数寄存器的最低位被连到了控制逻辑, 也就说控制逻辑可以观察当前乘数寄存器的最低位,并据此来生成相关的控制信号, 这些控制信号就包括是否要让加法器进行 加法运算,以及是否要让乘积寄存器保存当前的运算结果。
另外,这个乘数寄存器还需要有向右移位的功能, 同样也是由控制逻辑发出的信号来进行控制的。
现在我们就有了一个完整的乘法器。就来看一看这样的一个乘法器是如何工作的。首先我们要做的工作是初始化。 也就是对这三个寄存器的内容进行设置。 我们现在要进行的运算当中被乘数是 1000, 也就要把 1000 放置到被乘数寄存器当中去。 那这个 4bit 的数是如何放到 8bit 的寄存器当中去的呢? 我们现在已经看到,我们需要在高位填上 4 个 0,为了便于区分, 我在这里将我们运算所得的数用粗体表示, 那么在被乘数寄存器当中现在的低四位 1000 就是我们这个运算本身所有的数, 而高四位的 4 个 0 是这个乘法器的系统自动补入的,所以这里用斜体来表示。 那这就是被乘数寄存器的内容了。
然后我们看乘数寄存器。 乘数寄存器很简单, 它是四位宽的,对应了 4 位的乘数,直接填入即可,
然后是乘积寄存器。 现在运算工作还没有开始,所以乘积寄存器中当前的内容是 0. 现在初始化工作已经完成,
我们开始运算了。 第一步, 请大家回忆我们用纸笔是如何进行这个运算的。 第一步我们应该做什么呢? 首先是检查乘数寄存器的最低位, 看是否为 1,现在发现它是 1,那么就需要将 被乘数寄存器当中的内容和当前乘积寄存器当中的内容进行相加, 我们把这一步命名为第一步之后的一个小的步骤,称为 1A, 在这一步控制逻辑会控制加法器,将 加法器的两个输入,也就是被乘数寄存器的内容和乘积寄存器当中的内容进行加法运算, 然后将加法器的运算结果送入乘积寄存器,在下一个时钟上来临的时候, 因为乘积寄存器的写入信号是有效的, 所以它就会采样输入端的数据,并保存到寄存器当中。 这样在这个时钟上升元之后,乘积寄存器当中的内容 就变成了 00001000,
然后我们来看第二步, 第二步应该做什么呢?我们还是需要回忆之前讲过的适合硬件做的乘法运算。 这时候我们需要对被乘数进行左移,以便为下一次运算进行准备。所以控制逻辑会给出左移的信号, 那么在下一个时钟来临的时候,被乘数寄存器就会完成一次左移, 最左端的 0 被丢弃了,在最右端补入一个 0
然后我们再来看第三步,第三步又是要做什么呢? 我们注意乘数寄存器是有右移功能的, 控制逻辑会给出右移的控制信号, 当下一个时钟上升来临的时候,乘数寄存器就会向右移动一位。 这样做只是为了方便对乘数的对应位进行判断, 在硬件上,如果要依次的对乘数从低位到高位进行逐位的判断, 那就要用硬件来记住之前判断到了哪一位, 那与其记住这样的信息,不如把乘数每次向右移一位。 这样每次只需要判断乘数寄存器当中的最低位就可以了。 而且我们根据乘法运算的过程也可以知道, 我们对乘数的使用是由低到高逐位使用的。 一旦使用过之后就不会再用了。所以我们可以放心的把乘数进行右移, 并把刚才的最低位丢弃。
所以在做完加法运算之后的第二步和第三步,实际上是在为下一轮的工作做准备。 但是我们还需要进行一个判断。那就是到底有没有下一轮。 这就是第四步,由控制逻辑进行判断, 现在是否已经完成了运算,对这个四位的乘法器来说, 一共要产生四个中间结果并将他们相加,所以与刚才类似这样的工作一共要执行四轮, 简单的计数对硬件来说是非常容易的, 所以控制逻辑可以很容易的判断出当前是否已经是第四次循环了, 当然现在不是,所以我们需要进行下一轮。
第二轮的运算方式和刚才第一轮是完全一样的。 首先判断乘数寄存器当前的最低位是否为 1, 如果为 1,则要进行加法并进行更新乘积寄存器当中的内容, 但是现在是 0,所以不需要做这一步工作。 那控制逻辑就不会产生对应的加法控制信号,以及要写入乘积寄存器的写控制信号。
于是直接进入第二步,还记得第二步是什么吗? 第二步是让被乘数寄存器左移一位。 所以在下一个时钟上升元之后,被乘数寄存器就会左移。
然后是第三步,第三步是让乘数寄存器右移一位。 再过了一个时钟上升沿,乘数寄存器就右移了一位。
然后是第四步,第四步是做什么? 第四步是判断当前的运算是否已经结束了。 当然现在还没有到第四轮,所以运算还没有结束。
因此我们还继续执行第三轮,每轮的第一步都是一样的, 就是判断乘数寄存器的最低位,在这里我们就可以看出来这样机制的好处。 就是每轮的操作内容完全是一样的, 硬件上不需要设计额外的机制去知道当前是进行到哪一轮, 也不需要智力因素的介入去判断 当前到底要分析乘数的哪一位或者如何进行中间结果的对齐等工作。 它所需要做的都是很机械的左移, 右移,判断当前乘数寄存器的最低位,这些非常简洁明了的工作。
那在第三轮的第一步我们发现乘数寄存器的最低位还是 0, 那我们就不再详细描述第三轮当中的每一步了。我们会直接跳到第四轮。 但请先想一想当我们到了第四轮的第一步的时候,被乘数寄存器当中的内容应该是什么?乘积寄存器当中的内容应该是什么, 而乘数寄存器当中的内容又会是什么?如果你有纸笔的话不妨在纸上把你所设想的这三个寄存器当中的内容 写下来,然后我们一起对比一下你的判断是否正确。
现在我们假设硬件已经依次的做完了 第三轮的第二步第三步和第四步。 现在我们到了第四轮的第一步,我们注意到被乘数寄存器又左移了一位。
它的最低 3 位现在都是移位补入的,”乘积寄存器“内容没有变化 而”乘数寄存器“又往右移动了一位。 现在只剩下最低位的这个 1,是我们初始化的时候填入的,而它高位的 3 个 0,我们看到它都是斜体的,就标明了是后来移位补入的。
那么在第 4 轮的第 1 步,我们还是要判断乘数寄存器的最低位 这时候我们发现是 1,这时候控制逻辑会做什么工作呢? 其实和第 1 轮一样,它就会控制加法器进行加法运算,将当前”被乘数寄存器“的内容和”乘积寄存器“的内容进行相加,并向”乘积寄存器“发出信号 让”乘积寄存器“在下一个时钟上升沿的时候,采样加法器的输出结果。 我们要注意,”被乘数寄存器“当中的内容已经移到了位置。 从这里我们也可以看出 用这样的方法,控制逻辑不需要关心当前”被乘数寄存器“和”乘积寄存器“ 的内容进行相加时如何进行对齐,它只要保证每一次往左移一位 然后再需要进行加法的时候,它们的对齐关系一定是正确的。 那么在执行完加法运算,并将运算结果保存到”乘积寄存器“当中之后,我们还需要对”被乘数寄存器“和”乘数寄存器“进行一个移位的操作。 那么还是和刚才一样,你可以在纸上写一下你所预想的这三个寄存器当中的内容
我们将直接跳到第 4 轮的第 4 步。
这时候我们注意,”乘积寄存器“当中的内容已经发生了变化 而被乘数和乘数寄存器也都发生了移位。 这时候”被乘数寄存器“当中,真正的被乘数 1000,已经移到了高 4 位 而低 4 位都是后来移位补入的。我们再看”乘数寄存器“ 。现在”乘数寄存器”当中这 4 个 0 全都是后来移位补入的,原先的乘数已经全部移出了 。这也说明,我们对乘数的每一位都进行了判断,我们已经完成了所有的中间结果。 当然对于硬件控制逻辑来说,它不可能像我们这样用人眼 去观察“乘数寄存器”当中乘数是否已经全部的移出 。但它的判断方法更为简单。 还是看这是否是第 4 次循环,当然我们知道,这确实是第 4 次 循环,所以在这个时候,这个乘法运算就已经完成了。 所以在最后一轮当中,被乘数和乘数这两个寄存器的移位并没有实际的意义。 好了,现在我们已经得到了这个乘法的乘积,它就在现在的”乘积寄存器“当中。 这个运算结果是 01001000。 我们可以看到,这和我们用纸笔算出来的结果是一样的。
现在,我们用这个四位乘法器的例子,知道了一个乘法器的运算过程 。那我们就来对这个运算的过程进行一个总结。
这是一个 N 位的乘法器的工作流程图。当我们做好了初始化工作之后 第 1 步,就是检查“乘数寄存器”的最低位 如果这个最低位是 1,那么就将“被乘数寄存器”和 “乘积寄存器”的内容相加,运算结果还放入“乘积寄存器”当中。 之后,再执行第 2 步,也就是将“被乘数寄存器"的内容左移一位,当然如果在第 1 步的检查当中,最低位等于 0 那就跳过第 1a 步,直接执行第 2 步;执行完第 2 步之后, 第 3 步,是将”乘数寄存器“的内容右移一位 ,第 4 步,是检查是否已经到了第 N 次循环, 如果不是,那就意味着运算还没有结束,我们只需要 回到第 1 步,再检查当前”乘数寄存器“的最低位 ,并执行相应的操作就可以了。如此往复循环,直到有一次在第 4 步检查,发现已经是第 N 次循环了。 那这就意味着这个乘法运算的工作就已经完成了 ,我们所需的运算结果就放在”乘积寄存器“当中。 这就是一个 N 位乘法器的工作流程。
现在,我们只要有足够的晶体管 构造出合适的逻辑门和触发器 就可以制造出一个完整的、可以正常工作的乘法器了。 虽然它的实现还非常地初级,但 它肯定可以正确地完成我们想要的乘法运算。