这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

组成原理

CPU
Memory
Device
Control Bus
Address Bus
Data Bus
System Bus

计算机组成原理在408试卷中占据45分,和数据结构一样,是分数占比最大的科目,同样会考察11道选择题和两道大题。

大题的考察重点在与指令系统、CPU以及存储系统。指令系统和CPU常常会放在一起考察,作为一道大题。存储系统系统常常会和操作系统中的相关知识在一起考察,在复习时可以将这两门课的相关内容放在一起复习。


计算机组成原理的考察目标包含如下内容(来自408考研大纲):

  1. 掌握单处理器计算机系统中主要部件的工作原理、组成结构以及相互连接方式。
  2. 掌握指令集体系结构的基本知识和基本实现方法,对计算机硬件相关问题进行分析,并能够对相关部件进行设计。
  3. 理解计算机系统的整机概念,能够综合运用计算机组成的基本原理和基本方法,对高级编程语言(C语言)程序中的相关问题进行分析,具备软硬件协同分析和设计能力。

1 - 概述

计算机组成原理的基本概念,可能会在选择题中考察,看到题目能够选出答案即可。
# 计算机系统概述

## 计算机系统层次结构

- 计算机系统的基本组成
- 计算机硬件的基本结构
- 计算机软件和硬件的关系
- 计算机系统的工作原理

## 计算机性能指标

1.1 - 计算机系统层次结构

了解基本概念,可能在选择题中考察。

计算机系统的基本组成

硬件系统和软件系统共同构成了一个完整的计算机系统。硬件指的是有形的物理设备,是计算机系统中实际物理装置的总称。软件指的是在硬件上运行的程序和相关的数据及文档。

硬件和软件关系:硬件是计算机的物理部分,它提供了运行软件所需的基础设施,而软件则是指令集,指导硬件如何工作以执行特定的任务。

计算机硬件

冯·诺依曼基本思想

冯·诺依曼提出的 “存储程序” 的思想奠定了当代计算机的基本结构,以此概念为基础的各类计算机通称为 冯·诺依曼机,其特点如下:

  1. 采用 “存储程序” 的工作方式。
  2. 计算机硬件系统由 运算器、存储器、控制器、输入设备和输出设备5大部件组成。
  3. 指令和数据以同等地位存储在存储器中,形式上没有区别,但计算机应能区分它们。
  4. 指令和数据均用二进制代码表示,指令包含操作码和地址码,操作码指出操作的类型,地址码指出操作数的地址。

计算机的功能部件

  1. 运算器 (Arithmetic Logic Unit, ALU)
    • 功能:负责执行所有的算术运算(如加、减、乘、除)和逻辑运算(如AND、OR、NOT、比较等)。
    • 组件:包括运算部件(执行具体的数学和逻辑操作)和临时存储用的寄存器。
  2. 存储器 (Memory)
    • 功能:存储数据和指令。主存储器(如RAM)临时存储正在运行的程序和数据,而辅助存储器(如硬盘、SSD)用于长期存储。
    • 种类:包括随机存取存储器(RAM)、只读存储器(ROM)、硬盘、SSD等。
  3. 控制器 (Control Unit)
    • 功能:管理和协调计算机的各个部件,确保指令按正确的顺序执行,并控制数据流。
    • 组件:包括指令寄存器、程序计数器和一个解码器,它们共同参与指令的获取、解码和执行。
  4. 输入设备 (Input Devices)
    • 功能:允许用户或其他系统将数据输入计算机。
    • 重要性:它们构成了用户与计算机系统之间的主要交互界面。
  5. 输出设备 (Output Devices)
    • 功能:显示或输出计算机处理的结果。
    • 例子:显示器、打印机、扬声器、投影仪等。

计算机软件

系统软件和应用软件

  1. 系统软件 (System Software)
    • 定义:系统软件是直接运行在硬件上的软件,为其他软件提供一个运行和执行的平台。
    • 功能:
      • 管理和控制计算机硬件,使其能够与应用软件进行交互。
      • 提供应用软件开发的基础服务和接口。
  2. 应用软件(Application Software)
    • 定义:应用软件是构建在系统软件之上,为用户提供特定功能或执行特定任务的软件。
    • 功能:
      • 解决用户的具体问题或满足特定需求。
      • 提供与用户的直接交互界面。

三个级别的语言

  1. 机器语言 (Machine Language):
    • 定义:这是计算机硬件直接理解和执行的语言,它是用二进制代码表示的(通常是0和1)。
    • 特点:
      • 与特定计算机架构紧密相关。
      • 非常低级:每条机器代码对应硬件的一个操作。
      • 对于人类来说,阅读和编写是困难的。
  2. 汇编语言 (Assembly Language):
    • 定义:这是一种低级编程语言,它使用符号和助记符(而非二进制代码)来代表机器语言的指令。
    • 特点:
      • 与特定计算机架构紧密相关。
      • 比机器语言更容易理解和编写。
      • 需要一个汇编器来将汇编代码转换为机器代码。
  3. 高级语言 (High-Level Language):
    • 定义:这是为了更方便地编写和理解计算机程序而设计的语言。它们与特定的计算机架构相对独立。
    • 特点:
      • 抽象度高,语法通常更接近自然语言或数学符号。
      • 可以在不同的硬件平台上运行,只需适当地编译或解释。
      • 需要一个编译器或解释器来将高级语言代码转换为机器代码(或执行)。

计算机系统的工作原理

从源程序到可执行程序

  1. 预处理(Preprocessing):预处理器会执行诸如宏替换、文件包含、条件编译等任务,仅限于某些语言,比如CC++
  2. 编译(Compilation):编译器将源代码或预处理后的源代码转换为中间代码或目标代码,标代码通常是特定平台的汇编语言代码或机器代码。
  3. 汇编(Assembly):汇编器将汇编语言代码转换为机器代码。
  4. 链接(Linking):链接器将一个或多个目标文件与所需的库文件链接在一起,生成一个可执行文件。这个步骤确保所有函数或方法的调用都能找到它们在内存中的正确位置。
  5. 加载和执行(Execution):当你运行可执行文件时,操作系统的加载器会将它加载到内存中。CPU开始按照程序的指令执行任务。
# 预处理
gcc -E hello.c -o hello.i
# 编译
gcc -c hello.c -o hello.o
# 汇编
gcc -S hello.c
# 链接
gcc hello.o -o hello
# 加载和执行
./hello

1.2 - 计算机性能指标

需掌握计算机的各种性能指标,为后续内容的基础,常常在选择题中考察。

CPU指标

主频

主频是指计算机中时钟信号的频率,通常以赫兹(Hz)为单位表示。例如,一个3.0 GHz的CPU意味着它的时钟周期每秒钟震荡30亿次。

时钟周期

CPU时钟周期是CPU完成一个基本操作所需的时间,与主频是互为倒数的关系。例如,3.0 GHz的CPU的时钟周期是1/3.0亿 = 0.333纳秒。

指令执行指标

CPI

CPI 的全称是 Cycle Per Instruction,也称每指令周期,即一条指令所需要的平均时钟周期。

IPC

IPC 的全程是 Instruction Per Cycle,也称每周期指令,即每个时钟周期执行的平均指令数,是 CPI 的倒数。

IPS

IPS 的全程是 Instruction Per Second,也称每秒指令数,即每秒平均能够执行多少条指令。

MIPS

MIP 的全称是 Million Instructions Per Second,及每秒能够执行 多少个 百万的指令。

浮点运算指标

各种FLOPS

这些都是评估计算机性能的指标,尤其在浮点运算方面。它们分别代表每秒可以执行的浮点运算次数:

  • MFLOPS: 百万次每秒
  • GFLOPS: 十亿次每秒
  • TFLOPS: 万亿次每秒
  • PFLOPS: 千万亿次每秒
  • EFLOPS: 百亿亿次每秒
  • ZFLOPS: 万亿亿次每秒

计算机指标

字长

字长(Word Length)指的是计算机在内部一次操作中所能处理的二进制数字位数。例如,一个32位的CPU一次可以处理32位的数据。

数据通路带宽(Data Bus Width)

数据通路带宽是CPU和内存之间传输数据的宽度,通常以位为单位表示。比如,64位的数据总线意味着每个时钟周期内,可以传输64位的数据。

主存容量

主存储器能够存储信息的最大容量,通常用字节来衡量。

吞吐量

吞吐量(Throughput)表示在单位时间内,系统可以完成的任务数量。在计算机网络中,它可能表示数据的传输速率;在计算中,它可能表示每秒执行的操作数。

2 - 数据表示和计算

本章在选择题中考察,需要熟练掌握补码表示以及浮点数的IEEE标准。
# 数据的表示和运算

## 数制和编码

- 进位计数制及其数据之间的相互转换
- 定点数的编码表示

## 运算方法和运算电路

- 基本运算部件
- 加/减运算
- 乘/除运算

## 整数的表示和运算

- 无符号整数
- 带符号整数

## 浮点数的表示和运算

- IEEE 754标准
- 浮点数的加/减运算

2.1 - 整数的表示

需了解原码、补码的计算方法,为后续内容的基础。

BCD码

BCD(Binary-Coded Decimal)码是一种二进制编码方法,用于表示十进制数字。每个十进制数字(0-9)都使用四位二进制数字表示。

BCD码的基本思路是单独表示每个十进制数字的二进制值,而不是像传统的二进制数系统那样对整个数字进行编码。例如,在传统的二进制编码中,数字"19"会表示为10011,但在BCD中,它被表示为两个独立的数字:“0001”(对应于1)和“1001”(对应于9),因此整个表示为“0001 1001”。

0 - 0000    1 - 0001    2 - 0010
3 - 0011    4 - 0100    5 - 0101
6 - 0110    7 - 0111    8 - 1000
9 - 1001

BCD编码在某些应用中是很有用的,特别是在需要与十进制界面进行交互的地方,如数字显示或某些早期的计算机系统。尽管它不如纯二进制编码效率高,但它简化了与十进制数据的转换过程。

整数的表示

原码

原码(Sign-Magnitude)是一种简单的方式来表示二进制中的有符号整数。在这种表示法中,数字的最高位(最左边的位)用于表示符号,其余的位表示数字的大小。通常,符号位为0表示正数,而1表示负数。

表示方法

原码的表示方法:

  1. 正数的原码:最高位为0,其余位表示这个数的绝对值的二进制形式。
  2. 负数的原码:最高位为1,其余位表示这个数的绝对值的二进制形式。
  3. 零的原码:符号位可以是0(表示+0)或1(表示-0),但在实际应用中,通常只使用一个零,即符号位为0。

举例(以8位二进制数为例):

  • +5 的原码是:00000101
  • -5 的原码是:10000101

原码的缺点

  • 存在正零和负零的表示。
  • 在进行算术运算时,正数和负数需要不同的处理,这使得硬件设计变得复杂。

由于上述的缺点,原码并不是计算机中最常用的表示法。在现代计算机中,补码是更常用的方式来表示有符号整数,因为它简化了算术运算的处理,并且没有+0和-0的冗余表示。

补码

补码(Two’s complement)是计算机科学中用于表示整数的一种方法,特别是在现代计算机的算术和逻辑操作中。使用补码可以使得加法、减法和负数的表示变得简单和统一。

表示方法

原码的表示方法:

  1. 正数的原码:最高位为0,其余位表示这个数的绝对值的二进制形式。
  2. 负数的原码:最高位为1,其余位表示这个数的绝对值的二进制形式。
  3. 零的原码:符号位可以是0(表示+0)或1(表示-0),但在实际应用中,通常只使用一个零,即符号位为0。

以8位二进制数为例:

  1. 对于正数,例如 +5,其二进制表示为 00000101,补码也是 00000101。
  2. 对于负数,例如 -5,首先写出5的二进制表示:00000101。
    • 按位取反得到:11111010
    • 加1得到:11111011
    • 所以,-5的补码是 11111011。

补码的计算方式

以8位补码为例讲解一下补码是如何从二进制位与实际数字结合的:

第7位第6位第5位第4位第3位第2位第1位第0位
$-2^7 = -128$$2^6 = 64$$2^5 = 32$$2^4 = 16$$2^3 = 8$$2^2 = 4$$2^1 = 2$$2^0 = 1$

例子:

  • 10000001对应的值为 $-128 + 1 = -127$
  • 10001001对应的值为 $-128 + 8 + 1 = -119$
  • 01000001对应的值为 $64 + 1 = 65$

为什么要使用补码

补码的设计使得负数的加法变得简单。当使用补码表示时,可以直接将两个数相加,即使其中一个数是负数,而不需要进行任何特殊处理。这简化了计算机硬件的设计。

2.2 - 浮点数表示

需掌握32位和64位浮点数的IEEE表示,可能在选择题中考察。

实数的二进制表示

浮点数在计算机中的存储遵循IEEE标准,但在这里为了方便理解IEEE标准,这里首先阐明一般实数在计算机中是如何存储的。

在这里实数分为两个部分存储:整数部分 和 小数部分,两个部分在逻辑上用 · 隔开。

比如对于以下浮点数的二进制表示:

$$d_m d_{m-1} \cdots d_1 d_0 \cdot d_{-1} d_{-2} \cdots d_{-n}$$

其中每一位对应的数值如下表所示:

$d_m$$d_{m-1}$$\cdots$$d_1$$d_0$$d_{-1}$$d_{-2}$$\cdots$$d_{-n}$
$2^m$$2^{m-1}$$\cdots$$2$$1$$1/2$$1/4$$\cdots$$1/2^{n}$

上述二进制表示对应的数值为

$$b = \sum_{i=-n}^{m} {2^{i} \times b_{i}}$$

其中$b_i = 0$ 或 $b_i = 1$,表示第i为是0还是1。

举例说明如何使用上述表示法计算实数:

  • $101.11_{2}$ 对应的数值为 $1 \times 2^2 + 0 \times 2^1 + 1 \times 2^0 + 1 \times 2^{-1} + 1 \times 2^{-2} = 5.75$
  • $1011.1_{2}$ 对应的数值为 $8 + 0 + 2 + 1 + \frac{1}{2} = 11.5$

IEEE Floating-Point

上述浮点数存储方式的缺点在于如果要表示比较大的数,就需要比较多的二进制位数,比如对于$5 \times 2^{100}$ 就需要103位。IEEE表示就解决了这个问题,在IEEE表示中,浮点数 $V$ 被表示为 $V = (-1)^{s} \times M \times 2^{E}$,其中 $s, M, E$ 的含义如下:

  • $s$ 为符号位
  • $M$ 为乘法因子
  • $E$ 为浮点数的指数部分

IEEE 754标准是定义浮点数表示和算术的国际标准,它定义了多种不同精度的浮点数格式,但最常见的是单精度 single precesion(32位)和双精度 double precesion(64位),浮点数分为 s, exp, frac 三个部分存储:

