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)
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作为偏移量
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位
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)
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 |
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]
//其他指令类似
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)
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地址处的指令继续执行。
//类似函数调用?
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中
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]。