RISC-V 汇编指令笔记
本文主要作为RISC-V Instruction的一个梳理。
RISC-V Instruction 的格式通常为
Operation code + Destination register + First operand register + Second oprand register
如,add x1, x2, x0 对应的 opcode = add; rd = x1; rs1 = x2; rs2 = x0.
对于RISC-V,有32个寄存器,分别是:
RISC-V寄存器表
| 寄存器 | 调用名字 | 用途 | 存储者 | 
| x0 | zero | 常数0 | N.A. | 
| x1 | ra | 返回地址 | Caller | 
| x2 | sp | 栈指针 | Callee | 
| x3 | gp | 全局指针 | / | 
| x4 | tp | 线程指针 | / | 
| x5-x7 | t0-t2 | 临时存储 | Caller | 
| x8 | s0/fp | 保存用寄存器/帧指针(配合栈指针界定一个函数的栈) | Callee | 
| x9 | s1 | 保存用寄存器 | Callee | 
| x10-x11 | a0-a1 | 函数参数/返回值 | Caller | 
| x12-x17 | a2-a7 | 函数参数 | Caller | 
| x18-x27 | s2-s11 | 保存用寄存器 | Callee | 
| x28-x31 | t3-t6 | 临时存储 | Caller | 
| f0-f7 | ft0-ft7 | 浮点临时存储 | Caller | 
| f8-f9 | fs0-fs1 | 浮点保存用寄存器 | Callee | 
| f10-f11 | fa0-fa1 | 浮点函数参数/返回值 | Caller | 
| f12-f17 | fa2-fa7 | 浮点函数参数 | Caller | 
| f18-f27 | fs2-fs11 | 浮点保存用寄存器 | Callee | 
| f28-f31 | ft8-ft11 | 浮点临时存储 | Caller | 
tips:   callee:是一个指针,指向拥有这个arguement对象的函数;
caller:保留着调用当前函数的函数的引用。
而RISC-V RV32标准指令集有以下几种框架:
- R-format for register-register arithmetic/logical operations
 - I-format for register-immediate arith/logical operations and loads
 - S-format for stores
 - B-format for branches
 - U-format for 20-bit upper immediate instructions
 - J-format for jumps
 - Others: Used for OS & Syncronization
 
R即Reg相关;I即立即数相关;S存储相关;B分支相关;U高位数相关(因为一条32位指令中无法表示高达32位的数据);J跳转相关。
tips: about arithmetic & logical operations.
- 逻辑右移(LSR)是将各位依次右移指定位数,然后在左侧补0,算术右移(ASR)是将各位依次右移指定位数,然后在左侧用原符号位补齐。
 - 逻辑左移与算术左移操作相同。
 - RISC-V采用小端格式(Little-Endian),即低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
 
R-Format
通常是xxx rd, rs1, rs2。
31 0
| Funct7 | rs2 | rs1 | Funct3 | rd | opcode | 
| 7 | 5 | 5 | 3 | 5 | 7 | 
Opcode = 0110011
Funct7 + Funct3 + opcode defines what operation to perform.
|   
  |  
     Funct7  |  
     Funct3  |  
     opcode  |  
     用途  |  
  
|   ADD  |  
     0000000  |  
     000  |  
     0110011  |  
     加法  |  
  
|   SUB  |  
     0100000  |  
     000  |  
     0110011  |  
     减法  |  
  
|   SLL  |  
     0000000  |  
     001  |  
     0110011  |  
     左移  |  
  
|   SLT  |  
     0000000  |  
     010  |  
     0110011  |  
     Set Less Than := rs1 < rs2 ? 1:0  |  
  
|   SLTU  |  
     0000000  |  
     011  |  
     0110011  |  
     SLT Unsigned  |  
  
|   XOR  |  
     0000000  |  
     100  |  
     0110011  |  
     异或  |  
  
|   SRL  |  
     0000000  |  
     101  |  
     0110011  |  
     逻辑右移  |  
  
|   SRA  |  
     0100000  |  
     101  |  
     0110011  |  
     算术右移  |  
  
|   OR  |  
     0000000  |  
     110  |  
     0110011  |  
     或  |  
  
|   AND  |  
     0000000  |  
     111  |  
     0110011  |  
     与  |  
  
相关伪指令:
mv rd, rs = addi rd, rs, x0
nop = addi r0, r0, x0
not rd, rs = xori rd, rs, 111111111111
Note: 因为某事突然发现RISC-V好像没有循环移位的指令(未查证),要实现循环移位估计要三条指令以上。
I-Format
Opcode 0010011
| Immediate | rs1 | Funct3 | rd | opcode | |
| 12 | 5 | 3 | 5 | 7 | |
| Shift-by-immediate | rs1 | Funct3 | rd | opcode | |
| 0x00000 | 5 | 5 | 3 | 5 | 7 | 
第一部分包括ADDI, SLTI, SLTIU, XORI, ORI, ANDI(立即数有12位)
和SLLI, SRLI, SRAI(立即数仅有5位)。
第二部分包括load instruction,格式同ADDI(12位的立即数)
Load Opcode 0000011
有LB(load byte) ,LH(load halfword=2 bytes), LW,LBU(load unsigned byte),LHU(load unsigned halfword)
S-Format
Opcode 0100011
| imm[11:5] | rs2 | rs1 | Funct3 | imm[4:0] | opcode | 
| 7 | 5 | 5 | 3 | 5 | 7 | 
包括SB,SW,SH
B-Format
Opcode 1100011
| imm[12] | imm[10:5] | rs2 | rs1 | Funct3 | imm[4:1] | imm[11] | opcode | 
| 1 | 6 | 5 | 5 | 3 | 4 | 1 | 7 | 
可以表示-4096~4094的范围
Note:The 12 immediate bits encode even 13-bit signed byte offsets (lowest bit of offset is always zero, so no need to store it).
包括BEQ,BNE,BLT(branch less than: if [rs1]<[rs2], then branch) ,BGE(branch greater than or equal: if [rs1]>=[rs2], then branch) ,BLTU,BGEU。
相关伪指令:
beqz x1, label = beq x1, x0, label
bnez x1, label = bne x1, x0, label
U-Format
| imm[31:12] | rd | opcode | 
| 20 | 5 | 7 | 
LUI – Load Upper Immediate lui rd, upper im(20-bit)
e.x. lui x10, 0x87654 # x10 = original value → 0x87654000
AUIPC – Add Upper Immediate to PC
e.x. auipc t0, 1 # t0 = original value → PC + 0x00001000
auipc t0, 0 # t0 = original value → PC
相关伪指令:
加载立即数
li rd, imm(32-bit) = lui rd, imm(20-bit)
addi rd, rd, imm(12-bit)
加载地址
la rd, label = auipc rd, imm(20-bit)
addi rd, rd, imm(12-bit)
J-Format
| imm[20] | imm[10:1] | imm[11] | imm[19:12] | rd | opcode | 
| 1 | 10 | 1 | 8 | 5 | 7 | 
jal x0, label Discard return address
jal ra, function_name Call Function within 218 (1 instruction = 22 bytes).
jr ra
# Call function at any 32-bit absolute address
lui x1, <high 20-bit>
jalr ra, x1, <low 12-bit> Call Function at 32-bit absolute address
# Jump PC-relative with 32-bit offset
auipc x1, <high 20-bit>
jalr x0, x1, <low 12-bit> Jump within 32-bit
相关伪指令:
j label = jal x0, label
ret = jr ra = jalr x0, ra, 0
Acknowledgement
- UC Berkeley CS61C
 - http://www.kvakil.me/venus/ 可以在线编译RISC-V的工具
 