s
exp
frac
s
exp
frac (51:32)
31
30
23
22
0
frac (31:0)
63
62
52
51
32
Single Precision
Double Precision
31
0
  • $1$ 位的 $s$ 与上述计算公式中的符号位 $s$ 相同,位于浮点数二进制表示的最高位,标志了浮点数的正负,如果 $s = 1$ 的话 $V$ 是负数,如果 $s = 0$ 的话 $V$ 为正数
  • $k$ 位的 $exp = e_{k-1} \cdots e_1 e_0$ 用于计算指数部分 $E$,使用原码表示,其中 $E = exp - Bias$,其中 $Bias = 2^{k-1} - 1$
    • 对于单精度浮点数,$k = 8$,$Bias = 2^{8-1} - 1 = 127$,$1 \le exp \le 254$,$-126 \le M \le 127$
    • 对于双精度浮点数,$k = 11$,$Bias = 2^{11-1} - 1 = 1023$, $1 \le exp \le 1022$,$-1022 \le M \le 1023$
  • $n$ 位的 $frac = 0 \cdot f_{n-1} \cdots f_1 f_0$ 用于计算因子 $M$,其中 $M = 1 + frac$,$frac$ 表示的小数计算方式见实数的二进制表示
    • 对于单精度浮点数,$n = 23$,$M$ 的最大值为 $2 - 2^{-23}$,$M$ 最小值为 $1$
    • 对于双精度浮点数,$n = 52$,$M$ 的最大值为 $2 - 2^{-52}$,$M$ 最小值为 $1$
s
s
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
s
s
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
≠ 0
≠ 0
s
s
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
frac
frac
s
s
≠ 0 and ≠ 255
≠ 0 and ≠ 255
frac
frac
Normalized
Normalized
Denormalized
Denormalized
Infinity
Infinity
NaN
NaN
Text is not SVG - cannot display

视频讲解

2.3 - 运算电路

包含数字电路的一部分内容,为部分其他内容的基础,了解即可,一般不会直接考察。

加法运算电路

最基本的加法单元是 半加器(Half Adder)。它有两个输入,一个是加数,一个是被加数,并有两个输出,一个是和,一个是进位。

half_adder_action

1-bitHalfAdderABCoutS

全加器(Full Adder)是半加器的扩展,它加上了前一位的进位作为第三个输入,并有两个输出,一个是和,一个是进位。全加器可以级联,用于多位加法。

full_adder_action

1-bitfulladderABCinCoutS

串联全加器:构成加法器

1-bitFullAdder1-bitFullAdder1-bitFullAdder1-bitFullAdderC3C2C1C0C4A3B3A2B2A1B1A0B0S3S2S1S0

为了进行多位数的加法,全加器可以串联起来形成一个串行进位加法器(ripple carry adder)。在这种安排中,每个全加器的进位输出连接到下一个全加器的进位输入。这样,一个 n 位的加法器可以通过串联 n 个全加器来实现。

减法运算电路

二进制中的减法可以通过加法来实现。减去一个数等同于加上它的补码。为了得到一个数的补码,你首先得到它的反码(每一位都取反)然后再加1。所以,一个简单的减法器可以通过使用加法器并对第二个输入(被减数)进行补码转换来构建。

乘法运算电路

二进制乘法与十进制乘法的手工计算方式类似:

       1011   (this is binary for decimal 11)
     × 1110   (this is binary for decimal 14)
     ======
       0000   (this is 1011 × 0)
      1011    (this is 1011 × 1, shifted one position to the left)
     1011     (this is 1011 × 1, shifted two positions to the left)
  + 1011      (this is 1011 × 1, shifted three positions to the left)
  =========
   10011010   (this is binary for decimal 154)

在计算机中实现乘法指令可以通过如下几种方式模拟以上过程:

1. 软件算法

如果没有专有硬件支持,可以通过一系列加法和位移操作来实现乘法。编译器将乘法运算转换为一个循环代码段,在循环代码段中通过比较、加法和移位等指令实现乘法运算。

// 如何使用加法和位移来实现两个整数的乘法(了解即可)
unsigned int multiply(unsigned int a, unsigned int b) {
    unsigned int result = 0;  // 结果初始化为0
    while (b > 0) {           // 当第二个操作数大于0时继续循环
        if (b & 1) {          // 检查b的最低位是否为1
            result += a;      // 如果是,将a加到结果上
        }
        a <<= 1;              // 将a左移一位,相当于a乘以2
        b >>= 1;              // 将b右移一位,去掉已经处理过的最低位
    }
    return result;            // 返回计算的乘积
}

2. 顺序乘法器

通过硬件的方式实现以上的软件算法,这是最基础的实现方式,类似于我们在纸上做乘法那样,一步一步进行。

3. 阵列乘法器

阵列乘法器(Array Multiplier)是一种用于执行乘法运算的硬件电路,它通过布置一系列全加器和半加器在一个二维网格或阵列中来实现,它能够并行处理多个位的乘法和累加,可以在一个或多个时钟周期内完成乘法操作。

除法运算电路

二进制除法在计算机中的实现与我们在十进制中所执行的传统长除法类似。与二进制乘法一样,我们将使用基本的二进制操作,如移位和减法。

   商(Quotient)
    0110
   =======
10 | 1101
-      10   (这是从 `110` 中减去的,因为它大于或等于 10)
   --------
        100 
    -   10   (这是从 `100` 中减去的,因为它大于或等于 10)
   --------
         10
     -   10   (这是从 `10` 中减去的,因为它大于或等于 10)
   --------
          0   (这是余数 Remainder)

2.4 - 类型转换

需了解整形和浮点型之间的类型转换,以及不同长度的类型之间的转换,可能在选择题考察,也会在大题中作为知识点考察。

有符号整数和无符号整数

这里需要了解有符号整数(int)和无符号整数(unsigned)这两个类型:

  • int:使用补码来存储数据。
  • unsigned:所有位,包括最高位,都用于表示数值,表示非负数。

以8位有符号整数和无符号整数说明一下

  • 8 位有符号整数
    • 表示的范围为 -128 ~ 127
    • 最大数为127,对应的二进制为0111 1111
    • 最小数为-128,对应的二进制为1000 0000
  • 8 位无符号整数
    • 表示的范围为 0 ~ 255
    • 最大数为255,对应的二进制为1111 1111
    • 最小数为0,对应的二进制为0000 0000

intunsigned进行类型转化时,位模式不变,可以理解成计算机存储单元中的二进制表示没有变化,只是从程序层面阐述该二进制数据的方式变了。

当我们将8位的有符号整数-128转化为无符号整数时,其值变成了128

整形和浮点数

  • floatint: 将浮点数转换为整数时,小数部分会被舍去。例如,将 3.9 转换为整数将得到 3。
  • intfloat: 将整数转换为浮点数时,结果会是一个等值的浮点数。例如,将整数 4 转换为浮点数将得到 4.0。

不同长度的类型转换

类型最小位数常见位数(32位系统)常见位数(64位系统)
signed char8位8位8位
short16位16位16位
int16位32位32位
long32位32位64位
long long64位64位64位
  • 较小的整数类型被转换为较大的整数类型时,高位会被自动填充为0
  • 较大的整数类型被转换为较小的整数类型时,高位会被自动截断

shortint的类型转化为例说明:

/* 将short转为int */
short s = 0x1234;
int i = s;
// 高16位被填充为0
// i = 0x00001234

/* 将int转为short */
int i = 0x12345678;
short s = i;
// 高16位被截断
// s = 0x5678

隐式和显式类型转换

  1. 隐式类型转换

你在一个表达式中混合使用 intfloat 时,C语言会自动进行类型转换以使得表达式可以正确计算。通常情况下,低精度类型会被提升到高精度类型,即 int 会被转换为 float

  1. 显式类型转换

也可以使用类型转换运算符显式地转换一个类型为另一个类型。

/* 隐式类型转换 */
int i = 5;
float f = 2.5;
float result = i + f;  // i 被隐式转换为5.0然后进行计算

/* 显式类型转换 */
int i = 5;
float f = 3.2;
int result = (int)f + i; // f 被显式转换为3,然后与i相加

3 - 存储系统

本章是重中之重,在选择题和大题中每年都会考察,需要理解通透。其中cache和虚拟存储器常常和操作系统中的相关知识放在一起考察,需要能够将两门课相关内容联系起来。
# 存储器层次结构

## 存储器分类

## 层次化存储器的基本结构

## 半导体随机存取存储器

- SRAM存储器
- DRAM存储器
- Flash存储器

## 主存储器

- DRAM芯片和内存条
- 多模块存储器
- 主存和CPU之间的连接

## 外部存储器

- 磁盘存储器
- 固态硬盘

## 高速缓冲存储器

- cache的基本原理
- cache和主存之间的映射方式
- cache中主存块的替换算法
- cache写策略

## 虚拟存储器

- 基本概念
- 页式虚拟存储器
- 段式虚拟存储器
- 段页式虚拟存储器

3.1 - 存储系统

需了解各种存储器的特点,可能在选择题中考察。

存储系统的层次结构

Regs
L1 cache
(SRAM)
L2 cache
(SRAM)
L3 cache
(SRAM)
Main Memory
(DRAM)
Local secondary storage
(local disks)
Remote secondary storage
(distributed file systems, web servers)
Smaller,
faster
Larger,
slower
  1. 寄存器(Registers):
    • 寄存器是位于处理器内部的最快速存储单元。
    • 它们提供极快的数据访问速度,但其容量非常有限。
  2. 一级缓存(L1 Cache):
    • L1缓存位于处理器内部,比寄存器稍大,但比其他缓存慢。
    • 它通常分为数据缓存(用于存储数据)和指令缓存(用于存储指令)。
  3. 二级缓存(L2 Cache):
    • L2缓存比L1缓存大,并且位于处理器和主内存之间。
    • 它的速度比L1慢,但比主内存快。
  4. 三级缓存(L3 Cache):
    • 在某些系统中,还有L3缓存,这是一种更大但速度更慢的缓存。
    • 它位于L2缓存和主内存之间,旨在进一步减少对主内存的访问。
  5. 主内存(RAM):
    • 就是我们常说的内存,比缓存慢,但比硬盘快得多,并且容量比缓存大。
    • 主内存用于存储正在运行的程序和当前使用的数据。
  6. 辅助存储(如硬盘驱动器或固态驱动器):
    • 辅助存储设备提供大量的永久存储。
    • 与RAM相比,这些设备访问速度较慢,但能够存储更多的数据,并且在断电时不会丢失数据。
    • 硬盘驱动器(HDD)和固态驱动器(SSD)是常见的辅助存储设备。

半导体随机存储器

半导体随机存储器的英文为 Semiconductor Random-Access MemoryRAM )。

首先说一下这个名词中的几个部分:

  • 半导体:这种存储器使用半导体材料(如硅)制成。晶体管是构成半导体存储器的基本组成部分。
  • 随机:随机的意思是随机访问,意味着可以以几乎恒定的时间访问存储器中的任意位置,它与其他存储技术(如磁盘或磁带)不同,后者需要按顺序访问数据。

随机存储器主要分为SRAM和DRAM,注意两者的区别:

特征SRAM(静态RAM)DRAM(动态RAM)
构造基于触发器的存储器单元基于电容器的存储器单元
稳定性静态存储,数据不需要刷新动态存储,需要定期刷新以保持数据
存取速度非常快,无需刷新相对较慢,需要刷新和预充电操作
能耗通常较高,因为使用更多的电力通常较低,因为不需要大量电力来维持数据的稳定性
存储密度相对较低,每个存储单元较大相对较高,每个存储单元较小
主要应用领域高速缓存、寄存器、高性能应用系统内存、大容量存储、移动设备

半导体随机存储器是 易失性 的,这意味着一旦断电,其中存储的信息就会丢失。SRAM 主要用于实现cache,DRAM 主要用于实现主存。

Flash存储

Flash存储器是一种 非易失性 的电子存储设备,它利用半导体技术来存储数据。通常用于长期数据存储,如USB闪存驱动器、固态硬盘(SSD)和移动设备的内部存储。它在读取速度上比RAM慢,但优于传统的硬盘驱动器(HDD)。

Flash存储器使用电子方式来擦写和重新编程存储单元。这意味着可以通过电信号快速擦除和写入数据。数据存储在小型存储单元中,每个单元由浮动门晶体管组成。这些晶体管可以保持其充电状态,从而代表不同的数据位。

Flash存储主要分为 NAND FlashNOR Flash 这两种类型。

ROM

ROM(Read-Only Memory)是一种 非易失性 存储设备,主要用于永久性地存储数据。

ROM主要用于读取操作。虽然早期的ROM在制造过程中就已经被编程,不能修改,但现代的ROM(如EPROM和Flash存储器)可以被重新编程。

ROM常用于存储固件,这是一种软件程序,直接嵌入在硬件设备中,用于控制设备的基本操作。例如,BIOS(基本输入输出系统)通常存储在ROM中。

注意一下ROM和RAM的对比如下:

特征RAM(随机存取存储器)ROM(只读存储器)
易失性是(断电时数据丧失)否(数据在断电时不丧失)
读写能力可以被随机读取和写入通常只读,只读数据不能随机写入
用途用于存储正在运行的程序、操作系统和数据用于存储固定程序代码、固件、启动程序等
存储容量通常较大,以支持多个程序同时运行通常较小,主要用于存储核心系统和固件
数据持续性不持久,数据在断电时丧失持久,数据在断电时不丧失
修改权限可以随机修改和写入数据通常只读,只读数据无法被修改

ROM 类型:

  • EPROM:可以通过紫外线照射来擦除数据,然后重新写入数据。写入数据和擦除数据都较为繁琐,且需要物理操作。常用作电脑的 BIOS 芯片,支持随机存取。
  • CDROM: 一种光盘存储设备,数据在生产时一次性写入,不能被修改(只能读取)。

3.2 - 内存

需掌握多模块存储器和主存容量扩展的工作原理,并了解 DRAM 芯片的原理,可能在选择题中考察。对于交叉编址并行存储器,也会在大题中考察相关概念的计算。

DRAM 芯片

刷新方式

特征集中刷新分散刷新异步刷新
刷新方式所有存储单元同时刷新根据存储单元的需求刷新根据使用情况和需求刷新
性能影响可能导致性能下降,因为刷新操作同时进行最小程度影响性能,仅刷新需要刷新的存储单元最小程度影响性能,根据实际使用情况调整刷新操作
硬件要求硬件和控制器相对简单需要更复杂的硬件和控制器需要智能的内存控制器和硬件支持
能源效率可能相对较低较高,因为只刷新需要刷新的存储单元较高,因为根据需求动态调整刷新频率
寿命可能影响寿命,特别是对于不经常使用的存储单元可以延长内存寿命可以延长内存寿命
灵活性有限的灵活性更大的灵活性高度灵活,可根据使用情况自动调整刷新频率

多模块存储器

利用多个结构完全相同的存储模块的并行工作来提高存储器的吞吐率:

  • 单体多字存储器
  • 多体交叉存储器
    • 高位交叉存储器
    • 低位交叉存储器

单体多字存储器

按同一地址码并行地访问各自对应单元,每一个单元为一个字,每字 m 位。可以同时选中存储器的 n 个单元,可以将带宽提高 n 倍。

仅做简单了解,这里不详细说明,考试重点在多体交叉存储器。

多体交叉存储器

在多体交叉存储器的实现方案中,有两种编码方式:高位交叉编制和低位交叉编址。其中低位交叉编址可以实现多个存储器的并行访问,高位交叉编址只能增大存储器的空间。

高位交叉编址

