chap 1. 计算机抽象及相关技术
八个伟大思想:
- 面向摩尔定律的设计
设计芯片的时候要考虑未来工艺,需要超前点 - 使用抽象简化设计
- 加速经常性事件
- 通过并行提高性能
- 通过流水线提高性能
- 通过预测提高性能
- 存储层次
Memory Hierarchy - 通过冗余提高可靠性
chap2 指令
RV字段
R型(用于寄存器)
funct7 | rs2 | rs1 | funct3 | rd | opcode | 总共 |
---|---|---|---|---|---|---|
7位 | 5位 | 5位 | 3位 | 5位 | 7位 | 32位 |
- opcode:指令基本操作
- rd:目的操作数寄存器,存放结果
- funct3:一个另外的操作码字段
- rs1:第一个源操作数寄存器
- rs2:第二个源操作数寄存器
- funct7:一个另外的操作码字段
funct3和funct7用来表示opcode的附加字段(比如add和sub的opcode都是0110011,而add的funct7是0000000,sub的是0100000
I型(用于带常数的算数指令和加载指令)
immediate | rs1 | funct3 | rd | opcode | 总共 |
---|---|---|---|---|---|
7位 | 5位 | 3位 | 5位 | 7位 | 32位 |
- immediate为补码,可以表示-2^11^ 到2^11^ - 1之间的整数,当I型格式用于加载指令时,immediate表示一个偏移量
- ld指令的funct3为3
S型(用于Store)
immediate[11:5] | rs2 | rs1 | funct3 | immediate[4:0] | opcode | 总共 |
---|---|---|---|---|---|---|
7位 | 5位 | 5位 | 3位 | 5位 | 7位 | 32位 |
- immediate设计成两个字段是因为想把rs2和rs1跟上面的处于同一位置,降低硬件复杂性,funct3和opcode也是同一位置
逻辑操作
-
RV里没有
!
的逻辑操作,可以使用xxx XOR 全FF实现 -
移位操作是I型格式,因为只用到immediate的低6位字母(不能移超过63次),所以高6位被当做另外的操作码字段,即funct6
调用约定
-
x10~x17:八个,用于传参/返回值
-
x0:一定是常量0,如果试图更改会被直接丢弃
-
x1:返回地址寄存器,用于返回到起始点
-
跳转-链接指令(jal):跳转到某个地址的同时将下一条指令的地址保存到目标寄存器rd
- jal x1, ProcedureAddress:跳转到ProcedureAddress并把返回地址写入x1
-
RV中x2是栈指针(stack pointer/ sp)
-
RV把19个寄存器分成两组:
- x5~x7以及x28~x31:临时寄存器,过程调用里不被【被调用者(callee)】保存
- x8~x9以及x18~x27:保存寄存器,在过程调用里必须被保存
-
RV使用帧指针(frame pointer)来表示过程帧的第一个双字(类似x64的rbp)
-
超过8个参数怎么办?跟x86的处理方式一样,额外的放stack上
大立即数处理
lui指令(load upper immediate)
取立即数高位,将20位常数加载到寄存器的31到12位,并把31位复制填充到最左边32位,最右边12位用0填充。
这条指令允许使用两条指令创建32位常量。lui的指令格式为U型,因为其他的不支持大常量。
加载一个大常量的过程如lui x19, 12到31位的数; addi x19, x19, 低12位的数
分支寻址
分支指令使用SB型指令,可以表示-4096到4094的分支地址,以2的倍数表示。
SB型
比如bne x10, x11, 2000 // if x10 != x11, goto location 2000
表示为
imm[12] | imm[10:5] | rs2 | rs1 | funct3 | imm[4:1] | imm[11] | opcode |
---|---|---|---|---|---|---|---|
0 | 111110 | 01011 | 01010 | 001 | 1000 | 0 | 1100111 |
opcode=1100111是条件分支的操作码,bne的funct3是001
唯一使用UJ型的jal指令(无条件跳转-链接)
比如jal x0, 2000 // goto location 2000 = 0111 1101 0000
imm[20] | imm[10:1] | imm[11] | imm[19:12] | rd | opcode |
---|---|---|---|---|---|
0 | 11 1110 1000 | 0 | 0000 0000 | 0 0000 | 110 1111 |
但是20位的地址空间太小了,另一种方法使用寄存器+偏移的方式,能够扩大到2^64^
使用哪个寄存器?
SPEC基准测试里有一半的条件分支跳到小于16距离的位置
因此如果用PC来当基址,那就很理想,这种叫PC相对寻址,RV对条件分支和无条件跳转使用PC相对寻址。在RV里PC相对偏倚表示分支和目标指令之间的半字数(2 bytes),jal里20位可以编码PC±2^19^个半字/ ±1MB的距离
同步
atomic exchange原语
jyy讲过,拿1去对🔐变量不断交换,交换出来0说明拿到锁了,交换出来1说明没拿到(被占用)
指令对
第二条指令返回一个值,表示该指令对是否被原子执行。
这对指令指保留加载(load-reserved)双字的特殊加载指令(称为lr.d)和一个条件存储(sotre-conditional)双字的特殊存储指令(称为sc.d),如果加载的内容跟存储前探测到的内容不同,条件存储就会失败,不会写入内存。成功就会把另一个寄存器的值更改为0,如果失败就改成非0。
sc.d指定了三个寄存器:保存地址、指示原子操作失败成功、如果成功就把指写入内存。
上面的过程实现了在x20指定的内存上的原子交换,即atomic_exchange(x23, mem[x20]
链接
三个工作步骤:
- 将代码和数据模块按符号特征放入内存
- 决定数据和指令标签的地址
- 修正内部和外部引用
MIPS vs RISC-V
相同
不同
- 除了eq、neq外的条件分支。RV只提供分支指令来比较两个寄存器,而MIPS提供比较指令,把比较结果写入一个寄存器(0 or 1)
- MIPS只执行小于比较,存在有符号和无符号版本(slt和sltu)
- 完整的MIPS指令系统 » RSIC-V
总结
- 讲了指令系统体系结构ISA(Instruction Set Architecture)的历史
- RV的指令结构
- 实现同步
- RV与x86、MIPS的比较