创建逻辑门模拟器

时间:2009-06-10 12:11:22

标签: boolean-logic

我需要创建一个用于创建逻辑电路和查看结果的应用程序。这主要用于A-Level(英国,一般为16-18岁)计算机课程。

我从来没有做过这样的应用程序,因此我不确定存储电路和评估结果的最佳设计(以可重复的速度,例如1.6Ghz单核计算机上的100Hz)。

我希望允许这些门用于制作“芯片”,然后可以在其他电路中使用(例如,你可能想要),而不是从基本门(和,或,nand等)构建电路。制作8位寄存器芯片或16位加法器。

问题在于这些电路的门数量会大幅增加,因此如果模拟在每个单独的门上工作,它将有1000个门进行模拟,因此我需要简化这些可放置在电路中的组件所以可以快速模拟它们。

我考虑为每个组件生成一个真值表,然后模拟可以使用查找表来查找给定输入的输出。虽然这些表的大小随着输入而大量增加,但问题出现了。如果芯片有32个输入,那么真值表需要2 ^ 32行。这在很多情况下使用大量内存比使用更多,因此对于非平凡组件不实用,它也不能用于可以存储其状态的芯片(例如寄存器),因为它们不能简单地表示为简单投入和产出表。

我知道我可以硬编码寄存器芯片之类的东西,但是因为这是出于教育目的,我想要它,以便人们可以制作自己的组件以及查看和编辑标准的实现。我考虑过允许使用代码(例如dll或脚本语言)创建和编辑这样的组件,以便例如加法器可以表示为“output = inputA + inputB”,但是假设学生已经完成了足够的编程。给定的语言能够理解和编写这样的插件来模仿他们的电路结果,这可能不是这样......

是否有其他方法可以采用布尔逻辑电路并自动简化它,以便模拟可以快速确定组件的输出?

至于存储组件我考虑存储某种树结构,这样一旦评估了链接到其输入的所有组件,就会对每个组件进行评估。

例如考虑:A.B + C. 模拟器首先评估AND门,然后使用AND门和C的输出来评估OR门。

然而,我刚刚想到,如果输出链接回输入,将导致死锁,因为输入将永远不会被评估...我怎样才能克服这个问题,因为程序只能评估一个一次门?

8 个答案:

答案 0 :(得分:5)

答案 1 :(得分:3)

你不是第一个想要建立自己的电路模拟器的人; - )。

我的建议是解决一小部分原语。当我开始我的时候(我计划恢复其中一天......)我有两个基元:

  • 来源:零输入,一个始终为1的输出。
  • 晶体管:两个输入AB,一个输出为A and not B

显然我有点滥用这个术语,更不用说忽视电子学的细节了。在第二点,我建议抽象到像我一样携带1和0的电线。我从这些绘制了门和加法器的图表中获得了很多乐趣。当你可以将它们组装成电路并在集合周围绘制一个框(带有输入和输出)时,你可以开始构建更大的东西,如乘法器。

如果你想要任何带循环的东西,你需要加入某种延迟 - 所以每个组件都需要存储其输出的状态。在每个循环中,您将从上游组件的当前状态更新所有新状态。

编辑关于您对可伸缩性的关注,如何默认为模拟每个组件的状态和上游邻居的第一原则方法,但提供优化子电路的方法:

  • 如果您的子电路S输入A[m],其中m <&lt; 8(例如,最多给出256行)并输出B[n]并且没有循环,为S生成真值表并使用它。这可以针对已识别的子电路自动完成(如果子电路出现不止一次,则可以重复使用)或选择。

  • 如果你有一个带循环的子电路,你仍然可以生成一个真值表。有定点发现方法可以在这里提供帮助。

  • 如果您的子电路有延迟(并且它们对封闭电路很重要),真值表可以包含状态列。例如。如果子电路具有输入A,内部状态B和输出C,其中C <-A和B,B <-A,真值表可以是:

    A B | B C
    0 0 | 0 0
    0 1 | 0 0
    1 0 | 1 0
    1 1 | 1 1

  • 如果您有一个用户断言的子电路实现了一个特定的已知模式,例如“adder”,请提供一个选项,使用硬编码实现来更新该子电路,而不是通过模拟其内部部件。

