rety2007 发表于 2023-9-15 07:12:45

CPU 的工作原理是什么?

看到很多介绍 CPU 的介绍,很多是工艺流程的介绍,模糊知道有各种指令集,各种门进行着各种运算,但还是不知道这运算的物理原理。还有那些所谓的 01 又是怎么保存和读取的呢?听说着 CPU 电路比北京市地图还大,我是大学物理水平,觉得大神说通俗些应该能明白这原理吧。

pcman 发表于 2023-9-15 07:13:12

steam上有个叫MHRD的游戏,就是让你从最基础的NAND门开始,用代码描述出一个CPU的电路结构,这个过程中你可以深刻理解CPU的工作原理。
其他答主都是从AND OR NOT三个逻辑门出发的,其实他们都可以用NAND的组合完成。游戏最开始的部分就是让你用NAND做出常用的三个逻辑门。
和机械计算机一样的各种机构(电路)通过组合完成了读写内存上的数据和指令,并按照指令对数据进行运算,然后写回内存的过程。
现实中的CPU和游戏中描述的差别不大,无非是每个部分又都被更加精巧复杂的电路代替了。逻辑开发过程也和游戏差不多,只不过描述语言更加高级一点,用起来更方便一些。
就像搭积木一样,游戏里最基本的就是NAND和D-flip flop(实际上现实中也是由NAND组成,游戏为了简化时序模拟而做成了基本模块)。你能做的组合就是把基本模块的输入输出用导线连起来,最终CPU就像是搭建了个高楼大厦一样。明白了基本原理,你很无聊的话也可以试试在minecraft里面用红石电路做个CPU,或者在现实中买一堆NAND自己焊一个。
P.S. 大概在十年前,我刚学了点verilog的时候,就有这样的问题。那个年头能找到的代码也就SPARC T1,但是没有相应的知识是无法理解这个过程的。现在risc v一片热火朝天,信息比当年丰富得多得多,甚至都有硬核游戏了。推荐任何有这个疑问的人都去尝试一下这个游戏,动手永远是最好的学习方式。

zeroera 发表于 2023-9-15 07:13:53

这事儿说来话长,我们从头推理,直到让你明白 CPU 的工作原理。
因为你的问题当中,可以看出是渴求直到最根本的物理原理,还有基本的指令执行和数据保存,所以本文不会涉及流水线等干扰因素,就推导出最最简单的 CPU 原理,甚至你自己都可以造一个。
让我们从一个故事开始吧~
据说知乎回答可能有部分动图有问题,您也可以到这里看。
图解 | 你管这破玩意叫计算机?
我和小宇早恋了,我们家住隔壁。

http://picx.zhimg.com/v2-d6146515fa7d2c95ad1f3a7d7269f25d_r.jpg?source=1940ef5c

一、编码与电路——信号的转换

晚上父母会把手机没收,但我们还想继续聊天,又不敢发出声音,于是我们想到了这个办法...


http://pic1.zhimg.com/v2-67c9f046f0f88aa06b159af4908bb3e9_r.jpg?source=1940ef5c

我们把所有的中文都用灯泡的亮灭组合来表示,同时约定好每隔一秒读取一次灯泡的状态并记录下来,这是我们的暗号。
我:亮亮灭灭亮
喜:灭亮亮灭灭
欢:亮灭亮灭亮
你:亮亮亮灭灭
这样,我们虽然没有了手机,依然可以日以继日地聊天,虽然效率很低,但依然很快乐。
我和小宇就这样在不经意间,将语言转换成为了灯泡的亮灭组合,这个过程叫做编码。

二、门电路——信号的关联

我和小宇就这样一直秘密保持着通话,直到上了大学,父母再也管不了我们用手机了。
但这么多年的小灯泡通话,使我们总觉得事情没那么简单,于是我们开始了一些新的探索。


http://picx.zhimg.com/v2-20d832a0f90a0b6d63d42c756a3bbd3f_r.jpg?source=1940ef5c

我们增加了一个开关。此时当两个开关同时闭合时,灯泡才会亮。
这样两个开关与灯泡之间,不再是之前简单的对应关系了,而是有了逻辑。
开关的断开与闭合分别对应着电路的断开与连通。而小灯泡的不亮与亮,也分别对应着电路的断开与连通。那这两者就可以统一,不再依赖于具体的实物表现了。


http://pica.zhimg.com/v2-193da9d5ca2068a208316c0b9ef43b7d_r.jpg?source=1940ef5c

还有,开关的连通与断开,是主动的。而小灯泡的连通与断开,是被动的,是结果。
我们把开关这里的连通与断开称为输入端,把灯泡的连通与断开称为输出端,并且将整个电路都封装在一个图形里,可以得到如下抽象:


http://pic1.zhimg.com/v2-53433523939b5c314d8a442883b273e6_r.jpg?source=1940ef5c

我们决定把这种电路叫做门电路, 上面这个叫与门。
为了今后更为抽象的探索,我们将电路连通表示为数字 1,电路断开表示为数字 0。
我们将这种表示方式称为二进制。
输入A输入B输出000010100110

http://picx.zhimg.com/v2-c1d6f01a47f3d70a22894f8f5cfe23b0_r.jpg?source=1940ef5c

慢慢地,我们发现了越来越多的玩法。


http://pic1.zhimg.com/v2-07e04c81cbb5258b58f3130f79e625f9_r.jpg?source=1940ef5c

上面这种电路,我把他抽象成如下门电路形状,叫做或门。


http://picx.zhimg.com/v2-5ad8028fdd4fea24ae4d192c82144ebc_r.jpg?source=1940ef5c

之后便一发不可收拾,我和小宇设计了越来越多的门电路,我们发现,只要是我们能想到的逻辑关系,都可以设计成对应的门电路。


http://pic1.zhimg.com/v2-8a1fba3bca8e91883bbd3711ab35ec6c_r.jpg?source=1940ef5c


三、加法器——信号的计算

十进制数可以转换成二进制数,而二进制数又可以对应到门电路的输入端与输出端。
于是我和小宇有了一个大胆的想法,能不能设计一个计算加法的电路呢?
我们首先从最简单的一位二进制数相加开始:
0+0=0;0+1=1;1+0=1;1+1=10
变成一张表格如下
加数 A加数 B加和输出进位输出0000011010101101即我们需要设计出一种电路,可以达到表中的输入与输出效果。
经过不懈努力,终于发现这个电路可以由异或门和与门两个门电路组成。


http://pic1.zhimg.com/v2-00249fdcb031b28d972a2273bad60d3d_r.jpg?source=1940ef5c

这个装置实现了二进制的一位加法,但它并不完美,因为只考虑了这两个数的进位输出,但没有考虑上一位的进位,所以只能叫半加器。


http://pic1.zhimg.com/v2-1636428986745d0c2e517de5ad3e126f_r.jpg?source=1940ef5c

如果将前一个进位考虑进来,只需再多一个半加器,并且拼接一个或门即可。


http://pica.zhimg.com/v2-4fae63012d90a343c652e66cccfe3a74_r.jpg?source=1940ef5c

此时我们已经建立好了一个完美的一位加法器,并自豪地称之为全加器。


http://pica.zhimg.com/v2-dea3456438b7a1693af11e4a440ff575_r.jpg?source=1940ef5c

全加器做出来之后,无论多少位的加法器就都可以做出来了,只需将全加器逐个拼起来即可。我们尝试做一个八位加法器。


http://picx.zhimg.com/v2-59abbc40d9c827ed1d7a427323d055bf_r.jpg?source=1940ef5c

OK,大功告成,有了加法器,理论上就可以实现任何的数学运算了。
因为我们知道乘法可以转换成加法,除法可以转换成减法,而减法又可以转换成补码的加法。现在我们可以自豪地称这个部件为,算术逻辑单元 ALU。


http://picx.zhimg.com/v2-39cefe9eddf98bbb0eaf401b01a8edce_r.jpg?source=1940ef5c


四、时钟——信号的震荡

我和小宇都非常高兴,终于用电路的方式实现了计算功能。
但慢慢的觉得没什么意思了,于是我们又突发奇想,设计了如下诡异的电路。


