ARTICLE DETAIL

资讯详情

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

Logisim搭建CLA182四位先行进位加法器:从原理到完整测试

Logisim搭建CLA182四位先行进位加法器:从原理到完整测试 大二下学期第一次进计算机组成原理实验室不少同学对Logisim的第一印象是这不就是个画电路图的工具嘛连线就完事了。结果做到CLA182四位先行进位实验时一排人卡在验证阶段明明照着PPT上的门电路图画完了输入一组加法却怎么都对不上预期值。问题就出在进位链上——它不是一根简单的导线每一条进位路径都有固定的逻辑依赖画错一根线、接反一个G和P结果都是看起来很像但就是不对。这篇文章我就按自己完整做完这个实验的流程把CLA182的来龙去脉、Logisim里的搭建顺序、以及我整理的一套完整测试用例全部写出来。内容面向正在学计算机组成原理、被实验课折磨的本科生也适合想自己动手验证先行进位到底怎么个快法的爱好者。看完之后你能独立完成整个电路也能用测试用例证明你的电路功能正确。1. 为什么CLA182让加法器变快先吃透进位链再动手想搭CLA182脑子里必须先把为什么需要它这个问题搞清楚。很多同学直接跳进Logisim开始拖门电路拖到一半就乱了根本原因就是不知道每个模块存在的意义。1.1 行波进位的延迟瓶颈在哪里先看最朴素的加法器方案。一位全加器有三个输入A_i、B_i以及来自低位的进位C_i两个输出和S_i以及送往高位的进位C_{i1}。把四个一位全加器串联起来就得到一个4位行波进位加法器。这个方案的致命问题在进位传递。第0位的进位输出C1要经过第1位的全加器才能算出C2C2再经过第2位才能算出C3。也就是说最高位的进位C4必须老老实实等着前面每一级算完一条链上的门延迟逐级累加。用数字说话一位全加器算进位大约要经过两级门那么4位的行波进位最坏路径大约是8级门延迟到了32位最坏路径就要64级门延迟。位数越多加法越慢这就是行波进位的局限。打个比方行波进位像一队人排队传话第一个人把话传给第二个第二个人再传给第三个全程必须一个接一个来。你要是让第100个人提前知道内容他也没办法因为消息还在路上。1.2 先行进位的核心思路把进位并行算出来CLA182的思路很直接既然每一位的进位C_{i1}只取决于A_0到A_i、B_0到B_i以及外部进位C0那我干脆把这些变量直接组合成一个逻辑表达式让所有进位同时开始计算而不是一级一级等。4位的情况下C1到C4的表达式可以被展开成若干与项之和的形式。这样每一位的进位都只经过固定的门延迟就能得到和位数无关。换句话说我在同一时刻给电路输入A0到A3、B0到B3和C0经过大约两到三级门延迟C1、C2、C3、C4会同时稳定下来。这就像把排队传话改成了群发消息每个人拿到原始信息后各自算自己的部分不用等别人。位数增加时门电路数量会变多但延迟还是那几级。1.3 74LS182在课程里的定位这里要把名字解释清楚。CLA是Carry Look-Ahead的缩写四位先行进位182这个编号来自经典的54/74LS182芯片那是一颗专门实现四位超前进位逻辑的TTL器件输出C1到C4以及组级联用的G*和P*。实验课里如果要求用Logisim实现CLA182通常有两种做法一种是在Logisim里直接调用芯片库里的74LS182符号另一种是用基础门电路把它等效搭出来。多数学校会要求后者因为这才真正考察你对进位逻辑的理解。我当时用的是唐朔飞教材配套的实验任务要求用门电路搭出与74LS182功能等价的四位先行进位部件。所以下面的所有搭建步骤都以门级等效实现为主线最后为了验证方便把整个电路封装成了子电路。2. 开工前的环境准备Logisim版本选择和布线习惯这个实验的工程量不算大但Logisim的版本、布线习惯和引脚规划会直接影响你的调试心情。我自己第一次就是直接在默认画布上乱拖结果信号线绕成一团根本查不下去。2.1 版本怎么选Logisim目前常见的版本是2.7.1和3.x系列。2.7.1是老牌的稳定版网上能下载到的中文教程大多数基于它3.x的界面更现代化菜单组织略有不同。我个人的建议是如果实验报告要求截图跟老师平常演示的版本保持一致如果自由选择用2.7.1或者3.6以上的版本都可以逻辑功能没有任何差别。下载的话去官网或者课程群老师提供的校内镜像注意别在第三方下载站乱下很多捆绑插件。装好后建议用英文界面因为网上能搜到的英文资料和Stack Overflow的问答基本都是英文菜单对照着找功能更省事。中文翻译在某些版本里把Label翻译成标签、把Splitter翻译成分线器反而容易让人不知道在说哪个功能。2.2 用一张信号规划表防止连错线动手拖门之前先在草稿纸上确定输入输出信号这是我最想强调的一步。别急着开软件画图先明确这个模块对外长什么样方向信号名含义输入A0, A1, A2, A3加数A的四个二进制位输入B0, B1, B2, B3加数B的四个二进制位输入C0来自低位的进位输入输出S0, S1, S2, S3四位和输出C1, C2, C3, C4各级进位输出输出G*组进位生成信号输出P*组进位传播信号其中C1、C2、C3在完整加法器里是中间信号但为了测试方便也可以单独引出观察。C4就是最高位的进位输出实验报告里经常也写成C_{out}。2.3 布线习惯标签替代长线Logisim和真实面包板不一样它允许你给任何一段导线添加标签Label。而相同名字的标签在逻辑上被认为是同一条信号线不需要物理连在一起。这个是画CLA182最实用的技巧没有之一。比如C2这个信号它从进位链中间算出来之后既要去计算C3和C4又要接到S2的异或门上。如果你从源门把线拉到每一个目标线路会横穿整个画布复杂到你自己都认不出来如果把每个需要的端点都标上c2逻辑上它们就自动连通了。但标签必须严格区分大小写和空格Logisim认为C2和c2是两个完全不同的信号。我第一次就把某个标签打成了小写结果那一路输出永远不亮排查了很久。2.4 布局思路左进右出中间分块整张画布按信号流方向从左到右布置。最左边放8个数据输入引脚和C0输入中间分成三块第一块算G0到G3和P0到P3第二块用它们算C1到C4第三块算S0到S3最右边放输出引脚。3. CLA182内部结构拆解从G/P定义到四级进位展开搭建之前还需要过一次逻辑推导把C1到C4的展开公式弄明白。这里不要求你背公式但要能自己从一位全加器推出来。3.1 一位全加器的进位公式一位全加器中第i位的进位输出可以写成C_{i1} A_i·B_i (A_i ⊕ B_i)·C_i这个式子非常关键。A_i·B_i表示这一位两个输入都为1时铁定要产生进位A_i ⊕ B_i表示这一位两个输入只有一个为1所以它不自己产生进位但能传递来自低位的进位。这时引出两个标准定义进位生成信号 G_i A_i·B_i进位传播信号 P_i A_i ⊕ B_i部分教材用A_i B_i于是 C_{i1} G_i P_i·C_i。需要注意P的定义在不同教材里有分歧有的写成A_i ⊕ B_i有的写成A_i B_i。这两种写法在进位链的逻辑功能上是等价的因为当A_i和B_i同时为1时G_i已经为1P_i用哪种都不影响进位结果。但要看清你实验报告用的是哪种避免和后面的和位计算混在一起。3.2 四位进位展开把C_{i1} G_i P_i·C_i反复代入得到C1 G0 P0·C0C2 G1 P1·G0 P1·P0·C0C3 G2 P2·G1 P2·P1·G0 P2·P1·P0·C0C4 G3 P3·G2 P3·P2·G1 P3·P2·P1·G0 P3·P2·P1·P0·C0观察一下门延迟。每一项都只是若干P做与运算再与一个G或C0做与运算最后全部做或运算也就是先算完各个与项再用一个或门汇总。不管C4的表达式里有多少项它的延迟基本是固定的两级左右这就是先行二字的来源。3.3 组级联的G*和P*如果只做4位加法算出C4就收工了。但计算机组成原理课通常不会只让你做4位后面还有16位、32位乃至更宽的ALU。如果要扩展难道把C1到C16的公式全部展开吗那样门电路数量会爆炸。标准做法是把4位看成一个超级位对外只暴露两个信号组进位生成 G* G3 P3·G2 P3·P2·G1 P3·P2·P1·G0组进位传播 P* P3·P2·P1·P0G*的含义是这一组4位内部无论如何都会产生进位输出的条件P*的含义是这一组4位不自己产生进位但能把外部进来的进位整体传出去。有了这两个信号16位加法器就可以用四个CLA182级联组间进位Cnz由上一组的G*和P*共同决定而不必把16位的公式全部展开。这个分层思想在后面的多周期CPU设计里还会反复出现。4. 实操搭建顺序先雕琢生成块与传播块再串进位链现在进入Logisim画布。你要是不按顺序乱画后面改一个引脚就够你头疼半天。我建议按照输入引脚 → G/P生成块 → 进位链 → 和位输出 → 组级联信号 → 封装子电路的步骤来。4.1 摆放输入输出引脚先拖出12个输入引脚A0到A3、B0到B3、C0。再拖出需要的输出引脚S0到S3、C1到C4、G*、P*。给每个引脚设置标签Logisim引脚属性里有Label一栏。注意输入引脚要选Input类型默认就是朝向右输出引脚选Output朝向左这样信号流方向才是从左到右。4.2 生成G和P信号对每一位i用一个AND门生成G_i用一个XOR门生成P_i。此时先不用管下面几位的进位专心把这8个中间信号做出来。实际操作里我会把每位的G_i和P_i上下排列G_i放在上面P_i放在下面这样后面进位链接起来时不用绕圈。G0到G3分别从A0与B0、A1与B1、A2与B2、A3与B3的与门得到P0到P3分别从对应的异或门得到。4.3 搭进位链这一步是重头戏表达式看起来吓人拆开其实很简单。C1最简单G0 OR (P0 AND C0)。一个两输入与门、一个两输入或门。C2 G1 OR (P1 AND G0) OR (P1 AND P0 AND C0)。这需要三个与项第一项P1·G0第二项P1·P0·C0然后和一个三输入或门汇总。C3 G2 OR (P2 AND G1) OR (P2 AND P1 AND G0) OR (P2 AND P1 AND P0 AND C0)。四输入或门。C4 G3 OR (P3 AND G2) OR (P3 AND P2 AND G1) OR (P3 AND P2 AND P1 AND G0) OR (P3 AND P2 AND P1 AND P0 AND C0)。五输入或门。在Logisim里或门的Number of Inputs属性可以调成你想要的扇入数不用真的堆五个两输入或门。同理那几个三输入、四输入与门也要记得调整属性否则默认两输入的门根本接不下那么多线。这里有一个细节我踩过坑C2的第二项P1·P0·C0要和C1里的P0·C0共享同一个与门结果吗逻辑上可以但我不建议在草图上做这种优化会让连线交叉更严重。实验课考察的是功能和原理不是门数量宁可多用两个门也要保证可读性。4.4 算和位S0到S3先行进位电路本身只处理进位但是完整验证加法器功能必须要有和输出。和位的公式是S_i A_i ⊕ B_i ⊕ C_i因为前面已经算了P_i A_i ⊕ B_i所以这里可以直接把P_i和C_i再做一次异或S_i P_i XOR C_i。对于S0C_i就是外部输入的C0对于S1到S3C_i分别取前面算出的C1到C3。这一步极其容易接错S1用的进位是C1S2用的是C2S3用的是C3千万别全接成C0。4.5 搭组级联的G*和P*G* G3 OR (P3 AND G2) OR (P3 AND P2 AND G1) OR (P3 AND P2 AND P1 AND G0)。这个表达式和C4的差别在于没有C0项而且是用G0而不是C0结尾。我建议在C4完成后再单独画这一组不要把G*的输出和C4混在一起。P* P3 AND P2 AND P1 AND P0一个四输入与门搞定。4.6 封装成子电路主画布搭建完成后回到项目面板右键当前电路选择Edit Circuit Appearance把输入引脚整理到左边、输出引脚整理到右边像一颗真实芯片一样排列。然后新建一个子电路比如叫CLA4把整个逻辑复制过去。右击子电路选择Set As Main可以作为顶层。封装的目的是为了后续做16位加法器时可以直接复用。我在实验报告里就是用封装后的CLA4模块拼出四个组再加上一个组间进位模块形成了16位先行进位加法器。这一部分在整个多周期CPU设计中也会频繁用到。5. 完整测试用例从最小验证到随机数狂轰电路画完最关键的事情就是验证。老师查实验时最常问的一句话就是你确定你的电路是对的空口说没用得拿出测试用例和数据来证明。这也是这次实验报告中分值最高的一部分。5.1 测试用例设计的原则测试不能只挑几个简单的数算一遍也不要指望把所有4096种输入组合全部穷举虽然4位组合不算多但实验时间有限。合理的做法是覆盖几种典型情况基础加法、无进位、有进位、临界进位、全1溢出、交叉位模式、随机数。下面这套测试用例是我整理好的你照着输就行。编号A (二进制)B (二进制)C0预期S (二进制)预期C4验证重点T0100000000000000全零基础T0200010001000100普通加法T0300100011001010普通加法带连续进位T0401010010001110普通加法T0501110001010000组内进位链全走一遍T0611110000011110加0保持T0711110001000001最高位溢出T0811111111011101全1相加组内进位传递T0900000000100010C0输入直接作用T1000010000100100低位进位逐级传递T1110100101011110交替位模式检查G/P交叉T1211000011011110高位段边界T1301011010100001交替位外部进位产生溢出T1401110111011100多次进位但未溢出T1510001000000001最高位自己的生成进位T1600110110010010随机组合1T1711010010011110随机组合2T1801101011100101随机组合3带进位T05和T07是两道最关键的测试。T05中A0111、B0001从第0位开始进位C1为1C2为1C3为1C4仍然为0整条进位链被完整走了一遍T07中A1111、B0001第0到第2位都有生成进位第3位既生成又传播最终C4输出1。如果你的电路这两项都正确进位链基本没问题了。5.2 怎么快速核对输出Logisim里核对输出最简单的方式是给S0到S3、C4接上LED灯或者探针然后手动拨动输入引脚。LED亮表示1灭表示0。也可以加一个Hex Digit Display十六进制数码管把S0到S3接到它的输入这样输出直接显示0-9或A-F对读十进制很方便。5.3 用脚本批量生成测试向量如果实验报告要求提供大量测试数据手动拨太慢了。我写了一个Python小脚本用穷举法生成所有4位输入组合的期望值你只需要把期望表格贴到实验报告里再在Logisim里抽几组验证。for a_bin in range(16): for b_bin in range(16): a a_bin b b_bin s a b carry 1 if s 16 else 0 s s % 16 print(fa{format(a, 04b)} b{format(b, 04b)} c00 fs{format(s, 04b)} carry{carry})脚本本身不复杂但它提醒了我一件事**测试期望值要自己按公式算一遍不要直接拿电路输出当答案。**否则电路错了测试也跟着错了整个验证过程失去意义。5.4 验证组级联信号上面的测试用例只验证了普通加法功能。如果实验要求检查G*和P*还需要单独做几组对照。G*为1的情况最直观的是A3和B3都为1比如T15中A1000、B1000此时G31所以G*必然为1。P*为1的情况要求每一位都满足P_i1也就是每组A_i和B_i必须恰好一个为1用XOR定义时。比如A1010、B0101每一位都是01或10的交替P0到P3全为1P*输出1。在Logisim里给G*和P*接上探针拨到这些组合时观察探针是否如预期亮起。这个信号在做16位扩展时非常重要要提前确认无误。6. 调试踩坑实录五个高频错误和定位技巧我在实验室帮同学看这个实验加起来不下十个人大家踩的坑高度重复。总结成这份排错清单比你自己对着电路发懵三个小时有用。6.1 红蓝灰三色线到底什么意思Logisim里导线的颜色是最直接的信号反馈。红色通常表示该点上电平为1蓝色/深绿色表示0灰色表示悬空高阻态或未连接完整。如果你看到某条期望为1的线一直是灰色说明信号源根本没有正确连到这个点而不是逻辑错误。排查时先点选导线看两端是否都有实心圆点标注的连接点。如果一端是空心圆说明没接上。这是Logisim最常见的问题之一。6.2 标签同名不同义大小写和空格前面提过C2和c2会被当成两个不同的信号。还有人在标签前后不小心打了空格比如C2 肉眼几乎看不出来但Logisim会把它当独立信号。如果你发现两个本该连通的点行为不一致先检查标签文本是否完全一致。6.3 引脚方向反了导致信号流错乱Logisim里引脚属性有Facing一栏决定引脚图标朝左还是朝右。输入引脚通常朝右放置输出引脚通常朝左放置。方向反了不影响逻辑但会导致你接线时下意识接错尤其是输出引脚朝右拉线时很容易接到旁边不相关的输入上去。6.4 P定义用OR还是XOR这是一个经典的混淆点。进位公式里P_i用A_i B_i没问题和位公式里S_i A_i ⊕ B_i ⊕ C_i必须用异或。如果你在生成P时用了OR门那么后面计算S_i就必须另外用XOR门计算A_i ⊕ B_i不能直接把P_i拿来和C_i做异或。更稳妥的做法是P_i统一用XOR门生成。这样既满足进位公式的传播定义如前文所说在逻辑上与OR等价和位的计算也能直接复用。我当时第一次搭就用OR做了P结果进位链全对和位全错查了半天才反应过来。6.5 门电路的扇入没调Logisim门电路默认输入数是2。搭C3、C4、G*这些多输入项时如果直接想往两输入或门上接三根线你会发现根本接不进去。这时候双击门电路在属性栏把Number of Inputs改成3、4或5。别图省事堆一串二输入门既乱又容易接错。6.6 分线器的位序坑如果你为了减少引脚数量用Splitter分线器把A3到A0打包成一个4位输入那要注意位序方向。Logisim分线器的位序是从0开始还是从3开始取决于你拖出来的朝向和属性设置。接反之后输入A0111会被当成A1110来算表面看不出问题结果全错。6.7 定位问题的一个高效思路如果测试结果不对别直接盯着整张电路图找错。用探针逐级检查从输入开始一级一级往下看检查A0到A3、B0到B3、C0是否正常输入检查G0到G3、P0到P3是否与手动推导一致检查C1到C4是否与展开公式一致最后才检查和位S0到S3。这样可以快速把问题缩小到某一个模块。比如你发现C2的输出和手算不符那就只看C2相关的与门和或门基本是那几个中间项接错了。我自己做这个实验时最惨的一次是把G0和P0两条线在进位链的C1处接反了表现是某些组合加法正确、某些组合错误而且错误组合没有明显规律。最后就是靠逐级探针比对才锁定是C1那一级的两个输入恰好对调了。做完标准化测试之后建议再随机拨几十组输入快速扫一遍LED变化。这一步不需要记录目测和心算对照即可主要为了排除前几组测试碰巧全对的运气成分。等四张测试表全部打勾这颗CLA182才算真正过关。
返回列表