寄存器、内存和指令:指令集体系结构
指令集体系结构(ISAs)是计算机的最底层抽象。 ISAs旨在尽可能地接近硬件, 同时又通用到可以适用于大多数计算机。 因此,ISAs极度不友好,实际上很少有开发者直接使用它们编程, 更高级的编程语言往往以一种与ISAs完全不同的方式抽象计算机。 然而,了解ISAs是理解计算机硬件如何工作的良好起点, 它有助于解释高级编程语言和软件应用中的许多设计选择,这就是为什么在这里介绍它们。
存在多种不同的ISAs,如x86、ARM、MIPS和RISC-V。 它们中的每一个都有一些不同的设计(或者相当不同,比如CISC和RISC体系结构家族), 但是它们之间有一些概念是共享的。 这些概念是几乎所有计算机硬件的基本抽象, 本节将介绍这些概念。
寄存器、内存和指令:计算机最普适的抽象
几乎所有的ISAs都使用以下概念:
- 存在一组有限的寄存器,可以在其中存储数据。
- 存在一个(虚拟上无限大的)内存,可以在其中存储更多的数据。 内存中的每个位置都可以保存一些数据, 并且与之关联一个地址; 可以使用该地址访问存储在该位置的数据。
- 支持执行一组有限的指令的"处理器", 这些指令以某种方式修改寄存器或内存。
- 指令存储在内存中,并按顺序执行;
- 存在一个特殊的寄存器(通常称为“程序计数器”或“PC”), 它保存内存中的一个地址; 每次,在该内存地址处, “处理器”读取数据,将该数据解释为指令,执行它,然后以某种方式更新PC。
上述概念中有几个重要的事项需要注意:
- 相对于内存,寄存器只能存储非常有限量的数据。 在大多数ISAs中,寄存器的数量少于100, 所有寄存器中可以容纳的总数据量不太可能超过1兆字节(MB)。 相反,内存要大得多:现代计算机通常具有从4到几百千兆字节(GB)的内存; 甚至手机通常也有4GB或更多的内存。
- 从特定时间点开始,计算机将做的事情 完全由寄存器(包括PC)和内存中保存的数据确定。 可以将寄存器和内存看作程序的“状态”; 该状态完全确定了程序的行为。
- ISAs支持的指令通常是非常简单的操作 (CISC(复杂指令集计算机)是一类支持更复杂指令的ISA族,但它们的功能与完整的计算机程序相比仍然非常有限), 例如“将寄存器5和寄存器11中的数据相加,并将结果存储到寄存器0”、“将内存地址122处的值加载到寄存器1”或“将PC向前移动40个内存地址”。 这些指令不是完整的计算机程序; 它们是更大程序的构建块。 通过组合这些简单指令(称为“编程”), 可以创建几乎可以做任何事情的程序。
为什么我们需要寄存器?
您可能想知道为什么我们需要寄存器: 既然寄存器和内存都是程序的“状态”, 那么为什么我们不能只使用内存呢? 毕竟,寄存器只能存储非常有限量的数据, 而内存要大得多。
答案与计算机硬件的工作方式有关。 尽管寄存器很小,但它们非常快速; 相反,内存虽然大,但也很慢(与寄存器相比)。 因此,通常的做法是将需要频繁访问的数据存储在寄存器中, 而将其余数据存储在内存中。
这是ISA与硬件接近的一个很好的例子, 正如您所看到的,虽然抽象是“一般和抽象的特征”, 但它们通常取决于和反映它们应用于的基础对象。
其他ISAs
虽然此处介绍的内容适用于绝大多数ISAs, 但也有一些以不同方式抽象计算机的ISAs。 例如,WebAssembly(WASM) 是一种基于堆栈的架构,不具备寄存器。
计算机程序是如何运行的?
想象一下,一个手持笔记本的人。 在开始时,这个人手上的笔记本在某一页上; 然后,在每个时间点,这个人读取一页, 根据该页的内容做一些事情(进行一些计算并记住结果,或者将某些东西写到另一页), 然后翻到另一页,这个过程一直重复进行。
这个类比很好地解释了计算机上如何运行程序: 这个人是处理器;笔记本是内存, 这个人的脑记忆就是寄存器。
如前所述,ISAs仅支持一些功能非常有限的指令; 这些指令充当更大软件应用的构建块。 实际上,每个软件应用在计算机硬件上运行时,都会转化为大量(从数百到数百万)的ISA指令。 基本上,程序按照ISAs定义的方式运行:
- 在开始时,内存和寄存器被初始化为某些值。 通常,内存中有一个特殊的段,其中包含所有的指令; 该段里面的指令构成了“程序”。
- 在每个时间点,处理器在PC指定的内存地址处读取一个ISAs定义的指令, 执行它(进行一些计算并将结果写入寄存器,或者写入某个内存地址等), 然后更新PC(通常是下一条指令的内存地址,但也可能是其他位置)。
- 重复以上过程,直到程序运行结束。
graph TD
A([开始]) --> B([读取指令])
B --> C([执行指令])
C --> D([更新PC])
D --> B
如果有多个程序怎么办?
您可能会想,如果有多个程序在同一台计算机上运行怎么办? 既然它们使用同一块内存,它们不会互相干扰吗? 它们是按顺序执行还是同时执行?
简短的答案是,操作系统提供了另一层抽象来消除所有这些问题。 简单来说,操作系统“虚拟化”计算机硬件, 创造出多个,独立运行的计算机的假象。 每个程序都被分配了一个这样的“虚拟”计算机; 在程序的视图中,这个计算机上没有其他人,所以没有任何干扰。
操作系统如何创建这种假象超出了本节的范围。
结论
在本节中,我们讨论了计算机的最底层抽象:指令集体系结构(ISAs)。 与其他计算机的抽象,如更高级的编程语言相比, ISAs更接近硬件,但也不太友好。 尽管开发者在编程时通常使用完全不同的抽象, 但了解ISAs提供了理解计算机工作原理的良好基础。
几乎所有的ISAs都有一组寄存器,一块内存, 并定义了一组支持的简单指令。 有一个特殊的寄存器称为程序计数器(PC)。 程序运行的方式基本上是“在PC处获取指令-执行指令-更新PC-重复”。 ISA指令用作构建更复杂软件应用的基石; 实际上,每个软件应用在计算机上运行时都可以归结为大量简单的ISA指令。
恭喜,您现在理解了计算机硬件的工作原理! 现实世界的计算机硬件比ISAs复杂得多, 但是目前为止,ISAs是对真实硬件的良好近似。
接下来,我们将介绍一些基于ISAs的高级抽象, 这些抽象在大多数低级编程语言(如C/C++和Rust)中都存在。
AI提示样本
如果您想了解更多有关本节中的主题的内容, 可以与ChatGPT等AI进行交流。
以下是一些示例提示,以帮助您开始:
- 您能简要描述ARM体系结构及其指令吗?
- 您能举一个ARM汇编代码的例子并解释它正在做什么吗?
- CISC和RISC之间有什么区别?
- 指令集体系结构与图灵机相比有什么区别? 为什么图灵机没有寄存器?为什么ISAs中有寄存器?
- 当今最流行的指令集体系结构有哪些?