http://picx.zhimg.com/50/v2-bd01465d964613c557485ca006633f04_720w.gif?source=1940ef5c

当闭合开关 A 时,整个电路联通,开关 B 将会被吸下来,整个电路断开,电磁铁失去磁性,开关 B 又会弹上去,此时电路又联通,开关 B 又被吸下来。
就这样,开关 B 不断地快速地在开和闭之间循环进行,而我们始终没有去干预这个电路,因此该电路有了自反馈的特性。
由于开关 B 的来回震荡,我们将这种电路称为振荡器,由于它可以产生不断变化的电信号,就像时钟一样不停且规律地跑着,我们将这个装置又称为时钟。它所产生的交替的电信号称为时钟信号。

五、RAM——保存信号

虽然有了加法器,但是输入的数字从哪里来?能不能先保存在某个地方呢?
我和小宇经过多次实验,发明了一个非常复杂的电路:


http://picx.zhimg.com/v2-bcb80b3bec5c275d768838be1ee92159_r.jpg?source=1940ef5c

如果输入端为 1,改变"某控制端"信号(信号由 0 变化到 1 这个瞬间),则输出端变为 1,之后输出端仍然保持(存储)着刚刚的 1。
如果输入端为 0,改变"某控制端"信号,则输出端变为 0,之后输出端仍然保持(存储)着刚刚的 0。
如果想不明白也没关系,只要记住这个电路的设计,实现了一位的存储功能!我们叫它 1 位锁存器。


http://pic1.zhimg.com/v2-14a8374b13e8a5b5229825768eae436f_r.jpg?source=1940ef5c

然后我们把多个锁存器组合起来,再加上一些 3-8 译码器,8-1 选择器等电路,就可以实现一个能保存 8 位二进制的存储器,并且可以随机地读写它, 我们把它叫做 RAM,简称为内存。


http://pic1.zhimg.com/v2-c342217262322d245f35b2b7951f5fb2_r.jpg?source=1940ef5c

这个组件通过再次组合,可以形成 N × M 的 RAM 阵列。比如我们可以表示一个 1024 * 8 的 RAM 阵列。


http://pic1.zhimg.com/v2-5663632d29ad065d9a5b49e04acdf75d_r.jpg?source=1940ef5c

这表示存储容量为 1024 个单位,每个单位占 8 位。
为了更方便地表示,我们规定 1024 = 1K,8 位 = 1 字节(8 bit = 1 byte),那么我们就可以说,这个 RAM 的存储容量为 1K 个单位,每个单位占 1B。或者说,地址空间为 1K,存储容量是 1KB。
此时这个 RAM 模块已经近乎完美了,我们甚至可以单独对其进行使用,将数据存入某个地址,将某个地址中的数据读出。
怎么方便人操作呢?只需要将地址输入、数据输入、写操作端分别接入一个控制面板,由开关来控制这些信号的输入是 1 还是 0 即可,然后再将数据输出接入一些灯泡方便观察,这样一个单独的可以手动操作的存储装置,就搞定啦。(下图中有彩蛋~)


http://picx.zhimg.com/v2-616bbc91258db70f25f92e3e1cce078d_r.jpg?source=1940ef5c

有了可读写的内存,我们就可以事先把几个数字存储内存中了,接下来,我们能否让算术逻辑单元 ALU 自动地读取这个数字,进行加法运算呢?

六、程序——自动化

我们先引入一个新的组件,10 位计数器,这里的 Clk 就接入我们在第四部分讲的时钟信号,Clr 是清零端,具体效果下面动图一目了然。


http://picx.zhimg.com/v2-519d4027aaac36953380f3c2821c4233_r.jpg?source=1940ef5c

计数器的输出就是 0,1,2,3,4,5,可以当作内存中的地址。
我们把这个计数器,以及上面讲的 ALU 与 RAM 全部连在一起,尝试实现一个可以累积求和的装置。
我们想计算的是 1+2+3+4+5+6+7, 这个自动化的计算器是这么运行的
1、用控制面板在 RAM 的地址 0~6 处存上 1~7 这几个数字的,在上一节已经实现了。
2、当计数器的值是 0 时,数据 1 被输出到加法器进行计算,此时加法器 A=1,B=0,计算结果为 1,但记住锁存器存储的是上一次的加法器输出 0,这次的计算结果要等下一次锁存器遇到上升沿信号。
3、当计数器的值是 1 时, 数据 2 被输入到加法器,此时锁存器存储了上一次的计算结果 1,并将这个 1 输出给小灯泡,并同时回传到加法器的B,所以此时加法器 A=2,B=1,计算结果为 3
4、当计数器的值是 3 时,以此类推,请看下图


http://pic1.zhimg.com/v2-8190b0f405f1f66fe2cbd0de3ba06536_r.jpg?source=1940ef5c

我们将累加求和这个过程自动化了!之后如果想计算累加和,只需要用控制面板事先在内存里存好数据就可以了!是不是很方便?


七、程序指令

我们还想要更多的自动化!
现在这个装置,只能无脑地将 RAM 中的数据从头到尾一直累加下去,无法选择加哪个不加哪个,也无法选择什么时候停止。
比如我们 RAM 中的数据是这样的。
地址(16进制)数据(10进制)0x000x01100x020x03200x04300x05...我们只想让 RAM 蓝色地址处的数据进行累加,其他地方的数据忽略,并且到 RAM 0x05 处就停止,该怎么做呢?
我们可以再增加一个 RAM,这个 RAM 里存放的数据,表示"指令"的含义!
我们先发明三种指令。
add:把 RAM 这个位置处的值进行累加
nop:忽略此处的值(也就是什么都不做)
halt:停止(禁止计数器的值加一)
那么要想达到上述功能,相应的这个指令 RAM 中的数据应该是这样的。
注意:下面指令 RAM 的地址和上面数据 RAM 的地址之间有一一对应关系!
地址(16进制)指令RAM的值指令含义0x00nop什么都不做0x01add累加0x02nop什么都不做0x03add累加0x04add累加0x05halt停止...
我们需要引入一个控制单元,放在如下位置。


http://pica.zhimg.com/v2-99b8391cdca57aea042fbfe562f78f95_r.jpg?source=1940ef5c

遇到 nop 指令(0x00),那输出就将锁存器的 W 位禁止,不允许锁存器写操作,这样累加结果就不会录入。
再比如遇到输入为 halt 指令(0x05),就将计数器的 EN 位禁止,不允许计数器 +1,这样就达到了停止的效果。
此时再让时钟信号震荡起来,就可以达到有选择地求和过程,并且在指定位置悬停。那现在我们就让时钟信号震动起来,看看这个过程吧。(此处只留关键组件)


http://picx.zhimg.com/v2-23d7bf44a83db2217b507ed9f6685941_r.jpg?source=1940ef5c

这个控制单元该怎么实现呢?我们知道,只要给出输入,给出输出,任何组件都可以造出来。本文就不再展开了。
有了三个指令,我们知道了通过指令这种方式,配合各种复杂的控制器,即可实现将所有操作统统自动化。
接下来我们需要做的,就是设计控制器,以及约定好一大堆指令,使得通过这一大堆指令的排列组合,可以实现任何自动化的计算操作。

我们将设计好的一大堆指令
称作指令集
我们将指令排列组合后可以实现的功能
称作程序
我们将指令的排列组合这个过程
称作编程
我们将排列组合这些指令的人
称作程序员
而我们将承载这一切的装置,叫做什么呢?
没错,这个破玩意,就是





没错,其实答主的疑惑,已经不仅仅是 CPU 了,而是 CPU 与其他各个部件配合而成的,计算机的原理。
本文灵感来自一本计算机科普神作,《编码 | 隐匿在计算机软硬件背后的语言》,我在此向这本书致敬。本文和本书的核心目的是让你理解计算机的思想,实际上现在的计算机指令与数据都是放在内存中的,文中其他地方也都是对计算机的简化模型。
据说知乎回答可能部分动图有问题,可以来这里~
图解 | 你管这破玩意叫计算机?

