实验5:Logisim
截止日期:3月12日星期四晚上11:59:59 PT
本实验介绍Logisim——一个用于设计和模拟数字逻辑电路的教育工具。这是项目3的重要准备。
设置
您必须在本地机器上完成此实验。如果需要重新设置本地机器,请参阅实验0。
在本地机器的labs目录中,拉取您在过去实验中可能做的任何更改:
仍然在本地机器的labs目录中,使用以下命令拉取本实验的文件:
如果遇到任何git错误,请查看常见错误页面。
仍然在labs目录中,运行以下命令下载最新版本的Logisim:
bash tools/download_tools.sh
本实验中的所有工作都将使用Logisim Evolution完成。
开始前的一些重要警告:
- Logisim是一个GUI程序,因此不能在无图形界面环境(WSL、SSH等)中轻松使用。请在具有GUI、Java 9+和Python 3.6+的本地环境中运行它。如果您的本地系统是macOS或Linux,您可能已经准备好了。如果您使用Windows,请使用
Git Bash,它在Windows上运行并支持GUI。 - 请使用我们分发的Logisim版本,因为它与互联网上的其他版本不同(包含bug修复和课程特定内容)
- 不要移动工作人员提供的输入/输出引脚;如果引脚移动,您的电路将无法正确测试。如果您的电路未通过测试但您认为它是正确的,请检查您的电路是否适合
tests/ex#_test.circ中的相应测试框架 - Logisim不会自动保存您的工作。工作时请记住频繁保存(并提交)!
可能的设置错误
- 在Windows 10上尝试运行Python时出现"Permission Denied"(权限拒绝)
- 在Windows搜索提示符中搜索"app execution alias"(应用执行别名)。点击"Manage app execution aliases"(管理应用执行别名),它是"System Setting"(系统设置)的一部分
- 通过切换相应的可执行文件来禁用商店版本的Python。
截图
java.lang.UnsupportedClassVersionError
您需要更新到Java 16+。请按照实验0的设置说明操作。Exception in thread "main" java.lang.UnsupportedClassVersionError: com/cburch/logisim/Main has been compiled by a more recent version of the Java Runtime (class file version 60.0), this version of the Java Runtime only recognizes class file versions up to 52.0
练习1:介绍
与Venus类似,您可以从lab05文件夹内打开Logisim,使用命令:
短暂的启动序列后,应该会出现一个看起来有点古老的窗口。如果没有出现,请检查终端中的错误。
我们将从创建一个非常简单的电路开始,只是为了感受放置门和电线的感觉。开始之前,请注意一个有用的功能:缩放功能!它在左下角,将在接下来的几周内让您的生活变得更加轻松。缩放缩放缩放。

构建我们的电路
-
首先点击AND门按钮。这将使AND门的阴影跟随您的光标移动。在主原理图窗口中单击一次以放置一个AND门。 -
点击Input Pin(输入引脚)按钮。现在,在您的AND门左侧的某个位置放置两个输入引脚。 -
点击Output Pin(输出引脚)按钮。然后在您的AND门右侧的某个位置放置一个输出引脚。此时您的原理图应该看起来像这样:
-
点击Select tool(选择工具)按钮。点击并拖动以将2个输入引脚连接到AND门左侧的2个输入端。您只能绘制垂直和水平的电线。只需水平绘制一条电线,释放鼠标按钮,然后从电线末端开始点击并拖动以继续垂直绘制。重复相同的过程,将AND门右侧的输出端连接到输出引脚。完成这些步骤后,您的原理图应该看起来类似于此:
-
最后,Poke工具在您点击引脚时会切换引脚的值。如果您在电线上使用Poke工具,它将显示电线上的值。选择Poke工具,尝试点击原理图中的输入引脚,并观察发生了什么。输出是否符合您认为AND门应该做的事情?现在,尝试直接点击一根电线。该电线上的当前值应该会弹出;这在您以后构建更复杂的电路时会非常有用。 -
现在,删除电线,并尝试将每个输入引脚连接到
AND门上的另一个引脚,使电线交叉。一个极端的例子:
如果您在创建电线时将其拖动穿过另一根电线而不停下,电线不会连接。如果您在创建电线时在另一根电线上方停止拖动,将创建一个连接点(大圆圈),电线将连接。设计电路时一定要注意连接点!
电线颜色和值列表
请查看此列表。尝试自己重新创建每种颜色可能会有所帮助。

