CPU功能与结构

基础概念

🔥 高优先级

本节很重要,其实应该不需要我再强调了。本节要和指令系统放在一起理解,主要两点:1. 理解 CPU 的 架构方式 。2. 理解 CPU 中 各种寄存器的功能细节

CPU

作为计算机的“大脑”,CPU(中央处理器)是执行程序指令、处理数据的关键部件。从宏观的计算机体系结构来看,CPU 是冯·诺依曼架构中“运算器”与“控制器”两大核心部件的具体实现与集成。因此,剖析 CPU 的内部组成,本质上就是探究现代计算机如何通过精密的硬件设计,将“运算”与“控制”这两大基本功能高效、协调地融为一体,并最终执行复杂的任务。

组成结构

在介绍 CPU 的组成结构之前,首先回顾一下计算机的 冯诺依曼结构,其中 运算器控制器存储器输入输出 为计算机组成的五大部件,其中 CPU 涵盖的功能就包含 运算器控制器 这两个。

CPU 的核心功能包含 运算和控制 这两大模块,这对应了计算机五大部件中的 运算器控制器 。具体而言:运算功能(执行功能)是指 CPU 根据指令对数据进行算术或逻辑运算;控制功能则是指 CPU 通过指令协调计算机中各个部件的工作。

CPU 的结构简图如上图所示,CPU 由 运算部件控制部件 组成。但是其实这两者并不能完全涵盖 CPU 的所有结构,因为这种分类方式忽略了 CPU 了内总线,所以一种更完善的 CPU 组件分类方法是将其分为 数据通路控制器 这两部分:

  • 数据通路 (Datapath)是指令执行过程中,数据所经过的路径,包括路径中的部件。它是指令的 执行部件
  • 控制器 (Control Unit)对指令进行解码,生成对应的控制信号,控制 数据通路 的动作。能够执行指令发出控制信号,是指令的 控制部件

数据通路

CPU 的 数据通路 是指 CPU 在执行指令的过程中内部数据流动的路径,ALU寄存器组多路选择器 都属于数据通路的一部分。数据通路 描述了 信息从哪里开始,中间经过哪些部件,最后被传送到哪里。数据通路由 控制部件 控制,控制部件根据每条指令功能的不同,生成对数据通路的控制信号。

数据通路的元件主要分为 组合逻辑元件时序逻辑元件 两类:

组合逻辑元件

组合逻辑元件 (操作元件)指那些仅由 组合逻辑电路 组成的元件,其输出仅取决于当前的输入,而不受存储器或时钟信号的影响。输入和输出之间无反馈通路,信号是单向传输的。

数据通路中常用的组合逻辑元件有 算数逻辑单元ALU )、译码器多路选择器三态门 等,如下图所示:

  • 译码器 :用于操作码或地址码译码, n 位输入对应 2n 种不同组合,因此有 2n 种不同的输出,但是每次只有一个输出被使能。
  • 多路选择器 :有多个输入,输出与其中一个输入相同,需要用控制信号 Select 选择哪个输入作为输出。
  • 三态门 :可以被视为一种控制开关,由控制信号 EN 决定信号线的通断,当 EN=1 时,三态门被打开,输入信号等于输出信号;当 EN = 0 时,输出端呈现高阻态,数据通路被断开。

时序逻辑元件

对于 时序逻辑元件 (状态元件),其任何时刻的输出不仅与该时刻的输入有关,还与该时刻以前的输入有关,并且 具备状态存储 功能。此外,时序电路必须在 时钟节拍 下工作。

各类 寄存器存储器 ,如 通用寄存器组程序计数器状态/移位/暂存/锁存寄存器 等,都属于时序逻辑元件。

控制器

控制器 是计算机的指挥中心,它负责协调和控制计算机的所有操作。其核心功能是根据当前正在执行的指令 ,生成一系列控制信号 ,精确地指挥数据通路 中的各个部件(如 ALU、寄存器、多路选择器)协同工作,从而完成指令所规定的任务。

控制器可以被视为整个 CPU 的“大脑”或“指挥家”。它不直接处理数据,而是决定数据在何时、何地、以何种方式流动和运算。

