选自djhworld博客

作者:daniel harper

机器之心编译

参与:杜伟、张倩、李泽南

芯片的设计到底有多难?想要回答这个问题最好还是先自己实践一下。最近,来自 BBC 的一名资深软件工程师 Daniel Harper 使用 Go 语言成功模拟出了一个 CPU 的所有功能,并把自己的经历写成了博客,引起了人们的热议。这篇文章也告诉我们:完整地了解计算机的工作原理是多么重要。

Daniel 的经历在社交网络上不仅被好奇的群众点赞,也引发了大学芯片相关课程的学生和助教们的共鸣。如果你不知道 L1/L2 缓存的意义,认为自己没有搞清楚英特尔、ARM 芯片上著名的 Meltdown、Spectre 漏洞的意义,现在是时候开始学习了。

让我们看看 Daniel 是如何做到模拟 CPU 的:

几个月前,我实在不理解计算机如何在后台工作,也不清楚现代计算机的工作原理。之后,我读了 J. Clark Scott 的书籍《But How Do I Know?》,这本书讲述了一台与非门(NAND gate)8 位计算机,包括寄存器、RAM 以及 CPU、ALU 和 I/O 的位元,于是我想用代码进行模拟。

我对电路学知识的兴趣不大,而这本书只是简单概述了一些基础知识,包括接线以及在没有必备电气工程知识的情况下位元如何在计算系统中移动。对我而言,从这本书中获得的知识不多,所以必须亲身实践,并从不可避免的错误中吸取经验教训,这样使我能够有条理地用代码编写电路。

  • 相关成果的 GitHub 地址为:https://github.com/djhworld/simple-computer

这台简单的计算机可以用来计算。

示例程序

这是一个相当整洁的小东西,CPU 代码被实现为一个开闭的门,但它奏效了,我已经进行了测试,以此证明它能够运行。

该程序操控键盘输入,并将文本呈现给显示器,其中使用了一套精心制作的字形作为专业字体,我将其命名为「Daniel Code Pro」。唯一作弊的一点是获取键盘输入并显示输出内容,为此我必须通过 GLFW 与外界通信,但剩余部分是模拟电路。

我甚至编写了一个简单的汇编程序,这令人大开眼界。这并不是完美的,实际上有点胡扯。但是,我了解到了其他人很多年前已经解决了的问题,并认为自己的这项工作更好。

为什么要做这个?

我曾看到一个 13 岁的孩子在 Minecraft 中做这项工作,所以等你用电报继电器制作出一个真正的 CPU 时再来质问我吧!

我心中的计算模型还停留在计算机科学初级教科书的层面,并且驱动我在 2013 年所编写的 Gameboy Emulator 的 CPU 与现今计算机运行的 CPU 完全不同。甚至可以说,模拟器只不过是一种状态机(state machine),它没有从逻辑门(logic gate)层面描述 CPU。仅使用 switch 语句即可以实现大多数 CPU 且能够存储寄存器状态。

我不知道 L1/L2 缓存(cache)和 pipelining 是什么,也完全不确定自己是否理解 Meltdown 和 Spectre 漏洞论文,所以想要更深入地了解这些东西。一些人告诉我,他们正在优化代码以更好地利用 CPU 缓存,而我却不知道如何验证真假,只能选择相信他们。我真的不确定 x86 指令是什么。我不了解人们如何能够将工作交给 GPU 或 TPU 处理,也不清楚什么是 TPU,更不清楚如何使用这些 SIMD 指令。

但所有这一切都需要具有相关的基础知识,所以我只有在阅读相关书籍后才能对此有所了解。这意味着我需要回到基础知识和原理上面,并从一些简单的程序上手。《But How Do I Know?》一本书中的「Scott 计算机」就很简单,也是我选择它的原因。

功能强大的 Scott 计算机!可以运行的!

Scott 计算机是一个附有 256 字节 RAM 的 8 位处理器,并通过 8 位系统总线连接。该计算机拥有 4 个通用寄存器,能够执行 17 个机器指令。一些人搭建了一个很酷的视觉模拟器(visual simulator),无法想象需要花费多长时间才能跟踪全部的接线状态!

组成 Scott CPU 的所有组件图解。

《But How Do I Know?》这本书将带你从一个不起眼的与非门开始,然后是内存和寄存器,最后继续对这些组件分层,直到你得出与上述类似的结果。这本书对相关内容做了非常好的概述,所以我极力推荐大家阅读,即使你已经熟悉了相关概念。我不建议大家在 Kindle 上阅读,因为书中的一些图有时很难在屏幕上放大和辨认,这是 Kindle 的一大弊端。唯一不同的一点是我将计算机升级到了 16 位,因为仅存储 ASCII 表的字形就令书中所描述的大多数 8 位机器无法做到,因此留给有用代码的空间就不多了。

我的开发之旅

