1. 为什么学计算机的人都绕不开这个加法器实验先聊点题外话。很多人第一眼看到“logisim 实验通过 2 个半加器实现 1-bit 全加器通过 4 个一位全加器构成 4-bit 加法器”这个题目内心多半是“这有什么好写的不就是画个电路图吗”。但我可以负责任地说这个实验是数字逻辑和后续 CPU 设计之间真正的分水岭。我当年是在《计算机组成原理》实验课上第一次在 Logisim 里把 4 个一位全加器串起来当时觉得不过是在连线后来学到 ALU、流水线进位、溢出标志位才发现当年亲手接过的这条进位链几乎是理解整个处理器核心运算逻辑的基础。这个项目标题里其实隐藏了三层递进关系。第一层是半加器它处理两个二进制位的相加第二层是全加器它把人人都容易忽略的“低位进位 Cin”引入加法过程第三层是 4-bit 加法器它把多个一位全加器按进位关系串联扩展成能算多位二进制数的电路。三步走完你不仅在 Logisim 里画出了一张能动的电路图也把“组合逻辑电路设计”从理论变成了自己能亲手验证的东西。这篇文章适合这几类人看正在上数字逻辑课、需要交 Logisim 实验报告的同学自学计算机底层想搞懂加法器到底怎么工作的爱好者还有打算做 CPU 设计实验想先把数据通路基础打牢的人。我会尽量把每一步的“为什么”也讲清楚而不只是告诉你该怎么连线这样才能在换了一道类似题、甚至换了一个仿真工具之后你依然能自己推出来。2. 准备知识Logisim 里需要掌握的“几个小动作”2.1 Logisim 界面里你必须先认识的几个元件Logisim 是一个教学用的数字电路仿真软件常见版本是 2.7.1开源、跨平台很多学校的计算机组成原理课都用它。打开软件后左侧栏是元件库我们这次用到的都在“导线Wiring”和“门Gates”两个分类下面输入引脚 / 输出引脚Pin在“导线”分类里。默认位宽是 1 位可以双击改属性里的“位宽Bit Width”。输入引脚通常放在电路左边输出引脚放在右边这不是硬性规定但这样画出来的图一眼就能看懂信号流向。与门AND Gate、或门OR Gate、异或门XOR Gate、非门NOT Gate在“门”分类里。默认输入数是 2双击或改属性可以增加输入端口数。需要说明的是全加器里的“第二个半加器”要求异或门搭出来之后如果输出不对先检查门的类型有没有选错。连线工具箭头图标默认选中状态下点击一个引脚端口拖到另一个端口就能连线。只要端口之间是高亮状态就说明这一头能连上松手即可。文本标签Text Label用来给输入端、输出端、进位信号加注释。实验报告里老师一般都要求标注清楚 A、B、Cin、Sum、Cout所以这个功能别忽略。探针Probe和小灯泡LED都可以用来观察信号状态。探针在“导线”分类里LED 在“输入/输出”分类里实测探针更方便因为它能直接显示引脚名和当前电平。Logisim 有一个对新手很不友好的细节当你从元件库拖动元件时默认是“选择模式”也就是用鼠标拖动、连线但如果你不小心敲击了键盘上的字母会触发快捷放置元件的功能比如按a会直接放一个与门按x会放一个异或门按i会放一个输入引脚。本来只想按 CtrlS 存盘结果屏幕上冒出一个莫名其妙的元件这种情况我见过太多人踩坑。万一出现直接按 Delete 删掉就行不用慌。2.2 为什么是半加器 → 全加器 → 4-bit 加法器这个路线先把这个“三步走”的设计逻辑理清楚你后面才会有方向感。半加器解决的是“两个二进制位相加”的问题。二进制加法和十进制一样也可能出现进位所以半加器要输出一个“和位”以及一个“进位位”。但它最大的问题在于它完全没有考虑低位可能传上来的进位。做 1 位以内加法还好一旦做多位加法低位相加产生的进位必须传到高位参与运算半加器就无能为力了。全加器则是在半加器的基础上多了一个输入端口 CinCarry in低位进位输入。它不仅要算 A 加 B还要把 Cin 一起算进去。这样多位二进制加法才能通过“低位进位 → 高位输入”的方式串联起来。这也是实验标题里“通过 2 个半加器实现 1-bit 全加器”的道理所在半加器是积木全加器是更完整的积木而 4 个全加器串起来就是能算具体数字的 4-bit 加法器。整个路线本质上是把复杂问题逐层分解。数字电路设计里最常用的思维方式是“先设计功能单元再考虑如何组合扩展”你跟着这个实验走一遍以后不管是做计数器、乘法器还是 CPU 里的运算器都会习惯性地先找“基础模块”。3. 第一步用 Logisim 搭出半加器3.1 半加器的真值表与逻辑表达式半加器Half Adder有两个输入 A、B分别是被加数和加数两个输出 SSum和 CCarry。先列出真值表ABS和C进位0000011010101101从这个表可以直接看出两个逻辑关系S A XOR B异或门正好实现“两个输入不同则为 1”的规则。C A AND B与门实现“两个输入都为 1 才输出 1”。所以半加器在 Logisim 里的结构非常简单一个异或门接出 S一个与门接出 C输入分别并联到两个门。这里有个需要注意的地方很多人一开始会把 S 和 C 的输出接反或者把异或门和或门混用结果测试时看到 01 和 10 两种情况输出正确但 11 时进位和和位对不上。所以每接完一步立刻用真值表逐行测试别等全部电路搭完再去查。3.2 在 Logisim 里具体怎么连线我按我演示时的步骤写一遍你照做基本不会有问题新建一个项目保存为half_adder.circ。在左侧“导线”分类里拖出两个输入引脚分别命名为 A、B。双击引脚可以修改标签建议把位宽保持为 1。拖出一个异或门XOR Gate和一个与门AND Gate。两个门可以垂直对齐摆放异或门放上面与门放下面方便后续连线。把 A 分别连到异或门的上面输入端和与门的上面输入端。B 分别连到异或门的下面输入端和与门的下面输入端。连线时鼠标靠近端口端口会变亮说明已经对准。拖出两个输出引脚一个命名为 S一个命名为 C。S 接异或门输出端C 接与门输出端。连接完成后点击菜单栏“仿真Simulate”里的“复位Reset”然后用“手指工具”点击输入引脚切换电平。你按下 CTRLT 可以持续自动仿真也可以手动切换。把四行真值表都测一遍A0B0 时S0C0A0B1 时S1C0A1B0 时S1C0A1B1 时S0C1。只要这四种情况全部对上半加器就算完工了。提示Logisim 的默认仿真模式下导线的颜色会随信号变化。在很多版本中绿色/深绿色表示 0亮绿色或淡绿色表示 1也有的版本用蓝绿色调区分。如果你在连线后看到某个连接点是红色的小方块说明有冲突或没接好这不是正常的“逻辑 1”状态需要重点检查。3.3 半加器的局限为什么单靠它不能做多位加法这一步很容易被忽略但恰恰是理解全加器的钥匙。你试一下把两个半加器串联让第一个半加器的 S 作为第二个半加器的一个输入再给第二个半加器加一个“能表示低位进位”的输入这不就是标题里的“全加器”了吗但是在动手搭之前先想清楚半加器的问题在哪。半加器只有两个输入 A、B当它做 11 的时候输出 S0、C1这个 C 就是进位。如果上面还有更高位这个进位必须“加”到那一位的计算里。可是半加器自己根本没有另一个输入端口可以去接收这个来自低位的进位。所以只要超过 1 位半加器单独就撑不住了。你需要一个带第三个输入 Cin 的全加器来接收它。这也是为什么实验标题强调“先实现全加器再构成 4-bit 加法器”顺序不能乱。4. 核心环节两个半加器加一个或门组成全加器4.1 全加器到底多了一个什么输入全加器Full Adder有三个输入A、B、Cin低位进位输入两个输出Sum和、Cout进位输出。列出全加器真值表ABCinSumCout0000000110010100110110010101011100111111这个表值得多看两遍。你会发现 Sum 这一列和“三个输入中 1 的个数是奇数则输出 1”的规则对应也就是说 Sum A XOR B XOR Cin。而 Cout 这一列则是“三个输入中至少有两个 1 则输出 1”。这个规律不是巧合它正是二进制加法进位的本质只要参与相加的三个位里 1 的个数不少于 2那结果必然产生进位。4.2 两个半加器是如何配合的现在来看标题里的关键操作用两个半加器加一个或门来实现全加器。第一个半加器负责计算 A 和 B 的和输出一个中间和 S1以及一个中间进位 C1。第二个半加器负责把 S1 和 Cin 再相加输出最终的 Sum同时也会产生一个新的中间进位 C2。这时候会出现一个情况C1 和 C2 都可能是 1那么最终 Cout 到底怎么取逻辑是只要 C1、C2 任意一个是 1最终进位就是 1。所以用一个或门把 C1 和 C2 连接起来输出就是 Cout。这里有一个很多初学者会纠结的问题C1 和 C2 会不会同时为 1理论上不会因为 A 和 B 如果同时为 1第一个半加器的 S1 就是 0那么第二个半加器无论如何也不会产生 C21反过来如果 A、B 不同时为 1那么 S1 可能是 1此时只有当 Cin1 时 C2 才为 1而 C1 在 A1、B0 或 A0、B1 时都是 0。所以两个中间进位最多只有一个为 1或者两个都为 0绝不会同时为 1。但也正因为如此这里用或门是完全正确的而不是异或门或与门。这个推论过程最好自己推一遍比死记“加一个或门”要有效得多。4.3 完整搭建步骤与连线细节在 Logisim 里你有两种做法第一种是“平铺法”也就是在一张图里画两个半加器再加一个或门。第二种是“子电路法”把之前做好的半加器保存成子电路然后反复调用。这里我先讲平铺法因为子电路法在 4-bit 加法器部分更常用到时我会详细说。平铺法的连线步骤新建一个电路命名为full_adder或者直接在原来的画布里接着画。先画第一个半加器一个异或门XOR1、一个与门AND1。这两个门的输入都接 A、B。把 XOR1 的输出作为 S1接到第二个半加器的第一个输入把 AND1 的输出作为 C1暂时留着最后接或门。画第二个半加器再放一个异或门XOR2和一个与门AND2。XOR2 的一个输入接 S1另一个输入接 CinAND2 的两个输入也分别接 S1 和 Cin。把 XOR2 的输出命名为 Sum这就是全加器的和位输出。放一个或门OR1把 AND1 的输出 C1 和 AND2 的输出 C2 分别接到或门的两个输入或门输出命名为 Cout。把 A、B、Cin 三个输入引脚放好把 Sum、Cout 两个输出引脚放好。连完后测试一下把三种 8 组输入全部试一遍。重点看 A1、B1、Cin1 这一行此时 Sum1、Cout1代表 111 3二进制数是 11。如果你发现这一行输出不是 11问题大概率出现在 or 门或者第二个半加器的输入端接错了。这里还有一个非常常见的实操问题在 Logisim 里当你同时拖动两条线靠近时它们有时会自动合并成一个节点这是仿真软件自动连线功能导致的。如果你不希望两条线被连在一起可以选择“线束”工具或使用快捷键调整或者干脆把信号的布局拉得更开避免交叉。画电路图时尽量养成“输入在左、输出在右、走线不交叉”的习惯这能减少很多不必要的错误。4.4 为什么全加器不是“半加器 半加器 或门”这么简单这个问题听起来有点绕但实际是实验报告里老师最爱问的思考题。答案是结构上确实是“两个半加器 一个或门”但每个半加器的输入输出角色并不相同。第一个半加器处理的是原始两个加数 A、B第二个半加器处理的是第一个半加器的和 S1 与 Cin。如果你把 Cin 当成“另一个加数”那第二个半加器本质上还是在做“两个二进制位相加”只不过其中一位变成了进位输入。所以全加器的内部结构并没有出现“三个数同时相加”的魔法它只是通过两次两数相加把三数相加结果拆解掉了。这个思想在后来的加法器优化比如超前进位加法器里也一样用基本的门单元去组合只是换了一种让进位更快产生的方式。5. 第三步用 4 个一位全加器构成 4-bit 加法器5.1 并行加法器结构里的“进位链”当你有了一个能处理 1-bit 的全加器扩展到 4-bit 就顺理成章了。思路是把 4 个全加器按从低位到高位的顺序排好让低位的 Cout 连接到高一位的 Cin。这就是典型的“行波进位加法器Ripple Carry Adder”也是教科书里最朴素的加法器实现。假设要计算 A3A2A1A0 B3B2B1B0最低位是第 0 位。最低位的 Cin 固定为 0因为没有更低位给它进位了然后第 0 位A0 B0产生 Sum0 和 C1C1 接到下一位的 Cin第 1 位A1 B1 C1产生 Sum1 和 C2C2 接到下一位的 Cin第 2 位A2 B2 C2产生 Sum2 和 C3C3 接到下一位的 Cin第 3 位A3 B3 C3产生 Sum3 和 Cout第 4 位进位。最终结果是一个 5 位的二进制数Cout Sum3 Sum2 Sum1 Sum0。这个 Cout 就是我们通常说的“溢出位/进位标志”在 CPU 里会被写进状态寄存器。我当年做实验时一开始把形成最终结果的顺序搞反了导致把进位当成最高位结果死活验算不对。这里要特别注意最低位在最右边最高位在最左边和我们平时写二进制数的习惯一致。5.2 在 Logisim 中如何快速补齐 4 位电路在 Logisim 中你有两种方式方式一每次都手动复制粘贴全加器。复制的时候选中整个全加器按 CtrlC、CtrlV。但这样布线容易乱而且元件名会重复调试起来很痛苦。方式二把全加器封装成子电路然后实例化 4 次。这也是我最推荐的方式因为后面假如要改成 8-bit只要再拉 4 个实例就行不用重画整个加法器。子电路步骤在工程面板里右键点击电路列表选择“添加电路Add Circuit”把当前做的全加器电路重命名为FullAdder。把这个电路的输入输出引脚整理好。这里要注意Logisim 会自动识别电路里的输入引脚 Pin 和输出引脚 Pin它们是子电路的对外接口。你双击子电路实例时引脚的位置就是你在 FullAdder 电路里摆的位置。回到顶层电路可以新建一个adder4bit电路从左侧元件库最下面找到“FullAdder”直接拖 4 个出来。把这 4 个 FullAdder 垂直排列最下面是低位最上面是高位。接着开始连线。A0、B0 接到第一个全加器它的 Cin 接地也就是接逻辑 0Cout 接到第二个全加器的 Cin以此类推。最终第 4 个全加器的 Cout 就是进位输出 C4。5.3 测试方案输入、输出、以及用十进制验证我强烈建议你在顶层电路里加 8 个输入引脚和 5 个输出引脚分别表示A3 A2 A1 A0加数B3 B2 B1 B0被加数Sum3 Sum2 Sum1 Sum0和C4进位输出然后选几组典型数据测试十进制A 二进制B 二进制期望结果二进制3 400110100001117 1011100010100010 61010011010000C4115 151111111111110C41测试时最直观的方法是把输入引脚按顺序排列比如最高位 A3 在最上面最低位 A0 在最下面然后从右往左读数据。比如 A1010就是从上到下点成 1、0、1、0。很多人在这一步会看反方向导致测试结果和期望完全不符。测完之后把仿真输出和手算结果对比。如果 C4 为 1代表结果超出 4 位二进制能表示的范围这是正常现象说明加法器正确实现了溢出的物理行为而不是“算了 0”。这时候不要急着说错误先看整体输出二进制序列是否和手算一致。5.4 位宽知识为什么不直接把输入引脚位宽改成 4这个问题非常关键也是很多人在做完之后才醒悟的。Logisim 里输入引脚可以设置位宽为 4那样你可以输入一个 4 位向量但门电路和全加器子电路的引脚位宽都是 1。即使你把输入位宽改成 4也不能直接接到 1 位端口上因为位宽不匹配Logisim 会出现错误提示。所以在做这个 4-bit 加法器时有两种合理策略策略一保持 1 位输入并列放置 8 个输入引脚。这种做法接线清晰适合教学实验和调试。策略二把加法器封装成更大的子电路让子电路内部用 1 位端口外部再用位宽为 4 的引脚对接。这属于更高阶的用法适合做 CPU 设计实验时复用。我建议初学者先把策略一跑通。等你彻底明白了每个全加器只能处理 1 位你再去研究位宽向量合并就不会一头雾水。6. 排错实录我踩过并且你应该避开的坑6.1 Logisim 仿真没反应或输出全是 0先排除最基本的问题你点击输入引脚切换电平但输出没有任何变化大概率是输入引脚根本没有连到门电路上。在 Logisim 里连线的判定非常严格如果端口没有完全对齐线会处于“悬空”状态而不是自动吸附。检查时把鼠标悬停在导线上如果发现某个端口高亮但导线没有连过去重新拉线。还有个容易忽略的点电路顶层的“输入引脚”和“输出引脚”在默认状态下位宽可能不是 1。如果你从元件库拖出来的是默认的 1 位引脚但某个引脚属性里被改成了 4那它接 1 位门时不会生效。解决办法是双击引脚把位宽改回 1。6.2 进位输出 Cout 总是得多 1 位我见过太多人在这里卡壳。比如 0111 0001手算是 010005 位可是电路里只输出 4 位 Sum最后的进位 C4 单独作为输出。如果你把 C4 和 Sum4 合并看数时顺序写反很容易把 01000 当成 00010误判为“错误”。这里必须养成的习惯是加法和手算一样进位要写在最高位前面。在电路图上我会把 C4 输出引脚放在 Sum3 的左边这样从左往右读就是 C4 Sum3 Sum2 Sum1 Sum0刚好对应 5 位二进制结果。6.3 最低位的 Cin 忘了接 0如果最低位的 Cin 悬空Logisim 会默认把它当作未定义状态而不是 0这时结果会完全不可预测。正确的做法是往最低位全加器的 Cin 输入端接一个常数 0。在 Logisim 里可以在“导线”分类下找到“常量Constant”把它的值设置为 0然后连到最低位的 Cin 上。别忘了这个小小的连接否则你整个加法器在所有奇数相加的情况下都可能出错。6.4 门电路类型选错全加器里第一个半加器的和位用异或门第二个半加器的和位也用异或门进位合并用或门。如果你在“Cout C1 OR C2”这一步误用了异或门由于 C1 和 C2 不会同时为 1功能上可能仍然正确但一旦碰到某些边界情况比如仿真器对悬空值的处理就可能出现不可靠结果。而如果你把“S A XOR B”误写成了“S A OR B”那么 11 时你会得到 S1、C1算出来是 3 其实没错但 10 和 01 时也没错只有 00 时 S0 也正确——看起来好像全对但事实上你把加法和二进制真值表理解错了等到做全加器时就会彻底乱套。所以每一步都要用真值表严格验证不要只看一两个典型输入。6.5 线的颜色和节点问题Logisim 里连线交叉时如果没有节点两条线互不相连只是视觉上交叉。有节点则代表相连。如果你画图时不小心在交叉点点击了一下可能会自动生成节点导致两条本不该相连的信号被短路。排查异常输出时先检查所有交叉点看看有没有意外出现的实心小圆点。如果不需要连接直接选中节点按 Delete 删除。这个问题在图纸越复杂时越致命因为它会悄无声息地改变整个电路的逻辑。7. 后续的扩展加法器还能怎么玩做完这个 4-bit 加法器其实你的实验基础已经很扎实了。我再提供几个扩展方向你可以根据兴趣尝试。7.1 用加法器实现减法有了加法器减法并不难。减去一个数等于加上它的补码。对一个二进制数取反加 1就得到它的补码。你可以在 B 输入端前面加一排非门取反再把最低位的 Cin 从 0 改成 1这样整个电路就相当于在算 A (~B) 1也就是 A - B。扩展之后你会更加理解为什么 CPU 里加法器才是核心减法只是个“变体”。7.2 用子电路封装出可复用加法器把 4-bit 加法器封装成一个子电路然后实例化两次就能组合出 8-bit 加法器。配合 Logisim 的位宽设置你还可以做一个更通用的参数化加法器。这在后面做单总线 CPU 设计、只有 ADD 指令的微型计算机实验时会非常有用。反正我当年做单总线 CPU 时整个 ALU 就是从 4-bit 加法器慢慢扩展来的。7.3 研究更快的进位方式行波进位加法器每高一位都要等低位的进位算出来速度慢得感人。感兴趣的话可以去搜索“超前进位加法器Carry Look-Ahead Adder”的实现思路它在电路里用额外逻辑直接计算各位的进位而不是逐级传递。虽然实验不一定要求但能亲手在 Logisim 里画出这种优化结构对理解“电路速度和复杂度平衡”这个问题帮助极大。最后再分享一个我个人的习惯每次搭完一个子电路我都会复制一份留底然后在原图上用不同颜色把输入、输出、进位路径分开标注。实验课上我还见过有人用笔在纸上把每个元件的真值表先写出来再连线虽然看起来慢但极大减少了返工时间。你愿意的话也可以试试先在纸上画好结构图再打开 Logisim 照图连线而不是一边想一边连。这种“先设计、再实现”的顺序才是这个实验真正想教给你的东西。