“不懂 CPU 工作原理又如何,直接用代码模拟一个!”

640?wx_fmt=gif

近日,一位来自 BBC 的软件工程师 Daniel Harper 从浅入深,分享了以代码的方式来实现 CPU 所有功能的可行性,希望对大家了解计算机的内容原理有所帮助。

“不懂 CPU 工作原理又如何,直接用代码模拟一个!”_第1张图片

作者 | Daniel Harper

译者 | 王艳妮,责编 | 屠敏

出品 | CSDN(ID:CSDNnews)

以下为译文:

几个月前,我突然意识到自己并不真正理解计算机内部的工作原理。我仍然不明白现代计算机具体是怎么工作的。

“不懂 CPU 工作原理又如何,直接用代码模拟一个!”_第2张图片

然而,我读了J. Clark Scott撰写的一本叫《But How Do It Know? 》的书,书中描述了一个简单8位计算机,从与非门(NAND gate)到寄存器、RAM、CPU、ALU和I / O的细节。此书使我产生了在代码中实现一个CPU的渴望。

我对电路的物理实现方面并不感兴趣,好在本书只是蜻蜓点水一般地给出了简单的介绍,使读者对电路方面有个大体的了解,而无需具备电气工程相关知识也能理解比特流是如何在这个体系中移动的。但是对我而言,纸上得来终觉浅,我必须要亲眼看到它是如何工作的,并经历一个不可避免的从自己错误操作中吸取教训的历程。史诗般的历程就从这个想法开始了,我画下一幅航海图,用以在波涛汹涌的“代码复现电路”的大海上扬帆。而今日忆起往昔种种,百感交集,简直要禁不住泪湿青衫了。

我此次大航海之旅的成果可以在“简单计算机”上看到; 是一台“简单”的计算机,而且是可以“计算”点东西的。

“不懂 CPU 工作原理又如何,直接用代码模拟一个!”_第3张图片

“不懂 CPU 工作原理又如何,直接用代码模拟一个!”_第4张图片

“不懂 CPU 工作原理又如何,直接用代码模拟一个!”_第5张图片

这是一个很酷的小东西,CPU代码通过海量的电门的开和关来实现,但它是好使的,我已经进行过单元测试了,我们都知道单元测试是证明某些东西好使的无可辩驳的证据。

它处理键盘输入,并使用我呕心沥血设计的字形集将文本呈现给显示器,用了我称之为“Daniel Code Pro”的专业字体。唯一走捷径的地方是,为了让键盘输入和显示器输出正常工作我必须用go channel才能通过GLFW与外界通信,但其余部分就都是模拟出来的电路了。

我甚至写了一个原始的汇编程序,至少可以说是使我大开眼界。它并不完美。实际上有点烂,但它让我清楚的了解了那些许多许多年前前人们早已解决的问题,我认为通过这个过程我变成了更好的自己。或者也有可能变得更差了,这取决于你问谁…


640?wx_fmt=png

但你为什么那样做?

 

 “我已经见过十三岁的孩子在Minecraft中做这样的事情了,当你用电报继电器建造一个真正的CPU时再说。”

我头脑中的的计算机模型还停留在cs入门级教科书上那种层次,而支持我在2013年所写gameboy模拟器的CPU实际上也与当今人们使用的CPU完全不同。即使这样说了,模拟器也只是一个状态机,它也没有描述逻辑门级别的东西。您只需使用switch语句并存储寄存器的状态即可实现大部分功能。

所以我在尽力地去更好地理解这些东西,因为我不知道L1 / L2 cache是什么,我不知道流水线是什么,我不完全确定我理解Meltdown和Spectre漏洞文件。有人告诉我他们正在优化代码以好好利用CPU cache的时候,我也不知道如何去验证所以只好相信他们的话。我不太确定x86指令的含义是什么。我不明白人们如何利用GPU或TPU工作。我甚至不知道TPU是个什么东西。我也不知道如何使用SIMD指令。

但所有这些都是建立在你需要的知识基础之上,所以如果只是先看看地图,我就没法最终到达目的地。这意味着要回归基础并从简单的东西开始动手实操。书中描述的“斯科特计算机”很简单。这就是我选择它的原因。

 

