文章目录
前言
R I S C − V RISC-V RISC−V 表示精简指令集计算机 R I S C ( R e d u c e d I n s t r u c t i o n S e t C o m p u t e r ) RISC(Reduced \ Instruction \ Set \ Computer) RISC(Reduced Instruction Set Computer) 的第五代指令集。其主要特点在于:指令长度固定,指令数量精简,通常在一个时钟周期内完成,且 R I S C V RISCV RISCV 完全开源。
而与其相对的 C I S C ( C o m p l e x I n s t r u c t i o n S e t C o m p u t e r ) CISC(Complex \ Instruction \ Set \ Computer) CISC(Complex Instruction Set Computer) 相比更加简洁高效。我们熟知的 x 86 x86 x86 其经过多年发展以及向前兼容的要求使得指令集非常繁杂,且授权费用高昂。
面向 32 32 32 位的 R I S C V RISCV RISCV 指令集称为 R V 32 RV32 RV32 ,另外对应有 64 64 64 位的 R V 64 RV64 RV64 和 128 128 128 位的 R V 128 RV128 RV128。 本文将以 R V 32 RV32 RV32 为主体,向大家详细介绍 32 32 32 位基础指令集 R V 32 I RV32I RV32I 的指令编码及其具体格式以及一些指令编码时立即数位置奇怪的原因。
RISCV指令集的模块化
R I S C V RISCV RISCV 的指令集按照不同的功能分为不同的子模块,以 R V 32 RV32 RV32 为例,模块用 R V 32 RV32 RV32 +字母命名,一个 R I S C V RISCV RISCV 指令集必须包含基础指令集 R V 32 I RV32I RV32I 以及可选的扩展部分,扩展部分包括标准扩展和用户自定义扩展。基础以及部分标准扩展指令集如下表所示:
RV32模块 | 全称 | 用途 |
---|---|---|
RV32I | Base Integer Instruction Set | 加减法,访问内存,控制转移分支指令,环境调用断点,内存屏障 |
RV32M | Integer Multiplication and Division | 整数乘法除法 |
RV32F | Single-Precision Floating Point | 单精度浮点数 |
RV32D | Double-Precision Floating Point | 双精度浮点数 |
RV32Q | Quad-Precision Floating Point | 四倍精度浮点数 |
RV32C | Compressed Instruction | 压缩指令,指令字长16bit,用于对指令大小有限制的环境 |
RV32A | Atomic Instruction | 原子指令,用于OS支持 |
RV32V | Vector Operation | 向量运算 |
RV32E | 通用寄存器变为16个,用作简单嵌入式设备,其余和RV32I基本一致 |
表中并未包含全部标准扩展,仅列出部分作为参考。
RV32I
R V 32 I RV32I RV32I 中共有指令格式 6 6 6 种,核心四种为 R I S U R \ I \ S \ U R I S U。六种指令格式分别是:
1 1 1 : R R R 型指令,用于寄存器和寄存器之间的算术运算。
2 2 2 : I I I 型指令,用于寄存器和立即数之间的算术运算以及用于从内存中加载数据。
3 3 3 : S S S 型指令,用于向内存存储数据。
4 4 4 : B B B 型指令,用于短距离分支指令。 S S S 型指令的变体。
5 5 5 : U U U 型指令,用于立即数高 20 b i t 20bit 20bit 操作指令。
6 6 6 : J J J 型指令,用于长距离跳转。 U U U 型指令的变体。
其中,通用寄存器 32 32 32 个,从 x 0 − x 31 x0-x31 x0−x31,共需 5 b i t 5bit 5bit 表示。 其中, x 0 x0 x0 被硬连线到 0 0 0 。
另有一个寄存器: p c pc pc ,用于存储当前正在执行的指令的地址。
四种主要的指令编码方式如下图所示:
可以看到,为了方便硬件设计,所有指令都保持 o p c o d e r s r d f u n c t opcode \ rs \ rd \ funct opcode rs rd funct 字段在寄存器位置的一致 (有例外,但 R V 32 I RV32I RV32I 中没有)。 f u n c t 3 funct3 funct3 字段主要用于区分具体的指令。
f u n c t 7 funct7 funct7 字段主要用于以后的扩展,指令中只使用很少一部分。例如: S U B , S U B W , S R A , S R A I , S R A I W SUB, SUBW, SRA, SRAI, SRAIW SUB,SUBW,SRA,SRAI,SRAIW 指令使用 f u n c t 7 = 0 b 0100000 funct7=0b0100000 funct7=0b0100000 相对于指令 A D D , A D D W , S R L , S R L I , S R L I W ADD, ADDW, SRL, SRLI, SRLIW ADD,ADDW,SRL,SRLI,SRLIW 中 f u n c t 7 = 0 b 0000000 funct7=0b0000000 funct7=0b0000000 只有很小的改动,该位主要用于对结果进行符号扩展。
其中, o p c o d e opcode opcode 长度为 7 7 7,占据指令 i n s t [ 6 : 0 ] inst[6:0] inst[6:0] 。一种 o p c o d e opcode opcode 代表了一种类别的操作, o p c o d e opcode opcode 具体映射如下表所示:
1: o p c o d e opcode opcode 最低两位 i n s t [ 1 : 0 ] inst[1:0] inst[1:0] 必须为 1 1 1 则指令有效。
2: o p c o d e opcode opcode 并不完全由 R I S U J B RISUJB RISUJB 这些指令格式决定,同样是 I I I 型指令, l o a d a d d i load \ \ addi load addi 有着不同的 o p c o d e opcode opcode。
另外,标准原话:"There is no dedicated stack pointer or subroutine return address link register in the Base Integer ISA; the instruction encoding allows any x register to be used for these purposes."
标准基础指令集中并未规定某一个特定寄存器用于堆栈指针和函数返回值的存储。但是按照调用约定, x 1 x1 x1 用于存储返回值,而 x 2 x2 x2 用于作为堆栈指针使用。具体如下图所示:
R型指令
R R R 型指令主要用于寄存器-寄存器之间的算术运算,不包含立即数。
例如: a d d x 18 , x 19 , x 10 add \ x18, x19, x10 add x18,x19,x10,其中, x 18 x18 x18 为 r d ( D e s t i n a t i o n R e g i s t e r ) rd(Destination \ Register) rd(Destination Register) 目的寄存器, x 19 x19 x19 为 r s 1 ( s o u r c e r e g i s t e r ) rs1(source \ register) rs1(source register) 源寄存器, x 10 x10 x10 为 r s 2 ( s o u r c e r e g i s t e r ) rs2(source \ register) rs2(source register) 源寄存器。
R R R 型指令的编码方式如下图所示:
所有 R R R 型指令的 o p c o d e opcode opcode 一样,都为 i n s t [ 6 : 0 ] = 0 b 0110011 inst[6:0]=0b0110011 inst[6:0]=