本章从一个宽泛的高级视角对计算机如何工作,以及完成这些工作用到哪些计算机部件的问题进行了阐述。
1617年约翰·纳皮尔发明的计算尺的先驱——皮拉尔的骨头。 通常认为可编程计算的观点是有查尔斯·巴贝奇提出的。1837年时,巴贝奇非常贫穷,以至于他的“分析机”显得过于复杂,无法建造。但是1888年,他的儿子建造并试验了一台更加廉价的机器。 1936年,阿兰·图灵,创建了完全可编程计算机的基础理论。
图灵机
1941年,康纳德·楚泽搭建了一台被称作Z3的可编程电动机械式计算机。它能够接受二进制编码和浮点数。楚泽的机器后来被证明是图灵完全的,也就是说符合通用计算的图灵准则。 楚泽搭建的Z3目的是为德国空军机翼的设计进行统计分析。二战在很多方面促进了电子计算机的发展。首先是受火炮弹道计算的驱动,随后是原子弹研发过程中处理复杂数学问题的需要。 并不是所有的计算都可以像加法和乘法等基础数学运算那样一步完成。一些计算需要迭代操作,顺序执行直到满足某些限制条件。还有一些计算过于复杂,运算过程中计算器必须不断检查操作过程和结果,以此判断工作是否完成,或者是否必须重复某些任务或开始新的任务。这就是可编程的由来,从这里开始,计算器迈出了从算术运算(Calculation)到编程计算(Computing)的关键性一步。 就是如此简单:计算机不是计算器,计算机有章可循。
2.1 计算机
计算机程序也是按步骤顺序执行的,处理数据,完成所有步骤和暂停或停止。 计算机能够理解的简单、基本的步骤被称为机器指令。机器指令可以组合出更复杂的操作——子程序、函数或进程。
2.2 按计划执行的盒子
作家泰德·尼尔森的一个比喻更贴近实际。他将计算机描述成“按计划的盒子”。计算机就是一个盒子,盒子内部就是计划,计划按照数据执行,而机器则按计划和数据执行。
2.2.1 执行和知晓
程序是计算机要执行的东西,数据就是计算机知晓的东西(该描述是由计算机作家汤姆·斯旺提出的)。 用于执行的固件被称作中央处理单元(Central Processing Unit,CPU),用于知晓的部件被称作存储器。 使用1679年由戈特弗里德·莱布尼斯发明的,用二进制数字符号编码的数字、符号和逻辑状态完成知晓的目的。 直到1937年克劳德·香农才使二进制数字在计算机数学和逻辑中的使用系统化。一个位就是一个二进制数字,一个表示1或0的最小不可分单位。随后我们将展开描述,计算机中通过电子状态的开关来描述位。
克劳德·香农
两个不同的存储单元,一个存储单元中保存着构成计算机程序的一系列机器指令,另一个存储单元保存程序要处理的数据,这种结构通常被称为哈佛结构,最早是由哈佛大学1944年研究出来的。
哈佛结构
2.2.2 程序就是数据
多元化天才约翰·冯·诺依曼从事过很多不同的领域,包括从数学到流体动力学,但是计算机行业的人记住他的是他的远见卓识。程序就是数据应该像数据一样保存在相同的存储系统中,使用和数据一样的存储地址空间。
冯·诺依曼结构
冯·诺依曼结构极大简化了编程计算,并引起20世纪50年代计算能力的大爆发。
2.2.3 存储器
系统存储器就是用于存储数据的一长排存储箱。存储箱中的每个单元都有一个唯一数字地址。所有单元的大小相同,在现代计算机中,通常是一个由八8个位构成的字节。存储器地址从0开始会更简单。 CPU使用存储器地址定位要读写的数据。他使用机器指令从系统存储器的指定地址取数据,将这些数据存放到寄存器中进行运算或测试。CPU使用其他机器指令将存储在寄存器中的数据写入系统存储器中。
2.2.3 寄存器
所有的CPU都拥有一定数量的被称作寄存器的存储单元。寄存器的读写速度非常快——比其他任何类型的存储器访问速度都快。通用寄存器有很多种,一些共同特性包括: 程序计数器:程序计数器,寄存器保存即将执行的需要从存储器中。取出来的下一条指令的地址。程序计数器在计算机程序中植了答了。 状态寄存器:状态寄存器有时称为标志寄存器。保存一个可分解为一个位或多个位的值。每一个位或一组位都随着CPU的执行状态而更新。当CPU比较两个寄存器的值时,某个相等标志的位将被置为1(如果相等)或0(如果不相等),这样紧随比较操作的指令就可以确定比较后的程序分支方向。 栈指针:栈指针保存了一个寄存器的地址。在该地址存放了一个被称作后入先出栈的数据结构。 累加器:累加器是一个寄存器,保存算术和逻辑操作的结果。之所以称为累加器,是因为在早期计算机中计算过程使用它累加中间结果。在现代计算机中,没有哪一个寄存器能够单独存放算术运算的结果,累加器的工作被分配给部分或全部通用寄存器。当然一些较老的机器指令假定单个寄存器足够存放操作结果,这也是累加器的称谓一直沿用至今的原因。
冯·诺依曼计算机组成
原始树莓派内部的ARM11处理器拥有16个可用于通用程序设计的寄存器,其中3个具有特殊功能。还有两个寄存器作为状态寄存器使用。 寄存器是弥足珍贵的,因为它们位于CPU内部,并且速度非常快,一款CPU拥有的寄存器数量越多,就可以越少地方问系统存储器来存储中间结果。
2.2.4 系统总线
关于计算的基础性挑战之一是在系统存储器和CPU之间尽可能快地传输数据。CPU和存储器之间有一条被称作系统总线的通道。系统总线是一组并排的由电子导体构成的导线,每一条导线携载一位信息。系统总线传输如下三类信息:
- 存储器地址
- 数据
- 允许CPU和系统存储器相互协调通过总线传输信息的控制信号
系统总线
CPU将存储单元的地址发送到总线上。同时,在控制线上放置一个或多个信号,告诉存储器电路该地址的作用(读或写)。随后,CPU将要写入指定存储单元中的信息发送到总线上,或者等待系统存储器将指定存储单元的,要返回给CPU的信息发送到总线上。计算机程序和程序数据存储在不同的存储单元中,但是除了计算机对他们的解析不同之外,数据字和机器指令之间没有本质的区别。
2.2.5 指令集
CPU可以执行的特有操作将它与其他CPU明显区分开来,这些特有操作就是机器指令。机器指令集中到一起就构成了指令集。 对某个系列的CPU而言,其指令集是独一无二的,绝大多数独立的CPU只拥有一套指令集。原始树莓派的ARM11处理器实际上拥有两套指令集。 指令集中的机器指令按功能分组:(从/向存储器中以及寄存器之间的)数据转移类指令;算术运算类指令;逻辑操作类指令;(读状态位或控制位的)位操作类指令等。早期的CPU大概只有十几条机器指令,现代CPU拥有上百条或更多机器指令。
CPU组成
程序员编写与人类语言更为类似的行为声明清单,这些行为声明清单转交给程序,并程序翻译成机器指令清单。翻译程序被称作编译器或解释程序(根据程序运行方式而定)。
2.3 电平、数字以及表示
在处理事件的CPU硅晶内部,计算机只处理电平信号。计算机芯片的操作实际上是一场电子活动风暴,在这场活动中电平在两个值——只有两个值——之间来回切换。一个没有任何电压(0V),另一个为高电平。不同计算机的高电平值不同,可能是5V、3V、3.6V、1.2V。通常以0V电平表示数字0,以3V电平表示数字1。 有必要了解计算机世界中的一个著名小约定。在计算机技术中,要从数字0开始计数。这种方式数存储单元实际上不是在统计他们,而是在给他们编号。给存储单元编号,既赋予他们名字又赋予他们次序。所有地址空间的第一个地址永远是0。 计算机当中通常使用二进制及十六进制。计算机并不真正使用十六进制数字。计算机使用编码为周期性电平信号的二进制数字,因为有1和0构成的长长的二进制数据串,阅读起来不方便,因此我们都使用十六进制,这是一种速记方法,以一种人们更容易接受的方式表达二进制数。
- 对于二进制,常常在数的后面加一个字母b或B。例如:011010B
- 对于二进制常常使用前缀0b。例如:0b011010。
- 有时也能见到在二进制数前添加前缀%,例如:1010。
- 对于十六进制数在数字后使用字母h或H。例如:F2E5H。
- 前缀
F2E5以及0xF2E5。
2.4 操作系统:幕后老板
操作系统就是程序,与所有程序一样,操作系统本质上是一系列机器指令,操作系统拥有特殊的权利,使其能够管理整个计算机系统。纵观计算机发展史,出现了数以千计的操作系统。但是,只有少数操作系统在市场上占有一席之地:Windows、GNU/Linux、Android、OS X以及iOS。
2.4.1 操作系统的功能
关于操作系统的高级定义可描述为:操作系统介于计算机用户和硬件之间,使用户在不干扰他人和计算机自身操作的前提下,使用计算机的各种资源。操作系统的主要工作考描述为:
- 进程管理:操作系统根据自身和用户需要,加载独立的用于执行的线程,为所有执行线程分配CPU执行时间。如果CPU是多核的,则在各内核上分配进程。
- 存储器管理:操作系统为运行的进程分配存储器空间,大多数情况下是独立于其它进程的存储器空间。
- 文件管理:操作系统维护着一个或多个文件系统,在磁盘和其他海量存储设备上,分配文件存储空间,管理文件的读写和删除。
- 外设管理:操作系统管理对诸如键盘、鼠标、打印机、扫描仪、图形协处理器以及海量存储设备的访问。
- 网络管理:通过一系列被称作网络协议的标准方法,操作系统管理计算机对外部网络的访问。
- 用户账户管理:所有现代操作系统都允许不同的用户在计算机上拥有自己的账户。
- 安全性:为保证进程运行时不受其他进程和操作系统的干扰,操作系统采取了若干机制。操作系统的绝大部分安全措施,通过定义一些规则来实现,这些规则明确了进程和用户可执行的操作。
- 用户界面管理:被称作操作系统外壳(shell)的软件机制,操作系统实现对计算机用户界面的管理。
2.4.2 内核
对于人们熟悉的微软windows,用户界面在整体上严格受到操作系统的限制,除了通过配置选项进行少量修改之外,无法进行大的改动。 Linux模块化设计的历史悠久。在某些特定的范围内,他的好多特性可能变了,但是其内部是一个被称作内核的整体代码模块。Linux内核拥有对计算机硬件的完全控制权,他通过具体的设备代码,以可以加载内核模块(Loadable Kernel Modules,LKM)的形式扩展内核,以此来适应硬件的差异性。
第三章将详细介绍ARM CPU和基于ARM的单芯片系统是如何构建的。