控制器的 基本工作原理 如下:

  1. 取指令 :控制器指挥程序计数器(PC)送出当前指令地址,从存储器中取出指令,并送入指令寄存器(IR)。
  2. 分析指令 :对指令寄存器中的指令进行译码 ,识别出指令的操作类型(如加法、跳转)、寻址方式以及所需的操作数。
  3. 执行指令 :根据指令译码的结果,控制器在正确的时序下,生成并发出对应的控制信号序列。这些信号控制数据通路打开或关闭特定的数据路径,选择 ALU 的运算功能,决定是否写入寄存器或内存等。
  4. 转向下条指令 :在完成当前指令后,控制器会更新程序计数器,为取下一条指令做好准备,从而开始新一轮的循环。

控制器的功能和组成详见 该节

8086 CPU

上文已经对 CPU 中的组件进行了分类,但是仅有抽象概念是不足够的,该节会提供一个非常简单的 CPU 实现来说明情况,这个 CPU 就是 8086

8086 是 Intel 首款真正的 16 位处理器,也是现代 x86 处理器的开端,只要掌握了这个 CPU 的架构,就能搞定绝大多数考试过程中会遇到的问题。

结构

上文已经提到了 CPU 的组成结构 可以分为 数据通路控制器 这两部分,8086 中的 数据通路 由指令队列、寄存器 和内总线组成。控制器 中包含指令译码器、时序控制单元、标志控制逻辑和微指令控制逻辑。

下文会按照这个脉络对 8086 中的组件进行详细说明。

寄存器

从功能的角度进行区分,8086 CPU寄存器 可以为分为 通用寄存器段寄存器指针寄存器附加寄存器标志寄存器 这五类:

  1. 通用寄存器 :用于存储任意的地址或者数据。
  • AX 寄存器:累加器(Accumulator),用于执行算术和逻辑运算。
  • BX 寄存器:基址寄存器(Base Register),通常用于存储内存地址。
  • CX 寄存器:计数寄存器(Counter Register),用于循环计数和移位操作。
  • DX 寄存器:数据寄存器(Data Register),用于输入/输出操作和大整数运算。
  1. 段寄存器 :用于存储内存段的起始地址。
  • CS (Code Segment) 寄存器:代码段寄存器,存储指向代码段的地址。
  • DS (Data Segment) 寄存器:数据段寄存器,存储指向数据段的地址。
  • ES (Extra Segment) 寄存器:附加数据段寄存器,通常用于数据访问。
  • SS (Stack Segment) 寄存器:堆栈段寄存器,存储指向堆栈段的地址。
  1. 变址寄存器 :用于支持变址寻址模式,和数组和指针操作相关。
  • SI 寄存器:源变址寄存器,通常用于数据传送操作。
  • DI 寄存器:目的变址寄存器,也通常用于数据传送操作。
  1. 指针寄存器
  • SP (Stack Pointer) 寄存器:堆栈指针寄存器,指向函数栈的顶部。
  • BP (Base Pointer) 寄存器:堆栈基址寄存器,指向函数栈的底部。
  • IP 寄存器:指令指针寄存器,存储当前执行指令的偏移地址。
  1. 标志寄存器
  • FLAGS 寄存器:标志寄存器,存储有关条件和状态的信息,例如进位、零标志、溢出等。

    1. 特殊寄存器
  • IR (Instruction Register) 寄存器:暂存读取的指令。

  • T 暂存器:暂存 ALU 一端的输入。

注意

哪些寄存器是汇编程序员可见的?

有在 8086 仿真器上编写过汇编程序的人会知道,可见的寄存器就是你编写汇编程序时可以直接通过指令进行控制的寄存器。

可见的寄存器包括:通用寄存器段寄存器标志寄存器Flags )和指令指针寄存器IP )。

当然更为方便地是记住哪些寄存器是不可见的:MARMDRIR

段寄存器

段寄存器 指向程序调用时的 内存结构中不同段的起始位置

  • CS 指向代码段(.text)的起始位置
  • SS 指向栈段(User Stack)的起始位置
  • DS 指向数据段(.data)的起始位置
  • ES 指向附加段(Extra Segment)的起始位置

对于运行在 8086 上的程序而言,其内存结构相比 现代进程内存空间 更加简单,但其中的逻辑结构是类似的:

