整数运算指令
格式为:[指令名] [目标], [源], [操作数]
例如:
add t0, t1, t2
意为将t1 + t2
存放入t0
xori t0, t1, 0x7EF
意为将t1 ^ 0x7EF
存放入t0
注意: RV32I指令长度为32bit,带立即数的运算指令(I型指令)的立即数只有12bit,因此带符号数只能取-0x800
到0x7FF
之间的数
具体地,运算指令有以下种类:
- 算术运算:
add
sub
- 逻辑运算:
and
or
xor
- 移位运算:
sll
srl
sra
访存指令
格式为:
[指令名(读)] [目的寄存器] [偏移量]([地址寄存器])
[指令名(写)] [源寄存器] [偏移量]([地址寄存器])
例如:
lb t0, (0x8)t1
意为将t1
寄存器中的地址加0x8
后得到的地址处的1
个字节存入t0
具体地,有:
- 读指令:
lw
lh
lb
- 无符号读指令:
lhu
lbu
- 写指令:
sw
sh
sb
比较指令
slt a0, a1, a2
意为若a1 < a2
则将a0
置1
,否则为0
,sltu
为对应的无符号数比较版本;slti
sltiu
为对应的立即数版本
例如以下代码段:
1 | addi a0, a0, 0x123 |
运行后a2
为0
,a3
为1
长立即数操作指令
lui a4 0x4daf1
将a4
的高20
位设为0x4daf1
auipc a5 0x6789a
将a5
设为PC + 0x6789a000
条件分支指令
beq a0, a1, equal
若a0 == a1
则跳转至equal
标号处
还有bne
bge
bgeu
blt
bltu
无条件跳转
jal s9, target
跳转至target
,将当前的PC + 4
(即下一条指令地址)存入s9
使用jal x0, target
则只会进行跳转,因为x0
不可改变
jalr x0, x1, 0
可以实现ret
,即跳转到x1 + 0
(x1
用来存储返回地址)
类似地,jal x1, func
可以实现过程调用(注意:这里没有维护栈帧)
杂项指令
看不懂,下一个 :(
伪指令
RV32I使用了一些方便用户的伪指令,其本质使用其他指令实现,例如ret
的真实实现是jalr x0, x1, 0
一定要善用伪指令和标号~
RV32I函数使用惯例
寄存器使用
a
开头为函数参数寄存器,调用者保存s
开头为被调用者保存寄存器t
开头为临时寄存器,调用者保存
函数格式
函数入口:
1 | entry_label: |
函数结尾:
1 | lw ra, framesize-4(sp) # 从栈帧读取返回地址 |