1. 引言
在数字逻辑与计算机组成原理的学习中,乘法器是一个核心组件,它展示了如何利用基本的逻辑门来实现复杂的算术运算。本教程将带领你在 Logisim 中构建一个手动版的无符号 8 位乘法器,通过清晰的步骤和原理讲解,让你掌握其设计与验证方法。
本教程将使用Logisim Evolution 3.9.0和Logisim 2.7.1两个版本进行演示。
*注:如果出现连线正确却不知道什么原因报错,保存后重新打开即可。
2. 原理
核心原理(原码一位乘法):
- 无符号二进制乘法的原理与十进制乘法类似,都是基于移位相加。对于一个8 位被乘数和一个8 位乘数,其乘积最多为 16 位。
- 本教程实现的乘法器采用“原码一位乘法”算法,该算法将被乘数和乘数视为无符号整数。
- 由于二进制只有“0”和“1”,所以我们可以把乘法理解为加法,将被乘数或是将“00000000”加到部分积上。
- 逐位(从低到高)检查乘数的每一位,如果乘数的这一位是“1”,则加上被乘数,否则加上“00000000”,然后用同样的方法继续判断乘数的下一位。
- 每次使用的那个乘数位,用完后可以直接丢弃。
- 每次加法结果的最后一位(即下图蓝色数字),在后续步骤不再参与运算,所以我们可以提前存起来,这样下一步就只用算8 位加法(本教材的方法只使用 8 位加法器)。
- 例子如下图,我们计算183 × 166 = 30378,最终结果为 16 位(0111011010101010=30378),绿色为高 8 位(01110110),蓝色为低 8 位(10101010)。
核心算法(移位相加法):
初始化:用三个寄存器分别存储乘数 A(最后会寄存积的低 8 位)、被乘数 B和部分积 P(最后会寄存积的高 8 位)。其中P 初始为 0,B在整个计算过程中保持不变,P 、A在每轮循环后右移一位。
检查乘数最低位:观察A 寄存器的最低位(即最右边一位)是1 还是 0。
条件选择加法:如果 A 的最低位为 1,则执行P = P + B;如果为 0,则P = P + 0(即不变)。
整体右移:将 P 和 A 拼接成一个 16 位的整体,然后整体向右移动一位。
P 的最低位移出后,补入 A 的最高位(这样 A 同时寄存未使用的乘数位和部分积的低位,节省寄存器)。
A 的最低位(即刚才已经检查过的那一位)被直接丢弃。
循环控制:重复步骤 2~4,共循环 8 次。
输出结果:8 次循环结束后,P 中存储的是乘积的高 8 位,A 中存储的是乘积的低 8 位。分别输出,即得到 16 位最终结果。
3. 准备工作
在开始搭建之前,请确保你已经准备好以下子电路:
- 8 位寄存器:【Logisim 本地搭建】带时钟信号的简单 8 位寄存器的详细教程
- 8 位三态门:【Logisim 本地搭建】三态门的详细教程
- 8 位加法器:【Logisim 本地搭建】半加器、全加器与 8 位加法器的详细教程
4. 搭建步骤
- 新建电路:新建一个电路,命名为“Multiplier_8”。
- 初始化寄存器:从上到下放置 3 个8 位寄存器,分别命名为“P”(用于保存部分积)、“A”(用于保存乘数)、“B”(用于保存被乘数)。
- Logisim Evolution:
- Logisim:
- Logisim Evolution:
- 布置 P 寄存器:
- 放置 1 个多路复用器/数据选择器(为了控制 P 的初始化),设置选择位为 1,数据位为 8。
- 其“输入0”端连接 8 位常量“0”。
- 其“输入1”端暂时置空。
- 其“输出”端通过分线器/分离器连接P 寄存器的输入“D7~D0”。
- 其“选择”端连接一个输入引脚“Load_P_Reg”。
- 放置 1 个输入引脚“Clock_P_Reg”连接P 寄存器的输入“Clock”。
- Logisim Evolution:
- Logisim:
- 布置 A 寄存器:
- 放置 1 个多路复用器/数据选择器(为了控制 A 的初始化),设置选择位为 1,数据位为 8。
- 其“输入0”端通过分线器/分离器连接 8 个输入引脚“A_Reg7~A_Reg0”。
- 其“输入1”端暂时置空。
- 其“输出”端通过分线器/分离器连接A 寄存器的输入“D7~D0”。
- 其“选择”端连接一个输入引脚“Load_A_Reg”。
- 放置 1 个输入引脚“Clock_A_Reg”,连接 A 寄存器的输入“Clock”。(Logisim版的A 寄存器的“Clock”用“输入引脚”连接后续会报错,必须换成“按钮”,其他寄存器的“Clock”可以根据自己的习惯使用“按钮”或“输入引脚”)
- Logisim Evolution:
- Logisim:
- 布置 B 寄存器:
- 放置 8 个输入引脚,分别命名为“B_Reg7~B_Reg0”,连接B 寄存器的输入“D7~D0”。
- 放置 1 个输入引脚“Clock_B_Reg”,连接 B 寄存器的输入“Clock”。
- Logisim Evolution:
- Logisim:
- 构建条件选择逻辑:
- 在B 存储器右边放置8 个与门,各个与门的一个输入端分别连接B 寄存器的输出“Q7~Q0”,另一个输入端连接A 寄存器的输出“Q0”。
- Logisim Evolution:
- Logisim:
- 构建寄存部分积逻辑:
- 在P 寄存器右边放置一个8 位寄存器,命名为“P_Buffer”,用于缓冲数据。
- 将P_Buffer 寄存器的输入“D7~D0”连接P 寄存器的输出“Q7~Q0”。
- 放置 1 个输入引脚“Clock_PB_Reg”连接P_Buffer 寄存器的输入“Clock”。
- P 寄存器和P_Buffer 寄存器中间的导线称为“线路1”,部分积将寄存到这段导线中,切断了组合逻辑反馈环路,为加法器提供稳定的输入。
- Logisim Evolution:
- Logisim:
- 构建加法逻辑:
- 放置一个8 位加法器。
- 将P_Buffer 寄存器的输出“Q7~Q0”连接到加法器的输入“A7~A0”。
- 将8 个与门的输出端连接到加法器的输入“B7~B0”。
- 加法器的进位输入“Cin”可以置空(Logisim版不能置空,可以接一个常量“0”或接地)。
- 加法器的输出“Cout~S0”连接 1 个9 位分线器/分离器(高位在上低位在下)。
- 为了方便观察数据,可以在加法器和分线器中间加上 9 个LED 灯。
- Logisim Evolution:
- Logisim:
- 构建移位逻辑:
- 在P 寄存器左边放置 1 个9 位分线器①和 1 个8 位分线器②。
- 在A 寄存器右边放置 1 个8 位分线器③。
- 9 位分线器①的输入端连接加法器分线器的输出。
- 其“8~1”位输出端连接8 位分线器的“7~0”位输入。
- 其“0”位输出端连接8 位分线器③的“7”位输入。
- 8 位分线器②的输出连接P 寄存器的多路复用器的“输入1”端。
- 8 位分线器③的“6~0”位输入连接A 寄存器的输出“Q7~Q1”
- 其输出端连接A 寄存器的多路复用器的“输入1”端。
- Logisim Evolution:
- Logisim:
- 构建输出逻辑:
- 放置 2 个8 位三态门,分别命名为“High”和“Low”。
- High 8 位三态门的输入端“A7~A0”连接P_Buffer 寄存器的输出“Q7~Q0”,输入端“EN”连接 1 个输入引脚“EN_H”。
- Low 8 位三态门的输入端“A7~A0”连接A 寄存器的输出“Q7~Q0”,输入端“EN”连接 1 个输入引脚“EN_L”。
- 两个8 位三态门的输出端同时连接8 个输出引脚“Q7~Q0”。
- Logisim Evolution:
- Logisim:
5. 成果验证
我们可以尝试计算183 × 166 = 30378,步骤如下:
- 输入乘数和被乘数:
- 在乘数寄存器 A 的键盘中输入“166”(A_Reg7~A_Reg0=10100110)
- 在被乘数寄存器 B 的键盘中输入“183”(B_Reg7~B_Reg0=10110111)
- 初始化 A 寄存器:
- 打开乘数寄存器 A ,给它一个上升沿,寄存初始数据(Clock_A_Reg=1)
- 关闭乘数寄存器 A(Clock_A_Reg=0)
- 如果你使用按钮,把以上两步变为:点击一下按钮
- 给乘数寄存器 A 上锁,代表我们已存入初始值(Load_A_Reg=1)
- 初始化 B 寄存器:
- 打开被乘数寄存器 B,给它一个上升沿,寄存初始数据(Clock_B_Reg=1)
- 此时,乘数最后一位和被乘数相与的结果已自动送入加法器
- 关闭被乘数寄存器 B(Clock_B_Reg=0)
- 初始化 P 寄存器:
- 打开部分积寄存器 P ,给它一个上升沿,把常数 0 寄存到线路 1 (Clock_P_Reg=1)
- 关闭部分积寄存器 P(Clock_P_Reg=0)
- 给部分积寄存器 P 上锁,代表我们已存入初始值(Load_P_Reg=1)
- 把部分积送入加法器:
- 打开缓冲寄存器 P_Buffer ,给它一个上升沿,把部分积送入加法器(Clock_PB_Reg=1)
- 关闭缓冲寄存器 P_Buffer(Clock_PB_Reg=0)
- 第一次加法结果:此时加法器已算出结果, LED 灯显示“0 00000000”
- 第一次循环寄存:
- 打开部分积寄存器 P ,给它一个上升沿,将加法结果寄存到线路 1(Clock_P_Reg=1)
- 关闭部分积寄存器 P(Clock_P_Reg=0)
- 打开乘数寄存器 A ,给它一个上升沿,整体右移一位,并寄存加法结果的最低位(Clock_A_Reg=1)
- 此时,乘数最后一位和被乘数相与的结果已自动送入加法器
- 关闭乘数寄存器 A(Clock_A_Reg=0)
- 打开缓冲寄存器 P_Buffer ,给它一个上升沿,把部分积送入加法器(Clock_PB_Reg=1)
- 关闭缓冲寄存器 P_Buffer(Clock_PB_Reg=0)
- 第二次加法结果:此时 LED 灯显示“0 10110111”
- 第二次循环寄存:步骤同第一次循环寄存
- 第三次加法结果:此时 LED 灯显示“1 00010010”
- 第三次循环寄存:步骤同上
- 第四次加法结果:此时 LED 灯显示“0 10001001”
- 第四次循环寄存:步骤同上
- 第五次加法结果:此时 LED 灯显示“0 01000100”
- 第五次循环寄存:步骤同上
- 第六次加法结果:此时 LED 灯显示“0 11011001”
- 第六次循环寄存:步骤同上
- 第七次加法结果:此时 LED 灯显示“0 01101100”
- 第七次循环寄存:步骤同上
- 第八次加法结果:此时 LED 灯显示“0 11101101”
- 第八次循环寄存:步骤同上
- 输出高位乘法结果:
- 打开高位三态门 High,输出结果,此时输出为“01110110”(EN_H=1)
- 关闭高位三态门High(EN_H=0)
- 输出低位乘法结果:
- 打开低位三态门 Low,输出结果,此时输出为“10101010”(EN_L=1)
- 关闭低位三态门Low(EN_L=0)
6. 总结
通过本教程,你成功在 Logisim 中构建了一个手动版的无符号 8 位乘法器。这个过程让你掌握了二进制乘法的硬件实现原理,并熟悉了 Logisim 中寄存器、加法器、多路选择器等基本元件的使用。
你可以在此基础上进行扩展,例如实现有符号乘法(Booth算法)、增加流水线、或将其封装为一个子电路(Subcircuit)供更大系统调用。