生命游戏中的数字逻辑门实现 - 第一部分
这是系列文章的第一篇([2]、[3]、[4]、[5]),旨在康威生命游戏之上实现数字逻辑门,最终目标是设计Intel 4004处理器并用它来模拟生命游戏。(选择4月1日发布首篇纯属巧合。大概。)
本文将首先描述实现过程的第一步:在康威生命游戏(一种二维细胞自动机)之上创建标准基本数字逻辑门(例如与门、或门、非门)。
(为何这样做?主要因为可行,同时也出于对晦涩图灵完备性的执着——例如,曾编写代码证明C语言的printf函数具有图灵完备性。)
最终目标是能够在生命游戏之上“模拟”完整的Intel 4004(世界上首批大规模生产的微处理器之一)。设定目标频率为1Hz——希望能够实时观察电路运行。当然越快越好,但也不希望速度过慢。
实现过程需要时间,因此本文将从基础开始:生命游戏的运作原理,以及如何在其上构建简单电路。最终将展示如何制作简单电路,例如下方加法器,计算六(0110)加五(0101)得到十一(1011)。
生命游戏基础
如前所述,生命游戏包含一个(无限)网格,每个时间步中的所有细胞要么存活要么死亡。
规则非常简单。如果一个细胞在某个时间步存活,当有两个或三个邻居存活时(包括四个直接相邻细胞和四个对角相邻细胞)保持存活;否则死亡(类似于过度拥挤)。相反,如果某个细胞在某个时间步死亡,当恰好有三个邻居存活时,在下一个时间步变为存活,否则保持死亡。这些规则实际上非常强大。
► 滑翔机(Glider) — 这是滑翔机。它非常缓慢地……滑行……到网格的东南方向。是最简单的有趣形状之一,经历四种不同变换后,恢复到原始形式,但向下和向右移动了一格。
滑翔机的移动速度为c/4:需要四个网格状态滴答才能移动一格向下和向右。
[a] 符号c指代光速等效值:任何反应的最快移动速度为每网格滴答一格。滑翔机比这慢四倍。
(在此简要介绍右侧模拟器的操作方法。点击可启动和停止模拟。顶部按钮可增加和减少模拟速度。暂停时,点击“tick”可逐步前进。本页后续将使用相同模拟器,请熟悉操作。)
将滑翔机用作电路中的基本电荷携带组件。如果存在滑翔机,表示“导线”上有电荷流动;否则没有电荷。
► 滑翔机枪(Glider Gun) — 下一个最有用的组件称为Gosper滑翔机枪
[b] 以Bill Gospher命名,滑翔机枪是首个展示有限细胞配置无限产生细胞的实例。 每30步,滑翔机枪发射一个滑翔机,如前所述移动。
滑翔机枪实际上相当复杂,在低层次上不易理解。但不用担心,无需真正理解滑翔机枪的工作原理也能理解本页其余内容——只要知道它是向网格东南方向发射滑翔机的神奇装置即可。
将广泛使用滑翔机枪创建滑翔机流,以更好地表示电流流动。
► 吞噬者(Eater) — 电路构建中使用的最终单个组件称为吞噬者,因滑翔机与之碰撞时会被“吞噬”而吞噬者保持无损得名。
尽管非常简单,这是两个组件交互的首个真实示例。导致滑翔机死亡并不需要太多,但吞噬者更稳定,能在多种碰撞后存留。
[c] 吞噬者实际上能导致多种滑翔机死亡,但本文不涉及此内容。
滑翔机碰撞
实际上,上述滑翔机与吞噬者的碰撞只是组件交互的首个示例。理解基本组件后,理解滑翔机碰撞是理解电路构建前的最终必要背景知识。将演示三种基本碰撞类型,后续将全程使用。
► 碰撞示例1 — 滑翔机之间最简单的碰撞是两者均死亡的碰撞。两个滑翔机流以受控方式碰撞,每对滑翔机碰撞导致双方死亡。
注意同步两个滑翔机流的重要性。此处,来自左上滑翔机枪的两个滑翔机逃脱,因为来自左下机枪的滑翔机稍慢。将在下例修复此问题。
► 碰撞示例2 — 先前碰撞导致两个流完全消失,而第二次碰撞将“稀释”一个流,移除每隔一个滑翔机(因此结果流周期为60而非30)。
通过将两个枪紧密放置,可创建周期60枪,每60代发射一个滑翔机。这在后续非常重要。
► 碰撞示例3 — 使用半滑翔机流(周期60),可完全移除常规滑翔机流(周期30)。注意西南方向滑翔机流周期为60的原因与先前碰撞完全相同。
此碰撞有效的原因是两个滑翔机碰撞后留下2x2块。下一个来自周期30滑翔机枪的滑翔机将撞击此块,双方死亡,然后循环重复。
导线与门
导线通过滑翔机流实现。当滑翔机存在并移动时,导线具有1位;无滑翔机时表示0位。用于1位的滑翔机流总是滑翔机枪的两个周期,每60代一次。
构建上述加法器需要三个“真实”门(与门、或门和非门),以及三个处理滑翔机流的辅助门(非实际导线所需:分流器、交叉器和旋转器)。
每个电路完全由滑翔机构建,逻辑由不同滑翔机碰撞类型决定。后续文章将创建需要更复杂交互的更好门。但在此之前,需从基础开始。
每个门为270细胞方形。此值完全任意,只是边长需为30的倍数,因为这是滑翔机枪的周期。大小需为周期的倍数非常重要,以便滑翔机长距离移动进入新门时相位始终对齐。
非门
► 从六个门中最简单的开始:非门。此门从西北(1)接收单个输入流,向东北(4)发送输出。此时,无滑翔机流从位置(1)传入。因此,流(2)与流(3)碰撞。结果,沿滑翔机流(4)的输出继续无阻。
实现预期:无滑翔机流输入,因此有流输出。但流旋转了90度:如果流先前向右下移动,现在向右上移动。虽然可设计不旋转流的非门,但更复杂。留待后续处理。
► 现在处理替代情况:有输入,因此门不应发送输出。
输入对应流(1)存在。使用标准碰撞,此周期60流将流(2)从周期30稀释为60。并非流(3)始终与流(2)碰撞,而是允许流(3)每120代传递一个滑翔机通过流(2)。通过的滑翔机沿流(3)继续,直到与输出流(4)碰撞,双方终止。符合预期。
与门
► 下一个门:与门。高层次上,此门理念与先前所见非常相似,只是看起来更复杂。
有输出流(9)希望退出,但无外部交互时,流(8)导致其在离开前终止。流(3)-(7)尚无任何影响,只是空闲等待西北(1)或西南(2)的流输入。
► 现在沿(1)添加一个流,但不激活流(2)。有稍不同的交互。此次,流(4)与流(1)碰撞,允许流(3)继续。流(3)然后与流(7)碰撞,导致双方停止。流(8)仍然始终击中输出流(9)并阻止其退出门。再次符合预期:1与0=0。
注意虽然稳态正确,但流(1)到达后少数滑翔机设法滑过输出。这与实际电子学类似,稳态最终正确,但电压从高到低(或反之)下降期间一切略显混乱。
► 现在仅激活西南流(2)。再次预期无输出。通过类似方法实现。流(2)将与流(5)碰撞,将其从周期30稀释为周期60。这允许流(6)通过流5。但此流仅击中吞噬者并死亡。无事发生。结果,流(8)再次击中输出流(9)并停止它。
从此方向,无门泄漏。整个运行期间稳态行为正确。
► 有趣情况是当东北流(1)和西南流(2)均存在时。预期最终输出允许退出。运行模拟前,或许思考片刻预测如何发生。等待。
如首例,流(1)与流(4)碰撞,允许流(3)继续。如第二例,流(2)与流(5)碰撞,将其稀释为周期60并允许流(6)继续。
但现在一切汇聚。流(6)现在与流(3)碰撞,过程中将(3)稀释为周期60。流(3)现在可通过流(7)无阻,接触流(8)时将其完全移除。这允许输出流(9)发送出去。
或门
► 下一个门:或门。再次从西北(1)和西南(2)接收两个输入流,但任一激活时向东南发送输出。
当(1)和(2)均不存在时,发生不多(与与门情况相同)。流(3)-(8)仅空闲。流(9)将成为输出流,与流(10)碰撞阻止其通过。
► 现在沿西南流馈送位并激活它。如果西南流(2)存在,则流(2)与流(5)碰撞,将其稀释为周期60。这允许流(5)无阻通过流(6)。流(6)然后与输出流(9)碰撞,将其稀释为周期60。现在,当输出流(9)通过流(10)时,它们均为周期60并可相互通过。
注意此处无特殊含义要求输出流必须起始周期60。毕竟,周期60枪仅由两个周期30枪创建,如先前所示。
► 当另一输入流存在时,应获得类似结果。当从西北馈送位时,流(1)现在与流(4)碰撞,将其稀释为周期60。这允许其通过流(3)而非终止它。流(3)然后与流(7)碰撞,将其稀释为周期60。流(7)现在可通过流(8)并与输出流(9)碰撞,将其稀释为周期60。如前,这允许输出流(9)通过流(10)并退出网格。
虽然先前情况仅需两次碰撞交互,此情况需五次才能工作:稍复杂的原因在于所需90度旋转。
► 最后有两均激活的情况。滑翔机沿西北流(1)和西南流(2)流动。获得非常类似情况。再次流(1)与流(4)碰撞稀释它。因此,流(3)现在可与流(7)碰撞稀释它。流(7)现在可通过流(8)并到流(9)将其稀释为周期60。流(2)再次与流(5)碰撞,将其稀释为周期60。流(5)和(6)现在相互通过。流(6)现在通过流(9),其已被流(7)稀释。流(9)现在通过流(10)。
此处有些“额外工作”,两次稀释流,但无害。最终结果相同。
交叉器
► 如同实际电路板,需确保两条“走线”交叉时不相互干扰。
如果此门不存在,任何两流交叉时都会发生严重爆炸。虽然平面电路可做些处理,但即使最简单加法器也需能够交叉导线。
► 此交叉器门接收两个输入并产生两个输出,允许两流相互通过。
这是非常简单的门。仅将流2稍移位以免与流(1)碰撞。为此,使流(2)与流(3)碰撞稀释它。流(3)现在可通过流(4)。因此流(4)可继续。流(4)现在交叉过流(1),无影响,然后与流(5)碰撞完全停止它。这允许输出流(6)继续外出。因此,流(1)是否存在无关紧要。
旋转器
► 这是模拟器必需的首个“门”,实际电路无需存在:旋转器。实际电路上,仅改变走线角度或弯曲导线,但此处无法做到。改变滑翔机流角度需门实现。
旋转器从西北(1)接收单个输入流并向东北(4)输出,旋转90度。当输入流(1)不存在时,流(2)与流(3)碰撞并停止在那里。输出流(4)与流(5)碰撞,无事发生。
► 当输入流(1)激活时,它将与流(2)碰撞并停止它。这允许流(3)继续并与流(4)碰撞。这将流(4)稀释为周期60。现在可通过流(5)无损并退出。
需显式旋转滑翔机流的事实对电路设计非常重要。旋转滑翔机流与执行有意义操作(例如计算非)成本相同。这将在后续发挥作用。
(虽然非严格必需,但拥有旋转270度的门非常方便,完全对称。此处跳过。)
复制器
► 最终非逻辑“门”,再次实际电路非必需,是复制门。接收一个输入,并沿两个输出复制。
具体地,从西北(1)取流,复制到东南(6)和东北(4)。当输入流(1)不存在时,流(2)与流(3)碰撞并取消它。第一输出流(4)然后与流(5)碰撞,不前往任何地方。第二输出流(6)也与流(7)碰撞,不前往任何地方。
► 如果输入流(1)存在,则它与流(2)碰撞停止在那里。这允许流(3)继续,并与流(4)碰撞。此碰撞稀释流(4)。现在,流(4)可通过流(5)无损并退出。流(5)然后与流(7)碰撞,双方停止在那里。这允许第二输出流(6)也继续。
(再次,拥有复制但旋转270度的门很方便,此处未展示。)
创建4位加法器
最终必要步骤是创建如上所示四位加法器电路。下一篇文章将专用于使用这些门进行电路设计,但作为简短预告,简要讨论如何制作简单加法器。
设计电路时使用logisim(数字逻辑模拟器),然后编写某种“编译器”读取保存的电路XML文件并确定应添加上述每个门的位置。
电路本身是标准行波进位加法器,以朴素方式实现。每个全加器十三个门,本可更少,但如果这样做下次就无内容可谈……所以不用担心,会实现。
使用golly高效模拟生命游戏。这是独立主题,此处不深入,仅提及hashlife是非常棒的算法,应学习。顶部所示加法器仅是golly运行的重放,而非其他图中完成的实际运行生命游戏本身。如果想下载加法器电路在golly中查看,可在此获取。
下次将介绍如何使用这些原语在生命游戏之上设计有用电路。在生命游戏上设计电路与在实际物理上设计电路有一些有趣差异。将利用其中一些设计连接至时钟电路的高效七段显示器以计数。