《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 + x7addi 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, 0mv rd, rs:addi rd, rs, 0not rd, rs:xori rd, rs, -1neg rd, rs:sub rd, x0, rsbgt rs, rt, offset:blt rt, rs, offsetbnez rs, offset:bne rs, x0, offsetble rs, rt, offset:bge rt, rs, offsetjal offset:jal x1, offsetret:jalr x0, 0(x1)
详见《The RISC-V Instruction Set Manual Volume I: Unprivileged ISA》Chapter 25 RISC-V Assembly Programmer’s Handbook。