sjh163 发表于 2023-9-15 07:14:20

想了解CPU的工作原理莫过于从头开始用最基础的元素打造一个简单CPU。
接下来我会从最简单的晶体管开始一步步讲解CPU是如何构造出来的,明白了这个过程理解 CPU 的工作原理不在话下,在此之后我会从最基础的二进制机器指令一步步讲解高级语言的基本原理,通读本文后你将彻底明白CPU与高级语言的工作原理。
以下内容出自我的两篇文章《你管这破玩意叫CPU?》《你管这破玩意叫编程语言?》。
每次回家开灯时你有没有想过,用你按的简单开关实际上能打造出复杂的 CPU 来,只不过需要的数量会比较多,也就几十亿个吧。
伟大的发明

过去200年人类最重要的发明是什么?蒸汽机?电灯?火箭?这些可能都不是,最重要的也许是这个小东西:

http://picx.zhimg.com/v2-99fe4aed229e1e794e10c2dea15e230d_r.jpg?source=1940ef5c
这个小东西就叫晶体管,你可能会问,晶体管有什么用呢?
实际上晶体管的功能简单到不能再简单,给一端通上电,那么电流可以从另外两端通过,否则不能通过,其本质就是一个开关。
就是这个小东西的发明让三个人获得了诺贝尔物理学奖,可见其举足轻重的地位。无论程序员编写的程序多么复杂,软件承载的功能最终都是通过这个小东西简单的开闭完成的,除了神奇二字,我想不出其它词来。
AND、OR、NOT

现在有了晶体管,也就是开关,在此基础之上就可以搭积木了,你随手搭建出来这样三种组合:

[*]两个开关只有同时打开电流才会通过,灯才会亮
[*]两个开关中只要有一个打开电流就能通过,灯就会亮
[*]当开关关闭时电流通过灯会亮,打开开关灯反而电流不能通过灯会灭
天赋异禀的你搭建的上述组合分别就是:与门,AND Gate、或门,OR gate、非门,NOT gate,用符号表示就是这样:

http://picx.zhimg.com/v2-6601c7a6580b8f650c6e2e49afa6356e_r.jpg?source=1940ef5c
道生一、一生二、二生三、三生万物

最神奇的是,你随手搭建的三种电路竟然有一种很amazing的特性,那就是:任何一个逻辑函数最终都可以通过AND、OR以及NOT表达出来,这就是所谓的逻辑完备性,就是这么神奇。
也就是说给定足够的AND、OR以及NOT门,就可以实现任何一个逻辑函数,除此之外我们不需要任何其它类型的逻辑门电路,这时我们认为{AND、OR、NOT}就是逻辑完备的。
这一结论的得出吹响了计算机革命的号角,这个结论告诉我们计算机最终可以通过简单的{AND、OR、NOT}门构造出来,就好比基因。

http://picx.zhimg.com/v2-f9129382758ab4358f3bf1719ed7d9e1_r.jpg?source=1940ef5c
老子有云:道生一、一生二、二生三、三生万物,实乃异曲同工之妙。虽然,我们可以用AND、OR、NOT来实现所有的逻辑运算,但我们真的需要把所有的逻辑运算都用AND、OR、NOT门实现出来吗?显然不是,而且这也不太可行。
计算能力是怎么来的

现在能生成万物的基础元素与或非门出现了,接下来我们着手设计CPU 最重要的能力:计算,以加法为例。由于CPU只认知 0 和 1,也就是二进制,那么二进制的加法有哪些组合呢:

[*]0 + 0,结果为0,进位为0
[*]0 + 1,结果为1,进位为0
[*]1 + 0,结果为1,进位为0
[*]1 + 1,结果为0,进位为1,二进制嘛!
注意进位一列,只有当两路输入的值都是 1 时,进位才是 1 ,看一下你设计的三种组合电路,这就是与门啊,有没有!再看下结果一列,当两路输入的值不同时结果为1,输入结果相同时结果为0,这就是异或啊,有没有!
我们说过与或非门是逻辑完备可以生万物,异或逻辑当然不在话下,用一个与门和一个异或门就可以实现二进制加法:

http://pic1.zhimg.com/v2-2a3c69207d7e4d20a44862e75c9fdf43_r.jpg?source=1940ef5c
上述电路就是一个简单的加法器,就问你神奇不神奇,加法可以用与或非门实现,其它的也一样能实现,逻辑完备嘛。
除了加法,我们也可以根据需要将不同的算数运算设计出来,负责计算的电路有一个统称,这就是所谓的arithmetic/logic unit,ALU,CPU 中专门负责运算的模块,本质上和上面的简单电路没什么区别,就是更加复杂而已。
现在,通过与或非门的组合我们获得了计算能力,计算能力就是这么来的。但,只有计算能力是不够的,电路需要能记得住信息。
神奇的记忆能力

到目前为止,你设计的组合电路比如加法器天生是没有办法存储信息的,它们只是简单的根据输入得出输出,但输入输出总的有个地方能够保存起来,这就是需要电路能保存信息。
电路怎么能保存信息呢?你不知道该怎么设计,这个问题解决不了你寝食难安,吃饭时在思考、走路时在思考,蹲坑时在思考,直到有一天你在梦中遇一位英国物理学家,他给了你这样一个简单但极其神奇的电路:

http://picx.zhimg.com/v2-44ea3219990b694b441ec22c51a6a08a_r.jpg?source=1940ef5c
这是两个NAND门的组合,不要紧张,NAND也是有你设计的与或非门组合而成的,所谓NAND门就是与非门,先与然后取非,比如给定输入1和0,那么与运算后为0,非运算后为1,这就是与非门,这些不重要。
比较独特的是该电路的组合方式,一个NAND门的输出是两一个NAND门的输入,该电路的组合方式会自带一种很有趣的特性,只要给S和R段输入1,那么这个电路只会有两种状态:

[*]要么a端为1,此时B=0、A=1、b=0;
[*]要么a端为0,此时B=1、A=0、b=1;
不会再有其他可能了,我们把a端的值作为电路的输出。
此后,你把S端置为0的话(R保持为1),那么电路的输出也就是a端永远为1,这时就可以说我们把1存到电路中了;而如果你把R段置为0的话(S保持为1),那么此时电路的输出也就是a端永远为0,此时我们可以说把0存到电路中了。
就问你神奇不神奇,电路竟然具备存储信息的能力了。现在为保存信息你需要同时设置S端和R端,但你的输入是有一个(存储一个bit位嘛),为此你对电路进行了简单的改造:

http://pic1.zhimg.com/v2-266a2ac1972f0a2590e8cfda557af614_r.jpg?source=1940ef5c
这样,当D为0时,整个电路保存的就是0,否则就是1。
寄存器与内存的诞生

现在你的电路能存储一个比特位了,想存储多个比特位还不简单,复制粘贴就可以了:

http://pic1.zhimg.com/v2-a6b85e03c21d8fde999fa84d8daf48e6_r.jpg?source=1940ef5c
我们管这个组合电路就叫寄存器,你没有看错,我们常说的寄存器就是这个东西。
你不满足,还要继续搭建更加复杂的电路以存储更多信息,同时提供寻址功能,就这样内存也诞生了。
寄存器及内存都离不开上一节那个简单电路,只要通电,这个电路中就保存信息,但是断电后很显然保存的信息就丢掉了,现在你应该明白为什么内存在断电后就不能保存数据了吧。
硬件还是软件?

现在我们的电路可以计算数据、也可以存储信息,但现在还有一个问题,那就是尽管我们可以用AND、OR、NOT表达出所有的逻辑函数,但我们真的有必要把所有的逻辑运算都用与或非门实现出来吗?这显然是不现实的。
这就好比厨师,你没有听说只专做一道菜的厨师然后酒店要把各个菜系厨师雇全才能做出一桌菜来吧!
中国菜系博大精深,千差万别,但制作每道菜品的方式大同小异,其中包括刀工、颠勺技术等,这些是基本功,制作每道菜品都要经过这些步骤,变化的也无非就是食材、火候、调料等,这些放到菜谱中即可,这样给厨师一个菜谱他就能制作出任意的菜来,在这里厨师就好比硬件,菜谱就好比软件。