从逻辑上来说,程序的执行需要四个段:

  • 代码段 :存储编译后程序指令的地方
  • 数据段 :存储有全局数据的地方
  • 栈段 :函数嵌套调用的发生场所
  • 额外段 :提供一些灵活性,供程序员发挥

不同的段寄存器与不同的段相关联,指向相关段的起始地址。

指针寄存器

对于有些段来说,仅仅知道其起始地址是不足够的,在程序执行过程中,需要一些额外的寄存器来实现我们需要的操作,指针寄存器 主要操作 栈段代码段

栈指针寄存器

栈指针寄存器 包含 BPSP 这两个,在进一步了解这两个寄存器之前,请复习一下 函数调用时的内存结构。

函数在执行过程中需要保存的数据与栈类似,具有先进后出的特点。

函数栈从高地址向低地址增长,嵌套调用的函数所对应的函数栈 在栈段上不断堆叠。如果我们在 main() 主函数中嵌套调用 f(g(h(1))),那么该程序对应的栈段对应的逻辑结构如下所示:

其中 BP 指向最后一个调用的函数栈的底部,SP 指向最后一个调用的函数栈的顶部,通过 BPSP 我们保存了最后一个函数栈帧的栈底(开始位置)和栈顶(结束位置)。

8086 中,指令指针寄存器指的就是 IP (Instruction Pointer)寄存器。

指令在 代码段 (.text 段)中是从低地址向高地址增长的,这种增长方式也符合 程序计数器 (PC 或 IP)的增长逻辑:在 指令执行的取指阶段,控制单元在完成取指后会控制 IP = IP + 指令长度 ,这样 IP 就指向了 下一条待执行指令的地址

变址寄存器

变址寄存器 主要用于实现变址寻址模式,方便对数组、字符串等数据结构中的 第 i 个元素 进行操作。8086 中的主要变址寄存器是 SI (源变址寄存器)和 DI (目的变址寄存器),下文分别从 数组字符串操作 两个例子说明一下:

数组操作

以下汇编代码段通过一个循环操作实现了对于数组中的前五个元素进行操作。注意在 8086 中,我们是在 CX 中保存 loop 的轮数,每次 LOOP 被调用后 CX 的值自动被减一。

; 假设 DS 指向数据段并且数组从数据段开始
MOV DS, addr         ; 将数组的起始地址保存到 DS 
MOV CX, 5            ; CX 用作循环计数器,假设数组有 5 个元素
MOV SI, 0            ; SI 作为索引寄存器,初始化为 0

NEXT_ELEMENT:
    MOV AX, [SI]     ; 从数组当前元素读取到 AX
    ;  AX 中的数据进行处理
    ADD SI, 2        ; 移动到下一个元素(假设每个元素 2 字节)
    LOOP NEXT_ELEMENT ; 循环直到 CX  0

字符串操作

以下汇编代码将一个字符串的前 length 个字符复制到另一个字符串中。

; 假设 DS  ES 已经分别指向源和目的数据段
MOV SI, OFFSET source ; SI 指向源字符串的起始位置
MOV DI, OFFSET dest   ; DI 指向目的字符串的起始位置
CLD                   ; 清除方向标志位,确保字符串操作从低地址到高地址

MOV CX, length        ; CX 初始化为字符串的长度

REP MOVSB             ; 复制 CX 个字节从 DS:SI  ES:DI
标志寄存器

标志寄存器Flags )用于存储处理器在 执行指令过程中产生的各种状态和条件 ,这些状态可以进一步被 控制器 所用,控制后续指令执行的行为。

标志寄存器中的不同位用于标记某个特殊的状态,8086 中的 标志寄存器 是一个 16 位 的寄存器,其中 9 个标志位 被使用,其他 7 个标志位 没有含义。

这些标志位在逻辑上可以被分为 条件标志 (conditional flags)和 控制标志 (control flags)两种:

条件标志

