Skip to content

计算机组成与设计硬件软件接口

2978 个字 13 行代码 4 张图片 预计阅读时间 15 分钟 共被读过

1 计算机抽象及相关技术

2 指令 : 计算机的语言

2.1 引言

设计原则 :

  • 简单源于规整
  • 更少则更快
  • 优秀的设计需要适当的折中

2.2 计算机硬件的操作

Java 编译器 : Just In Time 编译器

2.3 计算机硬件的操作数

  • 寄存器
    • 大小为 64 bits 双字
    • 数量有限通常为 32
    • x + 寄存器编号

2.3.1 存储器操作数

在内存和寄存器之间传输指令 : 数据传输指令
指令提供内存地址
载入指令(load):ld

Text Only
Ld x9, 8(x22)

X 22 基址寄存器
8 偏移量
字节地址: 0 8 16 24
RICS- V 是小端编址: 只在以双字形式和八个单独字节访问相同数据时会有影响 ^da8be4

存储指令(store)存储双字

Text Only
sd x9, 96(x22)
  • 对齐限制 :
    • 字的起始地址是 4 的倍数
    • 双字的起始地址是 8 的倍数
    • 但是 risc-v and Intel x 86 没有
    • MIPS
      Gibibyte (\(\displaystyle 2^{30}\)) and tebibyte (\(\displaystyle 2^{40}\))
      如果变量比寄存器数量更多,那么会把一些放到内存,即寄存器换出。

2.3.2 常数或立即数操作数

Text Only
ld x9, AddConstant4(x3)
Add x22, x22, x9

# Equals to 

addi x22, x22, 4 # x22 = x22 + 4

常数称为算数指令操作数
X0 可以用来表示 0
其实还有 RV 32
基址寄存器也被称为下标寄存器
我们假设指令都是 64 位

2.4 有符号数与无符号数

  • Binary digit Or bit
  • Least significant bit
  • Most significant bit
  • sign and magnitude
  • 补码转化 :
    1. 拓展符号位
    2. 取反
    3. 加一

2.5 计算机中的指令表示

  • 字段
  • 指令 32 位长
  • 指令的数字表示 : 机器语言
  • 指令序列 : 机器码
  • C java 0 xnnnn 来表示十六进制数
  • RISC-V:(R)
    • funct7 + rs 2 + rs 1 + funct 3 + rd + opcode
    • rd: 目的操作数寄存器
    • rs 1: 第一个原操作数寄存器
    • rs 2: 第二个原操作数寄存器
    • funct 7 (3): 操作码字段
  • 对不同的指令使用不同的指令格式
  • I
    • immediate + rs 1 + funct 3 + rd + opcode
    • 超过 32 个寄存器的话,rd and rs 1 都要增加额外的一位
    • ld
  • S
    • immediate + rs 2 + rs 1 + funct 3 + immediate + opcode
  • Reg 表示 0 31 之间的寄存器编号
  • 没有 subi 因为可以通过加负数来实现
  • 计算机构建基于两个关键原则 :
    • 指令由数字形式表示
    • 程序和数据一样保存在存储器中进行读写
  • 程序会以二进制数据文件的形式来发布
    • 二进制兼容性让行业围绕少数几个指令系统结构形成联盟

2.6 逻辑操作

  • sll, slli
  • srl, srli
  • sra, srai
  • and, andi
  • or, ori
  • xor, xori
  • not
  • 位移指令用的 I 型格式 :
    • 但它的格式有变化 :
      • funct 6 + immediate + rs 1 + funct 3 + rd + opcode
  • 算数右移用的是符号位
  • AND 实现了掩码

2.7 用于决策的指令

  • beq
  • bne

2.7.1 循环

C
while (save[i] == k) 
    i += 1;

I -> x 22
K -> x 24
Save -> x 25

Text Only
loop: slli, x10, x22, 3
Add x10, x10, x25
Ld x9, 0(x10)
Ben x9, x24, Exit
Addi x22, x22, l
Beq x0, x0, loop
Exit:

基本块 :

  • 除了在指令序列的结尾,序列中没有分支。
  • 除了在序列起始处,序列中没有分支目标和分支标签。
  • 对于符号 :
    • RISC-V 用不同的指令
    • MIPS 设置临时寄存器
    • ARM 条件代码或标志位
  • 不过也会有缺点 : 过多的指令设置条件代码,会让流水线执行困难

2.7.2 边界检查的简便方法

将符号数当作无符号数处理

2.7.3 Case/switch 语句

  • 编码形成指令序列的地址表 : 分支地址表 / 分支表
  • 间接跳转指令 jalr

2.8 计算机硬件对过程的支持

  • Procedure
  • 执行过程的六个步骤 :
    • 将参数放在过程可以访问到的位置
    • 将控制转交给过程
    • 获取过程所需的存储资源
    • 执行所需的任务
    • 将结果值放在调用程序可以访问到的位置
    • 将控制返回到初始点,因为过程可以从程序中的多个点调用
  • x 10~x 17: 参数寄存器,用于传递参数或返回值
  • x 1: 返回地址寄存器,用于返回到起始点
  • jal 跳转 - 链接指令