| 颜色 | 含义 |
|---|---|
| 深绿色 | 1位电线的值为0 |
| 亮绿色 | 1位电线的值为1 |
| 黑色 | 多位电线(许多组件具有位宽属性,可以在左下角的属性菜单中配置) |
红色(值为EEEE) | 电线上有多个值(在这种情况下,来自2个输入的0和1)。另外,记住在电线连接点会出现一个大圆圈。 |
蓝色(值为UUUU) | 电线处于浮动状态(即没有已知值) |
| 橙色 | 电线连接到具有不同位宽的组件。一个简单的例子是1位输入引脚连接到2位输出引脚。在所示示例中,MUX后面有一根稍微隐藏的电线,将2位低位数据线连接到1位选择线。要注意这些情况! |
无障碍提示:如果您有残疾且难以识别这些颜色,请随意使用更方便的颜色集。要执行此操作,请转到File -> Preferences -> Simulation Tab(文件->首选项->模拟选项卡)。当您在OH或Ed上展示电路时,请告知课程工作人员此更改,因为我们经常使用颜色作为调试工具。
练习2:子电路
就像C程序可以包含辅助函数一样,原理图可以包含辅助子电路。在本实验的这一部分,我们将创建几个子电路来演示它们的用法。
注意:Logisim Evolution通常不允许使用带空格或符号的名称、以数字开头的名称或与关键字冲突的名称(例如NAND)。
-
打开练习2的原理图(
File -> Open -> lab05/ex2.circ)。 -
通过双击左侧电路选择器中的
AND2来打开AND2示例子电路。
请注意末尾的
2;因为有一个名为AND的组件,所以我们不能将其称为AND。 我们创建了一个演示电路供您参考。它有2个1位输入引脚A和B,并将A & B的结果发送到RESULT输出引脚。这应该与您刚刚制作的练习电路非常相似。 -
现在,打开
NAND2子电路。是时候制作您自己的电路了!不使用左侧Gates库中的内置NAND门来填充此电路(即仅使用AND、OR和NOT门;它们在窗口顶部的工具栏中作为小图标提供,或在电路选择器的Gates库中)。完成后,类似地填充NOR2、XOR2、MUX2(2选1 MUX)和MUX4(4选1 MUX)。请注意,NAND、NOR、XOR和MUX已存在于Logisim中。本练习旨在帮助您理解如何使用子电路。- 请不要更改子电路的名称或创建新的子电路,否则您的电路可能无法正常工作
- 除了
AND、OR和NOT之外,不要使用任何内置门。但是,一旦您构建了一个子电路,您可以(并且鼓励)使用它来构建其他电路。您可以通过在电路选择器中单击子电路,然后像放置AND/NOT/OR门一样放置它来实现这一点 - 为每个电路写出真值表会有所帮助。您可能还会发现复习关于如何构建这些门的讲座幻灯片很有用
- 这份组合逻辑块讲义可能对您的MUX实现有用
- 对于
4-to-1 MUX,SEL0和SEL1分别对应于2位选择器的第0位和第1位。确保不要切换它们!
测试
打开终端会话并转到lab05文件夹。我们为每个练习提供了测试,您可以使用python3 test.py运行。对于每个测试,您的电路在测试框架电路(tests/ex2-test.circ)中运行,其输出与该测试的参考输出(tests/out/ex2-test.ref)进行比较。在输出文件中,每列对应主电路上的一个输入/输出引脚,每行显示一组输入和电路产生的相应输出。如果您的电路输出(tests/out/ex2-test.out)不同,您可以将其与参考输出文件进行比较;diff命令可能会有所帮助。
- 请注意,输出文件通过在每个值之间添加制表符(
\t)来"格式化",当制表符显示为8个空格宽时,它们看起来最好。8个或更多字符的值和列标题可能会打乱对齐,所以要注意这些! - 不要修改参考输出文件,否则本地测试可能会产生不正确的结果
- 您不需要编辑本实验的测试框架电路。但是,查看一下可能会很有用;我们将在下一个实验和项目3中做类似的事情!
检查点
在这一点上,请确保您熟悉Logisim环境、创建子电路以及在其他电路中重用此类电路。
练习3:存储状态
让我们实现一个重复递增值的电路。这个电路与您到目前为止为实验构建的电路之间的区别在于,它将把这个值作为状态存储在寄存器中。
-
打开练习3的原理图(
File -> Open -> lab05/ex3.circ)并转到空的AddMachine电路。- 记住要经常保存,并避免移动或编辑提供的输入/输出引脚。
-
从
Arithmetic库(左侧的电路选择器)中选择Adder子电路,并将加法器放置到您的AddMachine子电路中。
-
从
Memory库中选择Register(寄存器),并将一个寄存器放置到您的子电路中。下面是一张说明寄存器各部分的图片。
-
将
clk输入引脚连接到寄存器上的时钟引脚。通常,最好让电路中的所有组件使用同一个时钟,以便所有内容同步。在这种情况下,测试框架为其寄存器使用时钟,因此它通过这里的clk引脚将该时钟信号传递给您电路的寄存器。将来,如果您正在处理一个没有现有时钟信号的电路,可以使用Wiring库中的新Clock(时钟)来创建自己的时钟。 -
将加法器的输出连接到寄存器的输入,并将寄存器的输出连接到加法器的输入。
- 当您尝试连接组件时,可能会收到"Incompatible widths"(不兼容的宽度)错误。这意味着您的电线正试图连接两个具有不同位宽的引脚。如果您使用
Selection工具(顶部工具栏上的鼠标指针图标)单击一个组件,您会注意到窗口左下角字段中有一个Data Bits(数据位)属性。该值决定了组件输入和输出的位数。确保加法器和寄存器的数据位宽度都为8,这样"Incompatible widths"错误应该会得到解决。
- 当您尝试连接组件时,可能会收到"Incompatible widths"(不兼容的宽度)错误。这意味着您的电线正试图连接两个具有不同位宽的引脚。如果您使用
-
将一个值为
1的8位常量连接到加法器的第二个输入。您可以在Wiring库中找到Constant(常量)电路元件。要将其值更改为1,只需在Value属性中输入1并按Enter。现在您应该看到该值为0x1(Logisim会自动将您输入的十进制值转换为十六进制)。 -
将两个输出引脚连接到您的电路,以便您可以监控加法器和寄存器的输出。加法器的输出应连接到
ADD_OUT,寄存器的输出应连接到REG_OUT。因此,最后您的电路应该看起来类似于:
-
现在,打开本练习的测试电路(
lab05/tests/ex3-test.circ)。在左上角,我们有一个小型电路(类似于您的AddMachine)来跟踪当前周期。在其下方,您应该看到您的AddMachine电路连接到时钟和一些输出引脚。 -
通过转到
Simulate -> Tick Half Cycle(模拟->半周期滴答)(Command/Control + T)来滴答您的电路一次。您的AddMachine的输出应该增加了!此外,时钟现在应该是亮绿色的。这对项目3极其重要,所以请确保您知道如何滴答时钟和点击电线。

