RISC-V 常用汇编指令集
一、 通用寄存器介绍
| 寄 存 器 | ABI名 | 用途 | Saver |
|---|---|---|---|
| x0 | zero | 读取时总为 0, 写入时不起任何效果 (只有读RO 权限) | - |
| x1 | ra | 存放函数返回地址 (return address) | Caller |
| x2 | sp | 存放栈指针 (stack pointer) | Callee |
| x3 | gp | global pointer | - |
| x4 | tp | thread point | - |
| x5 - x7 | t0 - t2 | 临时 (temporaries) 寄存器,Callee 可能会使用这些寄存器,所以 Callee 不保证这些寄存器中的值在函数调用过程中保持不变,这意味着对于 Caller 来说,如果需要的话,Caller 需要自己在调用 Callee 之前保存临时寄存器中的值。 | Caller |
| x8 - x9 | s0/fp - s1 | 保存 (saved) 寄存器,Callee 需要保证这些寄存器的值在函数返回后仍然维持函数调用之前的原值,所以一旦 Callee 在自己的函数中会用到这些寄存器则需要在栈中备份并在退出函数时进行恢复 | Callee |
| x10 - x11 | a0 - a1 | 参数 (argument) 寄存器,用于在函数调用过程中保存第一个和第二个参数,以及在函数返回时传递返回值。 | Caller |
| x12 - x17 | a2 - a7 | 参数 (argument) 寄存器,如果函数调用时需要传递更多的参数,则可以用这些寄存器,但注意用于传递参数的寄存器最多只有 8 个 (a0 ~ a7) ,如果还有更多的参数则要利用栈。 | Caller |
| x18 - x27 | s2 - s11 | 保存 (saved) 寄存器,Callee 需要保证这些寄存器的值在函数返回后仍然维持函数调用之前的原值,所以一旦 Callee 在自己的函数中会用到这些寄存器则需要在栈中备份并在退出函数时进行恢复。 | Callee |
| x28 - x31 | t3 - t6 | 临时 (temporaries) 寄存器,Callee 可能会使用这些寄存器,所以 Callee 不保证这些寄存器中的值在函数调用过程中保持不变,这意味着对于 Caller 来说,如果需要的话,Caller 需要自己在调用 Callee 之前保存临时寄存器中的值。 | Caller |
Caller :调用者
Callee : 被调用函数
static void Caller (void)
{
Callee ();
}
- 1
- 2
- 3
- 4
二、算术运算指令
| 指令 | 语法 | 描述 | 例子 |
|---|---|---|---|
| add | add rd,rs1,rs2 | rd = rs1 + rs2 | add x5,x6,x7 |
| addi | addi a0, a0, 4 | a0 = a0 + 4, 加立即数,并且检查溢出 | addi a0, a0, 4 |
| sub | sub rd,rs1,rs2 | (rs1 - rs2)的值保存到 rd | sub x5,x6,x7 |
| lui | lui rd,imm | rd = (imm << 12) (20位的立即数左移12位) | lui x5,0x12345 |
| auipc | auipc rd,imm(20bit) | rd = (imm << 12) + pc (相对 pc 的偏移值) | auipc x5,0x1234 |
三、逻辑运算
| 指令 | 语法 | 描述 | 例子 |
|---|---|---|---|
| and 与运算 | and rd,rs1,rs2 | rd = (rs1 & rs2) | and x5,x6,x7 |
| or 或运算 | or rd,rs1,rs2 | rd = (rs1 | rs2) |
| xor 异或运算 | xor rd,rs1,rs2 | rd = (rs ^ rs2) | xor x5,x6,x7 |
| andi 与立即数 | andi rd,rs,imm | rd = (rs & imm) | andi x5,x6,10 |
| ori 或立即数 | ori rd,rs,imm | rd = (rs | imm) |
| xori 异或立即数 | xori rd,rs,imm | rd = (rs ^ imm) | xori x5,x6,10 |
立即数可以理解成C 语言里的常数
四、伪指令
| 伪指令 | 语法 | 等价语句 | 描述 | 例子 |
|---|---|---|---|---|
| neg | neg rd,rs | sub rd,x0,rs | rd = ~rs (取反) | neg x5,x6 |
| mv | mov rd,rs | addi rd,rs,0 | rd = rs | mov x5,x6 |
| nop | nop | addi x0,x0,0 | 空指令 | nop |
| li | li rd,imm | - - | rd = imm (32bit) 直接加载32位立即数 | li x5,0x12345678 |
| la | la rd,addr | - - | rd = addr 加载地址到寄存器 | la x5,0x12345 |
| not | not rd,rs | xori rd,rs,-1 | 按位取反 | not x5,x6 |
五、 移位运算指令
5.1、逻辑移位,补零
| 指令 | 语法 | 描述 | 例子 |
|---|---|---|---|
| sll | sll rd,rs1,rs2 | (rs1 << rs2) | sll x5,x6,x7 |
| srl | srl rd,rs1,rs2 | (rs1 >> rs2) | srl x5,x6,x7 |
| slli | sll rd,rs1,imm | (rs1 << imm) | slli x5,x6,10 |
| srli | srl rd,rs1,imm | rd = (rs1 >> imm) | srli x5,x6,20 |
5.2、 0x01 << 3 (0000 0001) --> (0000 1000) 0x08 低 三位补 0
5.3、算术移位
| 指令 | 语法 | 描述 | 例子 |
|---|---|---|---|
| sra | sra rd,rs1,rs2 | rd = (rs1 << rs2) | sra x5,x6,x7 |
| srai | srai rd,rs1,imm | rd = (rs1 >> imm) | srl x5,x6,20 |
六、 内存读写指令
注释: imm 为12 bits 有符号整数(立即数)
6.1、读指令
| 指令 | 语法 | 描述 | 例子 |
|---|---|---|---|
| lb | lb rd,imm(rs) | 从内存 imm + rs 处读取8bit数据(符号拓展)到 rd 中(符号拓展) | lb x5,40(x6) |
| lbu | lbu rd,imm(rs) | 从内存 imm + rs 处读取8bit无符号整数(0扩展)到 rd 中(0扩展) | lbu x5,40(x6) |
| lh | lh rd,imm(rs) | 从内存 imm+rs 处读取16bit数据(符号拓展)到 rd 中(符号拓展) | lh x5,40(x6) |
| lhu | lhu rd,imm(rs) | 从内存 imm+rs 处读取16bit无符号整数(0扩展)到 rd 中(0扩展) | lhu x5,40(x6) |
| lw | lw rd,imm(rs) | 从内存 imm+rs 处读取32bit数据到 rd 中 | lw x5,40(x6) |
6.2、 写指令
| 指令 | 语法 | 描述 | 例子 |
|---|---|---|---|
| sb | sb rs2,imm(rs1) | 将rs2中的8bit数据写入内存 imm+rs1 处 | sb x5,40(x6) |
| sh | sh rs2,imm(rs1) | 将rs2中的16bit数据写入内存 imm+rs1 处 | sb x5,40(x6) |
| sw | sw rs2,imm(rs1) | 将rs2中的32bit数据写入内存 imm+rs1 处 | sb x5,40(x6) |
七、条件分支指令
7.1、条件指令
| 指令 | 语法 | 描述 | 例子 |
|---|---|---|---|
| beq | beq rs1,rs2,imm | 如果rs1 == rs2,跳转到 imm 地址处 | beq x5,x6,100 |
| bne | bne rs1,rs2,imm | 如果rs1 != rs2,跳转到 imm 地址处 | bne x5,x6,100 |
| blt | blt rs1,rs2,imm | 如果rs1 < rs2(有符号方式),跳转 | blt x5,x6,100 |
| bltu | bltu rs1,rs2,imm | 如果rs1 < rs2(无符号方式),跳转 | bltu x5,x6,100 |
| bge | blt rs1,rs2,imm | 如果rs1 >= rs2(有符号方式),跳转 | bge x5,x6,100 |
| bgeu | bltu rs1,rs2,imm | 如果rs1 >= rs2(无符号方式),跳转 | bgeu x5,x6,100 |
注释:跳转的目标地址计算方法(对齐):(imm<<1)+pc 具体编程时由标号给出
7.2、伪指令
| 伪指令 | 语法 | 描述 | 例子 |
|---|---|---|---|
| ble | ble rs1,rs2,offset | 如果 rs1 <= rs2,跳转到 offset 地址处 | ble x5,x6,100 |
| bleu | bleu rs1,rs2,offset | 如果 rs1 <= rs2(无符号),跳转到 offset 地址处 | bequ x5,x6,100 |
| bgt | bgt rs1,rs2,offset | 如果 rs1 >= rs2,跳转到 offset 地址处 | bgt x5,x6,100 |
| bgtu | bgtu rs1,rs2,offset | 如果 rs1 >= rs2(无符号),跳转到 offset 地址处 | bgtu x5,x6,100 |
| beqz | beqz rs1,offset | 如果 rs1 == 0,跳转到 offset 地址处 | beqz x5,x6,100 |
| bnez | bnez rs1,offset | 如果 rs1 != 0,跳转到 offset 地址处 | bnez x5,x6,100 |
| bltz | bltz rs1,offset | 如果 rs1 < 0,跳转到 offset 地址处 | bltz x5,x6,100 |
| blez | blez rs1,offset | 如果 rs1 <= 0,跳转到 offset 地址处 | blez x5,x6,100 |
| bgtz | bgtz rs1,offset | 如果 rs1 > 0,跳转到 offset 地址处 | bgtz x5,x6,100 |
| bgez | bgez rs1,offset | 如果 rs1 >= 0,跳转到 offset 地址处 | bgez x5,x6,100 |
八、无条件跳转指令
8.1、无条件跳转指令
| 指令 | 语法 | 描述 | 例子 |
|---|---|---|---|
| jal | jal rd,label | 指令的下一条指令地址存入rd,跳转到label (20bit) | jal x1,label |
| jalr | jalr rd,imm(rs) | 12bit的imm符号拓展,(rs+imm)低位置0存到rd,跳转 | jarl x1,0(x5) |
8.2 伪指令
| 指令 | 语法 | 描述 | 例子 |
|---|---|---|---|
| j | j offset | jal x0,offset [不会保存跳转前的地址] | j label |
| jr | jr rs | jalr x0,0(rs) [不会保存跳转前的地址] | jr x5 |
九、函数调用
9.1、伪指令
| 指令 | 语法 | 等价语句 | 描述 | 例子 |
|---|---|---|---|---|
| jal | jal offset | jal x1,offset | 保存返回地址到x1,跳转到 offset | jal label |
| jalr | jalr rs | jalr x1,0(rs) | 保存返回地址到x1,跳转到rs寄存器保存的地址 | jalr label |
| call | call offset | auipc x1,offset[31:12]+offset[11];jalr x1,ofsset[11:0] (x1) | - - | call fun |
| ret | ret | jalr x0,0(x1) | 返回 | ret |
能举一个risc-v指令集中的sext.w指令的范例吗?
可以,sext.w指令的作用是将一个16位的有符号数扩展为32位的有符号数,例如:
lw t0, 0(s0) # 从地址s0+0处读取一个16位的有符号数 sext.w t1, t0 # 将t0中的16位有符号数扩展为32位有符号数,并存储到t1中
注意:以上回答仅供参考,具体实现方式可能因处理器架构和编译器而异
本文详细介绍了RISC-V架构的常用汇编指令,包括寄存器分配、算术、逻辑、移位、内存操作、条件分支、无条件跳转和函数调用,以及sext.w指令示例。
4705

被折叠的 条评论
为什么被折叠?



