<
  • 主题:
  • + -
  • 清除背景
  • 禁用背景
目 录
  1. 1. 计算机的运算方法
    1. 1.1. 整数表示
      1. 1.1.1. 无符号数与有符号数
      2. 1.1.2. 原码/补码/反码
      3. 1.1.3. 移码
    2. 1.2. 小数表示
      1. 1.2.1. 定点表示
      2. 1.2.2. 浮点表示
        1. 1.2.2.1. 浮点数的表示形式
        2. 1.2.2.2. 浮点数的规格化
      3. 1.2.3. IEEE 754 标准
        1. 1.2.3.1. IEEE 784中的移码
    3. 1.3. 定点运算
      1. 1.3.1. 移位运算
        1. 1.3.1.1. 算术移位
        2. 1.3.1.2. 逻辑移位
      2. 1.3.2. 加法与减法运算
        1. 1.3.2.1. 溢出判断
        2. 1.3.2.2. 补码定点加减法的硬件实现
      3. 1.3.3. 乘法运算
        1. 1.3.3.1. 硬件中的乘法运算
        2. 1.3.3.2. 原码乘法运算
        3. 1.3.3.3. 补码乘法(Booth乘法)
      4. 1.3.4. 除法运算
        1. 1.3.4.1. 原码除法
        2. 1.3.4.2. 补码除法
    4. 1.4. 浮点四则运算
      1. 1.4.1. 浮点加减运算
        1. 1.4.1.1. 规格化与阶码
        2. 1.4.1.2. 舍入
        3. 1.4.1.3. 溢出判断
      2. 1.4.2. 浮点乘除法运算
        1. 1.4.2.1. 浮点数乘法运算流程
        2. 1.4.2.2. 浮点数除法运算流程
    5. 1.5. 算术逻辑单元
      1. 1.5.1. ALU
      2. 1.5.2. 快速进位链
  2. 2. 指令系统
    1. 2.1. 机器指令
      1. 2.1.1. 指令格式
        1. 2.1.1.1. 操作码OP
        2. 2.1.1.2. 地址码A
      2. 2.1.2. 指令字长
    2. 2.2. 操作数类型和操作类型
      1. 2.2.1. 操作数类型
      2. 2.2.2. 操作类型
    3. 2.3. 寻址方式
      1. 2.3.1. 指令寻址
      2. 2.3.2. 数据寻址
    4. 2.4. RISC技术
      1. 2.4.1. RISC的发展背景
      2. 2.4.2. RISC的特点
      3. 2.4.3. RISC与CISC
  3. 3. CPU的结构和功能
    1. 3.1. CPU结构
      1. 3.1.1. CPU的功能
      2. 3.1.2. CPU的结构
      3. 3.1.3. CPU寄存器
        1. 3.1.3.1. 用户可见寄存器
        2. 3.1.3.2. 控制和状态寄存器
    2. 3.2. 指令周期
      1. 3.2.1. 指令周期的组成
      2. 3.2.2. 指令周期的数据流
    3. 3.3. 指令流水
      1. 3.3.1. 指令流水原理
      2. 3.3.2. 影响流水线性能的因素
      3. 3.3.3. 流水线性能
      4. 3.3.4. 流水线中的多发技术
      5. 3.3.5. 流水线结构
  4. 4. 中断系统
    1. 4.0.1. 中断的分类
    2. 4.0.2. 中断请求标记
    3. 4.0.3. 中断判优逻辑
    4. 4.0.4. 中断服务程序入口地址的查找
    5. 4.0.5. 中断响应
    6. 4.0.6. 保护现场和恢复现场
    7. 4.0.7. 中断屏蔽技术
      1. 4.0.7.1. 实现多重中断的条件
      2. 4.0.7.2. 屏蔽技术
  • 5. 控制单元CU
    1. 5.1. 微操作命令
      1. 5.1.1. 取指周期
      2. 5.1.2. 间址周期
      3. 5.1.3. 执行周期
      4. 5.1.4. 中断周期
    2. 5.2. 控制单元的功能
      1. 5.2.1. 控制单元的外特性
      2. 5.2.2. 多级时序系统
        1. 5.2.2.1. 时钟周期/机器周期/指令周期
        2. 5.2.2.2. 操作对应的时序
      3. 5.2.3. 控制方式
  • 6. 控制单元的设计
    1. 6.1. 组合逻辑设计
      1. 6.1.1. 微操作节拍安排
      2. 6.1.2. 组合逻辑设计步骤
    2. 6.2. 微程序设计
      1. 6.2.1. 微程序控制单元的工作原理
        1. 6.2.1.1. 机器指令与微程序的关系
      2. 6.2.2. 微程序控制单元结构
      3. 6.2.3. 微指令格式
      4. 6.2.4. 微指令的编码格式
      5. 6.2.5. 微指令序列地址的形成
      6. 6.2.6. 微指令格式
      7. 6.2.7. 静态微程序设计和动态微程序设计
      8. 6.2.8. 串行微程序控制和并行微程序控制
      9. 6.2.9. 毫微程序设计
  • 计算机组成原理(下)

    字数:44612 写于:2019-11-11
    最新更新:2019-11-11 阅读本文预计花费您128分钟

    计算机的运算方法

    整数表示

    无符号数与有符号数

    • 无符号数:所有的二进制位都用来表示数值大小,没有符号位,对于一个n位无符号数,其表示范围是0到2n-1。无符号数只能表示正数和零,无法表示负数,常用于表示内存地址、ASCII码、计数器等确定非负的数值
    • 有符号数:用二进制位的最高位作为符号位(0表示正,1表示负),其余位为数值位,能表示正数、负数和零,有符号数的表示有原码、补码、反码三种编码方式

    原码/补码/反码

    有符号数的表示中,由于机器无法识别符号形式的正负,因此通常用0表示正,1表示负。带有+和-符号的数称为真值(如:-1100),使用0、1表示正负的数称为机器数(如:11100)

    • 原码:符号位为0表示正数,符号位为1表示负数,数值位即真值的绝对值,故原码表示又称为带符号的绝对值表示。它存在两个零问题(以8位字长为例:+0 (00000000) 和−0 (10000000) ),运算器计算加减法需要先判断符号位再进行操作
    • 反码:对于正数,反码与原码相同;负数的反码在原码基础上,符号位保持不变,数值位逐位取反即可求出,它通常作为求补码的中间步骤,同样存在 +0 (00000000) 和 −0 (11111111) 问题
    • 补码:正数的补码与原码、反码相同,负数只需要在反码的基础上加 1,它是现代计算机表示有符号数的标准,可以减法操作转化为加法操作,即:A - B = A + [-B],这样运算器无需单独设计减法电路,大大简化了硬件设计

    移码

    当使用补码表示一个真值时,很难从补码本身直接判断其真值的大小,如比较数值大小时:101011(-21的补码)> 010101(21的补码),这与原数值大小结果相反

    移码是在补码的基础上,将符号位取反,其余位不变。其本质是将所有数值增大2n-1(n为字长),即将所有数值在数轴上整体向右平移了一个固定值,如:

    真值 补码 移码 移码对应无符号数
    -128 10000000 00000000 0
    -1 11111111 01111111 127
    0 00000000 10000000 128
    +1 00000001 10000001 129
    +127 01111111 11111111 255

    通过移码,我们人为设定了一个零点 10000000(-128),并保证了原数大小顺序。这样做的好处是将移码直接当作无符号数来比较,可以通过硬件实现按位比较两个数的大小,比用补码快得多

    小数表示

    在计算机中,有两种方式表示小数点的位置,即定点表示和浮点表示,定点表示的数称为定点数,浮点表示的数称为浮点数

    定点表示

    定点表示中,小数点位置分为两种:

    • 定点小数:小数点位置固定在符号位之后,数值最高位之前,即符号位 . 数值位,该表示方式下数值为纯小数,且绝对值一定小于1,表示范围为 -( 1 - 2-n) 到 (1 - 2-n),n为数值位长度
    • 定点整数:小数点位置固定在数值最低位之后,即符号位 数值位 .,该表示方式下数值为纯整数,表示范围为 -( 2n - 1) 到 (2n - 1),n为数值位长度

    浮点表示

    浮点数即小数点的位置可以浮动的数,它用类似科学计数法的方式表示小数,同一个小数有多种不同表示方式,如:352.47可以表示为3.5247 × 102,3524.7 × 10-1,0.35247× 103

    因此,浮点数可以统一表示为:

    N = S × r j

    S为尾数(可正可负,常用定点小数表示),j为阶码(可正可负,常用移码定点整数表示),r是基数

    浮点数的表示形式

    在计算机中,基数通常是2,并进行省略,浮点数表示方式为:

    阶符阶码数值数符尾数数值
    • 阶码的位数通常远少于尾数位数,且直接决定了数值的数量级,硬件比较大小时,CPU可以从高位向低位依次比较,因此阶码置于尾数前
    • 尾数决定精度,尾数位数越多,能表示的有效数字就越多,精度越高
    • 阶码决定表示范围,阶码位数越多,小数点能移动的范围越大,能表示的数值范围就越大
    • m位阶码(不包含符号位),n位尾数(不包含符号位),能表示:
      • 最大正数:2(2m-1)×(1-2-n )
      • 最小正数:2-(2m-1)×2-n
      • 最大负数:-2-(2m-1)×2-n
      • 最小负数:-2(2m-1)×(1-2-n)
    假设浮点数阶码的数值位有 m 位,尾数的数值位有 n 位,各有符号位1位,则有:
    类型 真值 阶码(补码表示) 尾数
    最大正数: 2 15×(1-2 -10) 01111 0.1111111111
    最小正数: 2 -15×2 -10 10001 0.0000000001
    最大负数: -2 -15×2-10 10001 1.1111111111
    最小负数: 2 15×(1-2 -10) 01111 1.0000000001
    浮点数的规格化

    浮点数表示中,同一个小数有多种不同表示方式,如:352.47可以表示为3.5247 × 102,3524.7 × 10-1,0.35247× 103,为了提高数据精度,并方便浮点数的比较,计算机中使用的尾数都需要进行规格化,表示为统一方式。

    规格化(Normalization)是指调整浮点数的尾数和阶码,使尾数的最高有效位保持为非零,以保证浮点数具有统一且唯一的表示形式。对于二进制浮点数,规格化后的形式通常表示为:

    1. xxxxx × 2 j

    如:0.001101 × 28 可规格化为 1.101 × 25,这是IEEE 754标准定义的表示形式。书上的非零最高位指的是小数点后第一位,因此该值规格化为 0.1101 × 26

    IEEE 754 标准

    现代计算机中,浮点数的表示使用IEEE 754标准:

    数符S阶码(含阶符)尾数
    • 表示整个浮点数正负的数符置于最高位
    • 阶码使用移码表示,因此阶符会作为阶码的一部分,合并表示
    • 尾数使用规格化表示,且最高有效值1在整数位上,即表示为 1.1010 而不是 0.11010。在二进制表示中,float和double整数位的1会进行隐藏,即1.1010在存储时存储为1010,小数点位于首部;long double不采用隐藏方案。

    IEEE标准中常用的浮点数有三种:

    类型 总位数 符号位S 阶码 尾数
    单精度(float) 32 1 8 23
    双进度(double) 64 1 11 52
    扩展双精度(long double) 80 1 15 64
    IEEE 784中的移码

    传统的移码只需要在补码的基础上,将符号位取反,这样会将所有数值增大2n-1,如:float的阶码有8位,在使用移码表示阶码时会将其在原真值的基础上增大 128,即偏置值bias=128

    IEEE 784标准中,偏置值设置为Bias = n n-1 - 1(单精度浮点数bias=127,双精度bias=1024),这样做的好处是:

    • 保留全 0 阶码表示非规格化数或零
    • 保留全 1 阶码表示无穷大或 NaN

    但它也将单精度阶码能表示的范围由理论上的 −128到+127 缩减为 −126到+127

    真值 补码 移码 移码对应无符号数
    -126 10000010 00000001 1
    0 00000000 01111111 127
    +127 01111111 11111110 254
    以单精度浮点数表示数值 178.125 : 其二进制表示为:10110010.001 规格化浮点数表示为:1.0110010001 x 27 规格化浮点数二进制表示为:1.0110010001 x 2111 计算阶码 阶码使用移码表示,进行偏移:7 + 127 =134,由此得IEEE阶码:10000110 也可以直接以二进制形式计算IEEE 阶码: 00000111 + 011111111 = 10000110 计算尾数: 原尾数:1.0110010001 规格化数隐藏最高位(整数位)的 1,存储时只保存: 0110010001 补齐到23位 01100100010000000000000 添加符号位 添加符号位并结合阶码尾数,由此得到178.125这一数值计算机内的最终表示: 01000011001100100010000000000000

    定点运算

    移位运算

    计算机中的二进制数进行 n位左移或右移操作,本质就是该数乘以或除以2 n

    算术移位

    算术移位中,无论正数还是负数,移位前后符号位均不变。移位的关键是空出的空位添补0还是1,不同的码制需要进行不同处理:

    真值 码制 添补
    正数原码、反码、补码0
    负数原码0
    补码左移添0
    右移添1
    反码1

    规则为:

    • 机器数为正时,不论是左移还是右移,添补代码均为0
    • 由于负数的原码数值部分与真值相同,故在移位时符号位不变,空位均添0
    • 由于负数的反码各位除符号位外与负数的原码正好相反,故移位后所添的代码应与原码相反,即全部添1
    • 分析负数的补码可发现,对其由低位向高位找到第一个”1”时,在此“1”左边的各位均与对应的反码相同,而在此“1”右边的各位(包括此“1”在内)均与对应的原码相同。故负数的补码左移时,因空位出现在低位,则添补的代码与原码相同,即添0,右移时因空位出现在高位,则添补的代码应与反码相同,即添1
    • 移位在高位丢弃1(超出能表示的机器字长)时结果会错误,低位丢弃1时会影响精度
    设机器字长为8位(包含符号位),A = +41,则有: A 的原码、反码、补码相同 A = 0,0101001 ​
    移位 机器码 真值
    移位前 0,0101001 41
    左移1位 0,1010010 82
    左移2位 0,0100100 36(溢出错误)
    右移1位 0,0010100 20 (丢失精度)
    逻辑移位

    有符号数的移位称为算术移位,无符号数的移位称为逻辑移位。逻辑移位的规则是:逻辑左移时,高位丢弃,低位添0;逻辑右移时,低位丢弃,高位添0

    加法与减法运算

    由于减法运算可转化为加法运算(A - B = A + (-B)),因此计算机中的加减法运算在本质上是一致的,现代计算机统一采用补码来进行加减法运算:

    • 加法:[A]补 + [B]补 = [A + B]补
    • 减法:[A - B]补 = [A]补 + [ -B ]补,其中[-B]补是由 [B]补 连同符号位在内,每位取反,末位加 1 求得
    • 模运算:运算结果需要进行溢出判断,没有溢出时,只需要正常计算,并丢弃最高进位,即可得出运算结果。这在数学上是求模运算,即结果按 2 n+1取模(对整数)或按 2 取模(对小数)
    1. 假设机器字长为8位(含一个符号位),A=15,B=24,则A-B为: [A]补= 0,0001111 [B]补= 0,0011000 ;[ -B ]补= 1,1101000 [A - B]补 = [A]补 + [-B]补 = 0,0011000 + 1,1101000 ------------- 1,1110111 [A - B]补 = 1,1110111 A - B = 1,0001001 = -9
    溢出判断

    定点数加减法的溢出,常用两种判断方法

    单符号位法

    单符号位法:两个同符号数相加,如果结果符号与之相反则溢出。由于减法也是使用加法运算的,因此这里包含两种情况:

    • 对于加法,在某个字长范围内,只有正数加正数负数加负数才可能出现溢出,符号不同的两个数相加是不会溢出的
    • 对于减法,在某个字长范围内,只有正数减负数(本质正数加正数)或负数减正数(本质负数加负数)两种情况下才可能出现溢出,符号相同的两个数相减是不会溢出的
    假设机器字长为 4 位,其能表示的范围为-8 ~ +7: A = 4,B = 5,则 A + B 有 [A]补 = 0,101 [B]补 = 0,100 ---------------- [A+B]补 = 1,001 A、B符号为0,结果的符号为1,说明溢出
    • 进位判断法:当计算机中采用1位符号位判断时,为了节省时间,通常用符号位产生的进位与最高有效位产生的进位异或操作后,按其结果进行判断。若异或结果为1,即为溢出;异或结果为0,则无溢出
    双符号位法
    • 双符号位法(变形补码)用两位符号位(如 00 正,11 负)表示数值的正负,运算后若两位符号位不同(01 或 10)则溢出。01 表示正溢出,10 表示负溢出
    假设机器字长为 4 位,其能表示的范围为-8 ~ +7: 1. 计算3 + 4 = 7 00.011 00.100 ------- 00.111 符号位为 00,无溢出 2. 计算5 + 4 = 9 00.101 00.100 ------- 01.001 符号位为01,正溢出 3. 计算(-6) + (-5) = -11 11.010 11.011 ------- 10.101 符号位为 10,负溢出
    • 双符号位进位判断:当计算机采用变形补码判断是否溢出时,这些数据寄存器或主存里,每个数据只保存1位符号位,它们只有在输入到加法器中执行运算时,才会将符号位拓展为相同的两位,以节约存储空间,同时又享受双符号位溢出检测的便利
    补码定点加减法的硬件实现

    现代计算机主要使用单符号位法来判断溢出(而非双符号位法),其核心判别逻辑为符号位产生的进位数值最高有效位产生的进位进行异或操作(1为溢出0无溢出),所需的硬件设备包含:

    • 寄存器:存放加数、被加数、运算结果等
    • 加法器 (ALU):执行加法运算,加法和减法共用同一套电路
    • 求补控制逻辑:对减法运算中的 [A]补 - [B]补 中的 [B]补 运算为 [-B]补。对于其他数,它们将由编译器或其他输入设备进行求补,CPU拿到的、内存中存储的已经是补码,不会等到运算时才进行求补。
    • 溢出检测电路:判断是否溢出
    • 状态标志寄存器:包括OF(有符号数溢出标志)、(无符号数进位/借位标志)、ZF(结果为0标志)、SF(结果符号标志)等

    乘法运算

    计算机中的乘法,主要通过加法移位运算实现。根据机器数表示形式的不同,定点乘法可分为原码乘法补码乘法两类,其中原码乘法需要单独处理符号位,而补码乘法可将符号位与数值位统一参加运算。

    具体而言,乘法运算是通过判断乘数当前位、产生部分积、移位和累加完成的。以 1101 × 1011 为例:

    • 设置一个部分积寄存器,初始值为 0
    • 从乘数的最低位开始逐位处理。若当前位为 1,则在部分积中加上被乘数 1101 ;若当前位为 0,则不进行加法操作
    • 处理完一位,被乘数左移1位(值扩大两倍),然后根据乘数的下一位,决定部分积是否加上当前的被乘数
    • 乘数遍历完毕,乘法运算结束
    1101 1011 × -------- # 部分积初始为0000 1101 # 乘数最低位为1,部分积加上被乘数 1101 1101 # 被乘数左移1位,乘数最低第2位为1,则部分积加上当前被乘数 11010(算式中省略了最低位0) 0000 # 被乘数再左移1位,乘数位为0,不加被乘数 110100 (算式中表现为加0) 1101 # 被乘数再左移1位,乘数位为1,加被乘数 1101000 -------- 10001111 # 最后求出的部分积即为乘法运算结果
    硬件中的乘法运算

    传统的乘法计算方式(以n位被乘数 × n位乘数为例)需要不断左移被乘数,并加到部分积中,左移次数为乘数的位数,最终会生成 2n 位的积。这种运算方法需要 2n 位乘数寄存器、部分积寄存器、加法器,硬件开销大,电路复杂。

    因此,现实中的硬件采用了另外一种方式:在运算时,计算机会将部分积A和乘数Q合并存放为(A,Q)形式,A、Q可以合并存放到同一个寄存器,也可以分开存放到两个寄存器中,它们会整体右移,并带来以下优点:

    • 乘数右移,方便依次判断最低位的值,来决定部分积是否要加上被乘数,这些被判断过的值不再有意义,可以移出丢弃
    • 部分积右移,但被乘数不动,就能间接实现被乘数左移的效果,使得每次移动,被乘数能加到部分积的高位
    • 由于以(A,Q)形式存放数据,依次部分积右移出去的数据会填入乘数右移空出来的位,来高效使用硬件资源
    • 这种方式只需要 n 位加法器和计算电路,硬件成本低。
    原码乘法运算

    原码乘法运算中,乘积的符号通过两个乘数符号的异或求出,乘积的数值部分由两个数的绝对值相乘求得

    e.g设 x = - 0.1110,y = -0.1101,以原码方式求 x · y: [x]原 = 1.1110,符号位:1,绝对值:0.1110 [y]原 = 1.1101,符号位:1,绝对值:0.1101 积的符号:1⊕1 = 0 积的数值初始化部分积 A = 0.0000 乘数Q = 0.1101 合并存放(为方便存储部分积大于1的值,因此部分积保留了n+1位) (0.0000,1101) 1. 乘数最低位为 1,部分积加上被乘数绝对值,然后整体右移 1 位 部分积:0.0000 + 0.1110 = 0.1110 (0.1110,1101) 右移 (0.0111,0,110) 2. 乘数最低位为 0 ,部分积加 0 ,整体右移1位 右移后 (0.0011,10,11) 3. 乘数最低位为 1,部分积加上被乘数绝对值,然后整体右移 1 位 部分积:0.0011+ 0.1110 = 1.0001 (1.0001,10,11) 右移 (0.1000,110,1) 4.3. 乘数最低位为 1,部分积加上被乘数绝对值,然后整体右移 1 位 部分积:0.1000 + 0.1110 = 1.0110 (1.0110,110,1) 右移 (0.1011,0110) 结果 符号位为: 0 值为:0.10110110 因此 [x · y]补 = 0.10110110
    上述方法为原码1位乘法,为了提高乘法运算速度,还衍生出了原码2位乘法(参考原书P248),以及并行阵列乘法,但现代计算机更偏向于使用补码乘法,这里省略
    补码乘法(Booth乘法)

    普通二进制乘法采用“移位加法”的方式实现:每次处理乘数的一位,若该位为 1,则将被乘数加入部分积,当乘数中存在大量连续的 1 时,会产生许多重复的加法操作,运算效率较低。

    现代CPU中的乘法器普遍采用Booth算法或其改进版本(如Radix-4 Booth),Booth乘法利用补码的特点,将连续出现的多个 1 转换为一次加法和一次减法,从而减少部分积的数量,提高乘法运算效率。如:对于乘数 00111100,如果使用采用普通乘法,需要对连续的四个 1 分别产生部分积。而对于Booth算法,它将 00111100看作 01000000 - 00000100 两数相减,因此原本需要进行多次加法,现在只需要进行:1次加法(使用01000000作为乘数计算部分积),1次减法(对结果减去00000100与被乘数的积)

    Booth算法的工作流程:在执行时,Booth算法会对乘数进行重新编码(如:Radix-4 Booth编码),以将连续的“1”串转化为加法和减法操作,且数的符号会和数值一起参与运算,而不需要单独的符号处理硬件电路。Booth算法具体步骤为:

    • 设部分积 A、乘数 Q、被乘数 M
    • 将A和Q合并存放到同一寄存器中(A,Q)
    • 在乘数最低位后添加一个附加位 0,构成(A,Q0),然后以乘数的每两位作为一组依次遍历运算:
      • 00 或 11 :不操作,只右移
      • 01 :部分积加被乘数
      • 10 :部分积减被乘数
    • 每步操作后:将寄存器 (A,Q) 整体算术右移一位(保持A的符号位),最后一步除外,运算到最后一步时,乘积不再右移
    • 遍历完毕后,Q的所有位数会被移出,原寄存器(A,Q)会只留下多次计算后的部分积(A),即乘法运算的最终结果
    e.g设机器字长为 4 位(包含1个符号位),计算 3 × (-2): 被乘数 [M]补 = [3]补 = 0,011 ;[-M]补 = 1,101 乘数 [Q]补 = [-2]补 = 1,110 初始化部分积 A = 0,000 初始化 乘数 [Q]补 末尾添加附加位 0 合并存放(A,Q0),因此最初的寄存器(A,Q) = 0000,11100 迭代过程 1.Q的值 11100 最低两位为 00 ,因此只需要把(A,Q)整体右移1位 (0000,11100) 右移1位后: (0000,01110) 2. Q的值 01110 最低两位为 10 ,执行 部分积 - 被乘数,然后(A,Q)整体右移1位 部分积:0000 - 0011 = 1101(-3) (1101,01110) 右移位 (1110,10111) 3. Q的值 10111 最低两位为 11,(A,Q)整体右移1位 移位后 (1111,00111) 4. Q的值 00111 最低两位为 11,(A,Q)整体右移1位 移位后 (1111,10101) 迭代结束: 乘数有 4 位 ,迭代 4 次,乘数已被移出完毕,Q遗留的辅助位 1 丢弃 此时: A = 1111,Q = 1010,n位 × n位 = 2n位积 拼接得 11111010(8位补码),最高位为符号位: 转换为十进制: 1,1111010 → 取反加一得 1,0000110 = -6,故积为 -6 结果正确,且优点如下: + 运算步骤并没有出现多次累加,而是通过多次移位高效完成 + 部分积移位时,乘数也在移位,如果二者分开移位,它们的位数会越来越长,且乘数的高位在补没有意义的0。二者合并移位时,部分积移出的位数会进入乘数的高位,有效节约硬件资源。直到计算结束时,寄存器中只留下部分积。 + 部分积、乘数既可以存放于同一寄存器,也可以分开,后者只需要将部分积移出的位数,移入乘数寄存器的高位,而不需要扩展寄存器的位数 整体运算
    步骤 乘数最低位组合 部分积A 右移位前(A,Q) 右移位后(A,Q)
    1 00 0,000 (0000,11100) (0000,01110)
    2 10 0000 - 0011 = 1101(-3) (1101,01110) (1110,10111)
    3 11 1110 (1110,10111) (1111,00111)
    4 11 1111 (1111,01011) (1111,10101)

    除法运算

    笔算除法主要通过以下步骤:

    • 比较被除数和除数大小,如果被除数够除,则上商1,否则商0
    • 被除数与除数做减法,求出余数;商0时,被除数与0做减法
    • 将被除数的下一位移入余数(被除数位数不够时低位补0),余数作为被除数重复上述步骤
    • 符号通过被除数和除数符号单独处理
      loading
      二进制除法

    计算机中的除法运算本质上是对上述过程的硬件化实现:

    • 除法运算结果的符号通过被除数和除数的符号异或求出
    • 通过比较被除数(或余数)和除数的绝对值大小来决定商1还是商0,这可以通过减法运算实现,即 |x|-|y|,若差为正则商1,差为负则商0
    • 为了实现笔算中将被除数的下一位落到余数中,硬件通常将余数寄存器左移一位,并从被除数(或商寄存器)中移入下一位数据,从而形成新的部分余数
    • 每产生一位商,就重复一次“左移 → 比较 → 减法 → 确定商位”的过程,直至得到完整商和余数
    原码除法

    原码运算中,符号位单独异步处理,值运算处理被除数和除数的绝对值

    恢复余数法

    根据上述除法实现思路,商0还是商1本质上取决于|x|-|y|的结果,因此恢复余数法的核心思想是采用“先减后判断”的策略,即:

    • 直接对被除数(或余数)做减法运算,减去除数
      • 如果结果为正数,则商1,并保留该结果作为新的余数
      • 如果结果为负数,则商0,并将刚减去的除数重新加回去,使余数恢复到减法前的值
    • 将余数进行左移1位,进入下一轮运算
    e.g已知 x = -0.1011 , y = -0.1101,求 x/y: 符号位通过异或单独计算,计算值时只取其绝对值 [x]原 = 0.1011 [y]原 = 0.1101,[-y]补 = 1.0011(|x|-|y|通过 [x] + [-y]实现) 运算步骤 1. 被除数x 减去除数 y ,通过 + [-y]补 实现 0.1011 + 1.0011 = 1.1110 余数为负数,说明 |x| < |y|,商0,当前商0 2. 做减法是为了试探商应该上0还是1,由于试探操作导致现在被除数本身已经被减去了y,因此需要重新将值恢复到试探前。即执行 + y操作,这也是恢复余数法名称的由来 1.1110 + 0.1101 = 0.1011 (恢复到了上一步) 3. 余数左移一位(逻辑左移) 1.0110 4. 开始第二轮减法,+ [-y]补 1.0110 + 1.0011 = 0.1001 余数为正数,说明 |x| > |y|,商1,当前商01 5.余数左移一位 1.0010 6.开始第三轮减法,+ [-y]补 1.0010 + 1.0011 = 0.0101 余数为正数,商1,当前商011 7. 余数左移一位 0.1010 8.开始第四轮减法,+ [-y]补 0.1010 + 1.0011 = 1.1101 余数为负,商0,当前商0110 9. 恢复余数,+ y 1.1101 + 0.1101 = 0.1010 10.余数左移一位 1.0100 11.开始第五轮减法,+ [-y]补 1.0100 + 1.0011 = 0.0111 余数为正,商1,当前商为01101 结果 商够4位,值0.1101 符号位异步结果为0 因此 x/y= 0.1101

    恢复余数法的缺点是,每当余数为负数时,都需要恢复余数,操作步骤繁多,效率较慢,且操作不规则,硬件设计复杂,加减交替法可以克服这些缺点。

    加减交替法

    加减交替法又称为不恢复余数法,它是对恢复余数法的一种改进。由于恢复余数法的步骤可以归纳为先计算 |x| - |y|:

    • 当余数 R > 0 时,商1,再对 R 左移一位,然后减去除数,即:2R - y
    • 当余数 R < 0 时,商0,先恢复余数执行R + y,再将R左移一位,然后减去除数,即:2(R+y)-y,即 2R + y

    由此,上述步骤可总结为:

    • 当 R > 0 时,商1,执行 2R - y
    • 当 R < 0 时,商0,执行 2R + y

    因此,加减交替法只做 + y 或 - y 操作,不进行恢复余数

    e.g已知 x = - 0.1011,y = 0.1101,求 x/y: 同样,符号位通过异或单独计算,计算值时只取其绝对值 [x]原 = 0.1011 [y]原 = 0.1101,[-y]补 = 1.0011 1. 执行 x - y ,通过 x + [-y]补 实现 0.1011 + 1.0011 = 1.1110 余数为负,商0,当前商0 2.余数左移1位 1.1100 3.由于上一步R < 0,执行 余数 + y 1.1100 + 0.1101 = 0.1001 余数为正,商1,当前商01 4.余数左移1位 1.0010 5.由于上一步R > 0,执行 余数 - y 1.0010 + 1.0011 = 0.0101 余数为正,商1,当前商011 6.余数左移1位 0.1010 7.由于上一步R > 0,因此执行 余数 - y 0.1010 + 1.0011 = 1.1101 余数为负,商0,当前商0110 8. 余数左移1位 1.1010 9.由于上一步R < 0,因此执行 余数 + y 1.1010 + 0.1101 = 0.0111 余数为正,商1,当前商01101 结果 商值为 0.1101 符号位异步结果为0 因此 x/y= 0.1101

    加减交替法中,n 位小数的除法共上商 n + 1 次(第一次商用来判断是否为溢出),逻辑左移 n 次,因此可用移位次数判断除法是否结束

    补码除法

    补码除法中,符号位和数值部分一起参与运算,符号位无需单独处理。补码除法也分为恢复余数法和加减交替法,加减交替法用的较多,只介绍加减交替法,其计算流程为:

    • 求商:由于补码本身带有符号,因此不能简单通过判断绝对值 |x| - |y| 来看被除数 x 够不够除 y (决定商 1 还是商 0),而是需要连同被除数与除数的符号位也考虑在内:
      • [x]补 与 [y]补 同号,执行 [x]补 - [y]补 运算,若余数[R]补 与 [y]补 同号,表示够减,商1;若[R]补 与 [y]补 异号,表示不够减,商0
      • [x]补 与 [y]补 异号,执行 [x]补 + [y]补 运算,若余数[R]补 与 [y]补 同号,表示不够减,商1;若[R]补 与 [y]补 异号,表示够减,商0
    • 移位:将余数、商左移 1 位,重复上述计算,比较余数和除数的符号位,决定计算方式和商值
    • 修正末位商:n位数除法,需要n次移位,循环结束,最低位强制置为 1,进行截断。该方法硬件简单,最大误差仅为 2 -n
    • 余数修正:大部分除法无法除尽,如果需要余数,则需要对余数进行修正,如果最终余数与除数异号,则需加上除数 [y]补 进行校正
    e.g设 x = -0.1001,y = +0.1101,求[x/y]补: [x]补 = 1.0111 [y]补 = 0.1101,[-y]补 = 1.0011 计算 1. x 与 y 异号,执行 x + y 1.0111 + 0.1101 = 0.0100 余数与 y 同号,商1,当前商1 2. 余数、商左移1位(商只需空出低位给下一次商留位置) 余数 = 0.1000 3. 余数与 y 同号,执行 余数 - y 0.1000 + 1.0011 = 1.1011 余数与 y 异号,商0,当前商10 2. 余数、商左移1位 余数 = 1.0110 余数与 y 异号,执行 余数 + y 1.0110 + 0.1101 = 0.0011 余数与 y 同号 ,商1,当前商101 3. 余数、商左移1位 余数 = 0.0110 4. 余数与 y 同号,执行 余数 - y 0.0110 + 1.0011 = 1.1001 余数与 y 异号,商0,当前商1010 5.余数、商左移1位 余数 = 1.0010 这已经是第 4 次移位,计算结束,商末尾恒置 1 当前商10101 结果 [x/y]补 = 1.0101

    浮点四则运算

    浮点加减运算

    浮点数中,阶码的大小直接反映数值的量级,以及尾数小数点的实际位置,因此尾数不能直接进行加减运算,而需要对阶之后才能开始运算。浮点数的加减运算必须按以下几步进行:

    • 对阶:其目的为了让两操作数的小数点位置对齐,使两数的阶码相等。通常需要先求出阶差,再按小阶向大阶看齐的原则,使阶小的尾数向右移位,每右移一位,阶码加1,直到两数的阶码相等为止。尾数右移时,末尾的1丢弃,会影响数据精度
    • 尾数求和:对阶后的尾数可以直接求和/差
    • 规格化:求和/差后的尾数需要重新规格化
    • 舍入:尾数右移时,对末位0和1的处理有不同策略
    • 溢出判断:与定点加减法一样,浮点加减运算最后一步也是判断溢出,且判断需要在进行规格化和舍入之后进行,刚计算完看似溢出的数(尾数出现01.xxxx和10.xxxx),依旧可能通过右规完成规格化且不溢出
    e.g两浮点数 x = 0.1101 × 2 01,y = -0.1010 × 2 11,求 x + y: x,y通过阶码;尾数形式表示的补码为(这里尾数使用变形补码表示,符号位有两位,方便后面判断溢出): [x]补 = 00,01;00.1101 [y]补 = 00,11;11.0110 1. 对阶 阶差 = x阶码 - y阶码 = 0001 + 1101 = 11,10 = -2 因此 x 阶码比 y 的阶码小,根据小阶向大阶看齐原则,x的尾数需要右移2位,因此有对阶后的x: [x]补 = 00,11;00.0011 末尾1被丢弃,x的精度下降 2. 尾数求和 对阶后的两数: [x]补 = 00,11;00.0011 [y]补 = 00,11;11.0110 尾数相加: 00.0011 + 11.0110 = 11.1001 因此 [x + y]补 = 00,11;11.1001 3. 规格化 11.1001 × 2 11不是规格化数,因此需要规格化为 11.0010 × 2 10 因此,x + y = (-0.1110) × 2 10
    规格化与阶码

    进行尾数求和后,新的尾数通常需要重新规格化,这里规格化的介绍基于数值计算,而不是使用IEEE 754 标准

    二进制浮点数 S 规格化的定义为,其绝对值满足:

    1 2 |s| < 1

    对此,规格化数满足以下:

    S>0时 规格化形式 S<0时 规格化形式
    真值 0.1xxxx 真值 -0.1xxxx
    原码 0.1xxxx 原码 1.1xxxx
    补码 0.1xxxx 补码 1.0xxxx

    即满足:

    • 原码:无论正数、负数,数值为最高位为1
    • 补码:符号位与数值最高位不同

    在硬件中,数据通常存储为补码,并使用异或电路比较数值最高位和符号位是否相同,来判别一个数是否已规格化,但有两个特殊:

    • -0.5的补码为 1.1000,数值本身其实已经是规格化的数,但其符号位和数值位相同,为了方便硬件电路实现,因此特别规定 -1/2不是规格化数
    • -1 不满足 |s| < 1,但其补码为 11.0000 满足数值最高位与符号位不同,因此 -1 视为规格化的数
    左规

    当尾数为0.0xxxx1.1xxxx时,需要左规,尾数每左移 1 位,阶码减1,直到数符和数值最高位不同为止,上一个示例中就是左规

    右规

    当尾数溢出( > 1)时,即尾数出现01.xxxx10.xxxx时,需要右规,尾数每右移 1 位,阶码加1

    e.g两浮点数 x = 0.1101 × 210,y = 0.1011 × 201,求 x + y: x,y的补码表示 [x]补 = 00,10;00.1101 [y]补 = 00,01;00.1011 1. 对阶 阶差 = 0010 + 1111 = 0001 y的阶码比x小1,因此对阶后的y: [y]补 = 00,10;00.0101 2. 尾数求和 00.1101 + 00.1011 = 01.0010 因此[x + y]补 = 00,10;01.0010 3.尾数溢出,需要右规 尾数右移 1 位,阶码加 1 x + y = 0.1001 × 211
    舍入

    无论是在对阶还是右规过程中,尾数的低位丢失,会引起误差,影响数据精度,因此可通过舍入法提高尾数精度,常用的舍入法有两种:

    • 0舍1入:即被丢弃的末位数为 0 时直接舍弃,被丢弃的末位数为 1 时,则原数末位数 +1
    • 恒置1法:无论被丢弃的末位数为 0 或 1 ,都直接将右移后的尾数末位置为 1
    溢出判断

    浮点表示方式所能表示的数是离散的,有的数只能近似表示,且由于机器字长有限,因此计算机能表示的浮点数范围也有限,当数据发生上溢时,需要进行异常中断处理,数据发生下溢时,则直接将数当作机器零处理

    以2位阶符,7位阶码,2位数符,n位尾数的补码为例

    loading
    浮点溢出
    • 最小负数A:2 +127 × ( -1)
    • 最大负数a:2 -128 × (-2 -1 - 2 -n)
    • 最小正数b:2 -128 × 2 -1
    • 最大正数B:2 +127 × (1 -2 -n)
    • 下溢:指a-b之间,阶码小于 -128 的数,这些浮点数数值很小,趋近于0,因此计算机会将其作为零处理,而不做溢出处理
    • 上溢:A、B两侧,阶码大于 +127的数,这些浮点数数量级很大,已经超出机器能表示的范围,计算机需要中断计算,做溢出处理

    浮点乘除法运算

    x = Sx • r jxy = Sy • r jy

    • 乘法:乘积的阶码为相乘两数的阶码之,乘积的尾数为相乘两数的尾数之,即:
    x • y = ( Sx Sy ) × r jx + jy
    • 除法:商的阶码为被除数的阶码除数的阶码,尾数为被除数的尾数除以除数的尾数所得的商
    x y = Sx Sy r j x - j y
    浮点数乘法运算流程
    • 符号位处理:当尾数使用原码运算时,数符需要单独通过异或计算;当尾数使用补码运算时,数符本身位于补码中,连同数值一起参与运算,此时不需要单独的符号处理
    • 阶码相加:通常用补码定点加法完成,即 [ jx ]补 + [ jy ]补,也可以用移码表示阶码,但计算更复杂,具体参考P275
    • 阶码溢出判断:对规格化后的阶码进行溢出判断
    • 尾数相乘:按定点乘法规则运算,如果尾数是原码形式使用移位加法处理,如果尾数是补码使用Booth算法处理(连同符号位一起运算)
    • 尾数规格化:若乘积尾数不是规格化数(即尾数数值位最高位不为1),需左移尾数并相应减少阶码,乘法结果最多只需左规一次
    • 舍入处理:两个 n 位(寄存器字长为n)的尾数相乘将获得 2n 位乘积结果,为了将该结果存回寄存器,需要对尾数乘积结果进行舍入处理。主要的舍入方法有两种:
      • 0舍1入:如果被截去部分的最高位为 0 ,直接丢弃;如果为 1 ,则在所保留尾数的最低位加1(若加上1后,产生多次进位导致尾数溢出,如:变成了1.0xx形式,则需要再次右规)
      • 恒置1:不论移去的最高位是0还是1,直接将保留尾数的最低位强制置为 1,硬件实现简单,但误差稍大
    阶码溢出判断

    当使用补码表示阶码时,通常通过变形补码的符号位来判断是否溢出(具体参考“定点运算”中加减法的溢出判断):

    • 00 阶码为正,无溢出
    • 11 阶码为负,无溢出
    • 01 阶码上溢,做溢出处理
    • 10 阶码下溢,做机器零处理
    浮点乘法的规格化特点

    乘数和被乘数的尾数为规格化数,满足:

    0.5≤∣S∣<1

    因此它们的积的尾数满足:

    0.25≤∣Sx​Sy​∣<1

    即:乘积尾数只可能落在 [0.25,1),而规格化要求 [0.5,1),因此乘法结果最多只需左规一次,尾数左移1位,阶码减1,规格化后的尾数,应当满足以下要求:

    • 对于原码表示的尾数:小数点后第一位必须是1,即:0.1xxxx(正数)或1.1xxxx(负数)
    • 对于补码表示的尾数:符号位之后的“第一位有效位”必须与符号位相反,即:0.1xxxx(正数)或1.0xxxx(负数)
    e.g阶码取 3 位(不含阶符),尾数取 7 位(不含数符),均使用补码表示,结果保留 1 位字长 设 x = 2 -101 × 0.0110011,y = 2 011 × ( -0.1110010 ),求 x · y: [x]补 = 11,011;00.0110011 [y]补 = 00,011;11.0001110
    阶码运算 [jx]补 + [jy]补 = 11,011 + 00,011 = 11,110 阶码溢出判断 双符号位相同,11表示负数,其真值是 -010 = -2
    尾数计算(按定点乘法规则,Booth乘法) 00.0110011 × 11.0001110 Booth乘法中的部分积 - 被乘数运算,通过部分积 + [- 被乘数]实现 因此对被乘数 Sx = 00.0110011 求其 [-Sx]补 = 11.1001101 部分积 A = 00.0000000(为方便最后判断是否溢出,保留两个符号位) 乘数Q = 1.0001110末尾补0 在寄存器中合并存放(A,Q0): 00.0000000,100011100 1. 由于 1.00011100 末尾为 00,因此只需要将寄存器 (A,Q) 整体算术右移1位 00.0000000,010001110 2. 由于 0.10001110 末尾为 10,因此部分积减被乘数,然后(A,Q)右移1位 部分积:0 + 11.1001101 = 11.1001101 11.1001101,010001110 移位后(算术右1,保持A的符号不变) 11.1100110,101000111 3.由于 1.0100011 末尾为 11,因此(A,Q)右移1位 11.1110011,010100011 4.由于 0.10100011 末尾为 11,因此(A,Q)右移1位 11.1111001,101010001 5.由于 101010001 末尾为 01,因此部分积加被乘数,然后(A,Q)右移1位 部分积:11.1111001 + 00.0110011 = 00.0101100 00.0101100,101010001 移位后 00.0010110,010101000 6.由于 010101000 末尾为 00,因此(A,Q)右移1位 00.0001011,001010100 7.由于 001010100 末尾为 00,因此(A,Q)右移1位 00.000101,100101010 8.由于 100101010 末尾为 10,部分积减被乘数,然后(A,Q)右移1位 部分积:00.000101 + 11.1001101 = 11.1010010 11.1010010,100101010 最后一次运算不右移 尾数有 7 位(不包含符号位),已经执行完7轮右移 因此尾数结果为:11.110100101001010(丢弃了运算时遗留的乘数的符号位和辅助位)
    阶码结果为:11,110 尾数结果为:11.10100101001010 [ x · y ]补 = 11,110;11.10100101001010 需左规 [ x · y ]补 = 11,101;11.0100101001010 保留 1 倍字长,即 3 位阶码,7 为尾数(不包含阶符、数符) [ x · y ]补 = 11,101;11.0100101 最终结果: x · y = 2-011 x ( -0.1011011 )
    浮点数除法运算流程

    对于浮点数运算,对已经规格化的尾数,为了防止除法结果溢出,如果被除数绝对值大于除数绝对值,可以先将被除数右移 1 位,阶码加1,这样尾数相除结果必然是规格化的定点小数。

    符号位处理:当尾数使用原码运算时,数符需要单独通过异或计算;当尾数使用补码运算时,数符本身位于补码中,连同数值一起参与运算,此时不需要单独的符号处理

    • 阶码相减:阶码进行补码定点减法运算,即[ jx ]补 - [ jy ]补
    • 尾数相除:按定点除法规则进行运算,分为原码运算和补码运算,具体流程参考上文定点除法
    • 结果规格化:除法结果可能为非规格化数,需进行规格化处理
    • 阶码溢出判断:对规格化后的阶码进行溢出判断
    浮点除法的规格化特点

    被除数和除数的尾数为规格化数,满足:

    0.5≤∣S∣<1

    因此它们的商的尾数满足:

    • 最小:0.5/1 = 0.5
    • 最大:1/0.5 = 2
      0.5≤∣Sx​Sy​∣<2

    即:乘积尾数只可能落在 [0.5,2),而规格化要求 [0.5,1),落在该区间已经满足规格化,落在[1,2)时除法结果最多只需右规一次,尾数右移1位,阶码加1,规格化后的尾数,应当满足以下要求:

    • 对于原码表示的尾数:小数点后第一位必须是1,即:0.1xxxx(正数)或1.1xxxx(负数)
    • 对于补码表示的尾数:符号位之后的“第一位有效位”必须与符号位相反,即:0.1xxxx(正数)或1.0xxxx(负数)
    e.g按补码浮点数运算法则,计算:
    [ 2 5 × ( + 9 16 ) ] ÷ [ 2 3 × ( - 13 16 ) ]
    令 x = 被除数 = 2 101 × (0.1001) y = 除数 = 2 011× (- 0.1101) 则 [x]补 = 00,101;00.1001 [y]补 = 00,011;11.0011;尾数 [-y]补 = 00.1101 阶码相减 00,101 - 00,011 = 00,101 + 11,101 = 00,010 阶码溢出判断 双符号位相同,00表示正数,其真值是 010 = 2 尾数计算(按补码定点除法) 00.1001 ÷ 11.0011 [Sx]补 = 00.1001(记为 x ) [Sy]补 = 11.0011(记为 y );[-Sy]补 = 00.1101(记为 -y ) 1. 被除数 与 除数 异号,执行 x + y 00.1001 + 11.0011 = 11.1100 余数与 y 同号,商 1 ,当前商1 2.余数、商左移1位(商只需空出低位给下一次商留位置) 余数 = 11.1000 3. 余数与y同号,执行 余数 - y 11.1000 + 00.1101 = 00.0101 余数与y异号,商 0 ,当前商10 4.余数、商左移1位 00.1010 5. 余数与y异号,执行 余数 + y 00.1010 + 11.0011 = 11.1101 余数与y同号,商1,当前商101 6.余数、商左移1位 11.1010 7.余数与y同号,执行 余数 - y 11.1010 + 00.1101 = 00.0111 余数与 y 异号,商0,当前商1010 8. 余数、商左移1位 余数 = 00.1110 已经移位 4 次,商末尾恒置 1,计算结束 当前商10101 [Sx/Sy]补 = 1.0101 尾数结果为补码形式,符号位和小数点后最高位相反,已规格化 结果 [x/y]补 = 00,010;11.0101 [x/y] = 2 010 × ( -0.1011 ) 由此 xy = 22 × ( - 11 16 )

    算术逻辑单元

    ALU

    算术逻辑单元ALU(Arithmetic Logic Unit)是 CPU 中负责 数据处理与运算的核心部件,它支持:

    • 算术运算:包括加、减、乘、除、递增、递减,ALU本质只有加法器,减、乘、除等其他运算通过加法器、逻辑电路、移位运算组合而成。
    • 逻辑运算:包括AND(与)、OR(或)、XOR(异或)、NOT(取反)等逐位运算
    • 移位运算:包括逻辑左移/右移、算术右移(保留符号位)、循环移位
    • 比较运算:本质通过 A - B 减法运算,来产生标志位

    ALU执行指令时,控制单元根据译码结果生成控制信号,指定运算类型(加、减、逻辑、移位等),并从寄存器或数据通路中取出操作数A和B送入ALU。内部由相应硬件完成运算后,输出结果写回寄存器或送入后续数据通路,同时更新状态标志(如零标志Z、符号标志N/S反映正负)。这一过程通常在单周期或流水线阶段内完成,是CPU指令执行的核心环节

    快速进位链

    加法运算是ALU的基础,几乎所有算术运算(减法、比较、乘除等)都可以归结为加法实现,当处理长数据(如 32 位或 64 位)时,加法器的主要性能瓶颈不在于求和逻辑,而在于进位信号的传递,因为第 i 位的计算必须依赖第 i−1 位的进位结果,由此引发了进位链问题。

    为提高运算速度,ALU硬件采用并行加法器结构,n 个全加器级联组成 n 位并行加法器,每一位的“求和逻辑”可以同时进行,而进位的传递有两种方式:

    • 串行进位链:每一位的进位由低位逐级传递到高位,其优点是电路简单,但速度很慢,延迟随位数线性增长,因此在大位宽运算中性能较差
    • 并行进位链是指并行加法器中的进位信号是同时产生的,又称先行进位、跳跃进位等。理想的并行进位链是n位全加器的n位进位同时产生,但实际实现有困难。通常并行进位链有单重分组和双重分组两种实现方案:
      • 单重分组跳跃进位:将n位全加器分成若干小组,小组内的进位同时产生,小组与小组之间采用串行进位,这种方式速度有所提升,但组间进位仍是瓶颈
      • 双重分组跳跃进位:将n位全加器分成若干大组,每个大组中又包含若干小组,大组内各小组的最高位进位同时产生,而大组间进位采用串行传递,这种方式进一步提升了速度

    指令系统

    机器指令

    机器指令(Instruction)是CPU能直接识别并执行的二进制编码命令,是程序执行的基本单位,计算机中机器指令的集合称为该机的指令系统。

    指令格式

    指令格式是指令中各字段的组成与编码方式,一条机器指令通常由操作码地址码两部分组成:

    • 操作码(Opcode):说明要执行的操作类型(如加、减、取数、存数、转移等),操作码的位数反映了机器允许的指令条数,如操作码占7位,则该机器最多包含27=128条指令
    • 地址码(Operand / Address):指明操作数或其存放位置
    操作码OP

    操作码的长度可以是固定的,也可以是变化的,由此操作码分为:

    • 定长操作码:指令中操作码的位数固定,其特点是译码简单、控制方便,但灵活性差,通常用于RISC(精简指令集计算机)、大中型计算机(如:IBM 370)
    • 扩展操作码(可变长度操作码):操作码位数是可变的,可以通过预留码点进行扩展,Intel 8086系列采用扩展操作码
    可变长度操作码

    操作码长度不固定时,控制器需要采用扩展操作码技术,调整操作码与地址码的位数。如图是一种扩展操作码示意图,指令字长为16位。若采用定长操作码方案,4位为操作码OP,其余字段均是地址字段时,操作指令有 16 条。若采用扩展操作码技术,可以有不同分配方案,某种分配方案为:

    • 分配 4 位操作码,其余分为三个地址,则共有 15 条三地址指令(有1条前缀需要留给其他长操作码)
    • 分配 8 位操作码,其余分为两个地址,共有 15 条二地址指令(同样保留1条前缀)
    • 分配 12 位操作码,其余分为一个地址,共有 15 条一地址指令(同样保留1条前缀)
    • 分配 16 位操作码,不需要地址位,共有 16 条零地址指令(不需要保留前缀)

    loading
    扩展操作码

    地址码A

    地址码用来指出指令所需源操作数的地址结果的存放地址以及下一条指令的地址,这里的地址可以是主存的地址、寄存器的地址、甚至是I/O设备的地址。指令与地址有以下几种经典格式:

    • 四地址指令:4个地址分别是操作数一、操作数二、结果地址、下一条指令地址,可用于表示带跳转的运算,如:ADD R1, R2, R3, NEXT 表示计算 R1 + R2 存放到 R3,然后跳转到NEXT。但大部分CPU中,通常由程序计数器PC指出下一条指令地址,由此四地址指令几乎不用。
    • 三地址指令:3个地址主要用于显式指定两个操作数地址和结果存放的地址,而不再包含下一条指令地址,通常用于编译器的中间代码表示,如:MUL R1, R2, R3表示计算R1 * R2存放到R3
    • 二地址指令:现代主流的通用寄存器架构,OP A1, A2 中 A1 和 A2 的运算结果会存回(覆盖) A1
    • 一地址指令:常用于累加器结构(ACC),执行 OP A 操作时,ACC和A的操作结果会存入 ACC 中,唱见操作有,如:ADD X,每次累加X
    • 零地址指令:指令字中无地址码,主要有两类操作:
      • 空操作(NOP)、停机(HLT)这类指令本身只有操作码
      • 子程序返回(RET)、中断返回(IRET)这类指令,其操作数地址隐含在堆栈指针SP中,不需要在指令中给出

    指令字长

    指令字长通常是机器字长的整数倍或一半,可以是半字、单字、双字,通常取决于机器的数据总线和存储字长。

    操作数类型和操作类型

    操作数类型

    • 地址:一个无符号整数
    • 数字:包括定点数、浮点数、各进制的数等
    • 字符:文本或字符串
    • 逻辑数据:用于逻辑运算的数,如:布尔类型的数据,它们区别于算术运算的数

    操作类型

    不同机器支持的操作类型不同,以下是一些通用的操作类型:

    • 数据传送:指数据从源地址到目的地址的复制,如:寄存器、存储单元之间的数据传送,设备的读写、数据交换、置1、清0、进栈、出栈等,这类指令不改变数据本身的二进制数值,不影响状态标志位
    • 算术逻辑操作:实现算术运算(加、减、乘、除、增1、减1、取负数即求补)和逻辑运算(与、或、非、异或)等
    • 移位:包括算术移位、逻辑移位和循环移位,其最显著特征是会影响状态标志寄存器
    • 转移:多数情况下,计算机按顺序执行每条指令,如果需要改变这种顺序,可以使用转移类指令来改变程序计数器PC的值,以此改变执行流。转移指令按其转移特征分为以下几类:
      • 无条件转移不受任何条件约束,可直接把程序转移到下一条需执行指令的地址。例如“JMP X”其功能是将指令地址无条件转至X
      • 条件转移:根据当前指令的执行结果来决定是否需要转移,判断依据来自当前指令产生的标志位,如:零标志位(Z)、负标志位(N)、溢出标志位(V)、进位标志位(C)、奇偶标志位(P)等
      • 调用与返回:用于调用一些需要反复使用的子程序,它们需要在调用完毕后返回到原程序的断点,这些程序可能是一些子函数、外设的驱动程序等,执行时通常由调用指令(CALL)返回指令(RETURN)搭配使用,该过程隐含使用堆栈,CALL指令在执行时,会自动将“下一条指令的地址”(断点)压入堆栈,然后程序计数器PC指向子程序入口,RETURN时则自动从堆栈弹出断点送回PC
      • 陷阱(Trap)与陷阱指令:陷阱(Trap)是一种由CPU在执行过程中因异常事件或特定指令触发的同步中断机制。当系统运行时发生如除零错误、溢出、非法指令、存储器校验错、I/O设备故障或特权指令违规等情况,CPU会自动发出陷阱信号,暂停当前程序执行,转入相应的处理程序进行处理,以保证系统的正常运行。
        陷阱指令通常不直接提供给用户程序使用,在多数机器中作为隐指令(由CPU自动产生并执行)实现,用于处理异常情况。
        但在部分计算机系统中,也提供了显式的陷阱指令(又称“访管指令”或软中断指令),供用户程序调用操作系统服务,实现系统调用。例如 Intel 8086 的 INT n 指令,通过指定中断类型号触发相应的系统功能调用,本质上属于用户可用的陷阱机制
    • 输入输出:对于使用统一编址方式的I/O设备,I/O设备占用主存地址空间,访问这些设备直接使用访问主存的指令即可(如上述数据传送指令);对于使用独立编址的I/O设备,它们需要专门的IN/OUT指令
    • 其他:包括等待指令、停机指令、空操作指令、开中断指令、关中断指令、置条件码指令等,可用于处理机控制与调试。以及在一些大型或巨型机中,用于整个向量或矩阵进行求和、求积等各类运算的向量指令等

    寻址方式

    指令寻址

    分为顺序寻址跳跃寻址

    • 顺序寻址:指令顺序执行,通过程序计数器PC加1,自动形成下一条指令的地址
    • 跳跃寻址:通过转移类指令实现

    数据寻址

    数据寻址方式较多,通常在指令中给出的地址码并不是操作数的真实地址,而是一种形式地址(记作A),操作数的真实地址称为有效地址(记作EA),需要由寻址方式和形式地址共同确定,数据的寻址方式有以下类型:

    • 立即寻址:指令中直接给出了操作数本身(因此称为立即数),数据采用补码形式给出,指令执行时无需访问内存
    • 直接寻址:指令中给出的形式地址A就是操作数的真实地址EA,即 A = EA,指令执行时只需要访问一次主存,但缺点在于A的位数限制了操作数的寻址范围,而且必须修改A的值,才能修改操作数的地址
    • 隐含寻址:指令中不明显地给出操作数的地址,而是隐含在操作码或某个特定寄存器(如累加器ACC)中,常用于一地址指令格式,如 ADD A,另一个操作数默认在累加器ACC中
    • 间接寻址:即形式地址指向的存储单元中,存放着操作数的真实地址,EA = (A),指令执行阶段需两次访存。间接寻址可以多次嵌套,形成多次间接寻址,如:两次间接寻址,A地址单元的内容为另外一个形式地址 A1,A1所指单元的内容为EA,EA所指单元内容才是操作数。间接寻址能极大地扩大操作数的寻址范围,如:若设指令字长和存储字长均为16位,指令中的地址字段A仅为8位,直接寻址范围为 2 8,一次间接寻址范围为2 16,缺点是需要多次寻址,指令执行时间长。
    • 寄存器寻址:地址字段给出的是寄存器编号,操作数位于寄存器中,该寻址方式的特点是无须访存,指令执行速度快,节省存储空间
    • 寄存器间接寻址:寄存器中存放的是操作数所在主存地址,因此指令执行时,还需要访问一次主存,它比间接寻址少访存一次,寻址范围大(由寄存器位数决定)
    • 基址寻址:有效地址由基址寄存器(BR)的内容加上形式地址 A 形成,即:EA = (BR) + A,该寻址方式要求机器设有基址寄存器BR(隐式基址寄存器),或者指定一个通用寄存器作为基址寄存器(显式基址寄存器)。基址寄存器的地址通常由操作系统确定,在程序执行过程中不变,而指令中 A 的地址改变,常用于程序重定位,如:程序在内存中的装载位置具有动态性,其指令中仅包含相对于程序起始点的偏移量(A)。装载时,操作系统将本次装入的实际起始地址置入基址寄存器(BR)。执行期间,硬件自动完成基址与偏移量的加法运算,从而使得程序代码无需静态修改,即可重定位至内存中的任意空闲区域运行
    • 变址寻址:有效地址由变址寄存器(IX)的内容加上形式地址 A 形成,即: EA = (IX) + A。变址寄存器的内容通常由用户设定,在程序执行过程中其值可变,而指令字中的 A 不变,常用于数组、字符串等数据结构的遍历,如:处理数组时,可设定 A 为数组的首地址,不断改变变址寄存器 IX 的内容,来计算出数组中任一数据的地址
    • 相对寻址:有效地址由程序计数器(PC)的当前值加上形式地址 A 形成,即:EA = (PC) + A,该寻址方式的特点是,地址随PC值变化,主要用于转移指令
    • 堆栈寻址:操作数地址由堆栈指针(SP)隐含指定,常用于用于处理子程序调用、中断等,通过PUSH(入栈)和 POP(出栈)保护原程序地址

    RISC技术

    • RISC精简指令系统计算机(Reduced Instruction Set Computer)
    • CISC复杂指令系统计算机(Complex Instruction Set Computer)

    RISC的发展背景

    在RISC出现之前,处理器设计的主流是CISC(如Intel x86、Motorola 68000)。CISC的特点是指令种类多、寻址方式多、指令字长长,由此带来的代价是,处理器需要更复杂的控制器,控制器会占用大部分处理器面积,且处理器的设计周期也会变长,资金耗费大。1980年代,研究人员发现了80/20法则:典型程序中80%的语句仅仅使用处理机中20%的指令,而且这些指令都是属于简单指令,如取数、加、转移等。因此,研究人员提出了RISC技术设想:用最常用的20%的简单指令,重新组合出不常用的80%的指令功能。由此,RISC的发展经历了以下里程碑:

    • 1975年,IBM的研究员John Cocke研究发现了80/20法则,提出了RISC精简指令系统的设想,并主导了IBM的IBM 801 RISC研究项目,他也因此在1987年获得图灵奖
    • 1980年,David Patterson(加州大学伯克利分校)参与的RISC-I项目,和1981年John Hennessy(斯坦福大学)参与的MIPS项目,分别在80年代初独立研发出RISC处理器,正式确立了RISC的体系结构
    • David Patterson 和 John Hennessy 因对RISC的贡献,共同获得2017年图灵奖
    • 1987年,Acorn公司(英国)开发ARM处理器
    • 1990年代后 ARM凭借低功耗优势主导移动设备市场

    RISC的特点

    RISC机有以下特点:

    • 使用精简指令集
      • 使用频度较高的简单指令,复杂指令的功能由简单指令的组合来实现
      • 指令数量少:通常几十到一百多条,远少于CISC的数百条
      • 指令长度固定:指令采用定长编码格式,便于流水线操作和指令译码
      • 指令格式规整:操作码位置统一,简化硬件设计
    • 单周期指令执行:采用流水线技术,大部分指令在一个时钟周期内完成。采用超标量和超流水线技术,可使每条指令的平均执行时间小于一个时钟周期。CISC指令大多需要多个周期
    • Load/Store体系结构:只有Load(从存储器读数据)和Store指令(将数据写入存储器)可以访问内存,所有运算的操作数都来自寄存器,运算结果也存入寄存器,这使得访存行为高度可预测,便于流水线优化
    • 使用大量通用寄存器:精简指令集带来的好处是CPU控制器简单,控制器占用空间少,使得RISC处理器可以配备更多的通用寄存器,充足的寄存器可以减少与内存的交互次数,提升性能
    • 流水线技术:规整的指令格式天然适合深度流水线,现代RISC处理器普遍采用超标量、乱序执行等技术
    • 硬连线控制:控制器采用组合逻辑电路直接实现指令译码,不用CISC常用的微程序控制
    • 优化编译:RISC机靠优化编译来更有效地支持高级语言程序。由于RISC指令少,寻址方式少,使编译程序容易选择更有效的指令和寻址方式,而且由于RISC机的通用寄存器多,可尽量安排寄存器的操作,使编译程序的代码优化效率提高

    RISC与CISC

    现代处理器设计已不再严格区分RISC和CISC,而是偏向RISC与CISC的融合,如:x86处理器内部采用”RISC内核”,然后将CISC指令翻译成微操作后执行;ARM的Thumb-2包含一些复杂指令,以下是一些RISC和CISC架构的代表:

    RISC架构

    • ARM架构:常用于手机、平板、笔记本、嵌入式领域,如:Apple M系列、高通骁龙、联发科天玑、AWS Graviton、树莓派
    • RISC-V架构:常用于物联网(IoT)、AI加速器、嵌入式领域
    • MIPS架构:用于部分路由器/网络设备
    • PowerPC架构:用于IBM高性能服务器,如:IBM POWER系列

    CISC架构

    • x86、x86-64/AMD64架构:个人电脑、工作站的主流,如:Intel Core i、AMD Ryzen系列
    • IBM z/Architecture:独特的CISC架构,常用于IBM Z系列大型机,常用于金融交易等领域
    项目 RISC CISC
    指令集 精简,指令数量少 丰富,指令数量多
    指令长度 固定 不固定
    指令功能 每条指令功能简单 每条指令功能强大
    执行速度 单周期执行,速度快 多周期执行
    硬件设计 简单 复杂
    存储器操作 Load/Store架构,受限 存储器操作指令多
    芯片面积/功耗 面积小、功耗低 面积大、功耗高
    典型应用 嵌入式系统、移动设备 台式机、服务器
    代表处理器 ARM、MIPS、PowerPC、SPARC x86,IBM Z系列

    CPU的结构和功能

    CPU结构

    CPU的功能

    从功能上,CPU分为运算器控制器两大部分:

    • 运算器ALU:负责执行算术和逻辑运算,参考上文“计算机的运算方法”章节
    • 控制器CU:相当于整个计算机的调度中心,内部有时序系统,负责按照时钟节拍对指令进行取指、译码和执行,并向寄存器、ALU、主存和总线产生控制信号,使各部件在正确的时间完成正确的操作

    CPU的结构

    loading
    CPU的结构

    物理结构上,CPU由以下四大组件组成:

    • 算术逻辑单元ALU:负责执行算术和逻辑运算
    • 控制单元CU:负责控制与调度
    • 寄存器:存储指令、操作数、地址、状态标志等,它们有的位于ALU中,有的位于CU中
    • 中断系统:负责处理设备中断(如:I/O中断)、异常中断(如:系统非法指令)、用户/软件中断(如:用户操作),与CU协同工作,由中断系统负责事件响应,CU负责执行

    CPU寄存器

    CPU中的寄存器大致可分两类

    用户可见寄存器

    这类寄存器可由用户程序直接访问和使用,用于存放操作数、中间结果或地址等数据。通过合理使用寄存器,可以减少对主存的访问次数,提高执行效率,它们包括:

    • 通用寄存器:可用于存放操作数,也可用于存放地址,以满足某种寻址方式
    • 数据寄存器:用于存放操作数,寄存器位数决定了能存放的数值范围,有些机器允许使用连续的寄存器以存放双倍字长的值
    • 地址寄存器:用于存放地址,其本身可以具有通用性,也可用于特殊的寻址方式,如用于基址寻址的段指针(存放基地址)、用于变址寻址的变址寄存器和用于堆栈寻址的栈指针。地址寄有器的位数决定了最大的地址范围
    • 条件码寄存器:用于存放条件码,条件码指CPU根据运算结果由硬件设置的位,如:算术运算会产生正、负、零或溢出等结果。大多数条件码由CPU直接设置,用户无法访问。但部分条件码可被测试,作为分支运算的依据;部分条件码也可被设置,如:对于最高位进位标志C,可用指令对它置位和复位,因此说,条件码寄存器对用户来说是部分透明的
    控制和状态寄存器

    这类寄存器用户程序不能直接访问,一般用于CPU内部控制、状态保存和执行管理。它们主要供控制单元CU使用,操作系统程序在特权模式下可以访问,用于实现进程管理、中断控制和系统运行控制等功能。它们主要是:

    • MAR:存储器地址寄存器,用于存放将被访问的存储单元的地址
    • MDR:存储器数据寄存器,用于存放欲存入存储器中的数据或最近从存储器中读出的数据
    • PC:程序计数器,存放现行指令的地址,通常具有计数功能,当遇到转移类指令时,PC的值可被修改。
    • IR:指令寄存器,存放当前欲执行的指令
    • 当CPU和主存交换信息时,控制器将现行指令地址从PC送至MAR,启动存储器作读操作,从存储器中将指定地址单元内的指令读至MDR,再由MDR送至IR。
    • ALU可直接访问MDR和用户可见寄存器,ALU的外围还可以有另一些寄存器,这些寄存器用于ALU的输入/输出,以及用于和MDR及用户可见寄存器交换数据
    • 在CPU的控制和状态寄存器中,还有用来存放程序状态字PSW的寄存器,该寄存器用来存放条件码和其他状态信息。在具有中断系统的机器中还有中断标记寄存器

    指令周期

    指令周期的组成

    指令周期指CPU取出执行一条指令所需的全部时间。指令周期不是一个固定的值,不同的指令其指令周期长短不同,如:

    • 无条件转移指令“JMP X”,在执行阶段不需要访问主存,可以在取指阶段的后期将转移地址X送至PC,同时完成取指和执行,因此“JMP X”指令的指令周期就是取指周期
    • 地址加法指令“ADD X”,在执行阶段首先要从X所指示的存储单元中取出操作数,然后和ACC的内容相加,结果存于ACC,故这种指令的指令周期在取指和执行阶段各访问一次存储器,其指令周期就包括两个存取周期
    • 对于间接寻址的指令,第一次访存取出的是有效地址,第二次访存取出操作数,多次间接寻址甚至需要更多次访存。因此间接寻址的指令周期包含取指周期、间址周期、执行周期3个阶段
    • 对于有中断系统的主机,CPU会在每条指令执行结束后,都发出中断查询信号,如果有请求,则将当前程序断点保存到存储器中,进入中断响应阶段。这意味着,中断通常会在一条指令执行完毕后才会响应,而不会打断指令的执行,对于“乘法运算”这类运算时间长的指令(如:需要50个时钟周期),CPU会在指令执行过程中设置若干个查询断点,方便查询和响应中断。
    • 由此,一个完整的指令周期包括取指周期、间址周期、执行周期、中断周期4个子周期,其中间址和中断在一个指令周期中不一定存在。中断周期也可以独立于指令周期,将CPU工作理解为指令周期A-中断查询-指令周期B-中断查询..如此反复

    CPU工作周期的标志:为了区分CPU当前处于哪个工作周期,内部通常会设置4个标志触发器(为1表示当前出于该周期):

    • FE:取指周期标志
    • IND:间址周期标志
    • EX:执行周期标志
    • INT:中断周期标志

    指令周期的数据流

    为了便于分析指令周期中的数据流,假设CPU中有:存储器地址寄存器 MAR、存储器数据存器MDR、程序计数器PC、指令寄存器IR,则不同指令周期的数据流向:

    • 取指周期:PC中存放现行指令的地址,该地址会被送到MAR,然后送至地址总线,然后由控制部件CU向存储器发读命令,使对应MAR所指单元的内容(指令)经数据总线送至MDR,再送至IR,并且CU控制 PC 内容加1,形成下一条指令的地址。
    • 间址周期:取指周期结束后,CU便检查IR中的内容,以确定其是否有间址操作,如果需要间址操作,则将MDR中指示形式地址的右N位(记作Ad(MDR))送到MAR,并送至地址总线,此后CU向存储器发读命令,以获取有效地址并存至MDR。
    • 执行周期:执行周期的数据流是多种多样的,通常涉及各类寄存器间的数据传送,无法统一归纳
    • 中断周期:在中断周期中,核心任务是保存程序断点并加载中断服务程序入口。首先,控制单元(CU)将用于保存断点的存储器特殊地址(如栈指针内容)送入存储器地址寄存器(MAR),该地址随即被送往地址总线,以选定目标存储单元。接着,CU向存储器发出写命令,同时将程序计数器(PC)中保存的程序断点值送入存储器数据寄存器(MDR),使断点数据经数据总线写入存储器。完成断点保存后,CU还需将中断服务程序的入口地址直接送入PC,为下一个指令周期的取指阶段做好准备,从而确保程序能准确转向中断处理。

    指令流水

    指令流水原理

    不使用流水技术的计算机,取指令和执行指令重复出现,各条指令按顺序串行执行:取指令1-执行指令1-取指令2-执行指令2…,其中取指令操作由指令部件完成,执行指令操作由执行部件完成。该工作方式下,各部件的利用率并不高,如:指令部件工作时,执行部件基本空闲;而执行部件工作时,指令部件基本空闲。

    如果指令执行阶段不访问主存,则完全可以利用这段时间取下一条指令,使得取下一条指令的操作和执行当前指令的操作同时进行,两条指令部分周期重叠执行,此即指令的二级流水。这种指令部件取出指令并将它暂存起来,等到执行部件空闲后将指令传给执行部件执行,同时又取出下一条指令并暂存起来的工作方式成为指令预取

    loading
    指令二级流水

    通常而言,指令的处理过程可以分解为更细的几个阶段:

    • 取指(FI):从存储器取出一条指令并暂时存入指令部件的缓冲区。
    • 指令译码(DI):确定操作性质和操作数地址的形成方式。
    • 计算操作数地址(CO):计算操作数的有效地址,涉及寄存器间接寻址、间接寻址、变址、基址、相对寻址等各种地址计算方式。
    • 取操作数(FO):从存储器中取操作数(若操作数在寄存器中,则无须此阶段)。
    • 执行指令(EI):执行指令所需的操作,并将结果存于目的位置(寄存器中)。
    • 写操作数(WO):将结果存入存储器

    处理器通常有6个对应的操作部件可以同时工作,因此上述6个阶段通过流水线技术可以组成六级流水时序。假设执行9条指令,如果不使用流水线技术,执行完毕需要54个时间单元(假设指令的6个阶段都需要一个时间单元),而如果使用六级流水线技术,则只需要14个时间单元:

    loading
    六级流水时序

    影响流水线性能的因素

    指令执行过程中,有一些行为/冲突会破坏流水线流畅执行,共有三种相关冲突:

    • 结构相关:当指令在重叠执行过程中,不同指令争用同一功能部件产生资源冲突而产生的冲突,因此又称为资源相关。如:指令和数据共用同一个存储器,但只有一个访问接口,导致“取指”和“访存”无法同时进行。
      解决方法:
      • 插入暂停周期,让流水线在完成前一条指令对数据的访存前,暂停后一条指令的访存操作(暂停一个时钟周期)
      • 采用哈佛结构,使用两个独立的存储器分别存放操作数和指令,
      • 使用指令预取技术,如:8086CPU设置有指令队列,可以将多条指令预先取到指令队列中排队。传统指令计数器PC只保存有下一条指令的地址,而指令队列本身存储的是已经从主存取出的指令和操作数,且可以排队多条
    • 数据相关:当后续指令依赖前一条指令尚未算出的数据时,如果后续指令在完成运算前读取数据,该数据必然是错误的。假设有 i 和 j 两条指令,i 指令在前,j 指令在后,根据指令间对同一寄存器读和写操作的先后次序关系,数据相关冲突可分为:
      • 写后读相关(Read After Write,RAW):指令 j 试图在指 i 写入寄存器前就读出该寄存器内容,此时,指令 j 会错误地读出该寄存
        器旧的内容
      • 读后写相关(Write After Read.,WAR):指令 j 试图在指令 i 读出寄存器之前就写入该寄存器,此时,指令 i 会错误地读出该寄存器新的内容
      • 写后写相关(Write After Write,WAW):指令 j 试图在指令 i 写入寄存器之前就写入该寄存器,这样,两次写的先后次序被颠倒,就会错误地使由指令 i 写入的值成为该寄存器的内容。
        解决方法:
      • 采用后推法,即遇到数据相关时,就停顿后续指令的运行,直至前面的结果生成
      • 采用旁路技术(又称定向技术、相关专用通路技术,目前CPU主要使用的技术),一般情况下,上一条指令的执行结果需要送回寄存器,等下一条指令执行时需要再从寄存器中取出才能作为其源操作数。旁路技术指上一条指令通过ALU产生的结果,通过ALU内部的旁路通道和多路开关,重新送回ALU的输入端作为下一条指令的源操作数,而不需要送回寄存器,且上述数据传送仅发生在ALU内部
    • 控制相关:转移指令会改变程序流向,导致流水线中预取的后续指令失效,统计表明,转移指令约占总指令的1/4左右,比起数据相关来,它会使流水线丧失更多的性能。
      解决方法::为尽早判别转移是否发生,尽早生成转移目标地址;预取转移成功或不成功两个控制流方向上的目标指令;加快和提前形成条件码;提高转移方向的猜准率等

    流水线性能

    流水线性能通常用吞吐率、加速比和效率来衡量:

    • 吞吐率(Throughput Rate):在指令级流水线中,吞吐率是指单位时间内流水线所完成指令或输出结果的数量。对于 m 段指令流水线而言,设各段的时间均为 Δt ,则最大吞吐率为:
    Tpmax=1Δt

    流水线仅在连续流动时才可达到最大吞吐率。实际上由于流水线在开始时有一段建立时间(第一条指令输入后到其完成的时间),结束时有一段排空时间(最后一条指令输入后到其完成的时间),以及各种原因导致流水线无法连续流动,因此,实际吞吐率总是小于最大吞吐率。实际吞吐率是指流水线完成n条指令的实际吞吐率,对于 m 段的指令流水线,若各段的时间均为 Δt ,则实际吞吐率为:

    Tp=1Δt[1+(m-1)/n]=Tpmax1+(m-1)/n
    • 加速比(Speedup Ratio):指m段流水线的速度与等功能的非流水线的速度之比,n 条指令为例,加速比:

      Sp=m1+(m-1)/n
    • 效率(Efficiency):效率是指流水线中各功能段的利用率。由于流水线有建立时间和排空时间,因此各功能段的设备不可能一直处于工作状态,总有一段空闲时间,通常用流水线各段处于工作时间的时空区与流水线中各段总的时空区之比来衡量流水线的效率

      E=TpΔt

    流水线中的多发技术

    流水线中的多发技术是提升指令级并行性(ILP)的核心策略,旨在突破传统流水线瓶颈,大幅提高处理器的吞吐率,以下介绍三种多发技术,其中假设处理一条指令分4个阶段:取指(FI)、译码(ID)、执行(EX)和回写(WR):

    loading
    多发技术
    • 超标量技术(Superscalar):指在每个时钟周期内并发执行多条独立的指令,而不只是提前取指令。超标量技术要求处理机中配置多套功能部件(如多个ALU、多个译码器等),使得处理器能在同一时刻处理多条指令。此外,由于硬件不能调整指令的执行顺序,因此还需要通过编译优化技术,在编译阶段就分析并找出那些可以并行执行的指令
    • 超流水线技术(Superpipelining):该技术侧重于提高流水线的主频,将一个时钟周期进一步细分为多个更短的阶段来执行(如:将原来的一个时钟周期再分为3段),使超流水线的处理器周期比普通流水线的处理器周期短,这样,在一个时钟周期内,同一个功能部件可以被使用3次,使流水线以3倍于原来时钟频率的速度运行。与超标量技术类似,它也不能调整指令的执行顺序,同样需要依靠编译程序来解决优化问题。其效果是使流水线的速度理论上提升为原来的数倍(如3倍)
    • 超长指令字技术(VLIW, Very Long Instruction Word):该技术采用多个处理部件,其核心思想是由编译程序挖掘出指令间潜在的并行性。编译器将多条能够并行执行的操作组合成一条具有多个操作码字段的超长指令字(指令长度可达几百位)。处理器在执行时,直接按照这条超长指令字的要求,将不同的操作派发到对应的多个处理部件上并行执行。VLIW较超标量具有更高的并行处理能力,但对优化编译器的要求更高,对Cache的容量要求更大

    流水线结构

    流水线技术除了用于指令执行,还用于复杂运算操作,因此有:

    • 指令流水线结构:流水线技术的经典应用。它将一条指令的执行过程划分为多个阶段,每个阶段由专门的硬件部件处理,从而实现多条指令在时间上重叠执行。为了在段间传递中间结果,各个功能部件之间通过锁存器暂存数据。
    • 运算流水线:流水线技术也用于加速复杂的的运算操作,如:一个复杂的浮点加减运算可以被分解为对阶、尾数求和、规格化三个段,每个子操作由专门的硬件在时间上重叠并行执行,划分各段时,应尽量保证每段操作时间一致,以避免因等待最慢的段而降低整体效率。同样,段间也需要用锁存器来暂存数据。

    中断系统

    中断是计算机系统实现异常处理和I/O设备管理的核心技术。当处理器在执行某个程序流的过程中,一旦检测到来自外部硬件设备或内部指令执行异常所发出的中断请求信号,便会暂停当前正在运行的程序,保护好当前程序的断点(如:程序计数器PC的值)和现场信息(如各寄存器的状态),然后根据中断类型自动转入内存中相应中断服务程序的入口地址执行。待该服务程序完成后,处理器再通过执行中断返回指令,恢复先前保存的现场和断点信息,使被中断的程序能够从断点处继续无缝运行

    中断的分类

    引起中断的因素:

    • 人为设置的中断:也称为自愿中断,是在程序中通过特定指令(如访管指令)人为设置的。机器执行到该指令时会“自愿”停止当前程序,转入中断处理,常用于系统调用
    • 程序性事故:由程序设计不周引起的内部事件,例如定点或浮点运算溢出、操作码无法识别、除法中除数为“非法”等。它们与当前执行的指令相关,本质上是内中断或异常。
    • 硬件故障:指计算机硬件本身的物理问题,如插件接触不良、磁表面损坏、电源掉电等。这类中断通常优先级最高且不可屏蔽,以确保系统安全。
    • I/O设备:这是最常见的中断源。当I/O设备被启动后准备就绪时,便通过接口中的中断请求触发器(INTR)向CPU发出中断请求。设备数量越多,这类中断源也越多。
    • 外部事件:来自CPU外部、与当前程序无关的事件,例如用户通过键盘请求干预程序运行等

    通常将引起中断的各个因素称为中断源,中断源可分两大类:

    • 不可屏蔽中断:这类中断CPU不能禁止响应,如电源掉电
    • 可屏蔽中断:CPU可根据该中断源是否被屏蔽来确定是否给予响应,若未屏蔽则能响应,若已被屏蔽,则CPU不需要响应

    中断请求标记

    计算机中有多个中断请求源,每个中断源对应一个中断请求标记,为了判断是哪个中断源提出请求,中断系统中设置了中断请求触发器(INTR),当其状态为”1”时,就表示对应中断源有请求,多个触发器的集合构成中断请求标记寄存器:

    loading
    中断请求触发器

    如上图中1,2,3,4,5,…,n分别对应掉电、过热、主存读写校验错、阶上溢、非法除法…..打印机等中断源。这些触发器的中断请求标记线可集中在CPU内部组成一个共用的中断请求寄存器,便于CPU统一查询,但它们本身既可以分散到各中断源中(如:位于I/O接口中),也可以集中在CPU的中断系统内部

    中断判优逻辑

    当多个中断源同时发出请求时,需要确定优先响应哪一个中断源的请求,即进行中断判优,中断判优可用硬件实现,也可用软件实现:

    • 硬件排队:一种为链式排队器,中断请求触发器分散在各接口电路中,接口电路按优先级编码犹如链条一样串接起来,中断请求信号逐级传递。另一种排队器设在CPU内,按优先顺序由高向低排列,当最高优先级的中断源有请求时,可封住比它级别低的中断源的请求。硬件排队的优势是速度快,但不灵活
    • 软件查询判优:CPU通过程序查询方式依次查询各中断请求标记的状态,查询顺序即优先级顺序,先查的先响应,其优点是灵活(顺序可调),缺点是速度慢,占用CPU时间

    中断服务程序入口地址的查找

    CPU响应中断后,最关键的一步是如何获取中断服务程序的第一条指令地址(即入口地址),并据此将控制权转移到该程序。通常有两种方式寻找入口地址:

    • 硬件向量法:中断源在发出中断请求的同时,通过数据总线向CPU提供中断向量地址(或中断类型号)。CPU利用该地址作为索引,直接访问内存中预先建立的中断向量表,从中读出对应的中断向量(即中断服务程序的入口地址),并自动装入PC。该方式的特点是地址查找由硬件自动完成,响应速度快,但需要专门的硬件。
    • 软件查询法:CPU响应中断后,硬件强制将PC置为一个固定的统一入口地址,该入口地址中存放了一段通用中断查询程序,当某一中断源有中断请求时,会首先执行该查询程序,由查询程序安排转移指令,直接指向此中断源的中断服务程序入口地址。这种方法不涉及硬设备,但查询时间较长

    中断响应

    • 响应中断的条件:中断系统中有一个允许中断触发器EINT,它可被开中断指令置“1”,表示允许CPU响应中断请求;也可被关中断指令置“0”,表示CPU禁止响应中断。CPU响应中断的条件是EINT必须为”1”,且INTR=1(有中断请求)
    • 响应时机:一般情况下,CPU总是在指令执行周期结束后,响应中断源的请求,在指令执行周期结束后,若有中断,CPU则进入中断周期;若无中断,则进入下一条指令的取指周期。对于某些执行时间很长的指令,若CPU的查询信号一律安排在执行周期结束时刻,有可能因CPU发现中断请求过迟而出差错。为此,可在指令执行过程中设置若干个查询断点,CPU在每个“查询断点”时刻均发中断查询信号,以便发现有中断请求便可及时响应。
    • 中断隐指令:CPU响应中断后,即进入中断周期。在中断周期内,CPU要自动完成一系列操作:
      • 保护程序断点:将当前程序计数器PC的内容(程序断点)保存到存储器中。它可以存在存储器的特定单元(如0号地址)内,也可以存入堆栈
      • 寻找中断服务程序的入口地址:通过硬件向量法或软件查询法获得中断服务程序的入口地址
      • 关中断:CPU进入中断周期,意味着CPU响应了某个中断源的请求,为了确保CPU 响应后所需做的系列操作不至于又受到新的中断请求的干扰,在中断周期内必须自动关中断,以禁止CPU再响应新的中断请求,通常使EINT置“0”完成关中断。
      • 上述保护断点、寻找入口地址、关中断等操作都是通过一条中断隐指令完成的。所谓中断隐指令,即在机器指令系统中没有的指令,它是CPU在中断周期内由硬件自动完成的一条指令

    保护现场和恢复现场

    • 保护现场应该包括保护程序断点和保护CPU内部各寄存器内容的现场两个方面。程序断点的现场由中断隐指令完成,各寄存器内的现场可在中断服务程序中由用户(或系统)用机器指令编程实现
    • 恢复现场是指在中断返回前,必须将寄存器的内容恢复到中断处理前的状态,这部分工作也由中断服务程序完成

    中断屏蔽技术

    中断屏蔽技术主要用于多重中断,多重中断是指,当CPU正在执行某个中断服务程序时,另一个中断源又提出了新的中断请求,而CPU又响应了这个新的请求,暂时停止正在运行的服务程序,转去执行新的中断服务程序,多重中断又称中断嵌套

    实现多重中断的条件
    • 一般情况下,CPU进入中断周期后,由中断隐指令自动将EINT置“0”,即关中断,这就意味着CPU在执行中断服务程序中禁止响应新的中断请求。CPU若想再次响应中断请求,必须开中断,这一任务通常由中断服务程序中的开中断指令实现
    • 优先级别高的中断源有权中断优先级别低的中断源,而为了保证级别低的中断源不干扰比其级别高的中断源的中断处理过程,需要采用屏蔽技术
    屏蔽技术

    中断屏蔽技术是计算机中断系统中实现优先级动态管理和中断嵌套的核心机制,它允许程序员或操作系统通过软件手段,灵活地改变中断源的响应优先级,而不必改动硬件连线。

    中断屏蔽技术的核心硬件是中断屏蔽触发器(IM),每个中断源都配有一个中断屏蔽触发器,用于控制该中断源的中断请求是否能够被CPU响应,当IM = 1时该中断源的请求信号被硬件逻辑“阻断”,无法送达CPU,即使有请求也不予响应。所有IM触发器的集合构成中断屏蔽寄存器,屏蔽寄存器的内容称为屏蔽字,CPU根据屏蔽字确定响应的优先级,如:屏蔽字0001111111111111,由于第1-3位为0,意味着第1-3级的中断源未被屏蔽,因此在执行某个中断程序且执行了开中断指令后,1、2、3级中断源可以中断4级以下中断源的中断服务程序。

    屏蔽技术的核心作用:
    • 实现中断嵌套:这是屏蔽技术最重要的应用。当CPU正在执行低优先级中断的服务程序时,可以通过设置屏蔽字(屏蔽当前低级别中断,开放更高级别中断),允许更高优先级的中断打断当前处理,从而实现“高优先级中断优先服务”的嵌套执行。处理完高级中断后,再返回继续处理低级中断
    • 动态调整优先级:硬件固定的优先级(如链式排队器决定的顺序)称为固有优先级。通过修改屏蔽字,可以改变各中断源实际的响应优先级。例如,可以让原本硬件优先级较低的外部设备,在特定时刻屏蔽掉其他中断,获得临时的优先响应权
    • 保护临界区代码:在操作系统内核执行某些不可打断的关键操作(如修改共享数据结构)时,通过设置屏蔽字关中断或屏蔽特定中断,可以保证这段代码的原子性执行,防止数据不一致

    控制单元CU

    控制单元(CU, Control Unit)是CPU内部负责“指令执行调度与控制”的核心部件,其基本功能是根据指令周期的不同阶段,对数据通路中的各类部件发出时序控制信号,从而协调完成指令的取指、译码、执行以及中断处理等过程,以达到执行程序的目的。

    微操作命令

    控制单元的核心功能是发出各种微操作命令(即控制信号)序列。计算机在执行程序的过程中,控制单元会发出各种微操作命令以完成程序指令,很多指令有相同或相似的操作,如:取指、间址、执行、中断操作,以下是指令周期的4个阶段对应的微操作命令

    loading

    假设CPU内有4个寄存器

    • MAR与地址总线相连,存放欲访问的存储单元地址
    • MDR与数据总线相连,存放欲写入存储器的信息或最近从存储器中读出的信息
    • PC存放现行指令的地址,有计数功能
    • IR存放现行指令

    取指周期

    取指令的过程可以归纳为以下操作:

    • 将现行指令地址送至存储器地址寄存器,记作PC → MAR。
    • 向主存发送读命令,启动主存作读操作,记作1 → R
    • 将MAR所指的主存单元中的内容(指令)经数据总线读至MDR内,记作
      M(MAR)-MDR。
    • 将MDR的内容送至IR,记作MDR → IR。
    • 指令的操作码送至CU译码,记作OP(PC)CU。
    • 形成下一条指令的地址,记作(PC)+1→PC。

    间址周期

    间址周期用于取出操作数有效地址,具体操作如下:

    • 将指令的地址码部分(形式地址)送至存储器地址寄存器,记作Ad(IR) → MAR
    • 向主存发送读命令,启动主存作读操作,记作1 → R
    • 将MAR所指的主存单元中的内容(有效地址)经数据总线读至MDR
      内,记作 M(MAR) → MDR
    • 将有效地址送至指令寄存器的地址字段,记作MDR → Ad(IR)。此操作在有些机器中可省略

    执行周期

    不同指令执行周期的微操作不同,分为以下几类:

    非访存指令

    • 清除累加器指令CLA:清空累加器,记作0 → ACC。
    • 累加器取反指令COM:只完成累加器内容取反,结果送累加器的操作,记作ACC取反 → ACC
    • 算术右移一位指令SHR:将累加器内容算术右移一位,记作L(ACC) → R(ACC)(ACC的符号位不变)
    • 循环左移一位指令CSL:执行累加器内容循环左移一位的操作,记作 R(ACO) → L(ACC),ACC0 → ACCn
    • 停机指令STP:将运行标志触发器G置“0”即可,记作0 → G

    访存指令:这里只考虑直接寻址的情况

    • 加法指令ADD X:该指令需要完成累加器内容与对应于主存X地址单元的内容相加,结果送回累加器任务:
      • 将指令的地址码部分送至存储器地址寄存器,记作Ad(IR) → MAR。
      • 向主存发读命令,启动主存作读操作,记作1 → R
      • 将MAR(通过地址总线)所指的主存单元中的内容(操作数)经数据总线读至MDR内,记作 M(MAR) → MDR
      • 给ALU发送加命令,将ACC的内容和MDR的内容相加,结果存于ACC,记作(ACC)+(MDR) → ACC
      • 如果加法指令是指定两个寄存器的内容相加,如“ADD AX,BX”,该指令在执行阶段无须访存,只需完成(AX)+(BX) → AX的操作
    • 存数指令STA X:该指令在执行阶段需将累加器ACC的内容存于主存的X地址单元中,具体操作如下。
      • 将指令的地址码部分送至存储器地址寄存器,记作Ad(IR) → MAR。
      • 向主存发写命令,启动主存作写操作,记作1 → W。
      • 将累加器内容送至MDR,记作ACC → MDR。
      • 将MDR的内容(通过数据总线)写入到MAR(通过地址总线)所指的主存单元中,记作MDR → M(MAR)
    • 取数指令LD AX:该指令在执行阶段需将主存X地址单元的内容取至累加器ACC中,具体操作如下:
      • 将指令的地址码部分送至存储器地址寄存器,记作Ad(IR) → MAR+ 向主存发读命令,启动主存作读操作,记作1 → R
      • 将MAR(通过地址总线)所指的主存单元中的内容(操作数)经数据总线读至MDR内,记作 M(MAR) → MDR
      • 将MDR的内容送至ACC,记作MDR → ACC。

    转移类指令:这类指令在执行阶段也不访问存储器。

    • 无条件转移指令JMP X:该指令在执行阶段完成将指令的地址码部分X送至PC的操作,记作Ad(IR) → PC。
    • 条件转移(负则转)指令BAN X:该指令根据上一条指令运行的结果决定下一条指令的地址,若结果为负(累加器最高位为1,即A0=1),则指令的地址码送至PC,否则程序按原顺序执行。由于在取指阶段已完成了(PC)+1 → PC,所以当累加器结果不为负(即A0=0)时,就按取指阶段形成的PC执行,记作A0·Ad(IR) +A0取反·(PC) → PC

    中断周期

    中断周期中,由中断隐指令自动完成保护断点、寻找中断服务程序入口地址以及硬件关中断的操作。假设程序断点存至主存的0地址单元,且采用硬件向量法寻找入口地址,则在中断周期需完成如下操作:

    • 将特定地址“0”送至存储器地址寄存器,记作0 → MAR
    • 向主存发写命令,启动存储器作写操作,记作1 → W
    • 将PC的内容(程序断点)送至MDR,记作PC → MDR
    • 将MDR的内容(程序断点)通过数据总线写入到MAR(通过地址总线)所指示的主存单元(0地址单元)中,记作MDR → M(MAR)
    • 将向量地址形成部件的输出送至PC,记作向量地址 → PC,为下一条指令的取指周期作准备
    • 关中断,将允许中断触发器清零,记作0 → EINT(该操作可直接由硬件线路完成)
    • 如果程序断点存入堆栈而非地址0,而且进栈操作是先修改栈指针,后存入数据只需将上述步骤1改为(SP)-1 → SP,且SP → MAR

    控制单元的功能

    控制单元的外特性

    控制单元的外特性描述的是它与外部环境之间的交互接口,即CU接收哪些输入信号、产生哪些输出信号

    loading
    控制单元的外特性

    输入信号

    • 时钟:CU受时钟信号控制,每一个时钟脉冲使CU发出一个操作命令或一组需同时执行的操作命令,以保证各操作按正确的先后顺序和节奏进行
    • 指令寄存器:现行指令的操作码字段是CU的关键输入,它决定了不同指令在执行周期所需完成的不同操作,与时钟配合可产生相应的控制信号
    • 标志:CU有时需要依赖CPU当前所处的状态(如ALU运算结果的正负、进位等)来产生控制信号,例如条件转移指令BAN需根据上条指令结果是否为负来决定转移与否
    • 来自系统控制总线的控制信号:如中断请求、DMA请求等
      输出信号
    • CPU内部的各种控制信号:用于控制CPU内部各寄存器之间的数据传送,以及控制ALU实现不同的运算操作
    • 送至系统总线(控制总线)的信号:如命令主存或I/O执行读/写操作,中断响应

    多级时序系统

    时钟周期/机器周期/指令周期

    多级时序系统是控制单元正确、有序地发出控制信号的时间基准。它采用“主频驱动、分频定步”的思想,将时间划分为时钟周期、机器周期、指令周期三个不同层级,以协调指令执行过程中各操作的先后与长短。

    • 时钟周期(Clock Cycle):又称为节拍(T cycle),控制计算机操作的最小时间单位,时钟信号由机器主振电路(如晶体振荡器)发出的脉冲信号经整形(或倍频、分频)后产生,时钟信号的频率即为CPU主频,每个节拍内机器可完成一个或多个互不冲突的微操作
    • 机器周期(Machine Cycle):CPU完成一次基本操作所需的时间单位,通常由若干个时钟周期组成,如:取指周期、存储器读/写周期、I/O读/写周期等,由于每一类操作所需要的时间长短不同,而主存访问速度是CPU操作的瓶颈,因此机器周期常以从主存读取一个指令字的最短时间作为基准。机器周期所含的时钟周期数可以相等(定长机器周期),也可以不相等(不定长机器周期),机器周期所含的时钟周期数少的机器,通常速度更快。
    • 指令周期(Instruction Cycle):指CPU从主存中取出一条指令并执行完该指令所需的全部时间。它由若干个机器周期组成。不同类型的指令(如取指、访存、执行)对应的指令周期长度可能不同
    loading
    机器周期
    设某计算机的CPU主频为8MHz,每个机器周期平均含2个时钟周期,每条指令的指令周期平均有2.5个机器周期,则该机的平均指令执行速度为多少MIPS? 解:主频为8 MHz 时钟周期为1/8 = 0.125 us 机器周期为0.125 x2= 0.25 us 指令周期为0.25x2.5 = 0.625 us。 所以平均指令执行速度为1/0.625=1.6 MIPS。(执行百万条指令数每秒)
    操作对应的时序
    • 一个程序编译后由多条指令组成,每条指令的执行时间称为指令周期,每条指令都包含取指、执行操作,但部分指令可能还包括间址、中断处理,因此不同指令的指令周期长度通常不同
    • 执行一次取指/间址/执行/中断操作所需的执行时间称为机器周期(CPU周期),由于不同操作所需时间各异,机器周期通常以访问一次主存的最短时间为基准来统一度量
    • 取指/间址/执行/中断操作由控制单元发出一系列微操作命令完成,在一个时钟周期内,控制单元可以同时发出一个或多个互不冲突的微操作命令,从而并行地完成若干微操作(现代CPU中,一个微操作也可能跨越多个时钟周期)
    + 以间址寻址加法运算 ADD X 指令为例,它是某个程序的一部分(被编译后的一条指令)它的执行需要一个指令周期 + 该指令包含取指、间址、执行三部分,对应了取指周期、间址周期和执行周期组成,每个周期可能由若干机器周期构成 + 它的取指操作通过微操作:将PC当前指令的后部分的地址送往MAR,MAR将值送入地址总线、CU通过控制总线发出读操作、主存将MAR所指主存单元的内容通过数据总线读至MDR完成,这些微操作执行通常需要一个或多个时钟周期(如:主存将MAR所指主存单元的内容通过数据总线读至MDR该微操作信号由CU在一个时钟周期的上升沿/下降沿发出,但它的完成可能需要多个时钟周期,取决于主存的性能)

    控制方式

    控制单元需要通过特定的控制方式,来为一条指令执行过程中的每个微操作确定其在时间上的先后次序,CU的控制方式有四种:

    • 同步控制方式:各项操作都由统一的基准时序信号控制,由于不同指令执行时间不同,为了提高CPU效率,同步控制有三种方案:
      • 采用定长的机器周期:不论指令所对应的微操作序列有多长,也不管微操作的简繁,一律以最长的微操作序列和最繁的微操作作为标准,采取全统一的、具有相同时间间隔和相同数目的节拍作为机器周期来运行各种不同的指令,这种方案对于微操作序列较短的指令来说,会造成时间上的浪费。
      • 采用不定长的机器周期:每个机器周期内的节拍数可以不等,以解决微操作执行时间不统一的问题。通常把大多数微操作安排在一个较短的机器周期内完成,而对某些复杂的微操作,采用延长机器周期或增加节拍的办法来解决
      • 采用中央控制和局部控制相结合的方法:这种方案将机器的大部分指令安排在统一的、较短的机器周期内完成,称为中央控制,而将少数操作复杂的指令中的某些操作(如乘除法和浮点运算等)采用局部控制方式来完成。
    • 异步控制方式:该方式不存在基准时标信号,没有固定的周期节拍和严格的时钟同步,执行每条指令和每个操作要多少时间就占用多少时间。这种方式微操作的时序由专门的应答线路控制,即当CU发出执行某一微操作的控制信号后,等待执行部件完成了该操作后发回“回答”(或“结束”)信号,再开始新的微操作,使CPU没有空闲状态,但因需要采用各种应答电路,故其结构比同步控制方式复杂。
    • 联合控制方式:结合同步控制和异步控制,这种方式对各种不同指令的微操作实行大部分统一、小部分区别对待的办法。例如,对每条指令都有的取指令操作,采用同步方式控制;对那些时间难以确定的微操作,如I/O操作,则采用异步控制,以执行部件送回的”回答”信号作为本次微操作的结束。
    • 人工控制方式:出于调机和软件开发的需要,在机器面板或内部设置一些开关或按键,来达到人工控制的目的,如:设置Reset(复位)键,当计算机出现死锁或无法继续运行时,使计算机恢复初始状态

    控制单元的设计

    控制单元CU的实现主要有两种设计方法:硬布线控制器和微程序控制器

    组合逻辑设计

    组合逻辑设计核心思想是通过门电路和触发器构成的硬布线逻辑实现CU。CU的外特性描述了CU有三个输入来源:

    • 指令译码器:负责将IR中的n位操作码输出为2n个输出,提供给CU
    • 节拍发生器:负责提供时钟信号,产生T0-Tn的节拍,节拍的宽度应满足数据信息通过数据总线从源到目的所需的时间
    • 状态标志:影响CU的控制信号,如:是否需要条件转移

    CU的输出为发给CPU内部及系统总线的控制信号

    微操作节拍安排

    安排微操作节拍应该遵循的原则:

    • 微操作的先后顺序不可随意更改
    • 凡是被控制对象不同的微操作,应尽可能安排在同一个节拍内
    • 占用时间教短的微操作,应该将它们安排在一个节拍内完成,并且允许这些微操作有先后次序

    假设机器采用同步控制,每个机器周期包含3个节拍T0,T1,T2。以下是一些微操作的节拍安排:

    • 取指周期:T0 PC→MAR, 1→R;T1 M(MAR)→MDR, (PC)+1→PC;T2 MDR→IR, OP(IR)→ID。
    • 间址周期:T0 Ad(IR)→MAR, 1→R;T1 M(MAR)→MDR;T2 MDR→Ad(IR)。
    • 执行周期:不同指令操作不同(如CLA清ACC、ADD加法、STA存数、LDA取数、JMP跳转、BAN条件转移等)。
    • 中断周期:T0 0→MAR, PC→MDR;T1 MDR→M(MAR), 向量地址→PC;同时硬件关中断

    组合逻辑设计步骤

    组合逻辑设计控制单元时,通常按照以下步骤:

    • 列操作时间表:明确每一个机器周期(取指、间址、执行、中断)里,每个节拍(T0、T1、T2)需要发出的所有微操作命令(即控制信号)
    • 写逻辑表达式:针对每一个控制信号,找出它在哪些节拍、哪些指令、什么状态条件下需要发出,写出对应的布尔逻辑表达式(如 C_i = T_x · 操作码 · 标志),并进行化简。
    • 画逻辑电路图:根据化简后的逻辑表达式,用与门、或门、非门等基本门电路,画出具体的硬连线逻辑电路

    微程序设计

    随着计算机发展,控制单元复杂性不断提高,特别是复杂指令集CISC时代(如x86架构),指令种类繁多且寻址方式复杂,不同的指令在不同状态下需要产生不同的控制信号,如果使用纯硬连线来生成所有这些指令在不同状态下的控制信号,硬件控制逻辑组合爆炸。且一旦物理电路彻底固化,如果硬连线控制逻辑中存在逻辑错误或需要后期升级,整批CPU芯片只能报废处理。为此,剑桥大学教授M.V.Wilkes于1951年就首先提出了微程序设计思想。

    微程序设计的核心思想是将控制信号以微指令形式存入控制存储器(CM),执行机器指令时只需要读取并执行微指令,产生对应的控制信号,而不需要再依赖复杂的逻辑电路去解析推导该给什么信号。本质上将复杂的布尔逻辑设计问题,转化为了线性的存储器寻址和读取问题,以解决组合逻辑控制单元线路庞杂的缺点。

    微程序控制单元的工作原理

    微程序控制单元中,每条机器指令都会被编写成对应的微程序,每一个微程序包含若干条微指令,每一条微指令对应一个或几个微操作命令。这些微程序存储于控制存储器中,以寻找机器指令的方法来寻找每个微程序中的微指令。这些微指令以二进制代码形式表示,每位代表一个控制信号(若该位为1,表示该控制信号有效;若该位为0,表示此控制信号无效),因此,逐条执行每一条微指令,也就相应地完成了一条机器指令的全部操作。由此,有以下概念:

    • 微程序:微指令的有序集合,对应一条机器指令
    • 微指令:一组微命令的集合(含操作控制和顺序控制两部分)
    • 微命令:构成控制信号的最小单位
    • 微操作:微命令执行的操作
    机器指令与微程序的关系

    采用微程序设计方法设计控制单元,其每条机器指令都对应一个专门的微程序,微程序按执行该指令所需的微操作顺序编写。通常而言,指令的取指、间址、中断这三个周期操作是固定且通用的,因此它们可以被编写为共用的微程序。最终,控制存储器中存放的微程序总数 = 机器指令数 + 3个(取指微程序 + 间址微程序 + 中断微程序)

    微程序控制单元结构

    loading
    微程序控制单元
    • 控制存储器(简称控存):微程序控制单元的核心部件,用来存放全部微程序
    • CMAR:控存地址寄存器,用来存放欲读出的微指令地址
    • CMDR:控存数据寄存器,用来存放从控存读出的微指令
    • 顺序逻辑是用来控制微指令序列的,具体就是控制形成下一条微指令(即后续微指令)的地址,其输入与微地址形成部件与指令寄存器相连

    微指令格式

    微指令的基本格式为:[操作控制][顺序控制],即它分为两个字段:

    • 操作控制:该字段发出各种控制信号
    • 顺序控制:该字段指出下条微指令的地址。微程序本身也是“程序”,它就同样面临着顺序执行、条件跳转和循环问题。它必须知道“当前时钟周期干完活之后,下一个周期该执行哪一条微指令”,因此微指令不能只存控制信号,它还必须拿出一部分比特位来存储控制流信息

    微指令的编码格式

    微指令的编码方式用于指出如何对微指令的控制字段进行编码,以形成控制信号,它又称微指令的控制方式,主要有以下几种:

    • 直接编码(直接控制法):微指令的每一位控制位直接对应一个微命令(0表示不发,1表示发出),其特点是速度最快(无需译码),控制简单直观;但字长极长,控存容量开销巨大
    • 字段直接编码(字段译码法):将控制位分成若干字段,每个字段经过译码器译码后产生一组互斥的微命令(即同一字段内每次只允许发一个),这样可以大幅缩短微指令字长,节省控存空间;但需增加译码硬件,速度稍慢。这是目前最常用、最均衡的方式
    • 字段间接编码(隐式编码):一个字段的译码结果依赖于另一个字段的状态(即某字段的译码需参考其他字段的值),其特点是进一步压缩了位数,但逻辑复杂、灵活性差,执行速度最慢,实际中较少单独使用
    • 混合编码:该方法是把直接编码和字段编码(直接或间接)混合使用,以便能综合考虑微指令的字长、灵活性和执行微程序的速度等方面的要求。

    微指令序列地址的形成

    当前微指令执行完后,需要给出下一条微指令的地址,后续微指令序列地址的形成大致有以下几种:

    • 直接由微指令的下地址字段指出:即微指令的顺序控制字段直接给出了下条微指令的地址,这种方式又称为断定方式
    • 根据机器指令的操作码形成:当机器指令取至指令寄存器后,微指令的地址由操作码经微地址形成部件形成。微地址形成部件实际是一个编码器,其输入为指令操作码,输出就是对应该机器指令微程序的首地址。它可采用 PROM实现,以指令的操作码作为PROM的地址,而相应的存储单元内容就是对应该指令微程序的首地址。
    • 增量计数器法:很多情况下,后续微指令的地址是连续的,因此对于顺序地址,微指令可采用增量计数法,即(CMAR)+1一CMAR来形成后续微指令的地址
    • 分支转移:当遇到条件转移指令时,微指令出现了分支,必须根据各种标志来决定下一条微指令的地址,此时微指令的格式为:[操作控制][转移方式][转移地址],转移方式指明判别条件,转移地址指明转移成功后的去向,若不成功则顺序执行。也有的转移微指令中设两个转移地址,条件满足时选择其中一个转移地址;条件不满足时选择另一个转移地址
    • 通过测试网络形成:微指令的地址还可通过测试网络形成,微指令的地址分两部分,高段h为非测试地址,由微指令的H段地址码直接形成;低段1为测试地址,由微指令的L段地址码通过测试网络形成。
    • 由硬件产生微程序入口地址:当电源加电后,第一条微指令的地址可由专门的硬件电路产生,也可由外部直接向CMAR输入微指令的地址,这个地址即为取指周期微程序的入口地址。当有中断请求时,若条件满足,CPU响应中断进入中断周期,此时需中断现行程序,转至对应中断周期的微程序。由于设计控制单元时已安排好中断周期微程序的入口地址,故响应中断时,可由硬件产生中断周期微程序的入口地址

    微指令格式

    微指令格式指的是微指令在控制存储器中的结构布局,即如何划分二进制位来同时实现操作控制(发出微命令)和顺序控制(决定下一条地址)。根据这两部分信息的组织方式,主要分为以下两大类:

    • 水平型微指令:控制字段的每一位或每个字段几乎直接对应一条控制信号,如:假设CPU共有40条控制信号(PC→MAR,MDR→IR,ALU加法…),那么微指令可能就是40位。其特点CPU几乎不用译码,直接把这些位送到控制线路即可,并行能力最强,执行速度最快,缺点是微指令很长(几十位甚至上百位),控制存储器(CM)容量较大
    • 垂直型微指令:对控制信号先进行编码然后存储,执行时也需要由译码器恢复成控制信号。如:假设CPU有8种寄存器PC、IR、MAR…水平型微指令需要8位,如:通过10000000选定PC寄存器。而垂直型通过编码使用3位表示这些寄存器,通过010选定MAR寄存器,CPU执行时需要将010译码为8位控制信号。这种编码方式的特点是执行速度略慢,需要译码,但控制存储器可以做很小

    静态微程序设计和动态微程序设计

    • 静态微程序设计:通常指令系统是固定的,控制存储器采用ROM,对应每一条机器指令的微程序是计算机设计者事先编好的,因此一般微程序无须改变,
    • 动态微程序设计:采用EPROM作为控制存储器,人们可以通过改变微指令和微程序来改变机器的指令系统,可以在一台机器上实现不同类型的指令系统

    串行微程序控制和并行微程序控制

    与机器指令一样,完成一条微指令也分两个阶段:取微指令和执行微指令,且它们由两个完全不同的部件完成

    • 串行微程序控制:如同指令流水一样,如果这两个部件依次执行取微指令和执行微指令,前者执行完毕后者才会执行
    • 并行微程序控制:两个部件并行进行,执行部件执行第i条微指令时,取微指令部件取出第i+1条微指令,这需要增加一个微指令寄存器来暂存下一条微指令,且当遇到需要根据本条微指令的处理结果来决定下条微指令的地址时,就不能并行操作,此时可延迟一个微指令周期再取微指令

    毫微程序设计

    微程序可看做是解释机器指令的,毫微程序可看做是解释微程序的,而组成毫微程序的毫微指令则是用来解释微指令的。采用毫微程序设计计算机的优点是用少量的控制存储器空间来达到高度的并行。

    毫微程序设计采用两级微程序的设计方法:第一级微程序为垂直型微指令,并行功能不强,但有严格的顺序结构,由它确定后续微指令的地址,当需要时可调用第二级。第二级微程序为水平型微指令,具有很强的并行操作能力,但不包含后续微指令的地址。第二级微程序执行完毕后又返回到第一级微程序。该过程中,微程序负责描述”下一步应该执行哪类微操作”,毫微程序负责输出真正的控制信号,该设计的优点是可以减少微程序控制存储器容量:微指令只保存毫微地址,而不是全部控制信号,且相同控制信号组合只需保存一次,当修改公共控制信号组合时,只需修改对应毫微程序。缺点是需要增加一级控制存储器,硬件结构更加复杂,执行速度略慢。

    上一篇:计算机网络(一)计算机网络概述与应用层
    下一篇:计算机组成原理(上)
    z z z z z