640?wx_fmt=png

伟大的斯科特!它活过来了!

 

斯科特计算机是一个连接到256字节RAM的8位处理器,全部通过8位的系统总线连接。它有4个通用寄存器,可以执行17个机器指令。有人为它做了一个网页端的视觉模拟器,这真的很酷,我都不敢想象跟踪所有接线状态需要多长时间!

“不懂 CPU 工作原理又如何,直接用代码模拟一个!”_第6张图片

一个Scott CPU所有组件的示意图

本书将带您从简陋的与非门,到内存位,到寄存器,然后继续逐层深入,直到您最终得到类似于上面图表的一个CPU。我真的建议您阅读它,即使您已经熟悉这些概念,因为这本书给出了一个非常好的概述。我不建议使用Kindle版本,因为图表有时难以在屏幕上放大和显示。根据我的经验,这是用Kindle看书过程中的一个老大难问题。

我的计算机唯一与之不同的是我将其升级到16位以便有更多的内存可供使用,因为甚至只存储ASCII表的字形就会使本书中描述的大多数8位机器捉襟见肘,就没有多少剩下的空间可用于有用的代码了。

 

640?wx_fmt=png

我的开发历程

 

我的开发过程,基本上只是阅读教材,仔细研究图表然后尝试使用通用的编程语言代码将其翻译出来,并且绝对不使用专为集成电路开发设计的内容的编程语言。我之所以是用Go写了它,是因为吧,我懂点儿Go语言。反对者们可能会说,你这个白痴!简直不敢相信你没有花时间学习VHDL或Verilog或LogSim之类的东西。但是到那时为止我已经写了从比特和字节到与非门,我已经陷得太深了。也许以后我会学习这些,并且为我当初浪费的时间而哭泣,但那是我宿命中终究要背负的苦难铸成的十字架。

在这个宏大的计划中,计算机的大部分组件只是在传递一堆布尔型变量,所以任何对布尔型友好的语言都可以完成这项任务。

将模式应用于那些布尔型变量可以帮助您(程序员)获得其含义,并且任何人需要做出的最重要的决定都是决定系统将使用哪种字节顺序并确保所有组件在总线之间传输内容顺序的正确性。

后台实施起来真的挺痛苦的。从偏移量我选择了小端,但在测试ALU时,不知道为什么结果总是出错,简直令人头秃。这一阶段我不知道写了多少个print函数。

开发确实持续了一段时间,可能在一些业余时间我搞了大约一个月或两个月,但是一旦CPU组建完成并“成功”算出了2 + 2 = 5,我就已经很高兴了。

好吧,在本书讨论I / O功能之前,只要有一个简单的键盘和显示界面,你就可以对机器进行输入和输出操作了。好吧,我已经都走到了这一步,没有必要让它一直都只是个半成品。我为自己设定了一个目标,即能够在键盘上输入内容并在显示器上呈现字母。

 

640?wx_fmt=png

外设

 

外围设备使用适配器模式充当CPU与外界之间的硬件接口。不难猜测,这就是软件设计模式的灵感来源。

“不懂 CPU 工作原理又如何,直接用代码模拟一个!”_第7张图片

通过这种对问题的分割,将键盘的另一端以及显示区域链接到一个由GLFW管理的窗口,实际上就非常简单了。事实上,我只是从模拟器中提取了大部分代码并重新整理了一下,使用go channel作为进出机器的信号。

 

640?wx_fmt=png

给予它新生

 

“不懂 CPU 工作原理又如何,直接用代码模拟一个!”_第8张图片

这可能是最棘手的部分,或者至少是最麻烦的部分。用如此有限的指令集写汇编很糟糕。用自己写的原始汇编器写汇编更糟糕,因为出了问题你怨不了任何别的人,只能怨你自己。

最大的问题是如何处理4个寄存器并追踪它们的状态,将数据暂存在内存中。做这些的时候我想起来Gameboy CPU有一个栈顶指针寄存器,所以你可以push和pop状态。不幸的是,这台计算机没有这么奢华的功能,所以我主要是将数据存入和取出内存。