http://pic1.zhimg.com/v2-9b88df74bdc51e910fb25cc08020904f_r.jpg?source=1940ef5c
同样的道理,我们没有必要为所有的计算逻辑实现出对应的硬件,硬件只需要提供最基本的功能,最终所有的计算逻辑都通过这些最基本的功能用软件表达出来就好,这就是所谓的软件一词的来源,硬件不可变,但软件可变,不变的是硬件但提供不同的软件就能让硬件实现全新的功能,无比天才的思想,人类真的是太聪明了。
同样一台计算机硬件,安装上word你就能编辑文档,安装上微信你就能在公号中读到码农的荒岛求生、安装上游戏你就能玩王者农药,硬件还是那套硬件,提供不同的软件就是实现不同的功能,每次打开电脑使用各种App时没有在内心高呼一声牛逼你都对不起计算机这么伟大的发明创造,这就是为什么计算机被称为通用计算设备的原因,这一思想是计算机科学祖师爷图灵提出的。
说到牛逼的通用设备,在这样也推荐一份牛逼的算法刷题资料,除了本文讲到的底层技术,,想进BAT、TMD、快手这样的一线大厂算法绝不可忽视,认认真真过上一遍这份资料,这些大厂算法面试一关大部分题目都不在话下:
Github疯传!阿里P8大佬写的Leetcode刷题笔记,秒杀80%的算法题!
http://picx.zhimg.com/v2-eae1dafec69c7a4247bf0be3c789be5c_r.jpg?source=1940ef5c
扯远了,接下来我们看下硬件是怎么提供所谓的基本功能的。
硬件的基本功

让我们来思考一个问题,CPU怎么能知道自己要去对两个数进行加法计算,以及哪两个数进行加法计算呢?
很显然,你得告诉CPU,该怎么告诉呢?还记得上一节中给厨师的菜谱吗?没错,CPU也需要一张菜谱告诉自己该接下来该干啥,在这里菜谱就是机器指令,指令通过我们上述实现的组合电路来执行。
接下来我们面临另一个问题,那就是这样的指令应该会很多吧,废话,还是以加法指令为例,你可以让CPU计算1+1,也可以计算1+2等等,实际上单单加法指令就可以有无数种组合,显然CPU不可能去实现所有的指令。
实际上CPU只需要提供加法操作,你提供操作数就可以了,CPU 说:“我可以打人”,你告诉CPU该打谁、CPU 说:“我可以唱歌”,你告诉CPU唱什么,CPU 说我可以做饭,你告诉CPU该做什么饭,CPU 说:“我可以炒股”,你告诉CPU快滚一边去吧韭菜。因此我们可以看到CPU只提供机制或者说功能(打人、唱歌、炒菜,加法、减法、跳转),我们提供策略(打谁、歌名、菜名,操作数,跳转地址)。
CPU 表达机制就通过指令集来实现的。
指令集

指令集告诉我们 CPU 可以执行什么指令,每种指令需要提供什么样的操作数。不同类型的CPU会有不同的指令集。指令集中的指令其实都非常简单,画风大体上是这样的:

[*]从内存中读一个数,地址是abc
[*]对两个数加和
[*]检查一个数是不是大于6
[*]把这数存储到内存,地址是abc
[*]等等
看上去很像碎碎念有没有,这就是机器指令,我们用高级语言编写的程序,比如对一个数组进行排序,最终都会等价转换为上面的碎碎念指令,然后 CPU 一条一条的去执行,很神奇有没有。接下来我们看一条可能的机器指令:

http://pic1.zhimg.com/v2-98468a1839411c05e8de94d6866be93a_r.jpg?source=1940ef5c
这条指令占据16比特,其中前四个比特告诉CPU这是加法指令,这意味着该CPU的指令集中可以包含2^4也就是16个机器指令,这四个比特位告诉CPU该做什么,剩下的bit告诉CPU该怎么做,也就是把寄存器R6和寄存器R2中的值相加然后写到寄存器R6中。
可以看到,机器指令是非常繁琐的,现代程序员都使用高级语言来编写程序,关于高级程序语言以及机器指令的话题请参见《你管这破玩意叫编程语言?》。
码农的荒岛求生:你管这破玩意叫编程语言?指挥家:让我们演奏一曲

现在我们的电路有了计算功能、存储功能,还可以通过指令告诉该电路执行什么操作,还有一个问题没有解决。
我们的电路有很多部分,用来计算的、用来存储的,以最简单的加法为例,假设我们要计算1+1,这两个数分别来自寄存器R1 和 R2,要知道寄存器中可以保存任意值,我们怎么能确保加法器开始工作时R1和R2中在这一时刻保存的都是1而不是其它数?
即,我们靠什么来协调或者说靠什么来同步电路各个部分让它们协同工作呢?就像一场成功的交响乐演离不开指挥家一样,我们的计算组合电路也需要这样一个指挥家。

http://pic1.zhimg.com/v2-b93e98f4c910b58ad4bca663f0530036_r.jpg?source=1940ef5c
负责指挥角色的就是时钟信号。
时钟信号就像指挥家手里拿的指挥棒,指挥棒挥动一下整个乐队会整齐划一的有个相应动作,同样的,时钟信号每一次电压改变,整个电路中的各个寄存器(也就是整个电路的状态)会更新一下,这样我们就能确保整个电路协同工作不会这里提到的问题。
现在你应该知道CPU的主频是什么意思了吧,主频是说一秒钟指挥棒挥动了多少次,显然主频越高CPU在一秒内完成的操作也就越多。
大功告成

现在我们有了可以完成各种计算的ALU、可以存储信息的寄存器以及控制它们协同工作的时钟信号,这些统称 Central Processing Unit,简称就是 CPU。
接下来我们看一下CPU 与高级语言。
创世纪:聪明的笨蛋

CPU 相当原始,就像单细胞生物一样,只能把数据从一个地方搬到另一个地方、简单的加一下,没有任何高难度动作,这些操作虽然看上去很简单很笨,但 CPU 有一个无与伦比的优势,那就是一个字:快,这是人类比不了了的,CPU 出现后人类开始拥有第二个大脑。就是这样原始的一个物种开始支配起另一个叫做程序员的物种。
干活的是大爷

一般来说两个不同的物种要想交流,比如人和鸟,就会有两种方式:要不就是鸟说人话,让人听懂;要不就是人说鸟语,让鸟听懂;就看谁厉害了。最开始 CPU 胜出,程序员开始说鸟语并认真感受 CPU 的支配地位,好让 CPU 大爷可以工作,感受一下最开始的程序员是怎么说鸟语的:

http://pic1.zhimg.com/v2-5217ee8f03de90c5b20af177d0232196_r.jpg?source=1940ef5c
程序员按照 CPU 的旨意直接用0和1编写指令,你没有看错,这破玩意就是代码了,就是这么原生态,然后放到打孔纸带上输入给CPU,CPU 开始工作,这时的程序可真的是看得见摸得着,就是有点浪费纸。
这时程序员必须站在 CPU 的角度来写代码,画风是这样的:
1101101010011010
1001001100101001
1100100011011110
1011101101010010乍一看你知道这是什么意思吗?你不知道,心想:“这是什么破玩意?”,但 CPU 知道,心想“这就简直就是世界上最美的语言”。
天降大任

终于有一天程序员受够了说鸟语,好歹也是灵长类,叽叽喳喳说鸟语太没面子,你被委以重任:让程序员说人话。你没有苦其心志劳其筋骨,而是仔细研究了一下 CPU,发现 CPU 执行的指令集来来回回就那么几个指令,比如加法指令、跳转指令等等,因此你把机器指令和对应的具体操作做了一个简单的映射,把机器指令映射到人类能看懂的单词,这样上面的01串就变成了:
sub $8, %rsp
mov $.LC0, %edi
call puts
mov $0, %eax这样,程序员不必生硬的记住1011.....,而是记住人类可以认识的ADD SUB MUL DIV等这样的单词即可。

