ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Logisim实战:从全加器到8位可控加减法器搭建指南

Logisim实战:从全加器到8位可控加减法器搭建指南 计算机组成原理这门课很多人第一次接触算术运算单元就是从加法器开始的。课本上讲得头头是道但真正让你在Logisim里从零搭出一个能跑起来的8位可控加减法器还是会卡住不少人。我当年做这个实验的时候光是在溢出检测那块就折腾了大半个晚上后来带学弟学妹做发现大家踩的坑高度重合。这篇内容就是把我自己反复搭过好几遍的经验整理出来从全加器的底层逻辑到最终8位可控加减法的完整电路一步一步说清楚附带关键位置的电路连接思路和参数选择依据。不管你是刚上手Logisim的新手还是已经画过4位全加器想进一步扩展到8位可控加减法的同学都能直接照着复现。1. 整体设计思路与方案选型1.1 为什么选行波进位而不是超前进位做8位加法器摆在面前的第一条岔路就是进位方式的选择。常见的有行波进位Ripple Carry Adder简称RCA和超前进位Carry Lookahead Adder简称CLA两条路线。很多教程一上来就推超前进位说速度快、延迟低但对于Logisim实验来说我的建议是老老实实走行波进位。原因很直接。行波进位就是把8个全加器串起来前一级的进位输出直接接到下一级的进位输入结构极其规整调试的时候你可以逐级测量每一位的和与进位出了问题一眼就能定位到是哪一级的全加器接错了。超前进位虽然把进位延迟从O(n)降到了O(log n)但它的进位生成逻辑Generate和传播逻辑Propagate需要额外的与门、或门网络8位下来连线复杂度翻倍在Logisim里排查一根接错的线能让你怀疑人生。从实际教学实验的角度看行波进位8位加法器在最坏情况下比如11111111加00000001的进位传播延迟是8级门延迟在Logisim的仿真速度下完全感知不到。所以除非你的实验明确要求对比两种进位方式的性能差异否则行波进位是性价比最高的选择。1.2 可控加减法的核心原理补码“可控加减法”这个需求本质上是要用一个电路同时实现加法和减法通过一个控制信号来切换。这里的关键知识点是补码运算。在二进制补码体系中减法A - B可以转化为A (-B)而-B的补码等于B的各位取反再加1。也就是说A - B A (~B) 1这个1可以巧妙地通过把最低位的进位输入Cin置为1来实现。所以整个可控加减法器的设计思路就清晰了控制信号Sub0时B的每一位不变Cin0执行A B控制信号Sub1时B的每一位取反Cin1执行A (~B) 1 A - B每一位上用一个异或门就能实现“可控取反”把Sub信号和B的对应位做异或Sub0时输出BSub1时输出~B。这个设计妙就妙在只需要一个控制信号不需要额外的选择器硬件开销极小。1.3 8位数据通路的整体架构整个8位可控加减法器由以下几个模块组成8个全加器FA串联构成行波进位链每个全加器负责一位的运算8个异或门每位一个用于根据Sub信号对B进行可控取反溢出检测逻辑根据符号位和进位情况判断是否溢出输入输出引脚A[7:0]、B[7:0]、Sub、S[7:0]、Cout、Overflow数据流向是这样的A的每一位直接进入对应全加器的A输入端B的每一位先经过异或门与Sub做异或结果进入全加器的B输入端最低位全加器的Cin接Sub信号每个全加器的Cout接到下一级的Cin最高位的Cout作为最终的进位输出。2. 全加器模块的搭建与封装2.1 全加器的真值表与逻辑表达式全加器是整个过程的基础积木它的输入是A、B、Cin输出是Sum和Cout。真值表如下ABCinSumCout0000000110010100110110010101011100111111从真值表可以推出逻辑表达式Sum A ⊕ B ⊕ CinCout AB ACin BCin AB Cin(A ⊕ B)这两个表达式直接对应电路结构Sum用两个异或门级联实现Cout用三个与门加一个或门实现或者两个与门加一个异或门再加一个与门。2.2 在Logisim中绘制全加器打开Logisim新建一个电路命名为“FullAdder”。从左侧工具栏拖入以下元件2个异或门XOR Gate用于Sum的计算2个与门AND Gate用于Cout的计算1个或门OR Gate用于Cout的合并3个输入引脚Pin分别命名为A、B、Cin设置为输入模式2个输出引脚分别命名为Sum、Cout设置为输出模式连线方式第一个异或门的两个输入接A和B输出接第二个异或门的一个输入第二个异或门的另一个输入接Cin输出接Sum引脚。第一个异或门的输出同时接一个与门的输入该与门的另一个输入接CinA和B各接一个与门的两个输入两个与门的输出接或门或门输出接Cout引脚。画完之后右键点击电路名称选择“编辑电路外观”把全加器封装成一个方块左侧三个输入引脚右侧两个输出引脚。封装的好处是后面搭8位加法器时直接实例化8个全加器模块就行电路图干净整洁不会变成一团乱麻。2.3 全加器模块的验证方法封装好之后千万别急着往下做先单独验证全加器是否正确。在Logisim里可以用“组合逻辑分析”功能自动生成真值表也可以手动把所有8种输入组合过一遍。我习惯的做法是把A、B、Cin分别接到三个输入引脚然后逐一改变输入值观察Sum和Cout是否与真值表一致。注意Logisim中引脚的“输出”属性一定要设置正确。输入引脚要勾选“输出”为否输出引脚要勾选“输出”为是。这个属性搞反了会导致信号无法正确传播而且报错信息不明显新手很容易在这里卡住。实测下来全加器验证通过之后后面8位加法器的调试工作量至少减少一半。因为8位加法器本质上就是8个全加器的级联如果每个全加器都是对的那问题只会出在级联的连线上。3. 8位可控加减法器的完整实现3.1 可控取反电路的搭建在搭建8位加法器之前先要处理好B输入的可控取反。新建一个电路命名为“ControlledAddSub”。从工具栏拖入8个异或门每个异或门的一个输入接B的对应位B0到B7另一个输入统一接Sub信号。这里有一个细节值得说一下Sub信号需要同时驱动8个异或门和最低位全加器的Cin。在Logisim中一个输出引脚可以连接多个输入端口不需要额外的扇出缓冲。但为了让电路图更清晰我建议用一条“隧道”Tunnel来传递Sub信号这样连线不会横跨整个电路图。提示Logisim的隧道功能在“布线”工具组里标签相同的隧道在逻辑上是连通的。用隧道代替长距离连线电路图的可读性会大幅提升。这个技巧在后面接溢出检测的时候同样适用。3.2 8位行波进位链的连接接下来把8个全加器实例化到电路图中。从左侧“库”面板中找到你刚才封装的FullAdder拖入8个。按照从低位到高位的顺序排列建议从左到右依次是FA0最低位到FA7最高位。连接规则如下FA0的A输入接A0B输入接异或门0的输出Cin接Sub信号FA0的Sum输出接S0Cout接FA1的CinFA1的A输入接A1B输入接异或门1的输出Cin接FA0的Cout以此类推直到FA7FA7的Sum输出接S7Cout接最终的进位输出引脚Cout这里要特别注意位序。很多同学在连线的时候把A0接到了FA7上结果算出来的结果完全不对。建议在电路图上标注清楚每一位的编号Logisim的引脚标签支持自定义把A0到A7、B0到B7、S0到S7都标上调试的时候一目了然。3.3 溢出检测电路的实现溢出检测是8位可控加减法器中最容易出错的部分。溢出的判断规则是当两个同符号数相加或相减结果的符号与预期不符时就发生了溢出。对于加法运算溢出条件可以表示为Overflow Cn ⊕ Cn-1其中Cn是最高位的进位输出Cn-1是次高位的进位输出。也就是说当最高位和次高位的进位不一致时发生了溢出。对于减法运算由于我们把它转化成了加法A ~B 1溢出的判断逻辑是一样的但需要注意符号位的含义。在补码体系中最高位是符号位0表示正数1表示负数。减法A - B中如果A和B符号不同结果可能溢出。在Logisim中实现溢出检测只需要一个异或门把FA7的Cout和FA6的Cout分别接到异或门的两个输入输出就是Overflow信号。但这里有一个坑有些教材给出的溢出检测公式是“最高位进位与符号位进位的异或”而有些给出的是“最高位进位与次高位进位的异或”。这两个公式在数学上是等价的因为最高位的符号位进位就是次高位的进位输出。但在实际连线时你要确认自己用的是哪个信号。我的建议是直接用FA7的Cout和FA6的Cout做异或这样最直观不容易搞混。3.4 完整电路图的连线检查清单搭完整个电路之后按照以下清单逐项检查检查项正确做法常见错误B输入取反每位B经过异或门与Sub异或忘记接异或门直接接B最低位Cin接Sub信号接0或悬空进位链FA_i的Cout接FA_{i1}的Cin进位方向接反溢出检测FA7的Cout异或FA6的Cout用FA7的Cout异或Sub引脚属性输入引脚不勾选“输出”输入输出属性搞反位序标注每位引脚标注编号位序混乱导致结果错误这张表是我带过好几届学生之后总结出来的基本上每次出问题都逃不出这几项。尤其是进位链方向接反这个错误在Logisim里不会报错但结果会完全错误排查起来很费时间。4. 仿真验证与常见问题排查4.1 典型测试用例的设计电路搭好之后必须用一组有代表性的测试用例来验证。我通常会用以下几组数据加法测试Sub000000000 00000000 00000000Cout0Overflow001111111 00000001 10000000Cout0Overflow1正溢出11111111 00000001 00000000Cout1Overflow0正常进位10101010 01010101 11111111Cout0Overflow0减法测试Sub100000101 - 00000011 00000010Cout1Overflow000000011 - 00000101 11111110Cout0Overflow0结果为负数10000000 - 00000001 01111111Cout1Overflow1负溢出01111111 - 11111111 10000000Cout0Overflow0这几组数据覆盖了正常运算、进位、正溢出、负溢出、结果为零等典型情况。在Logisim中逐一输入这些值观察输出是否与预期一致。4.2 常见故障与排查方法问题一加法结果正确减法结果错误。排查思路首先检查Sub信号是否同时连接到了8个异或门和最低位的Cin。如果异或门接了但Cin没接减法就会变成A ~B结果差1。其次检查异或门的另一个输入是否都接到了Sub有没有漏接或者接错的。问题二低位结果正确高位结果错误。排查思路这通常是进位链的问题。检查FA_i的Cout是否正确接到了FA_{i1}的Cin。在Logisim中把鼠标悬停在连线上可以看到信号值逐级检查进位信号是否按照预期传播。问题三溢出标志始终为0或始终为1。排查思路检查溢出检测异或门的两个输入是否分别接到了FA7和FA6的Cout。如果两个输入接到了同一个信号异或结果永远是0。如果接到了FA7的Cout和Sub那结果就完全不对了。问题四Logisim报“振荡”错误。排查思路这通常是因为电路中存在反馈回路。检查是否有输出引脚意外连接到了输入引脚或者进位链中出现了环形连接。行波进位加法器本身是纯组合逻辑不应该出现振荡。4.3 调试技巧与效率提升在Logisim中调试组合逻辑电路有几个技巧可以大幅提升效率第一善用“戳记”Poke工具。在仿真模式下用戳记工具点击输入引脚可以直接切换输入值比反复修改引脚属性快得多。第二使用“日志”功能。Logisim的信号日志可以记录一段时间内所有信号的变化对于排查进位传播问题特别有用。第三分模块验证。不要等整个8位电路搭完再测试每封装一个模块就单独验证。全加器验证通过后再搭4位4位验证通过后再扩展到8位。这样一旦出问题排查范围小很多。第四保存多个版本。Logisim的撤销功能有限建议每完成一个关键步骤就另存一个版本。我通常会用“AddSub_FA.circ”、“AddSub_4bit.circ”、“AddSub_8bit.circ”这样的命名方式出问题了可以快速回退。注意Logisim中连线交叉时如果没有实心圆点表示两条线没有连接。很多新手以为交叉就是连接结果信号根本没传过去。确保所有需要连接的交叉点都有实心圆点。5. 从8位扩展到更多位的思路5.1 位宽扩展的通用方法8位可控加减法器搭好之后扩展到16位、32位甚至64位在原理上完全一样就是把全加器继续串联下去。但有几个实际问题需要考虑首先是电路图的可读性。8个全加器已经占了不少空间16个全加器会让电路图变得很长。Logisim支持子电路嵌套你可以把4个全加器封装成一个“4位加法器”模块然后用4个这样的模块级联成16位。这样电路图层次分明调试也方便。其次是进位延迟。行波进位加法器的延迟与位宽成正比16位加法器的最坏延迟是16级门延迟。在Logisim的仿真速度下这仍然可以接受但如果你的实验要求对比不同进位方式的性能就需要考虑超前进位或者进位选择加法器了。5.2 进位选择加法器的思路进位选择加法器Carry Select Adder是一种折中方案。它的核心思想是对于高位部分同时计算进位为0和进位为1两种情况的结果然后用一个多路选择器根据实际的进位信号选择正确的输出。这样高位部分的计算不需要等待低位进位延迟从O(n)降到了O(√n)左右。在Logisim中实现进位选择加法器需要把8位分成两组4位高4位用两个4位加法器分别计算Cin0和Cin1的结果然后用一个由低4位进位控制的多路选择器选择输出。这个结构比行波进位复杂但比超前进位简单适合作为进阶实验。5.3 与ALU的整合思路8位可控加减法器是ALU算术逻辑单元的核心部件之一。在实际的CPU设计中ALU除了加减法还需要支持与、或、非、异或等逻辑运算。你可以把可控加减法器作为一个子模块外面套一层功能选择逻辑根据操作码选择不同的运算结果输出。具体做法是把A和B同时送入加减法器、与门阵列、或门阵列、异或门阵列然后用一个多路选择器根据操作码选择最终输出。溢出标志只在加减运算时有效逻辑运算时溢出标志置0。这个结构在Logisim中实现起来并不复杂是计算机组成原理实验的常见扩展题目。我在实际带实验的时候发现很多同学搭完8位加减法器之后就觉得大功告成了其实把这个模块整合进一个简易ALU才能真正理解它在CPU中的位置和作用。建议有余力的同学一定要试试这个扩展。6. 实操心得与避坑指南6.1 连线规范与可读性Logisim的电路图如果画得乱七八糟调试的时候就是自己给自己找麻烦。我总结了几条连线规范输入引脚统一放在电路图左侧输出引脚统一放在右侧进位链用水平线连接避免交叉用隧道传递Sub、Cout等全局信号减少长距离连线每个模块用矩形框标注功能比如“可控取反”、“行波进位链”、“溢出检测”引脚标签用统一的命名规则比如A[7:0]、B[7:0]、S[7:0]这些规范看起来是小事但实际调试的时候能帮你省下大量时间。我见过有同学把8个全加器摆成一个圆圈进位线绕来绕去最后自己都找不到哪根线是哪根。6.2 参数选择的依据在8位可控加减法器中实际上没有太多需要计算的参数因为位宽是固定的8位。但有几个设计选择值得说明为什么Cin接Sub而不是接0因为减法需要加1才能完成补码转换。如果Cin接0减法就变成了A ~B结果比正确值小1。为什么溢出检测用Cn和Cn-1的异或这是补码加法的溢出判断标准。当两个同符号数相加如果结果的符号与两个操作数的符号都不同说明发生了溢出。Cn和Cn-1的异或恰好能捕捉到这种情况。为什么用异或门做可控取反而不是用多路选择器异或门的硬件开销比多路选择器小得多。一个2输入异或门只需要几个晶体管而一个2选1多路选择器需要更多的门电路。在8位的规模下8个异或门比8个多路选择器节省大量硬件资源。6.3 实验报告撰写的建议如果你是在做课程实验实验报告的撰写也有讲究。除了电路图截图和真值表建议加上以下内容设计思路的推导过程特别是补码转换的原理关键信号的波形图或时序分析测试用例的设计依据和覆盖范围遇到的问题和解决过程我在批改实验报告的时候最看重的就是“遇到的问题和解决过程”这一部分。电路图大家画得都差不多但调试过程中踩过的坑和总结的经验才是真正体现你理解深度的内容。6.4 常见问题速查表现象可能原因解决方法减法结果差1最低位Cin未接Sub检查FA0的Cin连接高位结果错误进位链断裂或接反逐级检查Cout到Cin的连接溢出标志异常异或门输入接错确认接的是FA7和FA6的Cout仿真报振荡存在反馈回路检查是否有输出接回了输入输入无法切换引脚属性设置错误确认输入引脚未勾选“输出”电路图混乱连线交叉过多用隧道和子电路整理布局这张表建议在调试的时候放在旁边遇到问题先对照排查大部分常见故障都能快速定位。6.5 进阶练习建议8位可控加减法器搞定之后可以尝试以下几个进阶练习第一把行波进位改成超前进位对比两种方案的电路复杂度和仿真延迟。这个练习能让你深入理解进位传播的瓶颈在哪里。第二增加乘法和除法功能做成一个完整的8位ALU。乘法和除法可以用移位加法的方式实现虽然效率不高但能帮你理解运算器的完整功能。第三把设计移植到Verilog或者VHDL在FPGA开发板上验证。从Logisim的图形化设计转到硬件描述语言是计算机组成原理实验的自然延伸。第四尝试设计一个简单的累加器电路用8位加减法器作为核心加上寄存器存储中间结果实现连续累加功能。这个练习能帮你理解运算器和寄存器的协同工作方式。我个人在实际操作中的体会是Logisim这个工具最大的价值在于它把数字逻辑的抽象概念变成了可视化的电路。你在课本上看到的“行波进位”、“溢出检测”这些术语在Logisim里就是一根根实实在在的线和一个一个的门电路。当你亲手把这些线连起来看着信号在电路中传播最终得到正确的结果时那种对数字逻辑的理解是看书看多少遍都换不来的。所以别怕麻烦多搭几遍多踩几个坑这些经验会变成你后面学习CPU设计时最扎实的基础。
返回列表