RISC-V ASM
RISC-V ASM
主要是RV32I的asm
operation
instruction(指令):直接对应二进制机器指令的字符串
pseudo-instruction(伪指令):一条伪指令指示汇编器产生多条实际的指令(instruction)
direction(指示/伪操作):通过类似指令的形 式(以“.”开头),通知汇编器如何控制代码的产生等,不对应具体的指令,比如.text是告诉汇编器放到.text节里,
macro:采用 .macro/.endm 自定义的宏
指令编码格式
funct3和funct7和opcode决定指令类型(加减乘除等等)
funct3:funct代表function 3代表占了3bits
- R-type:(Register),每条指令中有三个 fields,用于指定3个寄存器参数
- I-type: (Immediate),每条指令除了带有两个寄存器参数外,还带有一个立即数参数(宽度为 12 bits)。
- S-type: (Store),每条指令除了带有两个寄存器参数外,还带有一个立即数参数(宽度为 12 bits,但 fields 的组织方式不同于 I-type)
- B-type: (Branch),每条指令除了带有两个寄存器参数外,还带有一个立即数参数(宽度为 12 bits,但取值为 2 的倍数)。
- U-type: (Upper),每条指令含有一个寄存器参数再加上一个立即数参数(宽度为 20bits,用于表示一个立即数的高 20 位)
- J-type: (Jump),每条指令含有一个寄存器参数再加上一个立即数参数(宽度为 20bits)
rd:r代表register d代表destination
rs:s代表source
算法运算指令
ADD
ADD RD(5),RS1(5),RS2(5) RD=RS1+RS2
5表示占5个bit
编码格式:R-type
- opcode:01 100 11
- fuct3:000 funct7 0000000
SUB
SUB RD, RS1, RS2 RD=RS1-RS2
编码格式:R-type
- opcode:01 100 11
- fuct3:000 funct7 0100000
ADDI(ADD Immediate)
ADDI RD, RS1, IMM RD=RSI+IMM
编码格式:I-type
立即数只能表是-211211-1 (-20482047) 立即数参与运算前会被做符号拓展位32位imm
LUI(Loda Upper Immediate)
LUI RD,IMM RD=IMM<<12
编码格式:U-type
和ADDI指令配合使用来给寄存器赋值大立即数
lui x1,0x12345 |
对于低12位的符号位是1的情况,由于addi有符号拓展,就需要用减法来实现
比如想让x1=0x12345fff
lui x1,0x12346 |
LI(Load Immediate)
LI RD,IMM RD=IMM
伪指令 可以给某个寄存器赋32位的值,就不需要我们自己用lui和addi指令来做,而是由汇编器来完成
AUIPC
AUIPC RD IMM RD=IMM<<12+PC
编码格式:U-type
LA(Load Address)
LA RD,LABEL 加载一个函数或变量的地址
伪指令 汇编器会利用auipc指令和其他指令来生成
NEG
NEG RD,RS RD=-RS
伪指令 实际是SUB RD,x0,RS(零寄存器x0)
MV
MV RD,RS RD=RS
伪指令 实际上是ADDI RD,RS,0
NOP
就是nop啦hh
伪指令 实际上是ADDI x0,x0,0
逻辑运算指令
AND
AND RD,RS1,RS2 RD = RS1 & RS2
编码格式:R-type
OR
OR RD,RS1,RS2 RD = RS1 | RS2
编码格式:R-type
XOR
AND RD,RS1,RS2 RD = RS1 ^ RS2
编码格式:R-type
ANDI
AND RD,RS1,IMM RD = RS1 & IMM
编码格式:I-type
ORI
AND RD,RS1,IMM RD = RS1 & IMM
编码格式:I-type
XORI
AND RD,RS1,IMM RD = RS1 & IMM
编码格式:I-type
NOT
NOT RD,RS RD=!RS 非
伪指令 实际上是XOR RD,RS,-1
移位运算指令
>>>逻辑移位
SLL(Shitf Left Logical)
SLL RD,RS1,RS2 RD=RS1<<RS2
编码格式:R-type
SRL(Shitf Right Logical)
SRL RD,RS1,RS2 RD=RS1>>RS2
编码格式:R-type
SLLI(Shitf Right Logical Immediate)
SLLI RD,RS1,IMM RD=RS1<<IMM
编码格式:I-type
SRLI(Shitf Right Logical Immediate)
SRLI RD,RS1,IMM RD=RS1>>IMM
编码格式:I-type
>>>算数移位
SRA(Shitf Right Arithmetic)
SRA RD,RS1,RS2 RD=RS1>>RS2
编码格式:R-type
SRAI
SRA RD,RS1,IMM RD=RS1>>IMM
编码格式:I-type
shamt(shift amount)意为移动量,五个bit来描述2^5 – 1=31对于RV32就够了
内存读写指令load store
LB(Load Byte)
LB RD,IMM(RS1) *(Byte*)(RD) = *(Byte*)(RS1+IMM) 读取的数据做符号拓展
LH(Load Halfword)
LH RD,IMM(RS1) *(Halfword*)(RD) = *(Halfword*)(RS1+IMM) 读取的两字节数据做符号拓展
LW(Load Word)
LW RD,IMM(RS1) *(Word*)(RD) = *(Wword*)(RS1+IMM) 四字节
LBU(Load Byte Unsigned)
LBU RD,IMM(RS1) *(Byte*)(RD) = *(Byte*)(RS1+IMM) 读取的数据做零拓展
LHU(Load HalfWord Unsigned)
LHU RD,IMM(RS1) *(Halfword*)(RD) = *(Halfword*)(RS1+IMM) 读取的数据做零拓展
编码格式均为I-type
SB(Store Byte)
SB RS2,IMM(RS1) *(Byte*)(RS1+IMM)=RS2[0:7]
SH(Stroe Halfword)
SB RS2,IMM(RS1) *(Halfword*)(RS1+IMM)=RS2[0:15]
SW(Store Word)
SB RS2,IMM(RS1) *(Word*)(RS1+IMM)=RS2
编码格式均为S-type
条件分支指令
跳转的目标地址计算方法:先将 IMM x 2,符号扩展后和 PC 值相加得到最终的目标地址,所以跳转范围是以 PC 为基准,+/- 4KB 左右 ([-4096, 4094])。
b-type里是没有0位的应为0位永远为0,-4096, 4094是因为 2*(-2^(11),2^(11)-1)
JAL(Jump And Link)
JAL RD,LABEL
编码格式J-type
调用子过程,把20位宽的立即数2后进行符号拓展和pc值相加,然后把下一条指令地址写入RD,所以跳转范围应该是2*(-2^(19),2^(19)-1)即(-1048576,1048574)约等于+/-1M*
JALR(Jump And Link Register)
JALR RD,IMM(RS1)
编码格式I-type
调用子过程,把12bit的IMM进行符号拓展后和RS1相加,将结果最低1bit设置为0(确保地址按照两字节对齐),跳转地址以RS1为基准,-2^11,2^11-1,上下**+/-2k**
对于超过1M的远距离跳转
auipc x6,IMM
jalr x1,x6,IMM
J
J offset 相当于x86的jmp
伪指令 相当于JAL x0,offset
JR
JR RS
伪指令 相当于JALR x0,0(RS)
调用约定
基于调用约定的伪指令
TODO: emm,编译32位riscv时缺少头文件了,暂时没解决,64位又有一点点不一样,暂时不做实例分析