RISC-V是一个基于精简指令集原则的开源指令集架构
ISA 指令集架构
ABI 应用程序二进制接口
PC 程序计数器
B-type 条件跳转指令
J-type 无条件跳转指令
I-type 寄存器-立即数指令
R-type寄存器-寄存器指令
(risc-v传输的数据都是32位字长,所以要进行扩展,sign-extended符号位扩展,zero-extended零扩展)
//offset,imm等、操作时都需要进行符号扩展,sexd()/(sign-extend)
1 R-type 寄存器-寄存器指令
funct-7 | rs2-5 | rs1-5 | funct-3 | rd-5 | opcode-7 | R-type |
0000000 | rs2 | rs1 | 000 | rd | 0110011 | R add |
0100000 | rs2 | rs1 | 000 | rd | 0110011 | R sub |
0000000 | rs2 | rs1 | 001 | rd | 0110011 | R sll |
0000000 | rs2 | rs1 | 010 | rd | 0110011 | R slt小置位 |
0000000 | rs2 | rs1 | 011 | rd | 0110011 | R sltu |
0000000 | rs2 | rs1 | 100 | rd | 0110011 | R xor |
0000000 | rs2 | rs1 | 101 | rd | 0110011 | R srl |
0100000 | rs2 | rs1 | 101 | rd | 0110011 | R sra |
0000000 | rs2 | rs1 | 110 | rd | 0110011 | R or |
0000000 | rs2 | rs1 | 111 | rd | 0110011 | R and |
1. ADD rd, rs1, rs2
x[rd] = x[rs1] + x[rs2],忽略溢出,保留低32bit
2. SUB rd, rs1, rs2
x[rd] = x[rs1] - x[rs2],忽略溢出,保留低32bit
3. AND rd, rs1, rs2
x[rd] = x[rs1] & x[rs2],按位与 & //&&逻辑与
4. OR rd, rs1, rs2
x[rd] = x[rs1] | x[rs2],按位或 |
5. XOR rd, rs1, rs2
x[rd] = x[rs1] ^ x[rs2], 按位异或 ^
6. SLT (set less than小于置1)
SLT rd, rs1, rs2
if (x[rs1] < x[rs2]) x[rd] = 1 else x[rd] = 0
7. SLTU (set less than unsigned)
SLTU rd, rs1, rs2
if((unsigned)x[rs1] < (unsigned)x[rs2]) x[rd] = 1 else x[rd] = 0
8. SLL (shift left logical)
SLL rd, rs1, rs2
rd = x[rs1] << rs2 [4 : 0],逻辑左移,低位补零,rs2的lower 5 bits作为偏移量,将寄存器rs1的值左移寄存器rs2的值这么多位,并写入寄存器rd //算数左移也是低位补零
9. SRL (shift right logical)
SRL rd, rs1, rs2
rd = x[rs1] >> rs2 [4 : 0],逻辑右移,高位补零,rs2的lower 5 bits作为偏移量
10. SRA (shift right arithmetic)
SRA rd, rs1, rs2
rd = x[rs1] >> rs2 [4 : 0],算数右移,高位补符号位,rs2的lower 5 bits作为偏移量
2 S-type用于内存存储操作
Imm-7 | rs2-5 | rs1-5 | funct-3 | Imm-5 | opcode-7 | S-type |
imm[11:5] | rs2 | rs1 | 000 | imm[4:0] | 0100011 | S sb字节 |
imm[11:5] | rs2 | rs1 | 001 | imm[4:0] | 0100011 | S sh半字 |
imm[11:5] | rs2 | rs1 | 010 | imm[4:0] | 0100011 | S sw字 |
Load指令使用的是I-Type指令的格式
Store指令使用的是S-Type指令的格式
Load和Store指令的偏移量均由一个12位的立即数给出,但是它们在指令中的位置不同,这是由指令的功能决定的:
Load指令需要将内存中的数据转移到寄存器组,因此需要提供目标寄存器;
Store指令需要将寄存器组中的数据转移到内存,因此需要rs1提供内存中将要写入数据的地址,rs2提供需要转移的数据。
8086 [段地址*16(逻辑地址)+偏移地址=物理地址] //数据线16位,地址线20位
1. SB (store byte)
sb rs2, offset(rs1)
mem(x[rs1]+(sign-extend)offset)=x[rs2] [7:0]
//把寄存器rs2的值存入地址为寄存器rs1的值加offset的主存中,保留最右端的8位
2. SH (store half)
sh rs2, offset(rs1)
mem(x[rs1]+(sign-extend)offset)=x[rs2] [15:0]
//把寄存器rs2的值存入地址为寄存器rs1的值加offset的主存中,保留最右端的16位
3. SW (store word)
sw rs2, offset(rs1)
mem(x[rs1]+(sign-extend)offset)=x[rs2] [31:0]
//把寄存器rs2的值存入地址为寄存器rs1的值加offset的主存中,保留最右端的32位
3 I-type寄存器-立即数指令
imm[11:0]立即数 | rs1-5 | funct-3 | rd-5 | opcode-7 | I-type |
imm[11:0] | rs1 | 000 | rd | 1100111 | I jalr |
1. JALR (jump and link register)
jalr rd,offset(rs1) //其他写法??jalr rd,rs1,offset
把下一条指令的地址存到rd中,然后跳转到rs1+offset地址处的指令继续执行。
//类似函数调用?
imm[11:0]立即数 | rs1-5 | funct-3 | rd-5 | opcode-7 | I-type |
imm[11:0] | rs1 | 000 | rd | 0000011 | I lb |
imm[11:0] | rs1 | 001 | rd | 0000011 | I lh |
imm[11:0] | rs1 | 010 | rd | 0000011 | I lw |
imm[11:0] | rs1 | 100 | rd | 0000011 | I lbu |
imm[11:0] | rs1 | 101 | rd | 0000011 | I lhu |
1. LW (load word载入字=4字节)
LW rd, offset(rs1)
x[rd] = mem[x[rs1] + (sign-extended) offset] [31:0]
2. LH (load half载入半字=2字节)
LH rd, offset(rs1)
x[rd] = (sign-extended) mem[x[rs1] + (sign-extend) offset)] [15:0]
(从地址为寄存器rs1的值加offset的主存中读一个字节,符号扩展后存入rd)
3. LB (load byte载入字节)
LB rd, offset(rs1)
x[rd] = (sign-extended) mem[x[rs1] + (sign-extend) offset)] [7:0]
4. LBU (load byte unsigned载入8位无符号字节)
LBU rd, offset(rs1)
x[rd] = (zero-extended) mem[x[rs1] + (sign-extend) offset)] [7:0]
(从地址为寄存器rs1的值加offset的主存中读一个无符号的字节,零扩展后存入rd)
5. LHU (load half unsigned载入8位无符号字节)
imm[11:0]立即数 | rs1-5 | funct-3 | rd-5 | opcode-7 | I-type | |||||
imm[11:0] | rs1 | 000 | rd | 0010011 | I addi | |||||
imm[11:0] | rs1 | 010 | rd | 0010011 | I slti | |||||
imm[11:0] | rs1 | 011 | rd | 0010011 | I sltiu | |||||
imm[11:0] | rs1 | 100 | rd | 0010011 | I xori | |||||
imm[11:0] | rs1 | 110 | rd | 0010011 | I ori | |||||
imm[11:0] | rs1 | 111 | rd | 0010011 | I andi | |||||
imm[11:0] | rs1 | 001 | rd | 0010011 | I slli | |||||
imm[11:0] | rs1 | 101 | rd | 0010011 | I srli | |||||
imm[11:0] | rs1 | 101 | rd | 0010011 | I srai |
(imm是一个12位的立即数,在与32位的寄存器进行逻辑运算时必须进行符号位扩展)
1. ADD rd, rs1, imm
x[rd] = x[rs1] + (sign-extended) imm,忽略溢出,保留低32bit
2. AND rd, rs1, imm
x[rd] = x[rs1] & (sign-extended) imm,按位与 & // &&逻辑与
3. OR rd, rs1, imm
x[rd] = x[rs1] | (sign-extended) imm,按位或 |
4. XOR rd, rs1, imm
x[rd] = x[rs1] ^ (sign-extended) imm, 按位异或 ^
5. SLTI (set less than immediate)
SLT rd, rs1, imm
if (x[rs1] < (sign-extended) imm) x[rd] = 1 else x[rd] = 0
6. SLTIU (set less than unsigned immediate)
SLTU rd, rs1, imm
if((unsigned)x[rs1]< (unsigned)(sign-extended)imm) x[rd] = 1 else x[rd] = 0
//移动指令中imm低6位作为偏移量,且当第6位为0指令才有效
1. slli (Shift Left Logical Immediate立即数)
slli rd, rs1, imm
rd = x[rs1] << imm,逻辑左移,空位补零,结果写入rd
2. srli (Shift Right Logical Immediate立即数)
srli rd, rs1, imm
rd = x[rs1] >> imm,逻辑右移,空位补零,结果写入rd
3. srai (Shift Right Arithmetic Immediate立即数)
srai rd, rs1, imm
rd = x[rs1] >> imm,算数右移,高位补符号位,结果写入rd
imm[11:0]立即数 | rs1-5 | funct-3 | rd-5 | opcode-7 | I-type | ||
0000 | pred | succ | 00000 | 000 | 00000 | 0001111 | I fence |
0000 | 0000 | 0000 | 00000 | 001 | 00000 | 0001111 | I fence.i |
0000 0000 0000 | 00000 | 000 | 00000 | 1110011 | I ecall | ||
0000 0000 0001 | 00000 | 000 | 00000 | 1110011 | I ebreak | ||
csr (control statue register) | rs1 | 001 | rd | 1110011 | I csrrw | ||
csr控制状态寄存器 | rs1 | 010 | rd | 1110011 | I csrrs | ||
csr | rs1 | 011 | rd | 1110011 | I csrrc | ||
csr | zimm | 101 | rd | 1110011 | I csrrwi | ||
csr | zimm | 110 | rd | 1110011 | I cssrrsi | ||
csr | zimm | 111 | rd | 1110011 | I csrrci |
4 B-type条件跳转指令
Imm-7 | rs2-5 | rs1-5 | funct-3 | Imm-5 | opcode-7 | B-type |
imm[12|10:5] | rs2 | rs1 | 000 | imm[4:1|11] | 1100011 | B beq等于 |
imm[12|10:5] | rs2 | rs1 | 001 | imm[4:1|11] | 1100011 | B bne不等 |
imm[12|10:5] | rs2 | rs1 | 100 | imm[4:1|11] | 1100011 | B blt小于 |
imm[12|10:5] | rs2 | rs1 | 101 | imm[4:1|11] | 1100011 | B bge大于等于 |
imm[12|10:5] | rs2 | rs1 | 110 | imm[4:1|11] | 1100011 | B bltu |
imm[12|10:5] | rs2 | rs1 | 111 | imm[4:1|11] | 1100011 | B bgeu |
1. BEQ (branch equal)
BEQ rs1, rs2, offset
if (x[rs1] == x[rs2]) pc += (sign-extended) offset
如果x[rs1]=x[rs2],pc的值被设置为当前值加上符号扩展偏移量,程序跳转到此时pc所指的地址继续执行。
//其他指令类似
2. BLTU (branch less than unsigned无符号)
BLTU rs1, rs2, offset
if((unsigned) x[rs1] < (unsigned) x[rs2]) pc += (sign-extended) offset
如果x[rs1]<x[rs2](视为无符号数),pc的值被设置为当前值加上符号扩展偏移量,程序跳转到此时pc所指的地址继续执行。
//其他指令类似
blt (Branch if less than)小于
bne (Branch if not equal)不等于
bge (Branch if greater or equal)大于等于
bltu (Branch if Less Than, Unsigned)
bgeu (Branch if greater or equal, Unsigned)
5 J-type无条件跳转指令
Imm-20 | Rd-5 | opcode-7 | J-type |
imm[20|10:1|11|19:12] | rd | 1101111 | J jal |
JAL (jump and link)
jal rd, offset
x[rd]=pc+4 //rd内存入下一条指令的地址,一条指令占4个字节
pc+=(sign-extended)offset //程序跳转,继续执行
//对比I-type的JASR(jump and link register)
imm[11:0]立即数 | rs1-5 | funct-3 | rd-5 | opcode-7 | I-type |
imm[11:0] | rs1 | 000 | rd | 1100111 | I jalr |
JALR (jump and link register)
jalr rd,offset(rs1) //其他写法??jalr rd,rs1,offset
把下一条指令的地址存到rd中,然后跳转到rs1+offset地址处的指令继续执行。
//类似函数调用?
6 U-type用于长立即数操作
Imm-20 | Rd-5 | opcode-7 | U-type |
imm[31:12] | rd | 0110111 | U lui |
imm[31:12] | rd | 0010111 | U auipc |
1. LUI (load upper immediate载入长立即数)
lui rd, imm
x[rd] = sext(imm[31:12] << 12)
//将符号扩展的20位立即数左移12位,即低12位抹零后存入rd中
2. AUIPC (add upper immediate to pc)
auipc rd, imm
x[rd] = pc + sext(imm[31:12] << 12)
//将符号扩展的20位立即数左移12位,即低12位抹零后加上pc,结果存入rd中
7 乘法和除法指令
funct-7 | rs2-5 | rs1-5 | funct-3 | rd-5 | opcode-7 | R-type |
0000001 | rs2 | rs1 | 000 | rd | 0110011 | R mul |
0000001 | rs2 | rs1 | 001 | rd | 0110011 | R mulh |
0000001 | rs2 | rs1 | 010 | rd | 0110011 | R mulhsu |
0000001 | rs2 | rs1 | 011 | rd | 0110011 | R mulhu |
0000001 | rs2 | rs1 | 100 | rd | 0110011 | R div |
0000001 | rs2 | rs1 | 101 | rd | 0110011 | R divu |
0000001 | rs2 | rs1 | 110 | rd | 0110011 | R rem余数 |
0000001 | rs2 | rs1 | 111 | rd | 0110011 | R remu |
//负数以补码的形式存放,补码等于原码取反加一(符号位不变),补码取反加一是绝对值
1. MUL (multiple乘法)
mul rd, rs1, rs2
x[rd] = x[rs1] * x[rs2]
把寄存器 x[rs2]与寄存器 x[rs1]相乘,乘积写入 x[rd]。忽略算术溢出
2. MULH (Multiply High)
mulh rd, rs1, rs2
x[rd] = (x[rs1] * x[rs2]) ≫XLEN
把寄存器 x[rs2]与寄存器 x[rs1]相乘,x[rs1] x[rs2]都视为二进制补码(都为有符号数),将乘积的高位(左32位)写入x[rd]。
//二进制补码(2的补码):(计算机中负数的表示方式)
第一步,每一个二进制位都取反值,0变成1,1变成0。
第二步,将上一步的得到的值加1
3. MULHSU (Multiply High Signed-Unsigned)
mulhsu rd, rs1, rs2
x[rd] = (x[rs1] * x[rs2]) ≫XLEN
把寄存器 x[rs2]与寄存器 x[rs1]相乘,x[rs1]为二进制的补码(有符号数),x[rs2]为无符号数,将乘积的高位写入x[rd]。
4. MULHU (Multiply High Unsigned)
mulhu rd, rs1, rs2
x[rd] = (x[rs1] * x[rs2]) ≫XLEN
把寄存器 x[rs2]与寄存器 x[rs1]相乘,x[rs1] x[rs2]都为无符号数,将乘积的高位写入x[rd]。
5. DIV (Divide除法)
div rd, rs1, rs2
x[rd] = x[rs1] / x[rs2 signed]
用寄存器 x[rs1]的值除以寄存器 x[rs2]的值,向零舍入(正数向下舍入,负数向上舍入,舍入的方向要朝向0),将这些数视为二进制补码,把商写入x[rd]。
6. DIVU (Divide Unsigned无符号除法)
divu rd, rs1, rs2
x[rd] = x[rs1] / x[rs2 unsigned]
用寄存器 x[rs1]的值除以寄存器 x[rs2]的值,向零舍入,将这些数视为无符号数,把商写入x[rd]。