我不知道处理器如何工作,所以我写了一个软件模拟器


几个月前,我突然对自己对计算机硬件原理一无所知而感到震惊。 我仍然不知道现代计算机是如何工作的。

我读了书“但是他怎么知道?” 克拉克·斯科特(Clark Scott)详细描述了一个简单的8位计算机:从逻辑门,RAM,处理器晶体管开始,以算术逻辑设备和输入输出操作结束。 我想用代码实现所有这些。

尽管我对微电路的物理不是感兴趣,但是这本书只是沿着波浪滑动,并且很好地解释了电路以及位在系统中的运动方式-读者无需了解电气工程。 但是文字描述对我来说还不够。 我必须看到实际情况,并从不可避免的错误中学习。 所以我开始用代码实现电路。 这条路很棘手,但很有启发性。

我的工作结果可以在简单的计算机存储库中找到:一个简单的计算器。 他很简单,他会计算。






样例程序

处理器代码实现为一堆打开和关闭可怕逻辑门 ,但它可以工作。 我运行了单元测试 ,我们都知道单元测试是程序正常运行的无可辩驳的证明。

该代码处理键盘输入,并使用为专业字体精心制作的字形集(我称为Daniel Code Pro) 在显示屏上显示文本。 唯一的弊端:要接受键盘输入和输出结果,我必须通过GLFW连接通道,否则,它是电路的完全软件仿真。

至少可以说,我什至写了一个粗鲁的汇编程序 ,使我对很多事情都睁开了眼睛。 他并不完美。 实际上,甚至有些cr脚,但他向我展示了很多人在很多年前就已经解决的问题。

但是,为什么要这样做呢?


“十三岁的孩子正在Minecraft中建造处理器。 当您可以使用电报中继器制作真正的 CPU时,请致电我。”

我对CPU设备的思维模型停留在初学者的计算机科学教科书级别。 我在2013年编写的Gameboy模拟器处理器实际上看起来并不像现代CPU。 即使仿真器只是一个状态机(状态机),它也不会在逻辑门级别描述状态。 仅使用switch并保持寄存器状态几乎可以实现所有功能。

我想更好地了解一切工作原理,因为例如,我不知道L1 / L2缓存和流水线是什么,而且我不确定我是否完全了解有关Meltdown和Spectre漏洞的文章。 有人说他们以一种使用处理器缓存的方式来优化代码,但是我不知道如何检查它,只说一句话。 我不太确定所有x86指令的含义。 我不了解人们如何向GPU或TPU提交任务。 一般来说,什么是TPU? 我不知道如何使用SIMD指令。

所有这些都是建立在需要首先学习的基础上的。 这意味着要回到基础并做一些简单的事情。 克拉克·斯科特(Clark Scott)的上述书籍描述了一个简单的计算机。 这就是为什么我从它开始。

斯科特的荣耀! 他工作!


斯科特的计算机是一个连接到256字节RAM的8位处理器,全部通过8位系统总线连接。 它具有4个通用寄存器和17个机器指令 。 有人为网络制作了一个视觉模拟器 :这真的很棒。 想到跟踪电路的所有状态要花多长时间,真是令人恐惧!


用Scott处理器的所有组件进行电路。 版权所有2009-2016。 齐格伯特·菲尔宾格(Siegbert Filbinger)和约翰·克拉克(John Clark Scott)

本书伴随您从适度的逻辑门到存储器和寄存器中的位的路线,并继续对组件进行分层,直到您获得与上图相似的内容。 我强烈建议您阅读本书,即使您已经熟悉这些概念。 只是不是Kindle版本,因为图表有时很难放大和分解屏幕上的“阅读器”。 我认为,这是一个长期存在的Kindle问题。

我的计算机与Scott的版本不同,不同之处在于我将其更新为16位以增加可用内存量,因为仅存储ASCII表的字形占用了Scott的8位机器的大部分,而为有用的代码留出了很少的空间。

我的开发过程


通常,开发是按照以下方案进行的:阅读文本,研究图表,然后尝试以通用编程语言实现它们,并且绝对不使用任何专用工具来设计集成电路。 我之所以在Go上编写模拟器,仅仅是因为我对这种语言有点熟悉。 怀疑论者可能会说:“愚蠢! 您不能学习VHDLVerilogLogSim或其他东西。 但是到那时,我已经写了我的位,字节和逻辑门,并且跳得太深了。 也许下次我将学习这些语言并了解我浪费了多少时间,但这是我的问题。

在大型电路中,只需在计算机中传输一堆布尔值,因此适合布尔代数的任何语言都适用。