开发过程实际上只是阅读文本、查找图表、然后尝试使用通用编程语言代码(而不是使用为集成电路开发而设计的代码)来翻译。

之所以用 Go 语言来写,是因为我对 Go 了解一点。杠精们可能会说,我不信你没有将时间花在学 VHDL、Verilog 或 LogSim 上,但我那时已经编写好了我的位元、字节和 NAND,我陷得太深了。也许我接下来会学那些东西。

从全局来看,大多数计算机只是传递一堆布尔值,所以任何对布尔值友好的语言都可以完成这项工作。

将模式应用于这些布尔值能够帮助程序员获得其含义,任何人都要做的最大决策是确定系统将使用哪种字节顺序(endianness),并确保所有组件都以正确的顺序在总线之间传递信息。

这绝对是实现中隐藏的痛点之一。从偏移量上看,我选择了较小的字节顺序。但在测试 ALU 时,我就遇到麻烦了。我试图找出为什么出来的数字是错误的。很多很多打印语句都发生在这个上面。

开发的确花了一些时间,大约是一两个月的业余时间。但一旦成功搭建出 CPU 并用它执行 2 + 2 = 5,我还是感到很欣慰。

书中讨论了 I/O 特性,设计了一个简单的键盘和显示界面,这样你就可以把东西放进机器或拿出来。我给自己设定了一个目标,那就是能够在键盘上输入一些东西,并在显示器上显示这些字母。

外设

在这里,外设使用的是适配模式,充当 CPU 和外部世界之间的硬件接口。这里并不难猜,肯定是软件设计模式获取灵感的地方。

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

通过分离关注点,使用 GLFW 将键盘输入的内容输出到屏幕是非常简单的过程。事实上我只是从模拟器中提取了大部分代码并整形了一下,使用 go 通道作为进出机器的信号。

让它跑起来

这可能是最难的一部分,至少也是最麻烦的。用如此有限的指令集编写程序集真的很糟糕。使用我编写的粗糙的汇编程序编写程序集更糟糕,因为你怪不得别人。

最大的问题在于同时处理这 4 个寄存器并跟踪它们,将它们作为临时存储存储到内存中。在这个过程中,我记得 Gameboy CPU 有一个堆栈指针寄存器,这样你就可以推送和弹出状态。不幸的是,这台电脑没有这么奢侈,所以我主要是在定制的基础上对内存里的东西进行移进移出操作。

我唯一花时间实现的伪指令是 CALL,以帮助调用函数。这可以让你运行一个函数,然后在函数被调用后返回到该点。由于没有堆栈,你只能调用一层的深度。

由于机器不支持中断,为获取键盘状态等函数,你必须实现糟糕的轮询代码。书中的确提到了实现中断的步骤,但那需要写更多代码。

无论如何,我最终编写出了四个程序,其中多数程序使用一些共享代码来绘制字体、获取键盘输入等。虽然与操作系统还有一定的距离,但它确实让我意识到一个简单的操作系统也可能提供一些服务。

但这其实并不容易,文本编写程序最棘手的部分是计算出何时转到新行,或当你按回车键时发生了什么。

*main-getInput:*    CALL ROUTINE-io-pollKeyboard    CALL ROUTINE-io-drawFontCharacter    JMP main-getInput

上述文本编写程序的主要循环。

我也没有抽出时间来实现退格键或其他任何修改键。这让我意识到制作文本编辑器需要做多少工作,这项工作可能是多么乏味。

反思

这个项目对我来说非常有趣,也很有收获。在用汇编语言编程的过程中,我基本上放弃了底层的 NAND、AND 和 OR 门。我上升到了上面的抽象层。虽然我做的这个 CPU 很简单,距离电脑里的 CPU 还很远,但通过这个项目我学到了很多,如:

  • 位元如何在使用总线的所有组件之间移动

  • 一个简单的 ALU 是如何工作的

  • 一个简单的 Fetch-Decode-Execute 循环是什么样的

  • 没有堆栈指针寄存器的机器+堆栈的概念很糟糕

  • 没有中断的机器很糟糕

  • 汇编程序是什么、如何工作

  • 外围设备如何与一个简单的 CPU 通信

  • 简单字体的工作原理和在显示器上显示它们的方法

  • 一个简单的操作系统会是什么样子

相关课程

如果你对于芯片的工作原理非常有兴趣,先上一些在线课程也是一个好方法。这一 Udacity 免费课程《高性能计算架构》源自佐治亚理工:

  • https://cn.udacity.com/course/high-performance-computer-architecture--ud007

原文地址:https://djhworld.github.io/post/2019/05/21/i-dont-know-how-cpus-work-so-i-simulated-one-in-code/

本文为机器之心编译,转载请联系本公众号获得授权

✄------------------------------------------------

加入机器之心(全职记者 / 实习生):hr@jiqizhixin.com