在高位交叉编址中,地址分为两个部分,高位用于存储存储器的下标,低位用于存储地址在该存储器内的偏移。

连续的数据在同一个存储器内编址,当一个存储器满了,接下来的数据在下一个存储器中编址。 如下图所示,若计算机地址空间大小为 4n,存储器 M0 中存储地址 0 到 n-1 的数据,存储器 M0 中存储地址 n 到 2n-1 的数据,以此类推。

所以在高位交叉编址中,相邻地址的数据存储在一个存储体中

M0
0
1
n - 1
M1
n
n + 1
2n - 1
M2
2n
2n + 1
3n - 1
M3
3n
3n + 1
4n - 1
体号
体内地址
地址译码
地址
高位交叉编址

在这种地址组织形式下,多个存储器芯片 串行工作只需要一个地址存储器即可,不必为每个芯片都配一个地址存储器(根据程序的局部性原理) 。

M0
M1
M2
M3
DR
地址总线
单字长
数据总线
AR

这种串行工作方式是无法提高 CPU 的性能的。 如上图所示,所有存储器都共享一个地址寄存器(AR,Address Register)和数据寄存器(DR,Data Regsiter)。

低位交叉编址

在低位交叉编址中,地址分为两个部分,低位用于存储存储器的下标,高位用于存储地址在该存储器内的偏移。

连续的数据交叉地在不同的存储器之间编址。 如下图所示,若计算机地址空间大小为 4n,地址为 0~3 的数据分别存储在 M0、M1、M2 和 M3 上,地址为 4~7 的数据也分别存储在 M0、M1、M2 和 M3 上,以此类推。

所以在低位交叉编址中,相邻地址的数据存储在不同存储体中

M0
0
4
4n-4
M1
1
5
4n-3
M2
2
6
4n-2
M3
3
7
4n-1
体号
体内地址
地址译码
地址
低位交叉编址

在这种地址组织形式下,多个存储芯片是 并行工作 的,且相邻地址处在不同的存储体中,因此就可以实现存储体的并行访问; 为了并行访问,每一个存储体均需要一个地址寄存器

M0
M1
M2
M3
AR
AR
AR
AR
DR
DR
DR
DR
地址总线
单字长
数据总线

使用 低位交叉编制 这种编址方式,计算机可以实现对于多个存储器的并行访问。 如上图所示,每个存储器都单独地配有一个地址寄存器(AR,Address Register)和数据寄存器(DR,Data Regsiter)。