我花时间实现的唯一伪指令是CALL,用来帮助调用函数,这允许你运行一个函数然后返回调用函数后的点。没有那个栈的话你只能调用一层函数。

此外,由于机器不支持中断,您必须部署可怕的轮询代码才能实现“获得键盘状态”等函数。本书确实讨论了实现中断所需的步骤,但它涉及太多电路设计了。

但无论如何,还是不要再抱怨了,我最终编写了四个程序,其中大多数都使用了一些共享代码来绘制字体,获得键盘输入等。不完全是像操作系统那样高大上的东西,但它确实让我对一些简单的,操作系统可以提供的服务抱更加欣赏的态度了。

但这并不容易,文本编写器程序中最棘手的部分是如何正确地计算出何时转到换行符,或者当你按下回车键时应该发生什么。

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

文本编写器程序中的主要循环

我没有实现退格键或任何修改键。这一过程让我了解到编写一个文本编辑器需要做多少工作以及这样的工作可能有多么乏味。

 

640?wx_fmt=png

反思

 

这对我来说是一个有趣且非常有益的项目。在使用汇编语言进行编程的过程中,我基本上忘记了最底层的与非门,与门和或门这些东西。我的思考范围已经进入了抽象的上层。

虽然这个CPU非常简陋,并且与我面前笔记本电脑里的CPU还差的很远,但我认为这个项目教会了我很多,比如以下几点:

  • 比特如何通过总线在所有组件之间移动

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

  • 简单的“取指令-译码-执行”循环是什么样的

  • 没有栈顶指针寄存器的机器+栈的概念本身都很糟糕

  • 没有中断机制的机器很糟糕

  • 汇编程序是什么以及可以做什么

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

  • 简单字体的工作原理以及在显示器上呈现它们的方法

  • 简单的操作系统可能是什么样的

所以下一步呢?这本书说自1952年以来还没有人建造过这样的计算机,这意味着有67年的材料可以供我学习,所以这应该够我忙上一阵的了。我看到x86手册有4800页,这些读物足够你进行轻松有趣的睡前阅读了。

也许我会调戏一下操作系统方面的东西,跟C语言的调调情,在一个令人遗憾的晚上试图焊接一个PiDP-11组件,然后可能最后以失败告终。我也不知道,到时候再说吧。

好吧说正经的,我认为我真的会开始研究基于RISC的东西,可能是RISC-V,但可能从早期的RISC处理器开始,以了解其家族的血脉传承。现代CPU有更多的功能,比如cache之类的,所以我也想了解这些。需要学习的东西太多了。

我在日常工作中需要知道任何这些东西吗?可能有帮助,但并不是真的需要。可我很享受这个过程,所以管他呢。感谢您阅读本文,么么哒。

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

作者简介:Daniel Harper,在BBC工作的高级软件工程师。

本文为 CSDN 翻译,转载请注明来源出处。

2019程序员转型学什么?

https://edu.csdn.net/topic/ai30?utm_source=csdn_bw

【End】

6月29-30日,2019以太坊技术及应用大会特邀以太坊创始人V神与以太坊基金会核心成员,以及海内外知名专家齐聚北京,聚焦前沿技术,把握时代机遇,深耕行业应用,共话以太坊2.0新生态。扫码,即享优惠购票!

640?wx_fmt=jpeg

 热 文 推 荐 

华为的前半生

百度只能靠 AI 续命了?

@程序员,2019 年软件开发新趋势必知!

代码有温度 科技需向善

☞惊!为拯救美国落伍的 STEM 教育,纷纷出手教老师编程?!

高考倒数 2 天!程序员惊现最燃表白!

被5月GitHub Top20榜单惊呆了! 原来区块链大佬都在做这个...

边缘计算将吞掉云计算!

B站超全分享!2万人收藏的免费计算机科学速成课

谷歌开源张量网络库TensorNetwork,GPU处理提升100倍!

☞“是!互联网从此没有 BAT!”

640?wx_fmt=png你点的每个“在看”,我都认真当成了喜欢

你可能感兴趣的:(“不懂 CPU 工作原理又如何,直接用代码模拟一个!”)