投稿或寻求报道:content@jiqizhixin.com

广告 & 商务合作:bd@jiqizhixin.com

编译原理什么是移进规约冲突_我这个人不懂什么CPU,于是我用代码模拟出了一个...相关推荐

  1. 编译原理什么是移进规约冲突_编译原理复习题

    可以微信扫码观看 河南城建 <编译原理>复习题丨杨海振整理丨20150521 一.单项选择题 1.构造编译程序应掌握   .D a. 源程序                         ...

  2. 3.03 bison移进/规约冲突和操作符优先级

    如果你已经储备bison的相关基础知识,阅读理解下面的代码会轻松得多.没有bison基础的同学请点击查看bison基本的语法规则及相关介绍. 移进/规约冲突一般是由文法二义性造成的,关于二义性可以看看 ...

  3. YACC移进规约冲突案例分析(一)

    总结 总结: bison给出的用例是发现冲突的最便捷方法. 第一种用例:明确用例(一个Example),直接反应问题. 第二种用例:混淆用例(两个Example),解析器无法区分两条语句. 也可以看o ...

  4. 编译原理 实验四 LR(0)分析法(LR0分析表的自动生成)

    写在前面 由于代码较长,csdn对文章总长度有字数限制,想只看完整代码的请移步另一篇博客. https://blog.csdn.net/qq_46640863/article/details/1257 ...

  5. 编译原理实验五:用Yacc设计语法分析器1

    所有实验的源代码:点此下载 实验目的: 学习如何使用Yacc设计一个语法分析器,并与用lex写的词法分析器链接起来. 实验内容: 使用yacc为实验2所给的语言写一个语法分析器(你可以重新设计该语言的 ...

  6. 考研复试6 编译原理

    第一章 编译器简介 1. 编译器的核心功能 把源代码翻译成目标代码 2. 编译器设计两个原则: 语义相同:以某种可察觉的方式改进输入程序 3. 编译器内部结构 前端:依赖于源语言,与目标机器无关.将输 ...

  7. 编译原理教程_6 LR分析法

    文章原稿 https://gitee.com/fakerlove/fundamentals-of-compiling 文章目录 6. LR分析法 6.1 简介 (1)LR分析法的优缺点 (2)分析表的 ...

  8. 编译原理个人作业--第五章——基于 编译原理 国防工业出版社 第三版

    1 文法 G 1 G_1 G1​为 E → E + T ∣ T T → T ∗ F ∣ F F → ( E ) ∣ i E\rightarrow E+T|T\\ T\rightarrow T*F|F\ ...

  9. 【编译原理】 LR(0) 分析表

    LR(0) 步骤 1. 写成 拓广文法 (S'→ S) 2. 活前缀的 DFA(靠近.后面的非终结符) 看状态Ii里面,是不是只存在一个规约项目.如果有两个规约项目,就是规约--规约冲突:如果同时有规 ...

最新文章

  1. 最新TeamViewer绿色便携单文件版之新手使用说明
  2. 10、查看索引(SHOW INDEX)
  3. python字典高级用法_Python 进阶编程之字典的高级用法
  4. 去除Java字符串中的空格
  5. 数组中的对象的特征值提取生成新对象实现方法
  6. Linux的软连接、硬链接和find命令
  7. Batteries for Mac(电池电量管理软件)
  8. android app 颜色搭配,色采 - 写给大家用的配色 App - Android 应用 - 【最美应用】
  9. java/php/net/pythont物流配送中心管理系统设计
  10. matlab hamming 原理,Matlab中加汉明窗 ahmming 作用
  11. 6轴并联机器人开发--机械设计
  12. 招投标工作中投标书编制的流程是怎样的?
  13. 重复安装GI的时候报错INS-32025
  14. Docker修改镜像源为阿里云
  15. SEO优化|如何让网站关键词排名快速提高
  16. fedora17下nvidia双显卡闭源驱动的安装
  17. 《神经科学:探索脑》学习笔记(第19章 脑的节律)
  18. STM32H750 SRAM中下载和调试程序
  19. 快到家了【经济学人】
  20. 如何把图片做成gif?怎样做出gif动态图?

热门文章

  1. 少走弯路,给3~5年程序员的唯一一条建议
  2. 【技术文档】jeecg3.7.1-maven版本搭建环境手把手入门-eclipse
  3. jeecg-framework-3.3.2-RELEASE 最新版本发布
  4. dom选择方法的区别
  5. Flask Bind-DLZ + Mysql DNS管理平台
  6. MySQL数据库(六) 一一 基本操作之事物和索引
  7. .NET MVC Scripts.Render 上下文不存在问题解决方法
  8. NIO框架入门(一):服务端基于Netty4的UDP双向通信Demo演示
  9. ubuntu修改主机名
  10. WeUI 为微信 Web 服务量身设计-h5前端框架