Text Only
Jal x1, ProcedureAddress
Jalr x0, 0(x1)

调用者将参数值放入 x 10~x 17
过程是被调用者
Program counter:PC
指令地址寄存器

Text Only
jal x0, Label // unconditionally branch to Label

2.8.1 使用更多的寄存器

  • Stack
  • Stack pointer x2:sp
  • 压栈弹栈
Text Only
leaf_example:
Addi sp, sp, -14
Sd x5, 16(sp)
Sd x6, 8(sp)
Sd x20, 0(sp)
Add x5, x10, x11
Add x6, x12, x13
Sub x20, x5, x6
Addi x10, x20, 0
Ld x20, 0(sp)
Ld x6, 8(sp)
Ld x5, 16(sp)
Addi sp, sp, 24
Jalr x0, 0(x1)
  • X 5~x 7, x 28~x 31: 临时寄存器
  • x 8~x 9, x 18~x 27: 保存寄存器

2.8.2 嵌套过程

  • Leaf procedure
  • 将所有必须保存的寄存器压栈,防止冲突
C
long long int fact (long long int n) {
    if (n < 1) return (1);
        else return (n * fact(n - 1))
}

n -> x 10

Text Only
fact:
    addi sp, sp, -16
    Sd x1, 8(sp)
    Sd x10, 0(sp)

    Addi x5, x10, -1
    Bge x5, x0, L1

    Addi x10, x0, 1
    Addi sp, sp, 16
    Jalr x0, 0(x1)

L1: addi x10, x10, -1
    Jal x1, fact

addi x6, x10, 0
Ld x10, 0(sp)
Ld x1, 8(sp)
Addi sp, sp, 16
Mul x10, x10, x6
Jalr x0, 0(x1)
  • 一些编译器保留一个寄存器 x 3 用作全局指针 gp

2.8.3 在栈中位新数据分配空间

栈也用于存储过程的局部变量
过程帧/活动记录

没看懂

2.8.4 在堆中为新数据分配空间

Static data segment
text segment
像链表等数据结构往往会随生命周期增长和缩短,所以会把他们存在堆里 (heap)

  • malloc ()
  • free ()
    详细阐述没看

2.9 人机交互

ASCII: american standard code for information interchange
QQ_1724935497889.png

加载无符号字节 (lbu)
存储字节 (sb)

Text Only
lbu x12, 0(x10)
sb x12, 0(x11)

字符串的表示有三种选择 :

  1. 第一个位置保留来给出字符串的长度
  2. 用额外的变量来存储长度(如结构体)
  3. 字符串的最后一个位置用字符标记结尾
    其中 C 语言用第三种,使用值为 0 的字节来终止字符串(null in ASCII)
C
void strcpy (char x[], char y[])
{
    size_t i;
    i = 0;
    while ((x[i] = y[i]) != '\0')
        i += 1;
}

x -> x 10
y -> x 11
i -> x 19

Text Only
strcpy:
    addi sp, sp, -8
    sd x19, 0(sp)
    add x19, x0, x0
L1: add x5, x19, x11
    lbu x6, 0(x5)
    add x7, x19, x10
    sb x6, 0(x7)
    beq x6, x0, L2
    addi x19, x19, 1
    jal x0, L1
L2: ld x19, 0(sp)
    addi sp, sp, 8
    jalr x0, 0(x1)

load half unsigned 加载半字 : lh
lhu
sh
QQ_1724937038460.png

2.10 对大立即数的 RISC-V 的编址和寻址

2.10.1 大立即数

load upper immediate 取立即数高位 lui
QQ_1724937286434.png
lui 可以加载 12~31 位
addi 可以加载 0~11 位

2.10.2 分支中的寻址

分支指令使用 SB 型的指令格式
QQ_1724937558366.png

2.11 指令与并行性:同步

2.12 翻译并启动程序

2.12.1 编译器

2.12.2 汇编器

2.12.3 链接器

2.12.4 加载器

2.12.5 动态链接库

2.12.5.1 启动 Java 程序

2.13 C 排序程序为例的汇总整理

2.13.1 swap 过程

2.13.2 sort 过程

2.14 数组与指针

2.14.1 用数组实现 clear

2.14.2 用指针实现 clear

2.14.3 比较两个版本的 clear

2.15 高级专题 : 编译 C 语言和解释 Java 程序

2.16 实例 : MIPS 指令

2.17 实例 : x 86 指令

2.17.1 Intel x 86 的演变

2.17.2 x 86 寄存器和寻址模式

2.17.3 x 86 整数操作

2.17.4 x 86 指令编码

2.17.5 x 86 总结

2.18 实例 : RISC-V 指令系统的剩余部分

2.19 谬误与陷阱

2.20 本章小结

3 计算机的算数运算

3.1 引言

3.2 加法和减法

3.3 乘法

3.3.1 串行版的乘法算法及其硬件实现

3.3.2 带符号乘法

3.3.3 快速乘法