http://picx.zhimg.com/v2-3be1443d5d2a6b0e3bbca7d09f55b712_r.jpg?source=1940ef5c
汇编语言就这样诞生了,编程语言中首次出现了人类可以认识的东西。
这时程序员终于不用再“叽叽喳喳。。”,而是升级为“阿巴阿巴。。”,虽然人类认知“阿巴阿巴”这几个字,但这和人类的语言在形式上差别还是有点大。
细节 VS 抽象

尽管汇编语言已经有人类可以认识的单词,但汇编语言和机器语言一样都属于低级语言。所谓低级语言是说你需要关心所有细节。关心什么细节呢?我们说过,CPU 是非常原始的东西,只知道把数据从一个地方搬到另一个地方,简单的操作一下再从一个地方搬到另一地方。因此,如果你想用低级语言来编程的话,你需要使用多个“把数据从一个地方搬到另一个地方,简单的操作一下再从一个地方搬到另一地方”这样的简单指令来实现诸如排序这样复杂的问题。有的同学可能对此感触不深,这就好比,本来你想表达“去给我端杯水过来”:

http://picx.zhimg.com/v2-369de9a4dc02c8a8c611c531094037f5_r.jpg?source=1940ef5c
如果你用汇编这种低级语言就得这样实现:

http://picx.zhimg.com/v2-ff96abb43db63fc71cfbeac8eb78a495_r.jpg?source=1940ef5c
我想你已经 Get 到了。

弥补差异

CPU 实在太简单了,简单到不能了理解任何稍微抽象一点诸如“给我端杯水”这样的东西,但人类天生习惯抽象化的表达,人类和机器的差距有办法来弥补吗?换句话说就是有没有一种办法可以自动把人类抽象的表达转为 CPU 可以理解的具体实现,这显然可以极大增强程序员的生产力,现在,这个问题需要你来解决。

http://pica.zhimg.com/v2-a59ecc9b5438141368226e2aba8ab01a_r.jpg?source=1940ef5c
套路,都是套路

思来想去你都不知道该怎么把人类的抽象自动转为 CPU 能理解的具体实现,就在要放弃的时候你又看了一眼 CPU 可以理解的一堆细节:

http://pic1.zhimg.com/v2-e58ef6353d84e82c122a8a1a4e507ffa_r.jpg?source=1940ef5c
电光火石之间灵光乍现,你发现了满满的套路,或者说模式。大部分情况下 CPU 执行的指令平铺直叙的,就像这样:

http://pic1.zhimg.com/v2-89198737ef963928a5cf2e4f6f88b2c0_r.jpg?source=1940ef5c
这些都是告诉 CPU 完成某个特定动作,你给这些平铺直叙的指令起了个名字,姑且就叫陈述句吧,statement。
除此之外,你还发现了这样的套路,那就是需要根据某种特定状态决定走哪段指令,这个套路在人看来就是“如果。。。就。。。否则。。就。。。”:
if ***
   blablabla
else ***
   blablabla在某些情况下还需要不断重复一些指令,这个套路看起来就是原地打转:
while ***
   blablabla最后就是这里有很多看起来差不多的指令,就像这里:

http://picx.zhimg.com/v2-7e8490ab8ae3397d57649be7b609f04c_r.jpg?source=1940ef5c
这些指令是重复的,只是个别细节有所差异,把这些差异提取出来,剩下的指令打包到一起,用一个代号来指定这些指令就好了,这要有个名字,就叫函数吧:
func abc:
   blablabla现在你发现了所有套路:
// 条件转移
if ***
      blablabla
   else ***
      blablabla
// 循环
while ***
      blablabla
// 函数
func abc:
      blablabla这些相比汇编语言已经有了质的飞跃,因为这已经和人类的语言非常接近了。接下来你发现自己面临两个问题:

[*]这里的blablabla该是什么呢?
[*]该怎样把上面的人类可以认识的字符串转换为 CPU 可以认识的机器指令

盗梦空间

你想起来了,上文说过大部分代码都是平铺直叙的陈述句,statement,这里的blablabla 仅仅就是一堆陈述句吗?显然不是,blablabla 可以是陈述句,当然也可以是条件转移if else,也可以是循环while,也可以是调用函数,这样才合理。虽然这样合理,很快你就发现了另一个严重的问题:blabalbla中可以包含 if else 等语句,而if else等语句中又可以包含blablabla,blablabla中反过来又双可能会包含if else等语句,if else等语句又双叒有可能会包含blablabla,blablabla又双叒叕可能会包含if else等语句。。。

http://picx.zhimg.com/v2-7e89acc83a07255f57552d81642e87a1_r.jpg?source=1940ef5c
就像盗梦空间一样,一层梦中还有一层梦,梦中之梦,梦中之梦中之梦。。。一层嵌套一层,子子孙孙无穷匮也。。。

http://pica.zhimg.com/v2-9572ff61bad922d836ece9274e539028_r.jpg?source=1940ef5c
此时你已经明显感觉脑细胞不够用了,这也太复杂了吧,绝望开始吞噬你,上帝以及老天爷啊,谁来救救我!
此时你的高中老师过来拍了拍你的肩膀,递给了你一本高中数学课本,你恼羞成怒,给我这破玩意干什么,我现在想的问题这么高深,岂是一本破高中数学能解决的了的,抓过来一把扔在了地上。此时一阵妖风吹过,教材停留在了这样一页,上面有这样一个数列表达:
f(x) = f(x-1) + f(x-2)这个递归公式在表达什么呢?f(x)的值依赖f(x-1),f(x-1)的值又依赖f(x-2),f(x-2)的值又依赖。。。

http://pic1.zhimg.com/v2-b1194769a2df25fb7232aa6031a60349_r.jpg?source=1940ef5c
一层嵌套一层,梦中之梦,if中嵌套 statement,statement 又可以嵌套if。。。
等一下,这不就是递归嘛,上面看似无穷无尽的嵌套也可以用递归表达啊!你的数学老师仰天大笑,too young too simple,留下羞愧的你佛手而去,看似高科技的东西竟然用高中数学就解决了,一时震惊的目瞪狗带不知所措无地自容。有了递归这个概念加持,聪明的智商又开始占领高地了。
递归:代码的本质

不就是嵌套嘛,一层套一层嘛,递归天生就是来表达这玩意的 (提示:这里的表达并不完备,真实的编程语言不会这么简单,这里仅仅用作示例):
if : if bool statement else statements
for: while bool statements
statement: if | for | statement上面一层嵌套一层的盗梦空间原来可以这么简洁的几句表达出来啊,你给这几句表达起了高端的名字,语法。数学,就是可以让一切都变得这么优雅。世界上所有的代码,不管有多么复杂最终都可以归结到语法上,原因也很简单,所有的代码都是按照语法的形式写出来的嘛。至此,你发明了真正的人类可以认识的编程语言。之前提到的第一个问题解决了,但仅仅有语言还是不够的。
让计算机理解递归

现在还差一个问题,怎样才能把这语言最终转化为 CPU 可以认识的机器指令呢?人类可以按照语法写出代码,这些代码其实就是一串字符,怎么让计算机也能认识用递归语法表达的一串字符呢?这是一项事关人类命运的事情,你不禁感到责任重大,但这最后一步又看似困难重重,你不禁仰天长叹,计算机可太难了。此时你的初中老师过来拍了拍你的肩膀,递给了你一本初中植物学课本,你恼羞成怒,给我这破玩意干什么,我现在想的问题这么高深,岂是一本破初中教科书能解决的了的,抓过来一把扔在了地上。此时又一阵妖风挂过,书被翻到了介绍树的一章,你望着这一页不禁发起呆来:

http://pica.zhimg.com/50/v2-0d54a5bef637b3a88c0cb09930611288_720w.jpg?source=1940ef5c
树干下面是树枝,树枝下是树叶,树枝下也可以是树枝,树枝下还可以是树枝、吃葡萄不吐葡萄皮,不吃葡萄倒吐葡萄皮,哎?这句不对,回到上面这句,树干生树枝,树枝还可以生树枝,一层套一层、梦中之梦、子子孙孙无穷匮、高中数学老师,等一下,这也是递归啊!!!我们可以把根据递归语法写出来的的代码用树来表示啊!