并行访问存储器可以采用 流水线 的方式,与 指令流水线 概念类似,在并行存储器的流水线中,对于每一个存储器中存储单元的读取可以被分为三个阶段:

  • $P_1$:送地址和命令(送地址至存储器的 AR 中)
  • $P_2$:存储器读取数据(读取数据到 DR 中,该周期也称作 存储周期
  • $P_3$:传送数据(从 DR 中读取数据并传输到内存的物理地址中)

假设 CPU 的时钟周期为 $t$,$P_1$ 和 $P_3$ 的耗时为一个时钟周期即 $t$。$P_2$ 的耗时为四个时钟周期即 $4 \times t$,那么对于上图所示的 四体交叉存储器,读取 八个字长的数据 的流水线如下所示:

M0
M1
M2
M3
M0
M1
M2
M3
存储体号
时钟周期
1
2
3
4
5
6
7
8
9
10
11
12
P1
P2
P3
P1
P2
P3
P1
P2
P3
P1
P2
P3
P1
P2
P3
P1
P2
P3
P1
P2
P3
P1
P2
P3
13

主存容量的扩展

虽然单体存储芯片的容量和字长在不断扩大,但是在实际应用的过程中,任然会出现芯片的容量或者字长满足不了应用的情况,因此就有了存储扩展的需求;

假设存储芯片的字长为 $N$,存储字数为 $M$,则存储芯片的容量为 $M \times N$。

storage chip

常见的存储扩展包括三种:位扩展、字扩展、字位扩展

  • 位扩展:扩展字长
  • 字扩展:扩展字数
  • 字位扩展:同时扩展字长和字数
位扩展法

bit expand

字扩展法

word expand

字位扩展法

bit word expand

位扩展

16K
× 8
WE
A
CS
16K
× 8
WE
A
CS
16K
× 8
WE
A
CS
16K
× 8
WE
A
CS
CPU
R/W#
A15-0
D31-0
D7~D0
D15~D8
D23~D16
D31~D24

如上图所示,用 $16K \times 8\ bit$ 的存储芯片用来构建 $16K \times 32\ bit$ 的存储器。

需要的芯片数量为 $(16K \times 32) / (16K \times 8) = 4$。

由于是位扩展,所以四个芯片的片选信号要连接在一起,并处在常有效的状况;(片选信号是读写操作的开关)。

由于原存储器的 $8$ 位的,扩展之后变为 $32$ 位,这 $32$ 位的位线同 CPU 的 $32$ 位数据线相连接,所有存储芯片并行工作,贡献 $32$ 位数据中的不同 $8$ 位;

图中,4 个存储器共同构成 $64KB = 2^{16}B$ 的存储空间,所以地址总线为 $16$ 位,即从 $A_{0}$ 到 $A_{15}$。 但是由于 $16KB$ 的存储芯片只需要 $14$ 根地址线,因此只需要 $14$ 位地址线与存储线相连,即从 $A_{2}$ 到 $A_{15}$。 这里 $A_{0}$ 到 $A_{1}$ 不被使用,因为这 低两位地址线 相当于被用来扩展字长。

字扩展

16K
× 8 (0)
WE
A
CS
16K
× 8 (1)
WE
A
CS
16K
× 8 (2)
WE
A
CS
16K
× 8 (3)
WE
A
CS
CPU
R/W#
A15-0
D7-0
D7~D0
D7~D0
D7~D0
D7~D0
ramsel 0
ramsel 1
ramsel 2
ramsel 3
MREQ#
A15-14

如上图所示,用 $16K \times 8\ bit$ 的存储芯片用来构建 $64K \times 8\ bit$ 的存储器。

需要的芯片数量为 $(64K \times 8) / (16K \times 8) = 4$。

地址总线的位数为 $16$, 但是由于 $16KB$ 的存储芯片只需要 $14$ 根地址线,因此只需要 $14$ 位地址线与存储线相连,即从 $A_{0}$ 到 $A_{13}$。 高两位地址线 $A_{14}$ 到 $A_{15}$ 与片选译码器相连,由此产生片选信号。

字位扩展

16K
× 8 (0)
WE
A
CS
16K
× 8 (1)
WE
A
CS
16K
× 8 (2)
WE
A
CS
16K
× 8 (3)
WE
A
CS
CPU
R/W#
A15-0
D7~D0
D7~D0
D15~D8
D15~D8
ramsel 0
ramsel 1
MREQ#
A15
D15-0

如上图所示,用 $16K \times 8\ bit$ 的存储芯片用来构建 $32K \times 16\ bit$ 的存储器。

需要的芯片数量为 $(32K \times 16) / (16K \times 8) = 4$。

地址总线的位数为 $16$,地址线 $A_{1} \sim A_{14}$ 与存储器相连,$A_{0}$ 不使用,被用来扩展字长。$A_{15}$ 用来产生片选信号。

视频讲解

3.3 - 外存

重点掌握磁盘存储器的结构,为操作系统磁盘管理的基础,常常在大题中考察。也许了解RAID和SSD的原理,可能在选择题中考察。

磁盘存储器

Sector
Sector
Cylinder / Track
Cylinder / Track
6 Heads, 3 platters
6 Heads, 3 platters
Text is not SVG - cannot display

存储区域

  1. Heads(磁头):磁头是位于硬盘驱动器的读/写臂上的设备,用于读取和写入磁盘上的数据。每个盘片(硬盘通常包含多个盘片,每个盘片都有两个表面)上都有一个磁头,因此每个磁头都可以读取或写入盘片上的数据。磁头通过移动到不同的磁道(track)来寻找并访问数据。
  2. Track(磁道):磁道是磁盘上的一个同心圆环。
  3. Cylinders(柱面):柱面是硬盘上的一个数据存储区域,由相同半径位置上的多个盘片上的磁道组成。换句话说,它是所有盘片上相同半径位置的磁道的集合。
  4. Sectors(扇区):扇区是磁盘上的最小数据存储单元。磁盘通常被划分成许多扇区,每个扇区可以存储一定数量的数据。扇区的大小通常是512字节或4KB。操作系统和磁盘控制器使用扇区作为数据的最小单元,以读取和写入数据。
magnetic layeraluminum plate1 bitcylindersectortrackdisk read-and-writeheadsdisk read-and-write headfloating on a cushion of air

性能指标

  • 平均存取时间 = 寻道时间(磁头移动到目的磁道的时间) + 旋转延迟时间(磁头定位到要读取扇区的时间) + 传输时间(传输数据所花费的时间),由于寻道和找扇区的距离远近不一,所以寻道时间和旋转延迟时间通常取平均值。
  • 数据传输率:磁盘单位时间向主机传送数据的字节数。假设磁盘转速为 $r$ 传/秒,每条磁道容量为 $N$ 字节,则数据传输率为 $D_{r} = rN$

RAID

RAID全称为独立磁盘冗余阵列(Redundant Arrar of Independent Disks) 由于磁盘存储介质数据的可靠性容易受到环境影响,而发生数据错误的代价非常大,因此需要考虑存储的容灾与恢复。

RAID将多个独立的物理磁盘组成一个独立的逻辑盘,数据在多个物理盘上分割交叉存储、并行访问,具有更好的存储性能、可靠性和安全性。

固态硬盘SSD

  • 无机械部件:SSD没有旋转盘片、磁头或机械臂等移动部件,它使用闪存存储芯片来存储数据。这意味着它不会受到机械故障的威胁,具有更高的耐用性。
  • 更快的读写速度:SSD的读写速度远远超过传统的机械硬盘,因为数据可以立即访问,无需等待盘片旋转和磁头寻道。这使得计算机启动更快,应用程序响应更迅速。
  • 低访问时间:由于没有机械延迟,SSD的访问时间极低,通常在微秒级别。这有助于加快文件读取和数据检索。
  • 长寿命:虽然每个存储单元有写入次数的限制,但现代SSD使用错误检查和纠正(ECC)技术,以延长其寿命,并且通常拥有较长的保修期。
  • 无碎片化:SSD不会发生碎片化问题,因此无需定期进行碎片整理操作。

3.4 - Cache

重点内容,每年都会在选择题和大题中考察,需要能够从一个宏观的角度思考 cache 在整个存储系统中的位置。

cache 原理

cache 工作原理

缓存(cache)是计算机系统中的一种用于加速数据访问的技术,其原理是在高速存储介质中暂时存储常用数据,以便更快地满足后续的访问请求。

缓存对于程序执行的加速主要来自于 计算机程序 的 时间局部性 和 空间局部性:

  1. 时间局部性
    • 如果一个数据项被访问,那么它在不久的将来很可能再次被访问。
    • 这种特性常见于循环结构和频繁访问的变量,例如循环中的计数器或者经常读取的配置值。
    • 在缓存设计中,利用时间局部性意味着一旦数据被加载到缓存中,它应该在那里保留一段时间,因为很可能很快会再次需要它。
  2. 空间局部性
    • 如果一个数据项被访问,那么存储在其附近的数据项也很可能在不久的将来被访问。
    • 这种特性在数组遍历或结构体访问时尤为明显,因为这些数据元素通常在内存中是连续存储的。
    • 利用空间局部性的缓存设计会在访问一个数据项时,同时把它附近的数据也加载到缓存中,因为这些数据很可能在接下来的操作中被用到。

cache 概念

  • 缓存块(cache 块):cache 中的一块存储空间
  • 主存块:主存中的一块存储空闲,主存块的大小一般与 cache 块一致
  • 块内偏移:某一个地址在块内的偏移,找到对应的块后,通过块内偏移找到改地址的具体位置
  • 块大小:用于判断块内偏移的位数,比如$1024 = 2^{10}$,所以 1KB 的块对应的块内偏移位数为 10

缓存块

什么是缓存块?

Cache block(缓存块),也被称为缓存行(cache line),是计算机系统中用于存储的最小数据单元,它是缓存中的一个固定大小的数据块。每个缓存块包含一定数量的字节或字(通常是 2 的幂次方个字节),并用于存储从主存(或更低级别的缓存)中加载的数据。

cache block 的目的是为了方便对于主存(main memory)数据的缓存,主存数据块的大小与缓存块大小一致,这样就可以将 cache block 和 main memory block 对应起来。

缓存块的大小?

Cache block 的大小在不同计算机体系结构中可以有所不同,通常以字节(bytes)或字(words)为单位来表示。典型的缓存块大小可以是 32 字节、64 字节、128 字节等。较大的缓存块可以容纳更多的数据,提高了数据的局部性,但在某些情况下,较小的缓存块可能更适合,特别是对于小规模的数据访问。

cache block 的大小在题目中一般会给你。

cache 和主存映射方式

Block 0
Block 1
Block 2c-1
Cache
Block 0
Block 1
Block 2c-1
Block 2c
Block 2m-1
Block 2c+1
Main Memory
Tag
Data
Group 0
Group 2c-1
Cache
Block 0
Block 1
Block 2c-1
Block 2c
Block 2m-1
Block 2c+1
Main Memory
Tag
Data
Block 0
Block 1
Block 2c-1
Cache
Block 0
Block 1
Block 2c-1
Block 2c
Block 2m-1
Block 2c+1
Main Memory
Tag
Data
Directed Mapped
Full Associative
Set Asscociative

1. 直接映射

在直接映射(directed mapped)缓存中,每个主存块只能映射到缓存中的一个特定缓存块。这意味着每个主存块只有一个缓存块可以存储它。

例子

假设我们有一个 256KB 的缓存,其中每个缓存块是 64B,对于直接映射的cache:

  • 缓存被分为 256KB / 64B = 4096 个缓存块。
  • 内存中的数据可以直接映射到这 4096 个位置中的其中一个,比如第 10000 个主存块映射到 10000 % 4096 = 1808个缓存块。
  • 当一个新的数据块需要被加载时,它会替换掉当前映射到该位置的数据块,不管缓存的其他位置是否为空。

2. 全相联映射

在全相联缓存(full associative)中,主存中的任何块可以映射到缓存中的任何缓存块。这意味着主存块的地址没有限制,可以映射到任何可用的缓存块。

例子

假设我们有一个 256KB 的缓存,其中每个缓存块是 64B,对于全相联映射的cache:

  • 缓存被分为 256KB / 64B = 4096 个缓存块。
  • 全相联缓存中的每个主存块可以放置在任何缓存块中,即第 0 到第 4095 个缓存块都可以存储该主存块。
  • 当缓存满时,基于某种替换策略替换掉 4096 个缓存块中的某一个。

3. 组相联映射

组相联缓存(set associative 或 group associative)是直接映射缓存和全相联缓存之间的一种折中方案。它将缓存块分为多个组,每个组包含多个缓存块。主存块可以映射到组中的一个缓存块。

N 路组相联

当我们说一个缓存是 N路组相连 的,意味着缓存被分为多个组,每个组有N个缓存块(N路)。这样,当一个内存地址被映射到一个特定的组时,它可以放在该组的任何一个缓冲块(一路)上。如果一个组是满的,新的数据会根据某种替换策略来替换组中的一个缓存块。

例子

假设我们有一个 256KB 的缓存,其中每个缓存块是 64B,我们希望有 4 路组相联的组织。

  • 这意味着缓存被分为 256KB / 64B = 4096 个缓存块。
  • 因为是 4 路组相联,所以这些块被进一步组织为 4096 / 4 = 1024 个组。
  • 每个组包含 4 个位置(即 4 路),任何内存地址映射到这个组的时候,可以放在这四个位置中的任何一个。
  • 比如第 10000 个主存块位于第 10000 % 1024 = 784个组,可能对应组内的任何一个缓存块。

cache 地址结构

当给定一个物理地址时,需要判断该地址对应的主存块可能被哪些 cache 块所缓存,并且检查所有可能的 cache 块的 tag 字段以判断是否被缓存,所以 cache 地址的结构从逻辑上可以分为如下部分:

  • 标记(tag):判断当前地址是否命中对应的 cache 块
  • cache 块匹配字段:通过该字段判断主存块可能被哪些 cache 块缓存
    • 对于直接映射为块号(cache block number):位数为$log_2{(\text{cache 块数量})}$
    • 对于全相联映射为空,因为每一个主存块都可能被任何一个 cache 块所缓存
    • 对于组相联映射为组号(group number):位数为$log_2{(\text{组数})}$
  • 块内地址(block offset):物理地址在主存块内的偏移

总结三种不同映射方式的地址结构如下:

tag
cache block index
block offset
tag
group index
block offset
block offset
tag
block offset
memory block index
Cache 物理地址格式
内存物理地址格式
直接映射
全相联
组相联

cache 存储结构

cache 的存储结构可以理解为一张表:

有效位
标记Tag
修改位
访问位
数据块
1
0x7498
1
0b00
block 30
0
0x0A82
0
0b10
block 4
1
0x89E2
0
0b11
block 12

其中字段的含义与页表近似:

  • 有效位:该 cache 行是否存储有缓存数据,位数为1位。
  • 标记:根据物理地址中的 tag 字段与该字段匹配,以判断是否命中,位数按照cache地址结构进行计算。
  • 修改位:标记该 cache 是否修改过,与写策略相关。
    • 如果采用全写法,则无需设置修改位。
    • 如果采用写回法,设置1位修改位。
  • 访问位:用于记录访问信息,服务于块替换算法,其位数取决于替换算法。
    • 如果采用LRU替换算法,则修改位的位数为$log_2{(\text{主存快对应的缓存块数量})}$。
  • 数据块:缓存的数据块,为物理内存中数据块的一个副本。

cache 中的块替换算法

块替换算法适用于全相联映射和组相联映射,因为一个主存块可能被多个cache块中的某一个 所缓存,查询和替换过程如下:

  • 根据 cache 块匹配字段找到所有可能缓存 该物理地址对应主存块 的 cache 块
  • 遍历所有可能缓存该主存块的cache块
    • 如果cache块的有效位为0,则替换该cache块,将主存块加载进来,并将有效位设置为1,停止遍历
    • 如果cache块的tag字段与物理地址的tag字段相匹配,则表示该次地址查询命中cache,停止遍历
  • 如果遍历完所有cache块都无法满足如上条件时,则根据块替换算法选择一个cache块进行替换

当我们访问一个物理地址时未命中时,需要将对应的主存块加载到 cache 中,如果这个该主存块对应的 cache 块都满了的话,就需要替换掉其中的某个 cache 块,替换算法包含如下种类:

  • LRU
  • FIFO
  • 随机算法
  • LFU

这里的具体思想与操作系统中的页面置换算法一致,请参考页面置换算法

cache 写策略

cache 的写策略代表当我们对某个物理地址上的数据进行写入时,应该如何写入对应的存储单元,以及如何协调cache和主存之间的数据一致性,写策略按照地址查询是否命中cache可以分为四种方式。

如果某次地址查询命中 cache,可以使用如下策略:

  • write-through(全写法):每次写操作都会同时更新缓存和主存。
  • write-back(回写法):当数据被修改时,它首先被缓存在 cache 中,只有当 cache 块被替换时才写入对应的主存块。

如果没有命中 cache,也有如下策略:

  • write-allocate(写分配):物理地址对应主存块被加载到 cache 块中(先执行一次对应主存块的读操作),然后更新 cache 块
  • not-write-allocate(非写分配):不加载主存块至 cache 中,直接更新主存块,只有当执行读操作时才将主存块加载进入cache块

命中和未命中的方法常常通过如下方式一起使用:

  • 全写法(write-through)和非写分配法(not-write-allocate)通常会一起使用,适用于那些写操作不频繁或者写操作不太可能访问同一数据的情况。
  • 回写法(write-back)和写分配法(write-allocate)通常会一起使用,适用于那些写操作频繁的情况。

不同映射方式对比

特点直接映射缓存全相联缓存组相联缓存
映射方式1 对 1(一对一)N 对 1(N 对一)N 对 M(N 对 M)
缓存块的数量有限数量高度可变有限数量
主存块到缓存块的映射关系固定的任意的部分灵活
缓存冲突可能发生避免可能部分发生
硬件复杂度较低介于两者之间
查找速度相对较慢介于两者之间
成本介于两者之间
性能优点简单、低成本无缓存冲突、高性能较低的缓存冲突,性能适中
主要应用场景低级别缓存高级别缓存通用用途

视频讲解

3.5 - 虚拟存储器

重点内容,每年都会在大题中考察,与操作系统内存管理放在一起复习。

虚拟存储器

虚拟存储器是一种计算机内存管理技术,它在物理内存和磁盘存储之间创建了一个抽象的、扩展的内存空间,以提供更大的可用内存容量。

虚拟内存和物理内存

  1. 虚拟内存(Virtual Memory):
    • 虚拟内存是一种计算机内存管理技术,它将计算机的物理内存扩展到磁盘上,从而提供了更大的可用内存空间。
    • 每个进程拥有自己的虚拟地址空间,这个地址空间通常比物理内存大得多。
    • 进程使用虚拟地址来访问内存中的数据和指令,而不需要了解物理内存的详细情况。
  2. 物理内存(Physical Memory):
    • 物理内存是计算机上实际存在的内存硬件,包括 RAM(随机存储器)芯片和其他存储设备。
    • 物理内存是计算机硬件用来存储正在运行的进程和操作系统内核的数据和指令的地方。
    • 物理地址是实际的内存地址,对应于计算机硬件上的存储器芯片中的位置。
stack
stack
Virtual address space
Virtual address space
Physical address space
Physical address space
heap
heap
text
text
page belonging to process
page belonging to process
page not belonging to process
page not belonging to process
Text is not SVG - cannot display

页式虚拟存储器

地址翻译机构

CPU
MMU
Virutal
address
(VA)
4100
CPU Chip
Physical
address
(PA)
Address
Translation
0
1
2
3
4
5
6
7
8
M - 1

CPU 中的内存管理单元(Memory Management Unit,MMU)是计算机体系结构的重要组成部分,它负责虚拟内存到物理内存的地址映射和内存访问的控制。MMU 的主要功能包括:

  • 地址转换:MMU 负责将程序使用的虚拟地址转换为对应的物理地址。
  • 地址保护:MMU 实施内存保护策略,以确保不同的程序或进程无法越界访问彼此的内存空间。
  • 内存访问权限:MMU 根据地址映射和保护位(在页表或段表中定义)来控制内存访问权限,包括读、写、执行等。

页表

页表(page table)是操作系统维护的一张表,用于将虚拟地址转化为物理地址,每个运行的进程都有自己页表。 进程的页表存储在其内存空间中的内核空间中, 详见进程内存空间。 在进程执行时,MMU 使用当前活动进程的页表来执行地址转换。

单级页表

单级页表结构

一个典型的页表结构如下图所示:

VPN
PPN
Valid
Dirty
Access
Proctect
Cached
0x000
0x1A4
1
1
1
RO
Cached
0x001
0x3EF
1
0
0
RW
Non-cached
0x002
0x0D8
1
0
0
RW
Cached
0x003
0x000
0
1
1
RO
Non-cached
虚拟页号
物理页号
有效位
修改位
访问位
保护位
缓存位
PTE 0
PTE 1
PTE 2
PTE 3

页表中的每一行叫做页表项(PTE, page table entry),页表项可包含如下内容:

  • 虚拟页框号(VPN,Virtual Page Number):对于单级页表而言,VPN 并不需要实际存储在页表的字段中,其隐性地作为页表项的下标进行存储。
  • 物理页框号(PPN,Physical Page Number):当前 VPN 所对应的物理页号。
  • 有效位(Valid Bit):有效位用于指示虚拟页是否有效。如果有效位为 1,表示虚拟页是有效的,可以用于地址转换。如果有效位为 0,表示虚拟页无效,访问它会导致错误。
  • 修改位(Dirty Bit):修改位用于指示虚拟页的内容是否已被修改。如果修改位为 1,表示虚拟页的内容已被更改,可能需要写回到磁盘或其他非易失性存储介质。
  • 访问位(Accessed Bit):访问位用于指示虚拟页是否已被访问。如果访问位为 1,表示虚拟页已被访问。这对于操作系统的页面置换算法很有用。
  • 保护位(Protection Bits):保护位用于指定虚拟页的访问权限,例如读取、写入或执行权限。这有助于操作系统实施内存保护策略。
  • 缓存位(Caching Bits):缓存位用于指示是否允许将虚拟页的内容缓存在高速缓存中。这有助于控制内存访问的性能。
通过单级页表的地址翻译过程

虚拟地址和物理地址的格式

  • 虚拟地址(Virutal Address)分为两个部分:
    • 虚拟页框号(VPN, Virtual Page Number):当前地址所在的页框在虚拟内存对应的所有页框中的下标
    • 页内偏移(VPO, Virutal Page Offset):地址在页面内的偏移
  • 物理地址(Physical Address)同样分为两个部分:
    • 物理页框号(PPN, Physical Page Number):当前地址所在的页框在物理内存对应的所有页框中的下标
    • 页内偏移(PPO, Physical Page Offset):地址在页面内的偏移

地址翻译过程

PPO 和 VPO 的内容一致,所以地址翻译主要在于通过将 VPN 转化为 PPN,VPN 的值为对应的页表项(PTE)在页表中下标,在找到对应的页表项后,判断 Valid 字段是否为 1:

  • 如果为 0 的话,调用缺页中断
  • 如果为 1 的话,读取其中的 PPN,完成地址翻译
Virutal Page number (VPN)
Virutal Page number (VPN)
Virtual page offset (VPO)
Virtual page offset (VPO)
Physical page number (PPN)
Physical page number (PPN)
Physical page offset (PPO)
Physical page offset (PPO)
Valid
Valid
Physical page number (PPN)
Physical page number (PPN)
The VPN acts
as an index into
the page table
The VPN acts...
Page
Table
Page...
If valid = 0,
then page
not in memory
(page fault)
If valid = 0,...
Text is not SVG - cannot display

多级页表

单级页表会有什么问题?

在单级页表中,为了管理大型虚拟地址空间,需要创建庞大的页表,其中包含了大量的页表项,这会导致页表本身需要占用大量的内存空间。

假如我们有一个 32 位 4GB 的虚拟地址空间、4KB 的页面和一个 4 字节的 PTE,那么我们将需要一个 4MB 的页面表始终驻留在内存中,即使应用程序只引用虚拟地址空间的一小块。

多级页表结构

VPN 1
VPN 1
VPN 2
VPN 2
· · ·
· · ·
VPN k
VPN k
VPO
VPO
PPN
PPN
Level 1
page table
Level 1...
Level 2
page table
Level 2...
Level k
page table
Level k...
PPO
PPO
PPN
PPN
Virtual Address
Virtual Address
Physical Address
Physical Address
Text is not SVG - cannot display

在多级页表中,虚拟页号 VPN 被分割为多个字段,假设被分割为 k 个字段的话,第 k 个字段对应的页表中的查询内容为 PPN,前 k-1 个字段对应的页表中的查询内容为下一级页表的位置。

如果当前多级页表对应的一级页表有 $m^k$ 个 PTE,将 VPN 分割为 k 个长度相同的子字段后,每个子字段对应的页表的 PTE 个数为$log_k{m^k} = m$。

其中,第一层有 $m$ 个页表,第二层最多有 $m^2$ 个页表在内存中存在, $\cdots$ ,第 k 层最多有 $m^k$ 个页表在内存中存在。

多级页表是如何节省内存的?

PTE 0
PTE 0
PTE 1
PTE 1
PTE 2 (null)
PTE 2 (null)
PTE 3 (null)
PTE 3 (null)
PTE 4 (null)
PTE 4 (null)
PTE 5 (null)
PTE 5 (null)
PTE 6 (null)
PTE 6 (null)
PTE 7 (null)
PTE 7 (null)
PTE 8
PTE 8
(1 K-9)
null PTEs
(1 K-9)...
PTE 0
PTE 0
· · ·
· · ·
PTE 1023
PTE 1023
PTE 0
PTE 0
· · ·
· · ·
PTE 1023
PTE 1023
1023 null PTEs
1023 null PTEs
PTE 1023
PTE 1023
VP 0
VP 0
· · ·
· · ·
VP 1023
VP 1023
VP 1024
VP 1024
· · ·
· · ·
VP 2047
VP 2047
Gap
Gap
1023
unallocated
pages
1023...
VP 9215
VP 9215
Level 1
page table
Level 1...
Level 2
page tables
Level 2...
Virtual
memory
Virtual...
2K allocated VM pages
for code and data
2K allocated VM pages...
6K unallocated VM pages
6K unallocated VM pages
1023 unallocated pages
1023 unallocated pages
1 allocated VM page
for the stack
1 allocated VM page...
Text is not SVG - cannot display

只有一级页表需要始终在主存中,对于其他层次的页表,可以按需分配,如果使用到的,就在内存中创建对应的页表结构,如果没使用到,就不需要为其分配内存。 这代表了巨大的潜在节省,因为典型程序的 4GB 虚拟地址空间中的大部分都是未分配的。

对于 k 级页表而言,前 k-1 级页表中 PTE 存储的关键字段都是下一级页表的位置,如果其中某个 PTE 的有效位为 0 的话, 那么操作系统无需为该页表项对应的下一级页表分配内存空间。

TLB

TLB(Translation Lookaside Buffer)是 CPU 内存管理单元(MMU)中的一种高速缓存,用于加速虚拟地址到物理地址的地址转换过程。 TLB 存储了最近用过的虚拟地址到物理地址的映射,以减少每次内存访问时的地址翻译延迟。

TLB 和页表的关系类似于 cache 与主存的关系,TLB 是一个有限大小的高速缓存,存储着页表中最近使用的某些页表项的副本。

由于页表存储在内存中,所以每一次通过页表的地址翻译过程都至少需要一次访存,开销还是比较大的。 所以为了降低这个开销,TLB 就应运而生,与 Cache 类似,你可以从概念上将 TLB 理解成一个硬件结构,与 Cache 类似,因为离 CPU 更近,所以其访问速度感更快。

如下图所示,TLB 将虚拟页号 VPN 从逻辑上分为两个部分:

  • 标记(TLBT, 即 TLB Tag):判断当前 VPN 是否命中 TLB 中的缓存项
  • 匹配字段(Match Field),通过该字段判断 VPN 可能被哪些 TLB 表项所缓存,这里 TLB 与 Cache 类似,同样具有三种映射方式,每一种映射方式匹配字段会具有不同的位数。
    • 对于直接映射,匹配字段为 TLB 表项编号,即行编号(TLB entry index),其位数为 $log_2{(\text{\small TLB 行数})}$
    • 对于全相联映射,匹配字段位数为 $\text{\small 空}$,因为每一个 VPN 都可能被任何一个 TLB 行所缓存
    • 对于组相联映射,匹配字段为组号(TLB group index),位数为 $log_2{(\text{\small TLB 组数})}$
Page Table
TLB Tag (TLBT)
Match Field
VPN
TLBT
PPN
TLB
Match Field
决定了可以去哪些行去寻找
以判断是否命中
PPN
PPO
若命中,则加载对应行的PPN
以完成地址翻译
VPO = PPO
MMU
VPN
VPO
Main Memory
未命中则通过页表
完成地址翻译

TLB 由许多表项(TLB Entry)构成,其表项个数决定了其容量大小。每一个表项包含两个字段,第一个是字段标志 TLBT(TLB Tag)字段,这里的标志字段与上文对于 VPN 的划分中的 TLBT 是相同的东西。 第二个字段是 PPN(物理页号),若进行地址翻译时命中 TLB 的某一行,则加载这一行的 PPN 以替换虚拟地址中的 VPN,实现地址翻译。

请求页式管理

请求页式管理(Demand Paging)是一种计算机操作系统中的内存管理技术,它允许进程在需要时才将页面(或者说虚拟内存中的数据块)加载到物理内存中,而不是一次性将整个进程加载到内存中。这个概念的核心思想是,将物理内存划分成固定大小的页框(page frame),并将虚拟内存划分成相应大小的页面(page)。

页面错误

当进程尝试访问一个虚拟页面,但该页面当前未加载到物理内存中时,会触发页面错误(page fault)。此时,操作系统会将相应的页面从磁盘加载到物理内存,进行页面替换。

那么如何判断访问的页面是否在物理内存中呢?

通过 查询 TLB页表 以判断某个虚拟地址对应的页面是否在内存中。

从虚拟地址(VA)中提取出虚拟页号(VPN),再查询 TLB 和 页表中是否存在包含 VPN 的记录。如果存在的话,则说明待访问的虚拟页面在内存中,否则就不在。

页面替换

如果物理内存已满,操作系统需要选择一个页面来替换。通常,操作系统会选择一个不再需要的页面进行替换,这个决策基于使用的页面替换算法

地址翻译过程

a
开始
虚拟地址越界
中止进程
YES
VPN 命中 TLB
NO
更新页表
更新 TLB
获取 PPN
结束
VPN 命中页表
NO
在内存中选择页面
内存是否存在
空闲页面?
页面替换算法选择
页面B
YES
将 B 写入磁盘
B的脏位是否为1?
将页面A写入B
所在的内存空间
选择空闲页面
将页面A写入
空闲页面
缺页中断处理过程
地址翻译过程

总的来说,地址翻译过程包含如下阶段:

  • CPU 尝试从 TLB 查找虚拟地址到物理地址的映射。
  • 如果没有命中 TLB,系统查找页表。
  • 如果没有命中 页表,会产生一个缺页中断。
    • 如果内存存在空闲页面,直接使用空闲页面
    • 否则使用页面置换算法选择一个页面以进行置换
  • 根据查询结果更新 TLB 和 页表 中的行。

访存过程

访存过程常常和地址翻译过程放在一起考察,在进程访问一个虚拟地址时,首先完成地址翻译得到物理地址,然后就是使用这个物理地址去访问内存。

访问内存时首先需要去判断 cache 是否命中,如果没有命中的话,就去访问内存,然后再更新 cache,详细过程如下图所示。

开始
找到相应的 cache 行
并匹配 tag 字段
判断是否命中?
使用 cache 地址格式
解析物理地址
使用物理地址
访问相应内存单元
结束
命中
未命中
找到物理地址
对应的主存块
主存地址对应的 cache 块
是否有空闲?
直接更新空闲块
使用替换策略
找到一个cache块
进行替换
访存过程
cache更新过程
结束

如果将 地址翻译过程 和 访存过程放在一起的话,使用一个虚拟地址访问内存,大致包含如下流程(这里 ? 表示不一定会发生):

虚拟地址 → TLB → (页表)? → (缺页中断)? → 物理地址 → Cache → (内存)? → (更新Cache)?

视频讲解

4 - 指令系统

本章也是重点,常常在大题中与CPU放在一起考察。需要熟练掌握指令的格式以及寻址方式,并且能够根据题目灵活应变。
# 指令系统

## 基本概念

## 指令格式

## 寻址方式

## 数据的对齐和大小端存放方式

## CISC和RISC

## 高级程序语言与机器代码之间的对应

- 编译器、汇编器和链接器
- 选择结构语句
- 循环结构语句
- 过程调用对应的机器级表示

4.1 - 指令格式和寻址方式

指令格式是计算机组成原理中的重点考察内容,需熟练掌握,熟练张常常在大题中与 CPU 的知识交叉考察。

计算机程序的执行过程

计算机程序的生命周期通常包括编译(compile)、汇编(assemble)、链接(linking)和执行(execute)等阶段。这些阶段是构建和运行程序的重要步骤。以下是这些阶段的简要说明:

  1. 编译(Compile):
    • 编译是将高级编程语言(如 C、C++、Java 等)源代码翻译为目标机器的汇编语言或机器代码的过程。
    • 编译器(如 GCC、Clang、Visual C++)负责将源代码转化为目标代码,并生成一个中间表示,如汇编语言或机器码。
    • 这个阶段的目标是检查源代码中的语法错误和逻辑错误,并生成可执行程序的中间文件。
  2. 汇编(Assemble):
    • 汇编是将汇编语言源代码(通常是由编译器生成的中间表示)转化为机器码的过程。
    • 汇编器(如 NASM、MASM)负责将汇编语言代码转化为可执行程序所需的机器码。
    • 这个阶段的目标是将源代码翻译为可执行代码,并生成一个目标文件。
  3. 链接(Linking):
    • 链接是将程序的不同部分(如多个源代码文件、库文件等)组合在一起,以创建最终的可执行程序的过程。
    • 链接器(如 ld、linker)负责解析程序中的符号引用,将它们与符号定义(如函数、变量)关联起来,以创建一个完整的可执行文件。
    • 这个阶段的目标是解决符号引用,创建可执行程序,并将各种模块整合到一个单独的可执行文件中。
  4. 执行(Execute):
    • 执行是将最终生成的可执行程序加载到内存中,并由计算机的中央处理单元(CPU)执行的过程。
    • 操作系统负责加载可执行程序,并将控制权转交给程序的起始点。
    • 可执行程序的指令将由 CPU 执行,从而实现程序的功能。

指令的格式

Opcode
Address
zero address
OP
one address
OP
A1
two address
OP
A1
A2
three address
OP
A1
A2
A3

指令中主要包含两个部分:操作码(opcode)以及 地址(address)。

这里地址是一个通用含义,指的是操作的对象,可以是一个内存地址,也可以是 CPU 中的一个寄存器。

指令类型

根据指令中的地址个数,可以将指令划分为以下类型。

指令格式含义
零地址指令$OP$
一地址指令$OP(A_1) \rightarrow A_1$
二地址指令$(A_1)OP(A_2) \rightarrow A_1$
三地址指令$(A_1)OP(A_2) \rightarrow A_3$

指令根据其操作码(opcode)的不同可以分为以下类别:

  1. 数据传输指令
    • MOV:将数据从一个位置传输到另一个位置,可以是寄存器到寄存器、内存到寄存器、寄存器到内存等。
    • PUSH:将数据(通常是寄存器中的值)推入堆栈。
    • POP:从堆栈中弹出数据并存储到寄存器中。
  2. 算术和逻辑运算指令
    • ADDSUBMULDIV:执行算术运算,如加法、减法、乘法和除法。
    • ANDORXORNOT:执行逻辑运算,如按位与、按位或、按位异或和按位取反。
    • INCDEC:递增和递减操作数的值。
    • CMP:用于比较两个值,并根据结果设置标志寄存器的状态。
  3. 控制转移指令
    • JMP:用于无条件跳转到指定的目标地址。
    • Jxx:条件跳转指令,根据特定的条件(如零标志、进位标志等)来决定是否跳转。
    • CALL:调用子程序或函数。
    • RET:从子程序返回。
  4. 输入/输出指令
    • IN:从外部设备或端口读取数据。
    • OUT:向外部设备或端口发送数据。
  5. 字符串操作指令(String Instructions):
    • MOVSLODSSTOSCMPS:用于在内存中执行字符串操作,如移动、加载、存储、比较。
  6. 陷阱指令(Trap Instructions):
    • INT:用于引发中断,通常用于与操作系统进行通信。
  7. 协处理器指令(Coprocessor Instructions):
    • CLISTI:用于清除和设置 CPU 的中断标志,通常只能在内核模式下执行。

寻址方式

计算机中的寻址方式(Addressing Modes)是指在指令中如何指定操作数的位置或地址。

寻址方式描述示例
立即寻址操作数直接包含在指令中。MOV R1, #5 (将5加载到R1寄存器)
寄存器寻址操作数在寄存器中。ADD R1, R2 (R2加到R1中)
直接寻址操作数的内存地址直接包含在指令中。MOV R1, [1000] (从内存地址1000取数据)
间接寻址操作数的地址由指令指定的内存地址提供,指令通过这个地址访问操作数。MOV R1, [R2] (R2中存储的是操作数的地址)
寄存器间接寻址操作数的地址存储在寄存器中,指令通过寄存器访问内存中的数据。MOV R1, [R2] (R2寄存器中是内存地址)
基址寻址使用基址寄存器和偏移量计算操作数的实际地址。MOV R1, [R2 + 4] (基址R2加偏移4)
变址寻址通过基址寄存器和索引寄存器的和来确定操作数地址,常用于数组操作。MOV R1, [R2 + R3] (R2与R3相加)
相对寻址操作数地址通过程序计数器(PC)当前值加上指令中的偏移量计算,常用于跳转指令。JMP LABEL (跳转到相对地址)
堆栈寻址通过堆栈顶指针(SP)来访问操作数,常用于函数调用和返回。PUSH R1 (将R1压入堆栈)

4.2 - 数据对齐方式

熟练掌握数据对齐和大小端,可能会在选择题考察,也会在大题中间接考察。

数据对齐

数据对齐是指数据在内存中的存放方式,它要求数据的起始地址必须是某个数(通常是4或8)的整数倍,这个数被称为对齐因子(Alignment Factor)或对齐边界(Alignment Boundary)。数据对齐的目的是为了提高内存访问的效率,因为许多计算机系统都是按照数据的对齐边界来设计内存访问硬件的。

不对齐的数据访问可能会导致性能下降,因为处理器可能需要额外的内存访问来获取不完整的数据。在一些严格要求数据对齐的架构中,不对齐的数据访问甚至会导致硬件异常。

例如,假设一个整数(int)占用4个字节,那么在内存中的起始地址就应该是4的倍数,如0x1004、0x1008等。

大小端

大小端(Endianness)是指多字节数据在内存中的字节序,也就是字节的排列顺序。主要有两种存放方式:

  • 大端模式(Big-Endian): 数据内部的高位字节存放在低位地址,低位字节存放在高位地址。也就是说,一个整数的第一个字节(最高有效字节)将存放在起始地址处。
  • 小端模式(Little-Endian): 数据内部的低位字节存放在低位地址,高位字节存放在高位地址。也就是说,一个整数的最后一个字节(最低有效字节)将存放在起始地址处。

举一个例子,假如定义数组 long a[2] = {0x76543210, 0xFEDCBA98}long 类型的大小为8字节,数组 a 在内存中的起始地址为 0x1000,则数组中两个元素在内存中的字节排列如下图所示:

0x10
0x32
0x54
0x65
0x00
0x00
0x00
0x00
0x00
0x00
0x00
0x00
0x76
0x54
0x32
0x10
0x89
0xBA
0xDC
0xFE
0x00
0x00
0x00
0x00
0x00
0x00
0x00
0x00
0xFE
0xDC
0xBA
0x89
0x1000
0x1000
0x1008
0x1008
Little Endian
Big Endian

大小端的选择通常是由计算机的CPU架构决定的,不同的架构有不同的字节序要求。例如,Intel x86和x86-64架构是小端,而网络协议通常是大端,因为大端的格式在字节流中的表示更加直观。

4.3 - CISC和RISC

了解CISC和RISC的概念,可能在选择题中考察。

CISC(Complex Instruction Set Computer)和 RISC(Reduced Instruction Set Computer)是两种不同的计算机体系结构设计哲学,它们在指令集架构和执行方式上有显著的差异。以下是它们的主要特点和区别:

CISC

  1. 指令集复杂:CISC计算机的指令集非常丰富,包含大量复杂的指令,其中一条指令可以执行多种操作,包括内存访问、算术运算、逻辑运算等。
  2. 多寻址模式:CISC指令通常支持多种寻址模式,允许直接访问内存,因此可以在一条指令中执行复杂的操作。
  3. 微程序控制:CISC计算机通常使用微程序控制单元,指令解码和执行过程相对复杂。
  4. 复杂硬件:CISC处理器通常包括大量的硬件单元,用于支持复杂的指令集,这使得CISC芯片相对较大。

RISC

  1. 指令集精简:RISC计算机的指令集更加精简,通常包含较少、更简单的指令。每条指令只执行一种操作。
  2. 固定寻址模式:RISC指令通常只支持一种或者很少种寻址模式,鼓励将数据加载到寄存器中后再执行操作。
  3. 硬布线控制:RISC计算机使用硬布线控制单元,指令解码和执行过程较为简单。
  4. 精简硬件:RISC处理器通常采用更精简的硬件,以提高性能和降低成本。

主要区别和优点:

  • CISC体系结构通过提供复杂的指令来减少编程工作,但它们可能会导致较慢的执行速度和复杂的硬件设计。
  • RISC体系结构通过简化指令集和加速执行来提高性能,但需要更多的指令以执行相同的任务。

4.4 - 高级语言和机器码

掌握从高级语言到机器代码的翻译过程,也需了解C语言中不同语句与汇编代码的对应关系,可能在大题中出现,能看懂就行。

编译器、汇编器、链接器

编译器 (Compiler)

编译器是一个软件程序,它将用高级程序设计语言(如C、C++、Java)编写的源代码转换为低级语言(通常是汇编语言)。编译器主要进行以下工作:

  1. 词法分析 (Lexical Analysis):将源代码分解成一系列的记号(tokens)。
  2. 语法分析 (Syntax Analysis):将记号组织成语法树,检查代码的语法结构。
  3. 语义分析 (Semantic Analysis):检查代码的语义正确性,比如类型检查。
  4. 优化 (Optimization):对代码进行优化,提高效率,减少资源消耗。
  5. 代码生成 (Code Generation):将优化后的代码转换为目标机器的汇编语言。

例如,GCC(GNU Compiler Collection)和MSVC(Microsoft Visual C++)都是流行的编译器。

汇编器 (Assembler)

汇编器是将汇编语言转换为机器语言的程序。因为汇编语言中的指令基本上是机器指令的直接映射(只是用符号代替了二进制代码),所以汇编器主要工作是:

  1. 解析指令:识别汇编代码中的指令和数据定义。
  2. 符号解析:解析标签和符号,将它们转换成地址或者数值。
  3. 生成机器代码:将汇编指令和操作数转换为对应的机器码。

链接器 (Linker)

链接器的作用是将由编译器生成的一个或多个目标代码文件(通常是汇编器生成的机器代码)合并为一个单一的可执行文件。在这个过程中,链接器:

  1. 解析外部引用:将不同代码模块之间相互引用的部分关联起来。
  2. 地址和存储分配:确定代码和数据在内存中的位置。
  3. 符号绑定:将程序中的符号(如函数和变量名)绑定到它们对应的内存地址。
  4. 重定位:调整代码和数据的引用,使它们指向正确的地址。
  5. 库链接:将程序使用的库中的代码合并到最终的可执行文件中。

链接器可以是静态链接器,它在程序开始执行之前完成所有的链接工作;也可以是动态链接器(运行时链接器),它在程序执行时进行链接。

选择结构语句

if (a > b) {
    max = a;
} else {
    max = b;
}
; 假设a, b的值分别存放在寄存器eax和ebx中
cmp eax, ebx         ; 比较a和b
jle else_label       ; 如果a <= b, 跳转到else_label
mov max, eax         ; a > b, max = a
jmp endif_label      ; 跳转到endif_label
else_label:
mov max, ebx         ; max = b
endif_label:

循环结构语句

while (count < 10) {
    count++;
}
; 假设count的值存放在寄存器ecx中
loop_start_label:
cmp ecx, 10          ; 比较count和10
jge loop_end_label   ; 如果count >= 10, 跳出循环
inc ecx              ; count增加
jmp loop_start_label ; 无条件跳回循环开始
loop_end_label:

过程调用

在汇编中调用函数包含如下步骤:

  • 参数传递:在函数调用之前,将参数值放入寄存器或栈中。
  • 调用指令:使用call指令将控制转移到函数的代码。

过程调用内部包含如下步骤:

  • 堆栈帧设置:在函数的开始处,设置局部变量所需的堆栈帧。
  • 执行函数体:执行函数中的代码。
  • 返回值处理:将函数的返回值放在一个特定的位置,通常是一个寄存器。
  • 堆栈帧恢复和返回:恢复调用者的堆栈帧并执行ret指令,这会跳转回调用点。

以下举一个实际的例子(了解即可):

int add(int x, int y) {
    return x + y;
}

void exampleFunction(int a, int b) {
    int sum = add(a, b);
    int localVariable = sum * 2;
    // ... 一些使用localVariable的代码 ...
}

// 调用exampleFunction
exampleFunction(10, 20)
; 假定 'a' 和 'b' 作为参数通过堆栈传递

.globl _add
_add:
    push ebp                ; 保存旧的基指针
    mov ebp, esp            ; 设置新的基指针
    mov eax, [ebp+8]        ; 将参数x移到eax,参数x在ebp+8的位置
    add eax, [ebp+12]       ; 将参数y加到eax中,参数y在ebp+12的位置
    pop ebp                 ; 恢复旧的基指针
    ret                     ; 返回,返回值在eax中

.globl _exampleFunction
_exampleFunction:
    push ebp                ; 保存旧的基指针
    mov ebp, esp            ; 设置新的基指针
    sub esp, 8              ; 在堆栈上分配8字节空间给局部变量

    ; 准备参数并调用 'add'
    push dword [ebp+12]     ; 将参数b压栈
    push dword [ebp+8]      ; 将参数a压栈
    call _add               ; 调用 'add'
    add esp, 8              ; 清理传递给 'add' 的参数

    ; 将返回值 'sum' 存储到局部变量
    mov [ebp-4], eax        ; 将eax的值('add' 的返回值)存储在 'sum' 的位置

    ; 创建另一个局部变量 'localVariable' 并计算 'sum * 2'
    mov eax, [ebp-4]        ; 将 'sum' 移到eax
    shl eax, 1              ; 将eax左移1位,相当于乘以2
    mov [ebp-8], eax        ; 将结果存储到 'localVariable'

    ; ... 更多使用 'localVariable' 的代码 ...

    ; 函数完成,清理堆栈,并恢复ebp
    mov esp, ebp            ; 重置堆栈指针
    pop ebp                 ; 恢复基指针
    ret                     ; 返回

; 函数调用的汇编表示
; 假设要传递给 exampleFunction 的参数为 10 和 20
; 先将参数推入堆栈,注意在32位架构中调用约定通常是从右到左传递参数

push 20         ; 将第二个参数 b 压入堆栈
push 10         ; 将第一个参数 a 压入堆栈
call _exampleFunction ; 调用 exampleFunction 函数
add esp, 8      ; 清理堆栈,移除参数(每个参数4字节,总共8字节)

; 在这里执行之后的代码
; ...

视频讲解

5 - 中央处理器

本章是重中之重,几乎每年都会在大题和选择题中考察。需要熟练掌握CPU的结构、寄存器类型以及指令执行的流程,关于CPU的考察也常常和指令系统混合在一起,需要能够从一个高维的角度,思考CPU、指令、控制器以及外部设备的关系。
# CPU

## CPU的功能和基本结构

## 指令执行过程

## 数据通路的功能和基本结构

## 控制器的功能和工作原理

## 异常和中断机制

- 基本概念
- 分类
- 检测和响应

## 指令流水线

- 基本概念
- 基本实现
- 结构冒险、数据冒险和控制冒险
- 超标量和动态流水线的基本概念

## 多处理器基本概念

- SISD、SIMD、MIMD、向量处理器的基本概念
- 硬件多线程的概念
- 多核处理器的基本概念
- 共享内存多处理器的概念

## 总线和输入/输出系统

### 总线

- 基本概念
- 组成及性能指标
- 事务和定时

### I/O接口

- 功能和基本结构
- 端口及其编址

### I/O方式

- 程序查询方式
- 程序中断方式
- DMA方式

5.1 - 功能和结构

重点内容,需熟练掌握CPU的结构以及各个寄存器的作用,每年都会在大题中考察。

CPU基本结构

AX
BX
CX
DX
SP
BP
SI
DI
Internal Bus
Temporary Registers
ALU
Flags
CS
DS
SS
ES
IP
Instruction Queue
Segment
Registers
EU (Execution Unit)
BIU (Bus Interface Unit)
MAR
MDR
CU
IR
External
Bus

ALU

  1. EU(Execution Unit,执行单元):
    • EU是CPU的核心功能单元,它执行指令中的实际计算和操作。
    • EU包含算术逻辑单元(ALU),用于执行算术和逻辑运算,例如加法、减法、逻辑与、逻辑或等。
    • EU还包括寄存器文件,用于存储和操作寄存器中的数据,这些寄存器包括通用寄存器、标志寄存器等。
    • EU还包括控制单元,负责解码指令、管理数据流、控制寄存器和标志的更新,以及协调指令的执行。
  2. BIU(Bus Interface Unit,总线接口单元):
    • BIU是CPU的一个子单元,负责与外部系统和内存之间的数据传输以及地址总线和数据总线的管理。
    • BIU包含指令寄存器(IR,Instruction Register),用于存储当前正在执行的指令,以及内存地址寄存器(MAR,Memory Address Register)和内存数据寄存器(MDR,Memory Data Register),用于执行内存访问操作。
    • BIU通过控制地址总线和数据总线来实现内存和I/O设备之间的数据传输,以及将指令和数据加载到EU中供执行。

寄存器

寄存器类型

  1. 通用寄存器(General-Purpose Registers):
    • AX 寄存器:累加器(Accumulator),用于执行算术和逻辑运算。
    • BX 寄存器:基址寄存器(Base Register),通常用于存储内存地址。
    • CX 寄存器:计数寄存器(Counter Register),用于循环计数和移位操作。
    • DX 寄存器:数据寄存器(Data Register),用于输入/输出操作和大整数运算。
  2. 段寄存器(Segment Registers):
    • CS(Code Segment) 寄存器:代码段寄存器,存储指向代码段的地址。
    • DS(Data Segment) 寄存器:数据段寄存器,存储指向数据段的地址。
    • ES(Extra Segment) 寄存器:附加数据段寄存器,通常用于数据访问。
    • SS(Stack Segment) 寄存器:堆栈段寄存器,存储指向堆栈段的地址。
  3. 指针寄存器(Pointer Registers):
    • SI 寄存器:源变址寄存器,通常用于数据传送操作。
    • DI 寄存器:目的变址寄存器,也通常用于数据传送操作。
    • SP 寄存器:堆栈指针寄存器,用于堆栈操作。
    • BP 寄存器:堆栈基址寄存器,通常用于堆栈操作。
  4. 附加寄存器(Extra Registers):
    • IP(Instruction Pointer) 寄存器:指令指针寄存器,存储当前执行指令的偏移地址。
    • FLAGS 寄存器:标志寄存器,存储有关条件和状态的信息,例如进位、零标志、溢出等。
Process-specific data
structures
(e.g. page tables, tasks and kernel stack)
Physical Memory
Kernel code and data
User stack
Memory-mapped region
for shared libraries
Run-time heap
Uninitialized data (.bss)
Initialized data (.data)
Code (.text)
Different for
each process
Identical for
each process
Kernel
virtual
memory
Process
virtual
memory
low
address
space
high
address
space

标志寄存器(flag register)

OF
DF
IF
TF
SF
ZF
AF
PF
CF
16-bits Flag Register

什么时候会被设置?

标志寄存器主要有两个功能:

  • 条件标志:保存指令执行结果的状态。在执行条件分支、算数和逻辑、比较或移位指令后,条件标志都会被设置。
  • 控制标志:控制指令执行的行为

条件标志(conditional flags)

  • OF(Overflow flag)
    • 溢出标志。
    • 当有符号整数运算的结果太大而无法适应目标寄存器时,OF标志会设置为1,表示发生了溢出。
  • SF(Sign flag)
    • 符号标志。
    • 根据操作结果的符号位来设置,如果结果为负数,则SF被设置为1,否则为0。
  • ZF(Zero flag)
    • 零标志。
    • 当操作结果为零时,ZF标志被设置为1,否则为0。
  • AF(Auxiliary carry flag)
    • 辅助进位标志。
    • 通常用于BCD(二进制编码十进制)算术运算,指示低四位的进位。
  • PF(Parityh flag)
    • 奇偶校验标志。
    • 根据结果中二进制位1的个数是奇数还是偶数,设置PF标志。奇数个1则PF为1,偶数个1则PF为0。
  • CF(Carry flag)
    • 进位标志。
    • 当无符号整数运算的结果超出了目标寄存器的位数,CF标志被设置为1,表示发生了进位。

控制标志(control flags)

  • TF(Trap flag)
    • 控制单步执行。
    • 当TF被设置为1时,CPU将进入单步执行模式。在单步执行模式下,每执行一条指令后,CPU将引发一个单步中断,允许程序员逐条调试程序。
  • IF(Interrupt flag)
    • 控制中断处理
    • 当IF被设置为1时,CPU允许中断请求。如果IF为0,CPU将禁止所有中断请求,无论是外部硬件中断还是软件中断。
  • DF(Direction flag)
    • 字符串操作的标志位。
    • 当DF被设置为1时,字符串操作(如MOVS、LODS、STOS)在内存中向高地址方向移动。这通常用于从高地址向低地址扫描字符串。当DF被清除为0时,字符串操作在内存中向低地址方向移动。这通常用于从低地址向高地址扫描字符串。

5.2 - 控制器

需熟练掌握CPU在执行指令时是如何控制信号控制各个部件的,这个过程偶尔会在大题中考察。还需了解硬布线控制器和微程序控制器的概念,可能在选择题中考察。
IR
Data Bus
Address Bus
Control Bus
Input
Device
Memory
Output
Device
Flags

Clock
Control Unit

控制器是计算机系统的指挥中心,控制器的主要功能有:

  • 指令解码:CPU从存储器取出一个指令后,控制器负责解码这个指令,以确定要执行的操作和涉及的操作数。
  • 生成控制信号:基于解码的指令,控制器生成一系列的控制信号,这些信号会驱动其他计算机部分(如算术逻辑单元、寄存器和存储器)按预期执行相应的操作。
  • 指令执行的顺序和时序:通过先后发出不同的控制信号,确保指令的逻辑正确被执行,

根据控制器产生微操作控制信号方式的不同,控制器可以分为硬布线控制器和微程序控制器。

控制信号

概念

控制信号是由控制单元(Control Unit)生成和发出的电信号,这些信号用于指挥CPU内部的各种操作。例如,控制信号可以指示算术逻辑单元(ALU)执行加法还是减法,或者指示寄存器进行读写操作。

类型

其实控制信号的种类很多,但就目前阶段而言,会考察的可以被总结为三类控制信号:

  • 读写信号:对内存或IO设备进行读写,比如 MemRMemW
  • 寄存器选择信号:选择特定的寄存器进行读写操作,比如 PCinPCout
  • 操作码信号:示算术逻辑单元(ALU)执行哪种运算,如加法、减法、与、或等。
R4
R3
R2
R1
Internal Bus
T1
ALU
MAR
MDR
Control Unit
IR
External Bus
MARout
PC
MARin
MDRout
MDRin
PCout
PCin
Memory
MemOp
ALUop (such as add, sub)
IRin
MUX
Word Length
MUXop
T2
T1out
T1in
T2out
T2in
0
1

指令的不同执行阶段对应的控制信号

指令的执行包含取指、译码、执行、写回阶段,在这四个阶段中控制单元会发出不同的控制信号,以实现指令的执行。

以指令ADD R0, (R1)为例,说明一下指令执行阶段四个阶段的控制信号。

取指和译码阶段

时钟功能控制信号解释
C1MAR ← (PC)PCout, MARin从 PC 中读取指令地址至 MAR 中
C2MDR ← M(MAR)MemR, MDRin存储器从MAR地址所在的内存单元读取数据
并加载到MDR中
C3MUXop ← PCIncrPCIncr在二路选择器中生成值 1 添加入 ALU 的一端
C4T2 ← PC + 1MARout, T2in, AddALU 计算下一条指令的地址
C5PC ← T2T2out, PCin将计算得到的地址加载进 PC 中
C6指令译码由指令译码器件完成

执行和写回阶段

时钟功能控制信号解释
C7MAR ← R1R1out,MARin将 R1 中的内容加载进 MAR
C8MDR ← M(MAR)MemR, MDRin存储器从MAR地址所在的内存单元读取数据
并加载到MDR中
C9T1 ← R0R0out, T1in将 R0 的内容存储在暂存器 T1
C10T2 ← MDR + T1MDRout, MUXop,Add, T2inMDR的内容存储进入ALU另一个入口
执行加法操作
并将结果存储进入T2
C11R0 ← T2T2out, R0in将计算结果写回 R0

硬布线控制器

定义:硬布线控制器是通过组合逻辑电路来实现的,通常使用逻辑门、多路复用器、解码器等组合电路元件。

特点

  • 性能:因为是硬件实现,所以通常速度较快。
  • 固定功能:一旦设计和实现完成,修改它就比较困难,需要改变物理电路。
  • 设计复杂性:对于复杂的控制逻辑,硬布线控制器可能会变得非常复杂,难以设计和验证。

微程序控制器

定义:微程序控制器基于存储的微指令集来实现控制逻辑。它使用一块称为“控制存储器”或“微指令存储器”的特殊存储器来存储微指令。每一个微指令定义了一系列的控制信号。

特点

  • 灵活性:由于控制逻辑是存储在存储器中的,所以更改控制逻辑只需要更改存储的微指令,而无需更改硬件。
  • 简化设计:对于复杂的控制逻辑,使用微指令可能会简化设计和验证过程。
  • 性能:通常比硬布线控制器慢,因为它需要从控制存储器中读取微指令。
  • 易于修改和扩展:添加新的指令或修改现有的指令相对容易。

指令、微指令、微命令

微命令是计算机硬件控制的基础指令,用于控制某些硬件单元完成某种操作。

一条机器指令对应一个微程序,一个微程序由数条微指令构成,每个微指令可以包含数个微命令。

微指令编码方式

下地址
操作控制
控制信号
下地址
操作控制
译码
译码
译码
直接编码方式
字段直接编码方式
  1. 直接编码方式

微指令中的微命令字段中每位都代表一个微命令。

  1. 字段直接编码方式

将微指令的微命令字段分为若干小段,把互斥行微命令组合在同一字段中,把相容性微命令组合在不同字段中,每个字段独立编码,每种编码代表一个微命令且各字段编码含义单独定义。

5.3 - 异常与中断

需了解异常和中断的概念和区别,可能在选择题中考察。

异常

在CPU中,异常是指在执行程序时遇到的非常规或意外情况,需要操作系统介入以调整、中断或改变程序的正常执行流程。CPU会使用异常处理机制来处理这些情况。

类型

  1. 除法错误(Division Error)
    • 触发条件:程序尝试除以零或执行其他非法的除法操作时触发。
    • 处理:通常会中断程序运行,并可能通过操作系统给出错误信息。
  2. 缺页异常(Page Fault)
    • 触发条件:程序尝试访问的内存页不在物理内存中时触发。
    • 处理:操作系统将相应的内存页从磁盘加载到物理内存中,并更新页表。
  3. 无效指令(Invalid Instruction)
    • 触发条件:CPU遇到未被定义或不可执行的指令时触发。
    • 处理:通常会中断程序的执行,并可能给出错误信息。
  4. 保护错误(Protection Fault)
    • 触发条件:程序尝试执行一些不被允许的操作,如访问受保护的内存区域或执行特权指令时触发。
    • 处理:通常会中断程序的执行,并可能给出错误信息。
  5. 机器检查(Machine Check)
    • 触发条件:硬件错误或故障,如内存错误、总线错误等。
    • 处理:取决于具体硬件和配置,可能包括中断程序、记录错误信息、尝试纠正错误等。
  6. 浮点异常(Floating-Point Exception)
    • 触发条件:浮点运算错误,如溢出、下溢、除以零、无效操作等。
    • 处理:可能包括提供一个近似结果、设置状态标志、中断程序等。

自陷

在CPU和操作系统的上下文中,“自陷”(也称为陷阱,trap)是一种机制,其中程序执行中的某些条件会导致处理器自动执行一个异常或中断的响应例程。自陷通常是由以下原因引起的:

  1. 异常:程序执行中出现了错误条件,例如除以零、访问非法内存地址、执行非法指令等。
  2. 系统调用:程序请求操作系统服务,例如文件操作、进程创建、网络通信等。在大多数系统中,这通过执行一个特定的指令(如syscall在x86架构上)来完成,它会触发自陷并进入内核模式。
  3. 断点调试:在软件开发的调试过程中,可以设置断点以在特定的程序点停止执行,允许开发者检查程序状态。当程序达到断点时,会触发自陷。

自陷流程与外中断处理流程类似:

  • 处理器检测到一个自陷条件。
  • 当前的程序执行被中断,处理器状态(如程序计数器、寄存器等)被保存。
  • 处理器切换到内核模式(如果它之前在用户模式下运行),这是一种更高的特权级别,允许执行操作系统代码。
  • 控制权转移到预定的自陷处理程序或中断处理程序。这通常是操作系统内核的一部分,能够处理异常或执行系统调用。
  • 自陷处理程序执行必要的服务或处理异常。
  • 一旦自陷处理完成,程序可以返回到自陷发生前的状态并继续执行,或者如果出现了无法恢复的错误,程序可能会被终止。

陷阱指令(trap instruction)是一种特殊的指令,用于故意中断当前的程序流,并将控制权转移给操作系统。这是一种由程序员显式请求的自陷(trap),通常用于执行系统调用、启动调试操作或其他由操作系统内核提供的服务。

中断

中断概念

  • 中断请求(IRQ,Interrupt ReQuest):
    • 外部设备通过中断请求线向CPU发送中断请求,每个设备通常有一个特定的IRQ号码。
  • 中断控制器(PIC, Prgrammable Interrupt Controller):
    • 包含一个中断控制器芯片用于集中处理和管理中断请求。这个控制器接收来自多个设备的中断请求,并将它们传递给 CPU。
  • 中断向量:
    • 中断服务程序的入口地址,是中断向量表中的一个表项。
  • 中断服务程序(ISR,Interrupt Service Routine):
    • 一旦中断向量被确定,处理器会跳转到相应的中断服务例程,即中断处理程序。
  • 中断向量表:
    • 一个数组或表格,包含了各种中断类型的中断处理程序的起始地址,每个中断向量的值对应于相应中断处理程序的地址。

分类

按中断类型

  1. 外部中断(External Interrupt):
    • 触发来源:外部设备或外部事件触发,如输入设备、时钟、外部信号等。
    • 响应:CPU响应外部事件,执行相应的中断处理程序。
  2. 内部中断(Internal Interrupt):
    • 触发来源:程序或CPU内部状态触发,如异常、错误等。
    • 响应:CPU根据内部条件触发中断,执行特定的中断处理程序。
  3. 软件中断(Software Interrupt):
    • 触发来源:软件或操作系统指令触发,常用于实现系统调用。
    • 响应:CPU执行一个特定的中断处理程序来响应软件的请求。

按是否可屏蔽

  1. 可屏蔽中断:可屏蔽中断是可以被禁用或屏蔽的中断。处理器可以通过设置特定的标志或寄存器来忽略这类中断。
  2. 不可屏蔽中断:不可屏蔽中断是不能被禁用或屏蔽的中断。这类中断通常与系统的关键和紧急事件相关。

中断处理流程

5.4 - 指令流水线

重点内容,熟练掌握指令执行的多个阶段和流水线的概念,并且能够在有冒险时绘制流水线的时空图。

指令执行的五个阶段

  1. 取指令(IF - Instruction Fetch): 从内存中取出指令。
  2. 指令译码(ID - Instruction Decode): 解析指令,确定其类型和操作数。
  3. 执行(EX - Execute): 执行指令,进行算数运算和逻辑运算等。
  4. 内存访问(MEM - Memory Access): 访问内存,读取或存储数据。
  5. 写回(WB - Write Back): 将执行结果写回到寄存器或内存。

指令流水线的基本概念

将指令执行的多个阶段由不同的硬件单独执行,各个阶段可以并行执行。这样,虽然每条指令的执行时间没有缩短,但是CPU的吞吐量得到了提升,也就是说,每单位时间内,CPU可以执行更多的指令。

Instruction
Clock Cycle
1
2
3
4
5
6
7
8
I1
I2
I3
I4
IF
ID
EX
M
WB
IF
ID
EX
M
WB
IF
ID
EX
M
WB
IF
ID
EX
M
WB

流水线的冒险和处理

结构冒险

含义

结构冒险是由于CPU的硬件资源有限而引起的。当两条或多条指令需要使用同一硬件资源时,就会发生结构冒险。

处理方法

  • 资源重复:增加硬件资源的数量,例如增加ALU或内存的端口数量。
  • 流水线阶段调度:通过调整流水线的执行顺序或延迟某些指令的执行来避免冒险。

例子

// 如果CPU只有一个内存端口,那么I1和I2不能在同一个周期访问内存,这就产生了结构冒险。
I1: LOAD R1, 0(R2)    // 将内存地址R2+0的值加载到寄存器R1
I2: STORE R3, 4(R4)   // 将寄存器R3的值存储到内存地址R4+4

数据冒险

含义

数据冒险是由指令之间的依赖性引起的。一条指令可能需要使用另一条指令的结果,如果这些指令过早地进入流水线,它们可能会尝试在数据准备好之前使用数据。

数据冒险可以分为三类:

  • 写后读(RAW, Read After Write):在一条指令尝试读取一个数据项的值时,而这个数据项的值还没有被前一条指令写入。
  • 读后写(WAR, Write After Read):一条指令尝试写入一个数据项的值时,而这个数据项的值还没有被后一条指令读取。
  • 写后写(WAW, Write After Write):两条指令尝试写入同一个数据项的情况,如果这两条指令的执行顺序不当,可能会导致不一致的结果。

处理方法

  • 流水线停顿(Pipeline Stall):暂停流水线直到数据准备好。
  • 重新排序指令(Instruction Reordering):编译器在编译时对指令进行重新排序,以减少数据冒险。
  • 数据前推(Data Forwarding):设置相关专用通路,直接将前一条指令的结果传递给需要它的下一条指令,不等结果写回寄存器。

例子

下述代码给出了数据冒险的三种情况:

// RAW
I1: ADD R1, R2, R3    // R1 = R2 + R3
I2: SUB R4, R1, R5    // R4 = R1 - R5

// WAR
I1: LOAD R1, 0(R2)    // R1 = Memory[R2+0]
I2: STORE R3, 0(R2)   // Memory[R2+0] = R3

// WAW
I1: MUL R1, R2, R3    // R1 = R2 * R3
I2: ADD R1, R4, R5    // R1 = R4 + R5

高级语言一条赋值语句被汇编微如下四条指令:

I1    LOAD  R1, [a]
I2    LOAD  R2, [b]
I3     ADD  R1, R2
I4   STORE  R1, [x]

四条指令对应的流水线执行如下图所示:

Instruction
Clock Cycle
1
2
3
4
5
6
7
8
I1
I2
I3
I4
IF
ID
EX
M
WB
IF
ID
EX
M
WB
IF
9
10
11
12
13
ID
EX
M
WB
IF
ID
EX
M
WB
14

其中 I3I1 之间存在 WAW 数据冒险,I3I2 之间存在 RAW 数据冒险,I4I3 之间存在 WAR数据冒险,所以 I3 必须等待 I1, I2 执行完才能进行后续操作, I4 必须等待 I3 执行完才能进行后续操作。

控制冒险

含义

控制冒险是由分支和跳转指令引起的。因为CPU需要在执行分支和跳转指令后,才能知道下一条要执行的指令在哪里,这导致了流水线的暂停或者无效的指令进入流水线。

处理方法

  • 预测不跳转(Predict Not Taken):预测每个分支都不会被采取,当分支被采取时,取消流水线中的指令并从正确的位置重新开始。
  • 预测跳转(Predict Taken):预测每个分支都会被采取,对预测错误的情况进行修正。
  • 延迟分支(Delayed Branch):编译器或处理器对代码进行优化,将分支指令后的一些不依赖于分支结果的指令先执行,从而减少因分支预测错误造成的开销。

实例

// 直到I1被执行,我们都不知道接下来是执行I2还是跳转到I3
I1: BEQ R1, R2, Label  // 如果R1等于R2,则跳转到Label
I2: ADD R3, R4, R5     // R3 = R4 + R5
I3: Label: MUL R6, R7, R8  // R6 = R7 * R8

5.5 - 多核处理器

了解相关概念即可,可能在选择题中单独考察。

SISD, SIMD, MIMD, 向量处理机

  1. SISD (Single Instruction stream, Single Data stream)
    • 定义:一个指令流和一个数据流在单一处理器上顺序执行。这种架构中的每个操作指令都在一个数据上执行。
    • 特点:简单、易于管理,但处理能力有限。
  2. SIMD (Single Instruction stream, Multiple Data streams)
    • 定义:一个指令在多个数据上并行执行。这种架构用于执行重复的数据操作,特别适用于图形处理和科学计算。
    • 特点:能高效处理大量数据,尤其在图像、音频和视频处理中表现出色。
  3. MIMD (Multiple Instruction streams, Multiple Data streams)
    • 定义:多个处理器或多核处理器并行执行不同的指令序列,每个指令序列作用在不同的数据流上。这种架构用于多任务和并行处理环境。
    • 特点:灵活、强大,能处理多任务和复杂的并行处理问题。
  4. 向量处理机 (Vector Processor)
    • 定义:使用向量寄存器来存储数据,并能在一个指令中处理整个向量数据。适用于执行大量重复和并行操作的科学和工程计算。
    • 特点:高性能,尤其在科学、工程和图形处理任务中表现出色。

多核处理器

CPU
Core
Single Core
Registers
Cache
BUS
Memory
I/O
CPU
Core
Registers
Cache
CPU
Core
Registers
Cache
BUS
Memory
I/O
Dual Core

现代一个CPU可以多个物理核心,一个物理核心可以使用超线程技术来实现多个逻辑核心。比如4核8线程的处理器,就是有4个物理核心,每个物理核心对应两个逻辑核心。

物理核心(Physical Cores):物理核心是处理器芯片上的实际硬件核心,它们能够独立执行指令和处理任务。一个物理核心可以看作是一个完整的处理单元,具有自己的寄存器、执行单元以及缓存。在4核心的处理器中,有四个物理核心。

硬件多线程

超线程技术的核心思想是将一个物理核心模拟成多个逻辑核心(线程),从而在同一时间内执行多个线程。每个逻辑核心都拥有自己的寄存器集合和执行单元,这些逻辑核心之间共享物理核心的资源,如缓存和执行单元。

共享内存多处理机

共享内存多处理机是一种计算机架构,其中多个处理器可以访问同一块物理内存。这样的架构允许处理器之间通过内存共享数据,从而实现并行处理和任务协同。

共享内存多处理机系统提供了一种有效的并行处理和数据共享机制,但也带来了同步、数据一致性和扩展性等方面的挑战。需要根据特定的应用和性能需求来选择和优化共享内存多处理机系统。

6 - 总线和输入输出系统

本章在选择题中考察,需要了解总线和I/O的相关概念,看到题目能够选出来即可。
# 总线

## 总线

- 总线的基本概念
- 总线的组成和性能指标
- 总线事务和定时

## I/O接口

- I/O接口的功能和基本结构
- I/O端口和编址

## I/O方式

- 程序查询方式
- 程序中断方式
- DMA方式

6.1 - 总线

需了解总线的组成、常见的总线标准以及定时方式,可能会在CPU和指令大题中作为知识点进行间接考察,也可能在选择题中出现一道。

总线的基本概念

总线是一组电子导线或信号线,它们允许不同的硬件设备(如CPU、内存、输入/输出设备等)之间进行数据传输和通信。总线是计算机内部和外部设备之间的信息传递通道。

总线架构方式

CPU
Memory
Device1
Device2
Device3
CPU
Memory
Device1
Device2
Device3
System Bus
DMA Bus
Memory Bus
I/O Bus
单总线结构
多总线结构的一种形式
  1. 单总线结构:
    • 在单总线结构中,所有的处理器、存储器和I/O设备都通过一个共享的通信通道进行连接。
    • 这种设计简单、成本低,但所有设备都必须竞争同一个总线,可能导致瓶颈。
  2. 多总线结构:
    • 多总线结构通过引入额外的总线来减轻单总线所带来的瓶颈问题。
    • 这种结构可能包括一个内部总线,专门用于处理器和主存储器之间的通信,以及一个或多个外部总线,用于处理器和外围设备之间的通信。
  3. 分层总线结构:
    • 在分层总线结构中,总线被组织成层次结构,每一层服务于不同级别的数据传输需求。
    • 例如,高速缓存和处理器可能在顶层使用高速总线,而存储器和I/O设备可能在下一层使用较慢的总线。

总线组成

总线通常由多个不同的信号线或导线组成,每条线承担特定的功能。以下是总线的主要组成部分:

  1. 数据总线(Data Bus):数据总线用于在计算机系统的各个组件之间传输数据。它通常由多条并行线组成,每条线传输一个数据位(比特)。数据总线的宽度决定了每次数据传输的位数,例如,32位数据总线可以一次传输32位二进制数据。
  2. 地址总线(Address Bus):地址总线用于传输内存地址或外部设备的地址信息,以确定数据的存储位置或目标设备。地址总线的宽度决定了系统可以寻址的内存或设备的数量。更宽的地址总线通常允许系统寻址更多的内存或设备。
  3. 控制总线(Control Bus):控制总线传输控制信号和命令,用于控制各个硬件组件的操作。这些控制信号包括读/写信号、时钟信号、中断信号、复位信号等。控制总线用于协调数据传输和操作的序列。

常见总线标准

  1. PCI (Peripheral Component Interconnect):PCI总线是一种用于连接内部扩展卡(如显卡、网卡、声卡等)到主板的标准。PCI总线存在多个版本,包括PCI、PCI-X和PCI Express(PCIe),它们在带宽、速度和适用范围上有所不同。
  2. SATA (Serial Advanced Technology Attachment):SATA是一种用于连接存储设备(如硬盘驱动器和光盘驱动器)到计算机的总线标准。它广泛应用于个人电脑和服务器中。
  3. ISA(Industry Standard Architecture):16位体系结构,只能支持16位的I/O设备,是已经被淘汰的插槽接口。
  4. IDE (Integrated Drive Electronics):IDE是早期计算机中用于连接硬盘驱动器和光盘驱动器的总线标准,现在已经被SATA所取代。
  5. USB (Universal Serial Bus):USB是一种通用的总线标准,用于连接各种外部设备(如键盘、鼠标、打印机、存储设备等)到计算机。USB有多个版本,包括USB 1.0、USB 2.0、USB 3.0、USB 3.1和USB 3.2,它们在传输速度和功能上有所区别。

还有一些其他总线标准比如 PCI-Express、EISA 这种,看到能够认出来是总线标准即可。

总线事务

总线事务是计算机总线操作的一个基本单位。一个总线事务通常涉及一系列的操作,这些操作可以是数据的读取或写入。

在一个总线事务中,主设备(发起事务的设备)通过总线控制线对总线进行控制,并发出地址和数据,以及读写信号。从设备(数据被读取或写入的设备)则识别地址,并根据读写信号进行相应的数据交换。

总线事务包含几个主要阶段:

  1. 请求(Request):主设备发出总线传输请求。
  2. 仲裁(Arbitration): 如果多个设备同时尝试使用总线,它们必须通过某种仲裁过程来决定哪个设备有权控制总线。这通常涉及一个优先级方案,以防止冲突和数据损坏。
  3. 寻址(Addressing): 主设备将目标地址放在总线上,以指定事务的目的地,如特定的内存地址或I/O设备。
  4. 传输(Transfer): 一旦地址被确认,数据传输就会发生。这可以是读操作,也可以是写操作。
  5. 终止(Termination): 一旦数据成功传输,事务就会结束。终止阶段可能包括从设备发出的确认信号,或者主设备撤销其对总线的控制。

总线定时

1. 总线同步定时方式:

  • 工作原理:在总线同步定时方式中,数据传输的时钟信号由一个中央时钟源(通常是主时钟源或总线控制器)生成,并将时钟信号传送到所有参与通信的设备。数据的传输和采样都按照这个中央时钟信号的时序进行。
  • 优点:传输速度快,总线控制逻辑简单。
  • 缺点:对于大规模系统或跨越较长距离的总线,需要保证时钟信号的一致性和稳定性,可能增加系统设计的复杂性。

2. 总线异步定时方式:

  • 工作原理:在总线异步定时方式中,数据传输的时钟信号不是由中央时钟源统一控制,而是由每个设备自己的时钟信号驱动。完全依靠传送双方相互制约的“握手”信号来实现定时控制,通常我们将交换信息的两个设备称为主设备和从设备,主设备发送“请求”,从设备接收到后回复“回答”。
  • 优点:可以适应异构系统,其中不同设备可能具有不同的时钟频率。
  • 缺点:比同步控制方式复杂,速度比同步定时方式慢。

异步定时根据“请求”和“回答”的类型,可以分为三种类型:

  • 不互锁:主设备持续发送请求一段时间,默认从设备接收到请求。
  • 半互锁:主设备接收到来自从设备的回答后停止发送请求,从设备发送回答一段时间,默认主设备接收到回答。
  • 全互锁:从半互锁的基础上,从设备接收到来自于主设备的回答后停止发送回答。
不互锁
不互锁
半互锁
半互锁
不互锁
不互锁
主设备
主设备
从设备
从设备
Text is not SVG - cannot display

6.2 - I/O 系统

重点掌握程序查询、程序中断和 DMA 三种 IO 方式,常常在选择题中考察。

输入/输出系统

  • 输入设备:用于向计算机系统输入命令和本文或数据,比如鼠标和键盘。
  • 输出设备:用于将计算机系统的信息输出到外部进行显示、交换的部件。
  • I/O 接口:外部设备和主机之间进行数据传输时进行各种协调工作的逻辑部件,暴扣传输过程中速度的匹配、电平和格式转换等。
  • I/O 软件:包含驱动程序、管理程序等,这些程序通过 I/O 指令来实现 CPU 和 I/O 设备的信息互换。
  • I/O 端口:接口电路中可以直接被 CPU 访问的寄存器

I/O 端口

I/O 端口主要包含数据端口、状态端口和控制端口,若干端口加上响应的控制逻辑电路组成接口。通常,CPU 能对数据端口执行读写操作,但对状态端口只能执行读操作,对控制端口只能执行写操作。

为了方便 CPU 对于 I/O 端口的方恩,需要对各个端口进行编号,每个端口对应一个端口地址。编址方式主要有如下两种:

  1. 统一编址(Memory-Mapped I/O):
    • 在统一编址中,计算机的内存和 I/O 设备都被看做是内存地址空间的一部分,即内存地址和 I/O 地址共享同一个地址空间。
    • 这意味着在访问 I/O 设备时,使用的是与访问内存相同的指令和地址。对于 CPU 来说,没有专门的 I/O 指令,只是通过读写特定的内存地址来访问 I/O 端口。
    • 优点是简化了编程,因为访问 I/O 设备的方式与访问内存一致。但缺点是可能导致内存地址的冲突,需要特别注意确保不会与内存地址冲突。
  2. 独立编址(Isolated I/O):
    • 在独立编址中,计算机使用专门的 I/O 指令和地址空间来访问外部设备,与内存地址空间分开。
    • 这意味着有专门的 I/O 指令集,用于读写 I/O 设备,并且有独立的地址空间用于寻址 I/O 端口。
    • 优点是更好地区分了内存和 I/O 访问,减少了潜在的地址冲突。但缺点是编程时需要使用不同的指令和地址,稍微复杂一些。

I/O 方式

程序查询方式

CPU 重复检查 I/O 设备的状态,确定是否可以进行数据传输。

  1. 查询:CPU 定期查询或检查 I/O 设备的状态寄存器,查看设备是否准备就绪。
  2. 判断:如果设备未就绪,CPU 会继续执行其他任务或持续轮询;如果设备就绪,则进行数据传输。
  3. 数据传输:CPU 直接与 I/O 设备交换数据,可以是读操作或写操作。
  4. 结束:数据传输完成后,CPU 继续执行其他任务,同时继续轮询 I/O 设备状态。

程序中断方式

在程序中断方式中,当 I/O 设备准备好进行数据传输时,会触发一个硬件中断来通知 CPU。 CPU 会暂停当前正在执行的任务,处理中断,然后恢复执行被中断的任务。

相比于轮询方式,CPU 在执行程序中断之前不需要一直检查 IO 设备的状态,这提升了效率。

中断处理过程

FR ⇔  stacked FR
CS ⇔  stacked CS
IP ⇔  stacked IP
X86
microprocessor
System Bus
PIC
System timer
Regsiters
Keyboard
Regsiters
Real-time clock
Regsiters
Mouse
Regsiters
IRQ0
IRQ1
IRQ2
IRQ3
IRQ4
IRQ5
IRQ6
IRQ7
Port 0x20:
Interrupt
command
register
Port 0x21:
Interrupt
data
register
0x0000: ISR 0 vector
0x0004: ISR 1 vector
0x0008: NMI vector   
· · · · ·
0x0204: ISR 129 vector
· · · · ·
0x03FC: ISR 255 vector
ISR 0
ISR 129
while (1) {                     
instructoin 1     
        ........                           instruction j        
      
instruction j+1  
........                
instruction n     
}                                  
Frame: saved registers
· · · · ·
Frame: saved registers
Memory
1
Program counter
register (CS:IP)
Flag register (FR)
2
INTR
        
INTA
4
5
INT# = 0x81
NMI
6
7
ISR n
8
9
9.1
9.2
3
10
9.3
  1. 中断触发:
    • 当外部设备完成操作或需要注意时,它会发送一个信号到处理器的中断请求(IRQ)线路。
    • 如果中断使能,并且当前的中断优先级允许,处理器会响应这个中断信号。
  2. 中断识别:
    • 处理器完成当前指令的执行,并开始中断处理过程。
    • 处理器检查中断向量表(一个存储了不同中断处理程序地址的表),确定哪个中断被触发。
  3. 保存上下文:
    • 处理器会保存当前任务的状态,通常包括程序计数器(PC)、程序状态字(PSW)和其他必要的寄存器,以便中断处理完成后能够恢复。
  4. 中断服务程序(ISR)调度:
    • 处理器根据中断向量表跳转到相应的中断服务程序(ISR)。
    • 在执行中断服务程序之前,处理器可能会禁止或优先级屏蔽进一步的中断,以防止中断处理程序被其他中断打断。
  5. 执行中断服务程序:
    • 中断服务程序执行所需的操作以响应外部中断,比如从 I/O 设备读取数据或向其发送数据。
  6. 恢复上下文:
    • 中断服务完成后,处理器通过恢复之前保存的状态(上下文)来恢复中断之前执行的任务。
  7. 中断返回:
    • 处理器执行一条专门的中断返回指令(比如 x86 架构中的 IRET 指令),该指令将程序计数器(PC)和程序状态字(PSW)等恢复到中断前的值,然后继续执行中断之前的程序。

多重中断和中断屏蔽

ISP
ISP
main
prorgam
main...
ISP1
ISP1
ISP2
ISP2
ISP3
ISP3
main
prorgam
main...
Text is not SVG - cannot display

若 CPU 在执行中断服务程序的过程中,又出现了新的更高优先级的中断请求,而 CPU 对新的中断请求不予响应,则这种中断称为单重中断。

若 CPU 暂停现行的中断服务程序,转去处理新的中断请求,则这种中断称为多重中断,又称中断嵌套。

CPU 要具有处理多重中断的功能,必须满足下列条件:

  1. 在中断服务程序中提前设置开中断指令。
  2. 优先级高的中断源有权中断优先级低的中断源。

可以利用中断屏蔽技术动态调整中断处理优先级,每个中断源都有一个屏蔽触发器,1 表示屏蔽该中断源的请求,0 表示可以正常申请,所有的屏蔽触发器组合在一起便构成一个屏蔽字触发器。

中断源
A
B
屏蔽字
C
D
A
B
C
D
1
1
1
1
0
1
1
1
0
0
1
1
0
0
0
1
优先级 A > B > C > D

如上图,中断屏蔽字中的每一位表示在执行一个中断的时候,我们是否屏蔽来自于其他中断源的请求。比如 B 的优先级高于 C、D,所以在处理来自于中断源 B 的中断时,需要屏蔽 B、C、D,即屏蔽字为 0100。

图示中断屏蔽字说明

DMA 方式

DMA(Direct Memory Access,直接内存访问)是一种计算机系统的 I/O(输入/输出)方式,它允许外部设备直接访问主内存而无需 CPU 的干预。

步骤

地址信息
数据信息
主线控制
缓冲区
1
3
2
4
5
磁盘控制器
主存
处理器
DMA 控制器
总线
  1. 预处理:在进行 DMA 传输之前,CPU 需要进行初始化设置,包含源地址、目标地址、数据传输长度以及数据传输方向。
  2. DMA 请求:外设向 DMA 控制器发送 DMA 请求,并向 CPU 发送总线请求。
  3. 获取总线控制权:CPU 响应总线请求,发出总线响应信号,DMA 控制器接管总线控制权,进行 DMA 操作周期。
  4. 数据传输:DMA 控制器进行数据传输,这个过程不需要 CPU 的干预。
  5. 释放总线控制权:一旦 DMA 控制器完成数据传输,它会发出 DMA 传输完成信号,通知外设设备数据已经传输完毕。同时 DMA 控制器会释放总线控制权,使 CPU 可以继续执行其他任务。

使用总线方式

  1. 总线独占(Bus Mastering):
    • 在这种模式下,DMA 控制器会取得对总线的独占控制权。在传输期间,CPU 将无法访问内存,因为总线已经被 DMA 控制器占用了。
    • 在独占期间,CPU 通常会执行不涉及内存访问的指令,如计算或寄存器操作,或者进入等待状态直到 DMA 操作完成。
  2. 周期挪用(Cycle Stealing,也叫做循环窃取):
    • 在循环窃取模式下,DMA 控制器会逐个窃取总线周期来进行数据传输,而不是一次性占据所有的总线周期。
    • 这意味着 CPU 在 DMA 控制器未使用总线时仍然可以访问内存。因此,DMA 和 CPU 会交替使用总线,通常不会显著影响 CPU 的操作。
  3. 分时多路复用(Time-Division Multiplexing):
    • 在分时多路复用模式下,DMA 控制器和 CPU 会在预定的时钟周期内轮流使用总线。
    • 这种方式确保了 CPU 和 DMA 控制器都可以在它们的时隙内访问内存,但都无法全时段访问。

视频讲解