计算机组成与设计硬件软件接口 ¶
约 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
X 22 基址寄存器
8 偏移量
字节地址: 0 8 16 24
RICS- V 是小端编址: 只在以双字形式和八个单独字节访问相同数据时会有影响 ^da8be4
存储指令(store)存储双字
- 对齐限制 :
- 字的起始地址是 4 的倍数
- 双字的起始地址是 8 的倍数
- 但是 risc-v and Intel x 86 没有
- MIPS 有
Gibibyte (\(\displaystyle 2^{30}\)) and tebibyte (\(\displaystyle 2^{40}\))
如果变量比寄存器数量更多,那么会把一些放到内存,即寄存器换出。
2.3.2 常数或立即数操作数 ¶
常数称为算数指令操作数
X0 可以用来表示 0
其实还有 RV 32
基址寄存器也被称为下标寄存器
我们假设指令都是 64 位
2.4 有符号数与无符号数 ¶
- Binary digit Or bit
- Least significant bit
- Most significant bit
- sign and magnitude
- 补码转化 :
- 拓展符号位
- 取反
- 加一
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 循环 ¶
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 跳转 - 链接指令
调用者将参数值放入 x 10~x 17
过程是被调用者
Program counter:PC
指令地址寄存器
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
- 将所有必须保存的寄存器压栈,防止冲突
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
加载无符号字节 (lbu)
存储字节 (sb)
字符串的表示有三种选择 :
- 第一个位置保留来给出字符串的长度
- 用额外的变量来存储长度(如结构体)
- 字符串的最后一个位置用字符标记结尾
其中 C 语言用第三种,使用值为 0 的字节来终止字符串(null in ASCII)
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
2.10 对大立即数的 RISC-V 的编址和寻址 ¶
2.10.1 大立即数 ¶
load upper immediate 取立即数高位 lui
lui 可以加载 12~31 位
addi 可以加载 0~11 位