http://pica.zhimg.com/v2-47e1c6361bd3dde7f31f4a8f9156689f_r.jpg?source=1940ef5c
你的初中老师仰天大笑,图样图森破,看似高科技的东西竟然靠初中知识就解决了。
优秀的翻译官

计算机处理编程语言时可以按照递归定义把代码用树的形式组织起来,由于这棵树是按照语法生成的,姑且就叫语法树吧。现在代码被表示成了树的形式,你仔细观察后发现,其实叶子节点的表达是非常简单的,可以很简单的翻译成对应的机器指令,只要叶子节点翻译成了机器指令,你就可以把此结果应用到叶子节点的父节点,父节点又可以把翻译结果引用到父节点的父节点,一层层向上传递,最终整颗树都可以翻译成具体的机器指令。

http://pica.zhimg.com/v2-dbd25eea2b3d3267e6397c0c3809b9c6_r.jpg?source=1940ef5c
完成这个工作的程序也要有个名字,根据“弄不懂原则”(该原则的解释见下文 :)
看完这篇还不懂高并发中的线程与线程池你来打我(内含20张图),你给这个类似翻译的程序起了个不怎么响亮的名字,编译器,compiler。
现在你还觉得二叉树之类的数据结构没啥用吗?对了,说到二叉树,在这样也推荐一份牛逼的算法刷题资料,想进BAT、TMD、快手这样的一线大厂算法绝不可忽视,认认真真过上一遍这份资料,这些大厂算法面试一关大部分题目都不在话下:
Github疯传!阿里P8大佬写的Leetcode刷题笔记,秒杀80%的算法题!至此,你完成了一项了不起的发明创造,程序员可以用人类认识的东西来写代码,你编写的一个叫做编译器的程序负责将其翻译成 CPU 可以认识的机器指令。后人根据你的思想构建出了C/C++、以及后续的Java、Python,这些语言现在还有一帮人在用呢。
总结

本文我们从最基本的晶体管一路讲解到CPU的工作原理,再从最低级的二进制机器指令到高级语言,相信如果你能读到这里定能有所收获。
最后,有同学问有没有书单,我也仔细回想自己认真读过的计算机数据,在这里也给出自认为很经典的几本,书单这东西贵精不贵多,我在这里精心挑选了10本 ,不要贪心,如果你真能把这里推荐的 10 本书读通,可以说你已经能超越 90% 的程序员了。
程序员必看经典书单最后的最后,有很多知乎朋友问有没有pdf版本,我也整理出来了,绘图非常精美,这里还汇总了部分知乎问题,总计14万字,我为其专门设计了封面,并将其命名为《计算机底层的秘密》,现在免费分享给大家。

http://pica.zhimg.com/v2-d4bd1b37bb52f033213cc7260a64f58b_r.jpg?source=1940ef5c

http://picx.zhimg.com/v2-8c23b3670d5815439806d79c65a18ad9_r.jpg?source=1940ef5c
可以使用这个下载链接:点击下载《计算机底层的秘密》 PDF
如果你觉得本文有所帮助,给点个赞呗! @码农的荒岛求生
作者:码农的荒岛求生
Github: https://github.com/xfenglu/everycodershouldknow
原文:你管这破玩意叫CPU?
你管这破玩意叫编程语言?
推荐:
码农的荒岛求生:CPU 空闲时在干嘛?

agou 发表于 2023-9-15 07:15:14

“陛下,请给我三个士兵,我将为您演示。”冯•诺伊曼兴奋起来。

“三个?只要三个吗,朕可以轻易给你三千个。”秦始皇用不信任的目光扫视着着冯•诺伊曼。

伟大的陛下,您刚提到东方人在科学思维上的缺陷,就是因为你们没有意识到,复杂的宇宙万物其实是由最简单的单元构成的。我只要三个,陛下。”

秦始皇挥手召来了三名士兵,他们都很年轻,与秦国的其他士兵一样,一举一动像听从命令的机器。

“我不知道你们的名字,”冯•诺伊曼拍拍前两个士兵的肩,“你们两个负责信号输入,就叫‘入1’、‘入2’吧,”

他又指指最后一名士兵,“你,负责信号输出,就叫 ‘出’吧,”

他伸手拨动三名士兵,“这样,站成一个三角形,出是顶端,入l和入2是底边,”

“哼,你让他们成楔形攻击队形不就行了?”秦始皇轻蔑地看着冯•诺伊曼。

牛顿不知从什么地方掏出六面小旗,三白三黑,冯•诺伊曼接过来分给三名士兵,每人一白一黑,说:“白色代表0,黑色代表1。好,现在听我说,出,你转身着着入1和入2,如果他们都举黑旗,你就举黑旗,其他的情况你都举白旗,这种情况有三种:入1白,入2黑;入1黑,入2白;入1、入2都是白。”

“我觉得你应该换个颜色,白旗代表投降。”秦始皇说。

兴奋中的冯•诺伊曼没有理睬皇帝,对三名士兵大声命令:“现在开始运行!入1入2,你们每人随意举旗,好,举!好,再举!举!”
入1和入2同时举了三次旗,第一次是黑黑,第二次是白黑,第三次是黑白。出都进行了正确反应,分别举起了一次黑和两次白。

“很好,运行正确,陛下,您的士兵很聪明!”

“这事儿傻瓜都会,你能告诉朕,他们在干什么吗?”秦始皇一脸困惑地问。

“这三个人组 成了一个计算系统的部件,是门部件的一种,叫‘与门'。”冯•诺伊曼说完停了一会儿,好让皇帝理解。

秦始皇面无表情地说:“朕是够郁闷的,好,继续。”

冯•诺伊曼转向排成三角阵的三名士兵:“我们构建下一个部件。你,出,只要看到入1和入2中有一个人举黑旗,你就举黑旗,这种情况有三种组合黑黑、白黑、黑白,剩下的一种情况一一白白,你就举白旗。明白了吗?好孩子,你最聪明,门部件的正确运行你是关键,好好干,皇帝会奖赏你的!下面开始运行:举!好,再举!再举!好极了,运行正常,陛下,这个门部件叫或门。”

然后,冯•诺伊曼又用三名士兵构建了与非门、或非门、异或门、同或门和三态门,最后只用两名士兵构建了最简单的非门,出总是举与入颜色相反的旗。冯•诺伊曼对皇帝鞠躬说:“现在、陛下,所有的门部件都已演示完毕,这很简单不是吗?任何三名士兵经过一小时的训练就可以掌握。”

“他们不需要学更多的东西了吗?”秦始皇问。

“不需要,我们组建一千万个这样的门部件,再将这些部件组合成一个系统,这个系统就能进行我们所需要的运算,解出那些预测太阳运行的微分方程。这个系统,我们把它叫做……嗯,叫做……”
“计算机。”汪淼说。

“啊一一好!”
冯,诺伊曼对汪淼竖起一根指头,“计算机,这个名字好,整个系统实际上就是一部庞大的机器,是有史以来最复杂的机器!
摘自:三体,作者刘慈欣

918外链网 发表于 2023-9-15 07:15:44

