首页 文章

创建逻辑门模拟器

提问于
浏览
8

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

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

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

问题是门的数量随着这样的电路大量增加,这样如果模拟在每个单独的门上工作,它将有1000个门进行模拟,所以我需要简化这些可以放在电路中的组件,这样它们就可以了快速模拟 .

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

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

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

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

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

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

8 回答

  • 2

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

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

    如果存在循环,则可以使用相同的算法,但是可以以这样的方式构建电路,使得它永远不会“休息”并且一些结总是在1和0之间变化 .

    实际上,OOps,在这种情况下不能使用这种算法,因为循环门(和取决于它们的门)将永远保持为“未定义” .

  • 1
  • 2

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

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

  • 5

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

    我的建议是 Build 一套最基本的原语 . 当我开始我的时候(我计划恢复其中一天......)我有两个基元:

    • 来源:零输入,一个输出始终为1 .

    • 晶体管:两个输入 AB ,一个输出 A and not B .

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

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

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

    • 如果您的子电路 S 输入 A[m] 且m <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”,请提供一个选项,使用硬编码实现来更新该子电路而不是模拟其内部部件 .
  • 1

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

    • 每个电路元素存储其布尔值

    • 当一个元素"E0"改变其值时,它会(通过观察者模式)通知所有依赖它的人

    • 每个观察元素评估其新值并同样如此

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

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

  • 1

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

  • 2

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

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

    由于我没有真正想过它,我不确定我采取什么方法..但它可能是一种混合方法,我肯定也很难编写流行的“芯片” .

  • 1

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

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

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

相关问题