答案 2 :(得分:2)

您可能需要在12个步骤的课程软件中查看From Nand To Tetris。在youtube上有一个视频谈论它。

课程页面位于:http://www1.idc.ac.il/tecs/

答案 3 :(得分:2)

当我制作电路仿真器时(遗憾的是,也是不完整的,也未发布),这是我处理循环的方式:

  • 每个电路元素都存储其布尔值
  • 当元素“E0”改变其值时,它会(通过观察者模式)通知所有依赖它的人
  • 每个观察元素评估其新值并同样

当E0发生变化时,会保留受影响的所有元素的1级列表。如果元素已经出现在此列表中,则会在新的2级列表中记住该元素,但不会继续通知其观察者。当E0开始的序列停止通知新元素时,处理下一个队列级别。即:序列被跟踪并完成第一个元素添加到第2级,然后下一个添加到第2级等,直到所有level-x完成,然后你移动到level-(x + 1)< / p>

这绝不是完整的。如果你有多个振荡器做无限循环,那么无论你接受什么顺序,都可以阻止对方轮到它。我的下一个目标是通过限制基于时钟的同步而不是级联组合来缓解这个问题,但我在项目中从来没有这么做过。

答案 4 :(得分:1)

你可以硬编码所有常见的。然后允许它们从硬编码的(其中包括低级门)中构建它们自己,这将通过评估每个子组件来评估。最后,如果他们的一个“芯片”具有少于X个输入/输出,您可以将其“优化”到查找表中。也许可以检测它的常见程度,并且只针对最常用的Y芯片执行此操作?这样你就可以获得良好的速度/空间权衡。

你总是可以JIT编译电路......

由于我没有真正考虑过这个问题,我不确定我会采取什么方法......但它可能是一种混合方法,而且我肯定也会对流行的“芯片”进行硬编码。 / p>

答案 5 :(得分:1)

你可以向他们介绍卡诺图的概念,这将有助于他们简化自己的真值。

答案 6 :(得分:1)

如果您可以禁止循环(输出链接回输入),那么您可以显着简化问题。在这种情况下,对于每个输入,将只有一个确定的输出。然而,循环可以使输出不可判定(或者更确切地说,不断变化)。

评估没有循环的电路应该很简单 - 只需使用带有“连接点”(逻辑门之间的连接)的BFS算法作为列表中的项目。从处于“未定义”状态的所有门的所有输入开始。一旦门具有“已定义”(1或0)的所有输入,计算其输出并将其输出结点添加到BFS列表。这样,您只需要评估每个门和每个交叉点一次。

如果存在循环,则可以使用相同的算法,但是可以构建电路,使其永远不会“休息”,并且某些连接总是在1和0之间变化。

OOps,实际上,在这种情况下不能使用此算法,因为循环门(以及依赖于它们的门)将永远保持为“未定义”。

答案 7 :(得分:1)

当我在制作一个“数字电路”模拟环境时,我有一个与传递函数相关的定义电路(一个基本门,一个多路复用器,一个多路复用器和一些其他基元)(即一个函数)根据当前输入计算所有输出),“议程”结构(基本上是“何时激活特定传输函数”,虚拟线和全局时钟的链接列表。

每当输出改变时,我任意设置导线以硬修改输入,并且在门延迟之后调整任何电路上的输入以调度传递函数。有了这个,我可以同时容纳时钟和非时钟电路元件(一个时钟元件被设置为使其传输功能在“下一个时钟转换加上门延迟”运行,任何非时钟元件只取决于门延迟)。

从来没有真正为它构建GUI,所以我从未发布过代码。