上二年级的小明正坐在教室里。现在是数学课,下午第一节,窗外的蝉鸣、缓缓旋转的吊扇让同学们昏昏欲睡。此时,刘老师在黑板上写下一个问题:
https://www.zhihu.com/equation?tex=6324+%2B+244675+%3D+%EF%BC%9F
小明抬头看了一眼,觉得这两个数字挺眼熟。他昨天翘课去网吧了,因此错过了刘老师讲的竖式计算加法。
“同学们算一算这道题。”刘老师和蔼可亲地说道。
小明盯着黑板懵逼。
小学二年级的他面对这样一道世界级难题,束手无策。小明伸出了自己的左手,打算用一个古老而深邃的方法--掰手指--尝试一下。
小明发现他的每只手只能输入0-5中的正整数,和的范围仅限于0-10,离6324还十分遥远。
“慢着!”小明看向了自己的左手。他发现,事情有一点不对劲。
我们也来看看小明的左手。这只左手有5根手指,我们把5根手指都伸开来记为11111,5根手指握拳记为00000,手背面向我们,左手小指是第一个1/0。
小明紧紧地握拳,然后伸出大拇指,此时的左手为00001。
“如果,”小明想,“这样是1”。他缩回拇指,伸出食指,此时的左手为00010;“这样是2”。他又伸出拇指,此时的左手为00011;“那么这样是3”。他缩回拇指和食指,伸出中指,此时的左手为对着自己竖中指00100;“这样就是4!”.....小明的左手飞速运动着,直到五根手指都伸直,像是钢铁侠射了一发掌心炮11111;“这样就是31!一只手可以表示0-31中的任意正整数!”小明为自己的发现感到激动。
可他不知道怎么表示加法。小明的同桌,英语课代表小红,看他摆弄了半天左手,忍不住问他在干什么。小明解释了他的发现。小红听了小明的一番高论,若有所思,提笔在数学书的封底画了一个表格:

http://picx.zhimg.com/v2-c997e5b8c786f1dd57f340adfd73502f_r.jpg?source=1940ef5c

小红画的表格

“如果我们能造一个机器,给它三个输入,它能返回两个结果,那我们就能算出这道题!”小红激动地说。“啥叫进位啊美女?”小明问道。“就是你列竖式的时候画的一小撇”,小红回答。“猎术士是什么,我知道猎魔人和古尔丹。”小红于是讲解了一下怎么列竖式计算十进制加法。
“我懂了。”小明说着,拿过小红的数学书,补全了表格:

http://picx.zhimg.com/v2-ab48e735a8bd4e79bd20094fba38b49d_r.jpg?source=1940ef5c

小明试着补全表格

“是这样吗?”小明问小红。小红拿过来看了看,说:“最后一行写错了,输出结果应该是1。你想啊,1+1+1应该等于11,左边这一位是输出进位,右边这一位是输出结果,都是1,所以输出结果应该是1。”
“噢。”小明又拿过书来,拿起橡皮铅笔改正:

http://pic1.zhimg.com/v2-5637db4d24fb38ed6e88d9404bbfab14_r.jpg?source=1940ef5c

小明改好了

“那为什么这个机器能算加法?我还是不懂。”小明问。
“假设我们已经造出来了这么个机器,长这样”小红继续在封底上画着:

http://picx.zhimg.com/50/v2-8ac43fa600293b3c0f542ce7a03eb21e_720w.jpg?source=1940ef5c

小红画的机器

“等会等会,怎么变成英文了,我英语不好。”小明叫道。“hmmm看来你没读双语幼儿园。左边这三个是输入,右边是输出,C是进位,C-in是输入进位,C-out是输出进位,Sum是和的意思,明白了么?”小红解释道。
“噢好。”
“假设我们已经造出来了这么个机器,造了好几个,我们这么连起来...诶纸不够大,我写不下了。”小明一听,赶紧从书桌膛里翻出来一本草稿纸,生怕同桌变成费马。
“谢谢。先这么连起来:”

http://picx.zhimg.com/v2-eefb79c87d5a2b45585fb6cbb476ab1c_r.jpg?source=1940ef5c

小红画图中

“哦哦哦我懂了,A和B就是两只手,最右边这个one-bit-adder算得是最小位数的和!”小明说道。
“正确!”
“你这样连的话,是说最小位的输出进位就是下一位的输入进位,下一位的输出又是下下一位的输入!天啊,这跟列竖式好像。”小明惊叫。
“Absolutely!”小红回答道。
小明又拿过草稿纸,接着画起来:

http://picx.zhimg.com/v2-6f6916719595c2fb9d7dfc7472a66a8d_r.jpg?source=1940ef5c

小明画图中

“把对应的每一位连到每一个adder里...”小明念念有词,“...再汇总一下输出”:

http://pica.zhimg.com/v2-fb7e6de0ae437c626fac6bc19b0e65f9_r.jpg?source=1940ef5c

小明画的加法器

“成了!这个东西可以算两只手加法的结果!”小明高兴极了。“可是离6324和244675还是太远了,输入5位远远不够呀。”小红皱了皱眉头。
“不不不!你在掰手指的时候有没有发现,每多一根指头,能表示的数就会多出来一大堆,我觉得只要加那么十几个就够了!1根指头能表示2个数(0,1),2根指头四个数(0,1,2,3),3根8个...”“是2的倍数!”小红接道,“小明,我觉得你的这个记数方法很有意思,要不叫小明式吧!”小红凝望小明的目光中有了一丝羞涩。
“二进制。”身后忽然传来低沉的声音。两人同时回头,发现数学课代表小刚正直勾勾地盯着那张草稿纸。他好像已聆听多时了。
“叫二进制吧,我看蓝猫淘气三千问讲过这个,一模一样,蓝猫说这是二进制。”小刚补充道。小刚的数学成绩是班里最好的,一进学而思就上的超常班。小红只能上尖子班,小明一般去网吧。
“那就叫二进制吧。”小明说。他和小红转过身来,老师让小组讨论的时候他们就这么坐。
小刚又道:“可是,怎么造出这个one-bit-adder呢?”他的眉头皱成一团,眼镜片看起来更厚了。小明和小红也陷入了沉默,三人一筹莫展,陷入僵局。
这时,小刚的同桌,物理课代表小兰入局。她忽然说道:“我听物理办公室的陈老师吹牛,他当年在大学里读电子工程,GPA一直是4.3,用实验室的导线开关和小灯泡就能造一个32位的加法器,不知道是怎么做到的。他还说什么与门是and或门是or,再加一个非门not,用它们表示逻辑,就能造出世间千千万万的计算机。”
小明听迷糊了,“等会等会,什么门?金拱门?”另两人也露出迷茫的表情。
小兰从桌子里掏出一个黑盒子。“这是下节课要用的教具,陈老师让我先拿着。”她打开盒子,取出三个零件和一个说明书。
“喏,你们看看这个”,她拿起第一个零件,“这个叫与门,有两个输入和一个输出。如果我们把输出连上小灯泡,接上电源,两个输入分别连上开关,那么是这么个情况:”

http://pic1.zhimg.com/v2-c70a0dd3d1758d19b446cdf64383c4c4_r.jpg?source=1940ef5c

小兰画的表格

“就是说,只有两个开关都闭合了,小灯泡才亮,有点像串联电路。”小兰补充道。
“诶,有意思了...”小刚扶了扶眼镜,似乎打算说什么,大家都看向他。
“没,没什么,我还在想,小兰你接着说。”
“那好。”小兰接着拿起第二块零件。“这个叫或门,有一个开关开着灯泡就会亮...”“等下!”小刚忽然打断,拿起笔在自己的白纸上画起来:

http://picx.zhimg.com/v2-5f00f7158a85626bdb59caafbc3d0bf8_r.jpg?source=1940ef5c

小刚画的表格

“是不是这样!”小刚激动地说,“如果0是关1是开,0是灭1是亮的话,或门的输入输出是不是这样?”小兰看了看道:“正是”。
她拿起第三个零件,“最后这个叫非门,只有一个输入,一个输出。它会输出一个相反的结果:输入有电流,输出就没有;输入没有电流,输出就有电流。用小刚的话来说,输入0输出则为1,输入1输出则为0。太简单了,懒得画表了。”小兰把非门放在桌上。
小刚说道:“这三个门可以表示三种逻辑。如果A、B是输入, https://www.zhihu.com/equation?tex=A%5Cvee+B 就是经过或门的结果, https://www.zhihu.com/equation?tex=A%5Cwedge+B 就是经过与门的结果, https://www.zhihu.com/equation?tex=%5Cneg+A 则是A经过非门的结果。”三人纷纷点头。
“可是,这和加法有什么关系呢?”小明问道。四人再度陷入沉默。
沉默。
忽然,小明拿起笔,一边画一边说道:“如果我们回去看小红画的表格,”