如果您再次
Tick Half Cycle(半周期滴答),您会注意到时钟变回深绿色,但数字不会改变。这是因为寄存器默认是上升沿触发的(即从低时钟信号变为高信号时触发)。如果您对查看半周期的变化不太感兴趣,也可以使用
Simulate -> Tick Full Cycle(模拟->全周期滴答)(F2)。
-
手动滴答电路可能会很累。好消息是:Logisim可以为您滴答电路!转到
Simulate -> Ticks Enabled/Enable Clock Ticks(模拟->启用滴答/启用时钟滴答)(Command/Control + K)。现在您的电路应该自动计数了!
如果您想让电路运行得更快,可以在
Simulate -> Tick Frequency(模拟->滴答频率)中更改滴答频率。要停止,请再次点击Ticks Enabled//Enable Clock Ticks(启用滴答//启用时钟滴答)(Command/Control + K)。如果您想重置电路,请使用Simulate -> Reset Simulation(模拟->重置模拟)(Command/Control + R)。 -
完成后,尝试运行提供的测试(使用
python3 test.py)。
检查点
在这一点上,请确保您熟悉在Logisim环境中设计和模拟使用组合逻辑和状态元件(寄存器)混合的简单数字逻辑电路。
高级Logisim功能
以下是三个Logisim功能,它们既可以为您节省大量时间,又可以使您的电路看起来更整洁。
分割器
分割器允许您将一个多位值拆分成较小的部分,或者(尽管名称如此)将多个一位或多位的值组合成单个值。在这里,我们将4位二进制数1100拆分为11和00,交换它们的位置,并将它们与0组合以创建最终的5位数00110:

