Skip to content

Latest commit

 

History

History
129 lines (61 loc) · 10.3 KB

File metadata and controls

129 lines (61 loc) · 10.3 KB

计算机程序有几种编码方式。例如,有些程序使用抽象指令集(abstract instruction sets )进行编码,并由模拟器或虚拟机执行。模拟器或虚拟机也是一个程序,它们是用来解释和执行抽象指令集的。Bash脚本、Java字节码程序和Python脚本,是使用抽象指令集编码的常见例子,需要模拟器或虚拟机来支持它们的执行。

原生程序(native program)是一种使用指令编码的程序,这些指令能够直接被计算机硬件执行,无需借助模拟器或虚拟机。在本书中,我们将重点讨论原生程序。因此,从现在起,无论何时我们使用“程序”这个词,除非另有说明,否则,我们指的是原生程序。

原生程序指令通常执行简单的操作,如对两个数字进行相加或者比较。但通过执行多个简单的指令,计算机能够解决复杂问题。

大多数现代计算机都是用数字电路制造的。这些机器通常使用映射到两种状态的电压水平(voltage levels )来表示信息。这两种状态可以是HIGH/LOW,或者是0/1 。因此,现代计算机的基本信息单位是一个二进制数字:1或0。所以计算机上的信息和指令被编码为二进制数字序列,或者说是位(bits)的序列。

1.1 计算机的主要组件

计算器通常由以下主要组件构成

  • 主存(Main memory ):主存用于存储正在执行的程序的指令和数据。主存通常是不稳定的,如果计算机被关闭,它的内容就会丢失。

  • 中央处理器(Central Processing Unit ):CPU负责执行程序,它从主存中获取程序的指令并执行。在执行指令期间,它经常会从主存中读写数据。

  • 持久化存储器(Persistent storage ):由于主存是不稳定的,通常有一个持久存储设备来在断电时保存程序和数据。硬盘驱动器(HDD)、固态硬盘(SSD)和闪存驱动器都是持久存储设备的例子。

  • 外围设备(Peripherals ):外设是连接到计算器的输入/输出设备,例如显卡、USB控制器、网卡等。

  • 总线(Bus):总线是在计算机组件之间传输信息的通信系统。这种系统通常由负责传输信息的线路(wires )和协调通信的相关电路(associated circuitries )组成。

图1.1展示了一个计算机系统,该系统的主存、CPU、持久化存储设备(HDD)和两个I/O设备通过系统总线连接起来。

图1.1 计算机系统中的组件通过一个系统总线相连

1.1.1 主存

计算机主存是用来存储程序指令和数据的存储设备,它由一组内存字[1](memory words )组成。每个内存字 能够存储多个bits(通常是8个),并由一个唯一的数字标识,该数字被称为内存字地址(memory word address)。

字节可寻址内存(byte addressable memory )是一种内存,其中的每个内存字(此时又称为memory location)存储一个byte[2],并与一个唯一的地址相关联。图1.2说明了字节可寻址内存的组织方式。可以看到,由地址5标识的内存字包含了值 $11111111_2$,而位于地址为0的内存字则包含了值 $00110110_2$

图1.2 字节可寻址内存的组织方式,(a)是2进制方式显示,(b)是16进制方式显示

[1] 原书中并没有精确定义什么是memory word,根据上下文推断,它和计算机科学中的 (word) 的意思不一样。 个人理解它就是计算机内存中的基本存储单位,因为原文是这样写的:

  • it(main storage) is composed of a set of memory words(说明是组成内存的最基本单元)
  • Each memory word is capable of storing a set of bits (usually eight bits) and is identified by a unique number, knownas the memory word address(说明是寻址的基本单元)

而在现代计算机上,byte就是内存中存储和寻址的最基本单元,所以在本书中我们可以认为memory word就是byte。但memory word是一个更加通用和抽象的概念,强调的是最小的存储和可寻址单元。在后面章节中我们可以看到,某些场景下memory word的长度不一定是8 bit,例如2.2.1中出现了 three-bit word 这样的说法。

[2] 原文中没有直接定义byte,按照约定俗成,一个byte就是8个bit。但历史上出现过各种长度(1~48)的byte,但现在几乎所有的架构都使用8作为byte的长度。

1.1.2 CPU

