【伯乐在线导读】:网友 r00nk 写的一篇文章(分 8 节),还专门建了一个网站。他为什么会写这个?因为他之前在 Reddit 上看到一个帖子,有人问“计算机实际上是如何工作的?比如,它如何传送、阅读、展示数据”。他之前的回答是最佳回复,后来继续补充丰富内容了,便有了下文。
二进制
让我们马上进入数据的梦幻王国。
五的符号是什么?5
十的符号是什么?10
等等,这不是符号“1和0”吗?
是的,在我们的编码系统中,当我们要表示”十”的时候,我们会写1和0。这里没有单独表示十的符号,我们简单地循环利用已有的一些符号(0~9)。所以我们把这样的编码系统叫做“base-ten”或者“decimal”(十进制)。
“1和0”,“真和假”,“开或关”这些东西你可能已经听过,它们指的都是一个不同的编码系统。在我们的十进制系统中,我们写“10”来表示十,但是在binary(二进制)中,我们写“10”来表示二。在二进制中没有单独表示二的符号,正像十进制中没有单独表示十的符号一样。“开”或“关”在二进制中就是指“1”或“0”。
为保证你已经理解了二进制,试着点击下面的二进制计数器:
(原图可交互,在原文可查看。)
与非
现在来讲些完全不同,但是相关的东西。
在计算机理论中有个叫“逻辑门”的东西,它是个有两个输入和一个输出的器件,只接收“开”或“关”这样的输入,输出也是,“开”或“关”。你可能已经看出它和二进制的关系。
一个逻辑门的输出是基于它的输入的。一个逻辑门的实例是NAND gate(与非门),试着点击左边的开关:
(原图可交互,在原文可查看。)
当与非门的两个输入都是“开”的时候,输出是“关”;其他情况输出都是“开”。
还有一些更多种类的逻辑门,不过我们现在只需要关心与非门。如果你想看看与非门在现实中什么样子,点这里。
内存
想知道计算机怎么存储数据吗?
下面这个器件叫“D型锁存器”(D-Lauch),它存储1个二进制位。
(原图可交互,在原文可查看。)
上面的开关是要存储的值(0 或 1),底下的开关控制这个器件是否存储。
八个这样的器件就可以用来在存储器中存储一个字节了。
更多逻辑门
在我们可以继续之前,我需要给你看看更多的逻辑门。
(原图可交互,在原文可查看。)
加法器
但是我们可以拿这些存储的数字做什么呢?
我们可以给它们做数学运算。
下面的器件叫做加法器(adder),它可以把两个位加起来。
(原图可交互,在原文可查看。)
在十进制中,如果要计算5+5,你就要追加一个1来生成10。当我们在二进制中计算1+1时,相同的事情就发生了,我们需要追加(输出)一个二进制1。
如果我们有多个位需要相加,我们可以把一个加法器的追加输入与另一个加法器的追加输入相连,这样来组合起这些器件。
编码
酷~我们现在有一个基本的计算器了。我们怎么样才能最大程度的发挥它并组成一台计算机呢?
编码。
现在你知道了数据是什么。编码也很好解释,它就是数据。至于为什么它和其他的数据不同,当然是因为CPU把它解释为指令。
比如我们想让这个计算机做数学运算,我们可以使用像下面的系统:
指令 | 编码 | |
“一个数加上另一个数” | 00000001 | |
“一个数减去另一个数” | 00000010 |
有了它,我们可以根据数据的形式安排逻辑门来怎么使用。
现在,真的很快,内存在计算机中由内存地址组织起来,这样就允许CPU在确切的位置来请求内存。一般来说地址大小以字节为单位,即8位。所以如果我们想要存取第5个内存位置或诸如此类,我们需要把它存为“00000101”。
回过头来加入更多的指令到我们的表中:
“移动这个数据到其他位置” | 00000011 |
酷。现在我们可以实现这样的东西:
“将第5个内存中的数和第7个内存中的数加起来”
把它分解:
(add) (memory address #5) (memory address #7)
实际上就是:
00000001 00000101 00000111
很可爱是吧?
指令指针
但是CPU怎么知道去哪里取指令呢?
在CPU中,有一小块存储。它可以做各种各样的事,比如可以保存某个叫“指令指针寄存器”的东西。指令指针寄存器保存下一个指令的地址,并且可以在每一个指令结束后自增。所以,CPU读取指令指针寄存器,取出下一个地址,执行它,指令指针寄存器自增,然后回到第一步。
指令指针寄存器的值可以存到一个专门的存储单元中。你有没有想过计算机中的一个无限循环是怎样的?就是当一个指令指针寄存器指向的指令让这个指令指针寄存器再次指向同一个指令的时候。
CPU
这是一个相对简单的可以给你玩玩的CPU:
(原图可交互,在原文可查看。)
如果要修改内存,在CPU开关关着的时候点击相应位即可。你也可以滚动查看内存。如果要让CPU开始执行指令的话,就打开开关。
这个CPU有3个不同的指令
指令 | 编码 | |
指令指针寄存器指向地址的下一位地址的数加上下下一位地址的数 | 00000001 | |
指令指针寄存器指向地址的下下一位地址的数减去下一位地址的数 | 00000010 | |
指令指针寄存器指向地址的下一位地址的数移动到其下下一位地址 | 00000011 |
所有的指令都有3个字节(包括操作数)。这意味着在每一个指令结束后指令指针寄存器将增加3。
这个指令指针寄存器可以通过存储地址00000000访问。