条件标志用于标记指令执行后的结果状态,用于影响程序的控制流,条件标志 包含以下几种:

  • OF (Overflow flag):溢出标志。

  • 有符号整数 运算的结果太大而无法适应目标寄存器时,OF 标志会设置为 1,表示发生了溢出。

    • CF (Carry flag):进位标志。
  • 无符号整数 运算的结果超出了目标寄存器的位数,CF 标志被设置为 1,表示发生了进位。

    • 加法时:CF=1 表示发生了 进位 (即结果超过了寄存器能表示的范围)。

    • 减法时:CF=1 表示发生了 借位 (即被减数小于减数)。

    • SF (Sign flag):符号标志。

  • 根据操作结果的符号位来设置,如果结果为负数,则 SF 被设置为 1,否则为 0。

    • ZF (Zero flag):零标志。
  • 当操作结果为零时,ZF 标志被设置为 1,否则为 0。

    • AF (Auxiliary carry flag):辅助进位标志。
  • 通常用于 BCD(二进制编码十进制)算术运算,指示低四位的进位。

    • PF (Parity flag):奇偶校验标志。
  • 根据结果中二进制位 1 的个数是奇数还是偶数,设置 PF 标志。奇数个 1 则 PF 为 1,偶数个 1 则 PF 为 0。

条件标志不需要 序员手动通过指令设置,当算数和逻辑指令(Add 和 AND 等)和 比较指令 (CMP)被执行时,相关的标志位会被 自动设置

条件标志通常用于控制 条件跳转指令 的执行。条件跳转指令会检查条件寄存器中的标志位,根据标志位的状态决定是否将 程序计数器 (PC)修改为目标地址,从而实现程序流程的跳转。


以下我们需要说明几个需要注意的点,这些知识点很容易被混淆:

注意

CF 和 OF 的区别?

标志位含义用于设置条件
CFCarry Flag(进位标志)无符号数运算加法时进位,减法时借位
OFOverflow Flag(溢出标志)有符号数运算加法或减法导致结果超出有符号数表示范围(如 +127 + 1 = -128)

上述的 设置条件 只是 逻辑结果 (针对 有/无符号数 的逻辑结果),硬件并不是这样判断的。

对于硬件加法器,它不区分数字是 有符号 还是 无符号 ,底层电路都是通过 加法器 + 补码机制 完成的。

不过我们通过对一些位进行组合来 实现 上述的逻辑结果。

注意

OF 标志位是如何被设置的?

在处理两个 n 位的有符号整数 加法时,OF (Overflow Flag)用于指示结果是否超出了有符号数的可表示范围。对于补码表示的系统,可以使用以下逻辑来判断溢出:

一种直观但不被硬件实际使用的方法:

  • 判断结果的最高位是否发生进位 ,如果有,则 OF = 1 ,否则 OF = 0
  • 然后 OFCF 是完全不同的事情,硬件不能通过“是否最高位进位”简单推出 OF ,因此考试或工程实践中通常采用更严谨的判断方式。

常用的标准判断方式(考试常考)

设参与计算的两个 n 位补码数为 A 和 B ,结果为 C=A+B ,我们关注它们的符号位 (即最高位,第 n−1 位):

情况A 的符号B 的符号C=A+B 的符号是否溢出
异号相加(一个正一个负)不重要不重要不重要❌ 不会溢出
同号相加 → 结果符号不变正 + 正 → 正00❌ 无溢出
同号相加 → 结果变号正 + 正 → 负01✅ 有溢出
同号相加 → 结果变号负 + 负 → 正10✅ 有溢出

因此,OF 的判断规则为:

当两个操作数符号相同,而结果符号与它们不同,就发生了溢出。

用逻辑表达式表示为:

OF=An−1​⋅Bn−1​⋅Cn−1​​+An−1​​⋅Bn−1​​⋅Cn−1​

  • 其中 An−1​,Bn−1​,Cn−1​ 分别表示 A,B,C 的最高位(符号位)
  • 也可理解为:
  • 两数为负,结果为正:溢出
  • 两数为正,结果为负:溢出

减法的溢出判断

由于减法 A−B 可以转化为加法 A+(−B) ,因此溢出的判断可以同样基于加法规则 来分析:

  • 将减法转化为加法后,使用上述符号位比较法判断 OF

控制标志