CPU是负责执行计算机程序的组件。 有多种实现和组织 CPU 的方法,但是,要了解程序如何执行,只需知道 CPU 包含:

  • 寄存器(Register):寄存器是位于 CPU 内部的小型存储设备。CPU 通常包含一小组寄存器。 例如,RISC-V 处理器包含 31 个 32 位寄存器,程序可以使用这些寄存器来在 CPU 内部存储信息。 计算机通常包含将值从主存复制到寄存器的指令(称为“LOAD”指令),以及将值从CPU寄存器复制到主存的指令(称为“STORE”指令)。
  • 数据通路(A datapath):CPU数据通路负责对数据执行操作,例如算术和逻辑操作。数据通路通常使用来自寄存器的数据执行操作,并将结果存储在寄存器上。
  • 控制单元(A controller unit):控制单元是负责协调计算机操作的单元。它能够通过总线发送命令来控制数据通路和其他组件,如主存。例如,它可以向数据路径和主存发送一系列命令,以编排程序指令的执行。

译者注:数据通路是执行单元的集合,例如执行数据处理操作的算术逻辑单元乘法器寄存器总线。它与控制单元一起组成中央处理器(CPU)

访问寄存器中的数据比访问主存中的数据快得多。因此,程序倾向将数据从内存复制到寄存器中以实现更快的处理。一旦数据不再需要了,可以丢弃或存回主存中以释放CPU寄存器。

指令集体系结构(ISA)定义了计算机指令集,包括但不限于指令的行为、编码和可以被指令访问的资源,如CPU寄存器。一个为特定ISA生成的程序,可以被兼容该ISA的计算机执行。

ISA往往随着时间的推移而演变,然而ISA设计者试图保持新版本的ISA与以前的版本兼容,以便遗留代码(即为旧版ISA生成的代码)仍然可以由新的CPU执行。例如:为80386 ISA生成的程序可以被任何实现或兼容该ISA的处理器执行,如80486 ISA。

1.2 执行程序指令

如前所述,现代计算机通常在主存中存储正在被执行的程序,包括它的指令和数据。CPU从主存中获取程序的指令来执行。另外,当执行指令时,CPU可往主存中读写数据。为了说明这个过程我们将考虑一个实现RV32I ISA的CPU。

RV32I ISA规定指令使用32位编码。因此,假设系统有一个字节可寻址内存,则每个指令占用4个内存字。RV32I ISA还规定指令按照它们在主存中出现的顺序执行。

我们考虑一个为RV32I ISA生成的小程序,由3条指令组成,在主存中地址为8000的地方开始存储。因为每一指令占用4个字节(即32位),且指令是连续存储在主存上,所以第1条指令位于地址8000、8001、8002和8003,第2条指令位于地址8004、8005、8006和8007,第3条指令位于地址8008、8009、800A和800B。图1.3展示了存储在主存中的指令。

图1.3 3条RV32I指令在主存中地址为8000的地方开始存储

CPU通常用一个寄存器来跟踪下一条需要被执行指令。在RV32上这个寄存器称为程序计数器(Program Counter )或PC寄存器,它存储了下一条要被执行的指令的内存地址。例如,在图1.3所示的代码中,在执行的第一个指令之前PC的值为8000。一旦位于地址8000的指令被获取了,PC中的值就增加4。等当前指令完成了,下一条指令(位于地址8004)就能被获取执行。算法1演示了一个简单的RV32I CPU的执行周期。

  • 首先,CPU根据PC中的地址,从主存中获取一条指令并将其存储在一个叫做IR的内部寄存器中,该指令由4个内存字(32bit)组成。

  • 然后,它更新PC,使其指向内存中的下一条指令。

  • 最后,它执行(在第一步中)获取到的指令。

注意,在执行指令时,CPU也可能读写主存中的数据。

# 算法1:RV32I指令的执行周期

while True do
# 获取指令并更新PC寄存器;
	IR ← MainMemory[PC] ;
	PC ← PC+4;
	ExecuteInstruction(IR);
end	

为了执行一个程序,操作系统本质上是将程序加载到主存中(例如,从一个持久存储设备),并将PC设置为指向程序入口点。

1.3 启动过程

由于主存是不稳定的,当计算机开机后,它就会包含垃圾信息(译者注:指内存中的信息无法持久化,开机后内存中都是无效的信息)。因此,CPU可能无法从主存中获取指令。在这种情况下,(为了解决这个问题)开机后PC会被设置为指向一个小型的非易失性内存设备,这样CPU就能从中获取指令,而该设备存储了一个执行启动过程的小型程序4。该程序初始化基本的计算机组件,检查启动配置(也存储在非易失性内存中),并根据其设置,从持久存储设备(例如硬盘驱动器)将操作系统的boot loader加载到主内存中。(译者注:注意区分硬盘驱动器和非易失性内存中这两个概念)

一旦操作系统boot loader加载到内存中,CPU就开始执行它,boot loader会依次完成计算机的设置并将主操作系统模块加载到主内存中。一旦启动过程完成,主操作系统模块的一个副本就位于主内存中,系统就准备执行其他程序,例如用户的程序。

[4] 这就是我们熟知的BIOS,但现在新一代的计算机使用新的UEFI标准了