http://picx.zhimg.com/v2-d39db1ff3791bbfced5c7f73df4f849a_r.jpg?source=1940ef5c

左三列是输入,右二列是输出

“Sum可以写成A、B、Cin的逻辑关系!”

============2019/6/18书接上回===================

https://www.zhihu.com/equation?tex=Sum+%3D+%5Cbar%7BA%7D+B++%5Cbar%7BC%7D+%2B+A%5Cbar%7BB%7D+%5Cbar%7BC%7D+%2B+%5Cbar%7BA%7D+%5Cbar%7BB%7D+C+%2B+ABC
“你们看,把 A and B 记作 AB,A or B 记作 A + B,not A 记作 A bar。Sum 输出为1只出现在表格的2、3、5、8行,也就是三个输入中1的个数为奇数的时候。我们把这4种情况记下来,那么这个式子...”
“可以拿逻辑门实现!!!”四人异口同声的叫道。
小红抢过草稿纸,又看了看物理教具的说明书,边画边说了起来:“说明书上写,这个火车头形状的符号表示 and gate;这个B2轰炸机形状的是or gate;这个小人形状的是not gate...”

http://picx.zhimg.com/v2-9c6f955172baf7ca563c872b7b2159ea_r.jpg?source=1940ef5c

小红画的与门,或门,非门

她又看了一眼小明的式子,说道:“这个式子的第一项可以这样...”

http://pic1.zhimg.com/50/v2-ea38a720462a6ee674540cc540718718_720w.jpg?source=1940ef5c

小红画的输出和的第一项

"你们看你们看,这不就是 https://www.zhihu.com/equation?tex=%5Cbar%7BA%7D+B++%5Cbar%7BC%7D 嘛!"小红自豪地说。
小明补全了电路:
https://www.zhihu.com/equation?tex=Sum+%3D+%5Cbar%7BA%7D+B++%5Cbar%7BC%7D+%2B+A%5Cbar%7BB%7D+%5Cbar%7BC%7D+%2B+%5Cbar%7BA%7D+%5Cbar%7BB%7D+C+%2B+ABC

http://pica.zhimg.com/v2-fa38582869101068980d89b9d1c8f0f4_r.jpg?source=1940ef5c
“先把与门都画了”

http://pic1.zhimg.com/v2-55b9d772fe15d371cbd41358c576e1ab_r.jpg?source=1940ef5c
“再把或门都加上,搞定。这东西可以算出Sum了,接下来用一样的办法把C-out弄出来。”小明准备继续画。
“你们看,这里还有几个零件。”小兰指着说明书说道:

http://picx.zhimg.com/v2-fe432a72ded4834b19e0946d0ab85810_r.jpg?source=1940ef5c

与非,或非,异或,同或

“与非门:一个与门的输出和一个非门相连,英文是not and,NAND gate。那个小圈圈代表一个非门。或非门是或门 + 非门,not or,NOR gate。第三个叫异或门,只有两个输入中一个为1一个不为1时,才会输出1,exclusive-or,XOR gate。第四个是同或门,也就是一个异或门加上一个非门。”
“啊哈!”小刚灵机一动,抓起笔来道:“我有一个绝妙的点子。”

http://pic1.zhimg.com/v2-64b6b52fa8bfb339802b35b3b2477850_r.jpg?source=1940ef5c

小刚简化后的电路

“小明的方案,要用17个门。我只要2个异或门就搞定了,牛逼吧?”三人瞪大了眼睛,仔细思考后纷纷点头道:“牛逼,牛逼。”
小刚随即画出了完整的one-bit-adder电路:

http://pic1.zhimg.com/v2-f313968b2608bc5bbc35d2ffa22c2307_r.jpg?source=1940ef5c

小刚的one-bit-adder

小明从从教具盒里拿出电源、小灯泡、开关和逻辑门,按照设计图制作出了全加器:
http://pic3.zhimg.com/v2-8e9eea6e0fa540a21b0e0b73f58041c6.jpg
加法器造出来啦!
https://www.zhihu.com/video/1124302170232877056

看到小刚的设计被完整的实现,小明欣喜:“啊哈哈哈,吾有上将小刚,则霸业可成,汉室可兴啊!”他把黑盒子里的零件全拿了出来,四人忙碌地工作着。很快,他们拥有了5个全加器,基于小红的设计连了起来:

http://pic1.zhimg.com/v2-b799b0b2ecda95693adabe4a7f7bdd80_r.jpg?source=1940ef5c

小红设计实现

“二进制的01100等于十进制的12,01010等于10,12+10=22,等于16+4+2,也就是二进制的10110...”四人人往代表输出结果的5个小灯泡望去:
亮,灭,亮,亮,灭;正是10110!
“成了!!!”
大家激动的拍打课桌
为了计算黑板上那道题,四人一共制作了32个一位全加器,将它们连接后,一个三十二位加法器便诞生了。他们历经艰辛,踩着自然规律和人类智慧的肩膀,把自己从枯燥的加法计算中解放出来!
窗外的蝉鸣渐渐平息,头顶的吊扇不再转动。
“刘老师,答案是250999!”小明站了起来,声若洪钟大吕,震慑天地。
他和小红、小刚、小兰分别对视了一眼,收获了坚定的目光--这目光,连同面前的32位加法器,如同新的转机和闪闪星斗,正在缀满没有遮拦的天空。
刘老师点了点头,欣慰的说道:“很好,看来四位同学对这部分知识掌握的不错!我们再来看几道题!”
他转过身,拿起板擦,把黑板擦了个精光,又从黑板槽里拾起半截粉笔,写了起来:

[*] 244675 - 6324 = ?
[*] 3.14159 + 5.535897 = ?
[*] 17 * 45 = ?
[*]3 / 2 = ?
一连四道题,让四人组陷入了深思:如何让自己的机器运算减法?乘法?除法?浮点数?
刘老师并没有停下,手中的粉笔运动得越来越快:
5.   Fibonacci 数列的第103项?
6.一圈共有N个人,开始报数,报到M的人出列,然后重新开始报数,问最后出列的人是谁?
......
疑惑越来越多了:如何存储?怎样实现分支?保证效率?
刘老师仍未停下,黑板快被写满了:
103.方程ζ(s)=0的所有有意义的解都在一条直线上吗?
104.大于2的偶数都可以写成两个质数的和吗?
......
134.生命,宇宙及所有事物的答案?
刘老师放下了粉笔,半截粉笔已经变成硬币的厚度。
“这些问题,我们能造个机器回答么?”小明撑着头,喃喃自语。
(完)
PS: 下学期大三了555,求一份2020 Summer 北美或国内的CS实习,有机会的看官可以考虑考虑在下,私信/评论区说一声就行。千恩万谢!
===2019/7/11 答疑===

[*]画图是啥软件?
    Logism,免费的,用之前要装 java.
2. 还有续集吗?
    没了,不好意思。本来想让他们造一个ALU的,结果全加器就写了三天,算了算了。
   不过话说回来,从全加器到算术逻辑单元 (ALU) 基本没什么复杂的,需要理解一下补码、反码,因为减法和位移要用。
   理解了运算原理再去看存储,看看啥叫Latch,啥叫D-flip-flop,以及寄存器是什么意思等等。
   接下来你就可以接触到硬核的内容了,比如内存读写和寄存器读写有什么不一样,比如流水线怎么搞,指令集怎么控制,为什么会有pipeline hazard。找本mips或者riscv的书看看,我们老师用的书是riscv的,Computer Organization and Design RISC-V Edition: The Hardware Software Interface, 写得好啊,而且淘宝电子版只要十几块。
   这些都搞懂的话,你差不多从门外汉级别升级成了坐在门槛上抽烟的老大爷级别。接下来学什么就别问我了,毕竟我也坐在门槛上。
3. 输入x输入y是啥?表格是不是画错了??你这写的啥我咋看不懂???
    x, y 跟小明小刚甲乙丙丁一样没什么意义,只是代号。表格没错。
   答主改不动了,看不懂没事儿,凑合着看呗,还能离了咋地
页: [1]
查看完整版本: CPU 的工作原理是什么?