3.3.4 RISC-V 中的乘法

3.3.5 总结

3.4 除法

3.4.1 除法算法及硬件实现

3.4.2 有符号除法

3.4.3 快速除法

3.4.4 RISC-V 中的除法

3.4.5 总结

3.5 浮点运算

3.5.1 浮点表示

3.5.2 例外和中断

3.5.3 IEEE 754 浮点数标准

3.5.4 浮点加法

3.5.5 浮点除法

3.5.6 RISC-V 中的浮点指令

3.5.7 精确算数

3.5.8 总结

3.6 并行性与计算机算数 : 子字并行

3.7 实例 : x 86 中的 SIMD 扩展和高级向量扩展

3.8 加速 : 子字并行和矩阵乘法

3.9 谬误与陷阱

3.10 本章小结

4 处理器

4.1 引言

4.1.1 一种基本的 RISC-V 实现

4.1.2 实现概述

4.2 逻辑设计的一般方法

4.3 建立数据通路

4.4 一个简单的实现方案

4.4.1 ALU 控制

4.4.2 设计主控制单元

4.4.3 数据通路操作

4.4.4 控制的结束

4.4.5 为什么现在不适用单周期实现

4.5 流水线概述

4.5.1 面向流水线的指令系统设计

4.5.2 流水下冒险

4.5.3 总结

4.6 流水线数据通路和控制

4.6.1 流水线的图形化表示

4.6.2 流水线控制

4.7 数据冒险 : 前递与停顿

4.8 控制冒险

4.8.1 假设分支不发生

4.8.2 缩短分支延迟

4.8.3 动态分支预测

4.8.4 流水线总结

4.9 例外

4.9.1 RISC-V 体系结构中如何处理例外

4.9.2 流水线实现中的例外

4.10 指令间的并行性

4.10.1 推测的概念

4.10.2 静态多发射

4.10.3 动态多发射处理器

4.10.4 高级流水线和能效

4.11 实例 : armCortex-A 53 Intel Core i 7 流水线结构

4.11.1 ARM Cortex-A 53

4.11.2 Intel Core i 7 920

4.11.3 Intel Core i 7 处理器的性能

4.12 加速 : 指令集并行和矩阵乘法

4.13 高级专题 : 数字设计概述——使用硬件设计语言进行流水线建模以及更多流水线示例

4.14 谬误与陷阱

4.15 本章小结

4.16 历史视角和扩展阅读

5 大而快 : 层次化存储

5.1 引言

5.2 存储技术

5.2.1 SRAM 存储技术

5.2.2 DRAM 存储技术

5.2.3 闪存

5.2.4 磁盘

5.3 cache 基础

5.3.1 cache 访问

5.3.2 处理 cache 失效

5.3.3 处理写操作

5.3.4 cache 实例 : Intrinsity FastMATH 处理器

5.3.5 总结

5.4 cache 的性能评估和改进

5.4.1 使用更为灵活的替换策略降低 cache 失效率

5.4.2 cache 中查找数据块

5.4.3 选择替换的数据块

5.4.4 使用多级 cache 减少失效代价

5.4.5 通过分块进行软件优化

5.4.6 总结

5.5 可靠的存储器曾测

5.5.1 失效的定义

5.5.2 纠正 1 位错、检测 2 位错的汉明编码

5.6 虚拟机

5.6.1 虚拟机监视器的必备条件

5.6.2 指令系统体系结构(缺乏)对虚拟机的支持、

5.6.3 保护和指令系统体系结构

5.7 虚拟内存

5.7.1 页的存放和查找

5.7.2 缺页失效

5.7.3 支持大虚拟地址空间的虚拟存储

5.7.4 关于写

5.7.5 加快地址转换 :TLB

5.7.6 Intrinsity FastMATH TLB

5.7.7 继承虚拟存储、TLB cache

5.7.8 虚拟存储中的保护

5.7.9 处理 TLB 失效和缺页失败

5.7.10 总结

5.8 存储层次结构的一般框架

5.8.1 问题一 : 块可以被放在何处

5.8.2 问题二 : 如何找到块

5.8.3 问题三 : cache 发生失效时替换哪一块

5.8.4 问题四 : 写操作如何处理

5.8.5 C: 一种理解存储层次结构的直观模型

5.9 使用有限状态自动机控制简单的 cache

5.9.1 一个简单的 cache

5.9.2 有限状态自动机

5.9.3 使用有限转台自动机作为简单的 cache 控制器

5.10 并行和存储层次结构 : cache 一致性

5.10.1 实行一致性的基本方案

5.10.2 监听协议

5.11 并行与存储层次结构 : 廉价磁盘冗余阵列

5.12 高级专题 : 实现缓存控制器

5.13 实例 : ARM Cortex-A 53 Intel Core i 7 的存储层次结构

5.14 实例 : RISC-V 系统其他部分和特殊指令

5.15 加速 : cache 分块和矩阵乘法

5.16 谬误与陷阱

5.17 本身小结

5.18 历史视角和拓展阅读

6 并行处理器 : 从客户端到云