功能和结构

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

CPU

组成结构

总线控制逻辑
ALU
通用寄存器
控制寄存器
脉冲源
启停控制线
时序信号产生部件
操作控制信号形成部件
指令译码器
指令寄存器
指令寄存器
地址总线
数据总线
控制总线
中断机构
执行部件
控制部件

CPU 包含 数据通路控制器

数据通路(Datapath)是指令执行过程中,数据所经过的路径,包括路径中的部件。它是指令的 执行部件

控制器(Control)对指令进行解码,生成对应的控制信号,控制数据通路的动作。能够执行指令发出控制信号,是指令的 控制部件

数据通路

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

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

  1. 组合逻辑元件(操作元件)

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

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

A1
A2
A3
Y1
Y2
Y3
Y8
A
B
MUX
Select
in
EN
译码器
多路选择器
三态门
虚线为控制信号
  • 译码器:用于操作码或地址码译码,$n$ 位输入对应 $2^n$ 种不同组合,因此有 $2^n$ 种不同的输出,但是每次只有一个输出被使能。
  • 多路选择器:有多个输入,输出与其中一个输入相同,需要用控制信号 Select 选择哪个输入作为输出。
  • 三态门:可以被视为一种控制开关,由控制信号 EN 决定信号线的通断,当 EN=1 时,三态门被打开,输入信号等于输出信号;当 EN = 0 时,输出端呈现高阻态,数据通路被断开。
  1. 时序逻辑元件(状态元件)

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

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

控制器

控制器是计算机的指挥中心,它负责协调和控制计算机的所有操作。 控制器的功能和组成详见 该节

8086

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

CPU 的内部结构由 BIU 和 EU 两部分构成,简单而言,BIU 负责读指令,EU 负责执行指令。两个组成部分的具体功能如下:

  • BIU(Bus Interface Unit,总线接口单元):
    • 主要功能
      • 从内存中取指令,并将其存储在指令队列中。
      • 计算存储器地址,并控制总线进行数据传输。
    • 组成:
      • 指令队列:用于存储从内存中预取的指令。
      • 特殊寄存器
        • 指令指针寄存器(IP, Instruction Pointer):存储下一条要执行的指令地址。
        • 指令寄存器(IR, Instruction Register),存储当前正在执行的指令
        • 内存地址寄存器(MAR, Memory Address Register),存储内存需要读取的地址
        • 内存数据寄存器(MDR, Memory Data Register),存储内存读取的数据单元
        • 段寄存器(Segment Registers)
  • EU(Execution Unit,执行单元):
    • 主要功能:
      • 从指令队列取出指令,进行译码。
      • 执行指令,包含算术运算、数据传输等。
    • 组成:
      • 算术逻辑单元(ALU),用于执行算术和逻辑运算,例如加法、减法、逻辑与、逻辑或等。
      • 通用寄存器: 包括 AX、BX、CX、DX、SI、DI、BP 和 SP 等寄存器,用于存储数据和地址。
      • 控制单元(CU, Control Unit),负责取指令和解码指令、生成控制信号、协调 CPU 中指令的执行过程。

BIU 和 EU 并行工作,以此提高 CPU 的效率。例如,当 EU 执行一条指令时,BIU 可以同时从内存中预取下一条指令,并将其存储在指令队列中。

寄存器

寄存器类型

AH
AL
BH
BL
CH
CL
DH
DL
Geneal Purpose 
Registers
AX
BX
CX
DX
Segment
Registers
CS
DS
ES
SS
Pointer
Registers
SP
BP
IP
Index
Registers
SI
DI
Flag
Register
FLAGS

这里为了方便大家对寄存器从概念进行分类,下面使用 8086 的寄存器进行说明,总的来说,寄存器可以为分为 通用寄存器、段寄存器、指针寄存器 以及 附加寄存器:

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

注意

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

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

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

当然更为方便地是记住哪些寄存器是不可见的:MAR、MDR、IR。

段寄存器

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

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

下图包含程序内存结构中所包含的不同段,

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

当然,上图是现代 linux 程序的内存结构,对于运行在 8086 上的程序而言,其内存结构更加简单,但其中的逻辑结构是类似的:

Stack Segment
Stack Segment
Data Segment
Data Segment
Code Segment
Code Segment
SS
SS
DS
DS
CS
CS
Extra Segment
Extra Segment
ES
ES
IP
IP
SP
SP
BP
BP
High Address
High Address
Low Address
Low Address
0000H
0000H
FFFFH
FFFFH
Text is not SVG - cannot display

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

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

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

指针寄存器

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

SP,BP 栈指针寄存器

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

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

----------------- ← SS
  main 的函数栈
-----------------
   f 的函数栈
-----------------
   g 的函数栈
----------------- ← BP (指向函数 h 的栈底)
   上一个函数的 BP
   函数参数
   局部变量        ← SP(指向函数 h 的栈顶)

其中 BP 指向最后一个调用的函数栈的底部,SP 指向最后一个调用的函数栈的顶部,通过 BP 和 SP 我们可以对最后一个调用的函数进行操作,具体可以参考 函数调用时的内存结构

IP 指令指针寄存器

指令在代码段(.text 段)中是从低地址向高地址增长的,这种增长方式也符合 程序计数器(PC 或 IP)的增长逻辑:在 指令执行的取指阶段,控制单元在完成取指后会控制 IP = 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 个标志位没有含义。

OF
DF
IF
TF
SF
ZF
AF
PF
CF
16 位标志寄存器

这些标志位在逻辑上可以被分为 条件标志(conditional flags)和 控制标志(control 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,表示发生了进位。

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

注意

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

对于两个 n 位数字的计算指令,只需要判断最高位是否有进位即可,如果有进位,OF 被设置为 1,否则被设置 0。

这是一种可行的方法,但在考试中常考察的是另一种方式,假设我们进行 $A$ 和 $B$ 的计算加法计算,两个数字都包含 $n$ 位,那么其计算结果可能包含以下几种情况:

  • $A$ 和 $B$ 中一个为负数,一个为正数,那么 $A+B$ 一定不会溢出。
  • $A$ 和 $B$ 中任意一个为 0,那么 $A+B$ 一定不会溢出。
  • $A$ 和 $B$ 都是正数
    • $A+B$ 的结果为负数,加法溢出
    • $A+B$ 的结果为正数,加法无溢出
  • $A$ 和 $B$ 都是负数
    • $A+B$ 的结果为正数,加法溢出
    • $A+B$ 的结果为负数,加法无溢出

令 $C=A+B$,则可以通过如下公式计算 OF:

$$\text{OF} = A_{n-1} \cdot B_{n-1} \cdot \overline{C_{n-1}} + \overline{A_{n-1}} \cdot \overline{B_{n-1}} \cdot C_{n-1}$$

对于减法指令,可以将其转化为等价的加法指令,进行同样逻辑的判断。

控制标志

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

  • 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 时,字符串操作在内存中向低地址方向移动。这通常用于从低地址向高地址扫描字符串。