(使用Select工具)点击分割器以在侧边栏(左下角)中获取其属性。您可以配置分割器上的臂数和每个臂上存在的位等属性。对于上面的电路,左侧和右侧分割器的属性如下所示:


请注意有一个名为Facing(朝向)的属性。您可以使用它来旋转分割器。在上面的示例中,右侧的分割器朝向West(西),而左侧的分割器朝向East(东)。
如果您看到橙色的错误电线,这意味着您的输入位宽与输出位宽不匹配。确保在用电线连接两个组件时,在该组件的菜单中正确设置位宽。

隧道
隧道允许您绘制一条"隐形电线"来将两个点绑定在一起。隧道按赋予电线的区分大小写的标签分组。它们用于连接电线,如下所示:

这实际上相当于:

应该注意哪些电线与哪些其他电线通过隧道连接,例如在这种情况下:

这实际上相当于:

我们强烈建议您在Logisim中使用隧道,因为它们使您的电路看起来更整洁(减少电线混乱),这意味着更容易调试。
扩展器
当更改电线的宽度时,为了清晰起见,您应该使用位扩展器。例如,考虑以下将8位电线零扩展为16位电线的实现:

与分割器相比,扩展器一目了然。在处理复杂电路时,这变得特别有帮助。
此外,考虑丢弃位的情况。尽管名称如此,扩展器也可以执行此操作:

虽然分割器更简约,但也稍微难以阅读。
练习4:循环右移
凭借您对分割器的了解以及对多路复用器的知识和经验,您已准备好实现一个非平凡的组合逻辑块:RotRight,代表"循环右移"(Rotate Right)。其思想是RotRight将输入INPUT0的位模式向右循环移动AMOUNT位。因此,如果INPUT0是0b1000000000000101且AMOUNT是0b0011(十进制的3),则该块的输出将是0b1011000000000000。请注意,最右边的3位从值的右端移出并回到左端。这可以通过位运算R = A >> B | A << (16 - B)来表示。
实现一个名为RotRight的子电路,具有以下输入:
INPUT0(16位),要旋转的16位输入AMOUNT(4位),旋转量(为什么是4位?)
您可以在ex4.circ中找到起始子电路。记住要经常保存,并避免移动或编辑提供的输入/输出引脚。
输出应该是INPUT0向右旋转AMOUNT位位置,如上所述。您不允许在解决方案中使用Logisim移位器,但允许使用所有其他组合逻辑(MUX、常量、门等)。Logisim的内置MUX(在Plexers菜单下找到)可能特别有帮助。您的解决方案不应涉及时钟或任何时钟元件(如寄存器)。
- 我们为您提供了
rot1、rot2、rot4和rot8的框架,它们将分别将输入旋转1、2、4和8位。您应该实现这些子电路并在RotRight的实现中使用它们。
提示
您可以使用提供的子电路旋转0-15范围内的任何数字。例如,要旋转9位,您可以先旋转8位,然后旋转1位。
完成后,尝试运行提供的测试。
练习5:反思和反馈表
我们每周都在努力改进课程——请填写此调查告诉我们您到目前为止在讨论课和实验中的体验!
练习6:[可选(OPTIONAL)]学期中期反馈表
我们还在进行一项学期中期调查,以了解您在整个课程中的体验。请填写此调查以获得额外学分!
提交
保存、提交并推送您的工作,然后在Gradescope上提交到实验5作业。