将方案应用于这些布尔值有助于我们(程序员)得出含义,最重要的是,确定系统将使用哪个字节顺序,并确保所有组件都以正确的顺序在总线上传输数据。

这很难实现。 为了避免产生偏见,我选择了一个具有相反字节顺序的表示形式,但是在测试ALU时,我不明白为什么会出现错误的数字。 我的猫听到了很多很多无法表达的表情。

开发进展不快:也许我花了大约一两个月的空闲时间。 但是当只有处理器成功完成操作时 2+2=5,我幸福地处在第七天堂。

一切都照常进行,直到涉及到I / O。 该书提出了一种系统设计,该系统设计具有简单的键盘和显示界面,可将数据输入机器并输出结果。 好吧, 我们已经走了很远 ,半途而废是没有意义的。 我设定了一个目标,以实现在键盘上打字并在显示屏上显示字母的目的。

周边设备


外围设备使用适配器模板作为CPU与外界之间的硬件接口。 很容易猜出该模板是从软件设计中借用的。


I / O适配器如何连接到GLFW窗口

通过这种分离,事实证明将键盘连接和显示到运行GLFW的窗口非常简单。 实际上,我只是从仿真器中提取了大部分代码,并对其进行了一些修改,以使Go通道可以作为I / O信号工作。

我们启动电脑




这可能是最难的部分,至少是最麻烦的部分。 用如此有限的指令集编写汇编程序很困难,而在我的粗略汇编程序中,情况更糟,因为您不能欺骗任何人,除非您自己。

最大的问题是要处理四个寄存器,通过从寄存器中提取数据来跟踪它们并将它们临时存储在内存中。 在此过程中,我记得Gameboy处理器具有堆栈指针寄存器,以方便加载和加载寄存器。 不幸的是,这台计算机没有那么豪华,因此您不得不不断地手动在内存之间传输数据。

我决定花时间在一条CALLCALL以调用一个函数,然后返回到该点。 没有此功能,呼叫只能在一个深度上进行。

另外,由于机器不支持中断,所以我必须实现可怕的键盘状态轮询代码。 该书讨论了实现中断所必需的步骤,但这使电路变得非常复杂。

但是,别再抱怨了,我仍然编写了四个程序 ,其中大多数都使用某种通用代码来呈现字体,键盘输入等。这不是操作系统,但是可以理解简单OS的功能。

这并不容易。 文本编写器程序中最困难的部分是正确确定何时跳转到新行或按Enter时会发生什么。

 main-getInput: CALL ROUTINE-io-pollKeyboard CALL ROUTINE-io-drawFontCharacter JMP main-getInput 
文本编写器程序的主要周期

我没有费心实现Backspace键和修饰键。 但是我意识到文本编辑器的开发需要多少工作,并且它是多么乏味。

结论


对我来说,这是一个有趣且非常有用的项目。 在汇编语言编程中,我几乎忘记了下面的逻辑门。 我进入了抽象的更高层次。

尽管此处理器非常简单,并且与笔记本电脑中的CPU相距甚远,但在我看来,该项目教会了我很多东西,尤其是:

  • 位如何在所有组件之间通过总线移动。
  • 简单的 ALU如何工作?
  • 简单的 Fetch-Decode-Execute循环是什么样的。
  • 没有堆栈指针寄存器和堆栈概念的机器很烂。
  • 那辆不间断的汽车也很烂。
  • 什么是汇编程序,它是做什么的。
  • 外设如何与简单的处理器交互。
  • 简单字体的工作方式以及如何在显示器上显示它们。
  • 一个简单的操作系统可能看起来像什么。

那接下来呢? 该书说,自1952年以来,没有人生产过这样的计算机。 这意味着我必须研究过去67年的材料。 我要花点时间 我可以看到x86手册的长度为4,800页,足以让您睡前愉快,轻松地阅读。

也许我会对C语言的操作系统有所宠爱,我会用PiDP-11构建套件和电烙铁来消磨夜晚,然后放弃这个东西。 我不知道,我们拭目以待。

认真地说,我正在考虑探索RISC体系结构,可能是RISC-V。 最好是从早期的RISC处理器开始,以了解其起源。 现代处理器具有更多功能:缓存等等,我想了解它们。 有很多东西要学。

这些知识会在我的主要工作中派上用场吗? 可能有用,尽管可能性不大。 无论如何,我都喜欢,所以没关系。 感谢您的阅读!

Source: https://habr.com/ru/post/zh-CN453158/


All Articles