控制标志 并不会被通常的运算指令自动修改,而是通过专门的指令来进行设置或清除。对于以下字段,了解即可:

  • IF (Interrupt flag)

  • 控制中断处理

  • IF 被设置为 1 时,CPU 允许中断请求。如果 IF 为 0,CPU 将禁止所有 可屏蔽中断,无论是外部硬件中断还是软件中断。

    • TF (Trap flag)
  • 控制单步执行。

  • TF 被设置为 1 时,CPU 将进入单步执行模式。在单步执行模式下,每执行一条指令后,CPU 将引发一个单步中断,允许程序员逐条调试程序。

    • DF (Direction flag)
  • 字符串操作的标志位。

  • DF 被设置为 1 时,字符串操作(如 MOVS、LODS、STOS)在内存中向高地址方向移动。这通常用于从高地址向低地址扫描字符串。当 DF 被清除为 0 时,字符串操作在内存中向低地址方向移动。这通常用于从低地址向高地址扫描字符串。

特殊寄存器

暂存器

每次 ALU 操作都需要两个操作数,但是 数据总线共享的 ,同一时刻只能传输一个操作数。所以在 ALU 会按照以下方式进行计算:

  • 先读取第一个操作数,暂存在临时寄存器 T 中;
  • 然后再读取第二个操作数;
  • 最后,ALUT 和第二个操作数一起执行运算。

所以在 只有一个内部数据总线 的设计里,为了配合 ALU 的两个输入,暂存器 被设置用于存储前一个时钟周期的数据。

指令寄存器

CPU 从内存或指令队列中取出一条指令时,这条指令会被送入 IR (指令寄存器),暂存在这里,供后续的译码和执行阶段使用。

控制单元(CU)可以对 IR 中的指令进行译码,生成一系列控制信号。

引脚

CPU 的 引脚 (Pin)是处理器与主板之间进行电气连接的接口,是 CPU 与外部组件(如内存、I/O 设备、电源等)之间通信的桥梁。引脚 的功能包括 数据传输地址定位中断控制时序控制 等,是实现 CPU 与外部世界交互的关键通道。

为便于理解,本节以 Intel 8086 处理器为例进行说明。需要注意的是,本节内容以了解为主,试题通常不会直接考察,但对于理解计算机体系结构十分重要。

8086 为例,8086 为 16 位计算机,其 数据总线 为 16 位,可寻址地址空间为 1 MB,所以其 地址总线 为 20 位。数据总线和地址总线 复用 ,地址总线的高位与状态线复用:

引脚名方向说明
AD0–AD15双向地址/数据复用线:
- 发地址时传送 A0–A15
- 传数据时传 D0–D15
A16/S3–A19/S6输出高位地址线与状态线复用

数据传输 过程中,低位地址与数据使用同一组引脚(AD0–AD15),通过时序的不同进行区分。为了确保地址被正确识别,8086 使用 ALE (地址锁存使能)信号配合外部锁存器将地址锁存下来。

为了支持外设对 CPU 发起中断请求,以及对处理器进行复位操作,8086 设置了如下相关引脚:

引脚名方向说明
NMI输入不可屏蔽中断,请求立即响应
INTR输入可屏蔽中断 请求
RESET输入复位输入,低电平有效,将 CPU 状态初始化
INTA#输出中断响应信号,通知外设 CPU 正在响应中断

此外,CPU 还需要通过控制信号对外设进行控制,下面列出了一些常用的控制信号:

引脚名方向说明
RD#输出读信号,低电平有效,表示从内存/I/O 读取
WR#输出写信号,低电平有效,表示写入内存/I/O
ALE输出地址锁存使能,表示当前 AD0–AD15 是地址
DT/R输出数据传输方向:读=0,写=1
READY输入外设准备就绪信号,不就绪则 CPU 等待
HOLD输入外设 请求总线控制权
HLDA输出总线控制权应答(HOLD Acknowledge)

其中,READY 信号的作用是支持不同速度的外设。当某些设备处理速度较慢时,CPU 会检测到 READY 为低电平,从而暂停当前操作,等待设备准备就绪,避免数据错误。

HOLDHLDA 是总线请求/响应配对信号,用于支持 DMA 等技术,使得外设可以在不经过 CPU 的情况下直接访问内存,从而提升数据传输效率。

相关笔记

  • 数据对齐
  • 指令格式与寻址方式
  • 高级语言与机器码
  • 指令系统
  • 指令操作码
  • 指令集种类