《Computer Organization and Design RISC-V Edition: The Hardware/Software Interface (2nd Edition)》第二章 “Instructions: Language of the Computer” 的学习笔记。
主要是在讲 RISC-V。可以参考 Specifications – RISC-V International(比 x86 短多了)。
(P.S. 其他书我是认真看了第一章但懒得写,这本(如果看过 CS:APP 的话)建议直接跳过第一章(
Registers
RISC-V (RV32) 的 register 是 32-bit 的,而 32-bit 称作一个 word(与 x86 不同)。
有 32 个 register,用 x0
~x31
来标识,每个 register 根据其功能还有一个(或多个)别名。
x0
/ zero
的值固定为 0,能起到很多作用,例如在 sub
中作为被减数来取负、作为 destination 来丢弃结果、在 conditional branch(不接受 immediate)中作为比较的参数。
其他寄存器在硬件层面上没有区别,但有用于 procedure 的 convention:
-
x1
/ra
是 return address(call 是jal x1, foo
,return 是jalr x0, 0(x1)
)。 -
x2
/sp
是 stack pointer。 -
x3
/gp
是 global pointer(指向 static variable 的位置)。 -
x4
/tp
是 thread pointer。 -
x8
/fp
可以用作 frame pointer。 -
x10
-x17
(a0
-a7
) 用来存放前 8 个参数或返回值(一般单个返回值就是x10
)。 -
x8
-x9
(s0
-s1
),x18
-x27
(s2
-s11
) 是 (callee-)saved。 -
x5
-x7
(t0
-t2
),x28
-x31
(t3
-t6
) 是 temporary (caller-saved)。
Basic Instructions
op1 = op2 op op3
add
, sub
, addi
, and
, or
, xor
, andi
, ori
, xori
, sll
, srl
, sra
, slli
, srli
, srai
, slt
, sltu
, slti
, sltiu
add x5, x6, x7
:x5 = x6 + x7
addi x5, x6, 20
:x5 = x6 + 20
,其中 immediate 是 12-bit signed integer。slt x5, x6, x7
:x5 = x6 < x7 ? 1 : 0
Data Transfer
load word: lw x5, 40(x6)
: x5 = Memory[x6 + 40]
store word: sw x5, 40(x6)
: Memory[x6 + 40] = x5
half word、byte: lh
, lhu
, sh
, lb
, lbu
, sb
,其中 u
用来决定高位补零还是符号位。
Conditional Branch
beq
, bne
, blt
, bltu
, bge
, bgeu
blt x5, x6, 100
: if (x5 < x6) goto PC+100
Unconditional Branch
jal x1, 100
: x1 = PC+4; goto PC+100
jalr x1, 100(x5)
: x1 = PC+4; goto x5+100
Instruction Format
RISC-V 的 instruction 都是 32 bits 长,有若干种不同的 instruction format。
其中 “rs” 是 register source,
R-type:
I-type:
S-type:
可以看出,在不同的 format 中,会尽量保留 rs、rd、opcode、funct3 的位置不变,以简化电路(其中保持 opcode 位置不变对于识别 instruction format 是必要的)。
Wide Immediates and Addresses
Wide Immediates
超过 12 bits 的 immediate 可以通过两条 instruction lui
(load upper immediate) 和 addi
load 到 register,其中 lui
是 U-type:
auipc
可以用来进行更大范围的 PC-relative branch,和 lui
类似,会将 PC 加上一个只有高位的 immediate 存于 register。
Addressing in Branches
branch 使用的 address 必须是偶数,而且 branch instruction 使用了特殊的编码格式。
unconditional branch 使用 B-type,和 S-type 类似:
jal
使用 J-type,和 U-type 类似:
jalr
使用 I-type。
通过对 immediate 的重排:
- 所有格式中 immediate 的符号位都在同一位。
- I、S、B、U 中
imm[10:5]
位置相同。 - S、B 中
imm[4:1]
位置相同。 - I、J 中
imm[4:1]
位置相同,U、J 中imm[19:12]
位置相同。
Synchronization in Parallelism
在 parallel execution 中,需要 processor 支持 atomic operation 来实现各种 synchronization,例如 lock。
RISC-V 提供一对命令 lr.w
(load-reserved word) 和 sc.w
(store-conditional word) 来实现 “atomically read and modify a memory location”:
lr.w
接受两个 register 作为 operand,分别是 destination 和 address,它单独一个命令自身的效果和lw
类似;sc.w
接受三个 register 作为 operand,后两个是 source 和 address,若在lr.w
和sc.w
之间 address 处被修改过则 store 会失败。第一个 operand 用来存放结果(0 表示成功,非零表示失败)、。
实现 atomic swap:(x20)
和 x23
)
again:
lr.w x10, (x20)
sc.w x11, x23, (x20)
bne x11, x0, again
addi x23, x10, 0
实现 lock:(x20)
为 0/1 表示 lock free/acquired)
acquire:
addi x12, x0, 1
again:
lr.w x10, (x20)
bne x10, x0, again
sc.w x11, x12, (x20)
bne x11, x0, again
release:
sw x0, 0(x20)
Pseudoinstructions
为了方便编写汇编,汇编中可以使用一些在 hardware 上不存在的 pseudoinstruction。例如:
nop
:addi x0, x0, 0
mv rd, rs
:addi rd, rs, 0
not rd, rs
:xori rd, rs, -1
neg rd, rs
:sub rd, x0, rs
bgt rs, rt, offset
:blt rt, rs, offset
bnez rs, offset
:bne rs, x0, offset
ble rs, rt, offset
:bge rt, rs, offset
jal offset
:jal x1, offset
ret
:jalr x0, 0(x1)
详见《The RISC-V Instruction Set Manual Volume I: Unprivileged ISA》Chapter 25 RISC-V Assembly Programmer’s Handbook。