RV32I指令集及其编码方式解读

文章目录

  • 前言
  • RISCV指令集的模块化
  • RV32I
    • R型指令
    • I型指令
      • load指令 (I型)
    • S型指令
    • B型指令 (S型指令变体)
        • PC相对地址
        • B型指令
        • 简单举例
    • U型指令
      • LUI指令
        • li伪指令
      • AUIPC指令
    • J型指令(U型指令变体)
      • JAL指令
      • JALR指令(I型指令)
  • 参考


前言

R I S C − V RISC-V RISCV 表示精简指令集计算机 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模块全称用途
RV32IBase Integer Instruction Set加减法,访问内存,控制转移分支指令,环境调用断点,内存屏障
RV32MInteger Multiplication and Division整数乘法除法
RV32FSingle-Precision Floating Point单精度浮点数
RV32DDouble-Precision Floating Point双精度浮点数
RV32QQuad-Precision Floating Point四倍精度浮点数
RV32CCompressed Instruction压缩指令,指令字长16bit,用于对指令大小有限制的环境
RV32AAtomic Instruction原子指令,用于OS支持
RV32VVector 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 x0x31,共需 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]=0b0110011,对应上述 o p c o d e opcode opcode 映射表中 O P OP OP 表项。
所有 R R R 型指令的编码方式及其各字段的值如下表所示:

inst[31:25]inst[24:20]inst[19:15]inst[14:12]inst[11:7]inst[6:0]指令助记符
0000000rs2rs1000rd0110011add
0100000rs2rs1000rd0110011sub
0000000rs2rs1001rd0110011sll
0000000rs2rs1010rd0110011slt
0000000rs2rs1011rd0110011sltu
0000000rs2rs1100rd0110011xor
0000000rs2rs1101rd0110011srl
0100000rs2rs1101rd0110011sra
0000000rs2rs1110rd0110011or
0000000rs2rs1111rd0110011and

s r a ( s h i f t   r i g h t   a r i t h m e t i c ) sra(shift \ right \ arithmetic) sra(shift right arithmetic) 算术右移指令需要高位补符号位。
位运算中没有逐位取反操作,若要对寄存器 x 10 x10 x10 的内容逐位取反,只需: x o r   x 10 , x 10 , x 0 xor \ x10,x10,x0 xor x10,x10,x0。此时, r d = 1 0 10 = 0 b 01010 rd=10_{10}=0b01010 rd=1010=0b01010 r s 1 = 1 0 10 = 0 b 01010 rs1=10_{10}=0b01010 rs1=1010=0b01010 r s 2 = 0 10 = 0 b 00000 rs2=0_{10}=0b00000 rs2=010=0b00000,因此指令二进制表示为: 0 b 0000000   00000   01010   100   01010   0110011 0b0000000 \ 00000 \ 01010 \ 100 \ 01010 \ 0110011 0b0000000 00000 01010 100 01010 0110011

I型指令

I I I 型指令主要用于寄存器-立即数之间的算术运算,也用于 l o a d load load 指令的指令格式。
例如: a d d   x 18 , x 19 , − 50 add \ x18, x19, -50 add x18,x19,50,其中, 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) 源寄存器, − 50 -50 50 为立即数 ( i m m e d i a t e ) (immediate) (immediate)
I I I 型指令的编码方式对比 R R R 型指令如下图所示:
在这里插入图片描述 I I I 型指令中用于算术运算的指令 o p c o d e opcode opcode 一样,都为 i n s t [ 6 : 0 ] = 0 b 0010011 inst[6:0]=0b0010011 inst[6:0]=0b0010011,对应上述 o p c o d e opcode opcode 映射表中 O P − I M M OP-IMM OPIMM 表项。
其中,立即数用 12 b i t 12bit 12bit 补码表示,其具体表示范围为: [ − 2048 , 2047 ] [-2048,2047] [2048,2047]。所有立即数通过符号扩展到 32 b i t 32bit 32bit 之后再进行运算。
所有 I I I 型指令的编码方式及其各字段的值如下表所示:

inst[31:20]inst[19:15]inst[14:12]inst[11:7]inst[6:0]指令助记符
imm[11:0]rs1000rd0010011addi
imm[11:0]rs1010rd0010011slti
imm[11:0]rs1011rd0010011sltiu
imm[11:0]rs1100rd0010011xori
imm[11:0]rs1110rd0010011ori
imm[11:0]rs1111rd0010011andi
0000000+shamt[4:0]rs1001rd0010011slli
0000000+shamt[4:0]rs1101rd0010011srli
0100000+shamt[4:0]rs1101rd0010011srai

1:伪指令 m v mv mv 用于寄存器值的拷贝, m v   x 10 , x 19 mv \ x10, x19 mv x10,x19 指令具体实现方式为: a d d i   x 10 , x 19 , 0 addi \ x10,x19,0 addi x10,x19,0
2:伪指令 n o p nop nop 用于 n o   o p e r a t i o n no \ operation no operation n o p nop nop 指令具体实现方式为: a d d i   x 0 , x 0 , 0 addi \ x0,x0,0 addi x0,x0,0
3:立即数逻辑运算中,最高有效位保持和 R R R 型指令 f u n c t 7 funct7 funct7 字段一致的 7 7 7 位宽度,方便硬件设计。
4:同时,由于寄存器字长为 32 32 32,故移位量 ( s h a m t = s h i f t   a m o u n t ) (shamt=shift \ amount) (shamt=shift amount) 只需要考虑在 [ 0 , 31 ] [0,31] [0,31] 即可,只需要 5 b i t 5bit 5bit 编码。关于在具体设计中移位长度大于 32 32 32 则直接结果置 0 0 0 还是对移位量按照 32 32 32 取余需要根据具体的架构设计。我在这里有过简要分析:移位案例。

load指令 (I型)

l o a d load load 指令用于从内存中读取数据到寄存器。
R V 32 I RV32I RV32I 提供了一个 32 b i t 32bit 32bit 的内存地址空间,其根据字节寻址。一个可能的 l o a d load load 指令: l w   x 10 , 2 ( x 2 ) lw \ x10,2(x2) lw x10,2(x2),用于从 ( x 2 ) + 2 (x2)+2 (x2)+2 所指向的内存地址取一个字。其中, r d rd rd 寄存器为 x 10 x10 x10 ,数据宽度为字长 w o r d word word,基地址寄存器 b a s e / r s 1 base/rs1 base/rs1 x 2 x2 x2,偏移量 o f f s e t offset offset 2 2 2
l o a d load load 指令格式和 I I I 型指令一致。具体如下图所示:
在这里插入图片描述其中, l o a d load load 指令的 o p c o d e opcode opcode o p c o d e opcode opcode 映射表中第一项 l o a d load load o p c o d e = 0 b 0000011 opcode=0b0000011 opcode=0b0000011
其中,基址偏移量 o f f s e t offset offset 12 b i t 12bit 12bit 补码表示,其具体表示范围为: [ − 2048 , 2047 ] [-2048,2047] [2048,2047]。通过符号扩展到 32 b i t 32bit 32bit 之后和基地址相加。
所有 l o a d load load 指令编码方式及个字段的值如下表所示:

inst[31:20]inst[19:15]inst[14:12]inst[11:7]inst[6:0]指令助记符
imm[11:0]rs1000rd0000011lb
imm[11:0]rs1001rd0000011lh
imm[11:0]rs1010rd0000011lw
imm[11:0]rs1100rd0000011lbu
imm[11:0]rs1101rd0000011lhu

1: l b   ( l o a d   b y t e ) lb \ (load \ byte) lb (load byte) 指令用于从内存中读取一字节内容,将其符号扩展之后放入 r d rd rd 寄存器。而与其对应的 l b u   ( l o a d   b y t e   u n s i g n e d ) lbu \ (load \ byte \ unsigned) lbu (load byte unsigned) 用于从内存读取一字节内容,将其 0 0 0 扩展后放入 r d rd rd 寄存器。 l h   ( l o a d   h a l f   w o r d ) lh \ (load \ half \ word) lh (load half word) l h u   ( l o a d   h a l f   w o r d   u n s i g n e d ) lhu \ (load \ half \ word \ unsigned) lhu (load half word unsigned) 同理。
2: w i d t h width width 编码中后两位表示宽度,最高位表示 u n s i g n e d unsigned unsigned

S型指令

s t o r e store store 指令用于把寄存器中的数据放入指定内存位置。
R V 32 I RV32I RV32I 提供了一个 32 b i t 32bit 32bit 的内存地址空间,其根据字节寻址。一个可能的 s t o r e store store 指令: s w   x 10 , 8 ( x 2 ) sw \ x10,8(x2) sw x10,8(x2),用于把寄存器 x 10 x10 x10 的内容放入 ( x 2 ) + 8 (x2)+8 (x2)+8 的内存地址空间。其中,不存在目的寄存器 r d rd rd,源寄存器 r s 1 rs1 rs1 寄存器为 x 10 x10 x10 ,存储数据宽度为字长 w o r d word word,源寄存器 r s 2 rs2 rs2 x 2 x2 x2,偏移量 o f f s e t offset offset 8 8 8
s t o r e store store 指令含 r s 1    r s 2    o f f s e t rs1 \ \ rs2 \ \ offset rs1  rs2  offset 但不含 r d rd rd,因此需要一种单独编码格式。
S S S 型指令格式如下图所示:
在这里插入图片描述1:其中, o p c o d e    f u n c t 3    r s 1    r s 2 opcode\ \ funct3 \ \ rs1 \ \ rs2 opcode  funct3  rs1  rs2 的位置和前面指令保持一致。立即数位置变动。
2:标准原话:"the instruction format was chosen to keep all register specifiers at the same position in all formats at the expense of having to move immediate bits across formats ",以立即数的编码移动为代价来使得所有寄存器在统一位置。
3:其中, s t o r e store store 指令的 o p c o d e opcode opcode o p c o d e opcode opcode 映射表中 S T O R E STORE STORE o p c o d e = 0 b 0100011 opcode=0b0100011 opcode=0b0100011
4:其中,基址偏移量 o f f s e t offset offset 12 b i t 12bit 12bit 补码表示,其具体表示范围为: [ − 2048 , 2047 ] [-2048,2047] [2048,2047]。通过符号扩展到 32 b i t 32bit 32bit 之后和基地址相加。
所有 s t o r e store store 指令编码方式及个字段的值如下表所示:

inst[31:25]inst[20:24]inst[19:15]inst[14:12]inst[11:7]inst[6:0]指令助记符
imm[11:5]rs2rs1000imm[4:0]0100011sb
imm[11:5]rs2rs1001imm[4:0]0100011sh
imm[11:5]rs2rs1010imm[4:0]0100011sw

以上文例子 s w   x 10 , 8 ( x 2 ) sw \ x10,8(x2) sw x10,8(x2) 为例,其 o f f s e t = 0 b 0000000   01000 offset=0b0000000 \ 01000 offset=0b0000000 01000 r s 2 = 0 b 01010 rs2=0b01010 rs2=0b01010 r s 1 = 0 b 00010 rs1=0b00010 rs1=0b00010 f u n c t 3 = 0 b 010 funct3=0b010 funct3=0b010,综上,该指令二进制表示为: 0 b 0000000    01010    00010    010    01000    0100011 0b0000000 \ \ 01010 \ \ 00010 \ \ 010 \ \ 01000 \ \ 0100011 0b0000000  01010  00010  010  01000  0100011

B型指令 (S型指令变体)

B B B 型指令为条件分支指令,用于在条件满足时跳转到指定标签位置。
一个可能的 b r a n c h branch branch 分支指令: b e q   x 1 , x 2 , l a b e l beq \ x1,x2,label beq x1,x2,label,用于比较寄存器 x 1 x1 x1 x 2 x2 x2 的值是否相等,相等程序跳转到 l a b e l label label 分支位置。其中,不存在目的寄存器 r d rd rd,源寄存器 r s 1 rs1 rs1 寄存器为 x 10 x10 x10 ,源寄存器 r s 2 rs2 rs2 x 2 x2 x2,条件成立跳转位置为 l a b e l label label

PC相对地址

在当今操作系统中,可执行文件执行时由于映射到内存虚拟地址空间的位置的不确定性所以需要类似 w i n d o w s windows windows 可执行文件中的重定位表来对一些地址做重定位。因此编译器在编译源代码过程中会尽量使用PC相对地址,介绍 R V 32 I RV32I RV32I 时有提到除通用寄存器外还有寄存器 p c pc pc 用于存储当前执行指令地址。分支指令中待跳转目的地址在指令编码中会记录为相对当前PC的单元偏移量,减少重定位的开销。

简言之,分支指令的跳转不以字节为单位。而在 R V 32 I RV32I RV32I 中,基本单元为 2 2 2 字节。不以 1 1 1 字节作为单元的单位的原因在于: R V 32 I RV32I RV32I 中所有指令的长度都为 4 4 4 字节,避免分支跳转到一条指令的中间位置。以 2 2 2 字节为基本单元的原因在于: R I S C V RISCV RISCV 中有 R V 32 C RV32C RV32C 扩展,该扩展用于把指令长度缩短到 2 2 2 字节,用于对机器码长度有限制的场景中。为了使得在该扩展用仍旧适用,取基本单元大小为 2 2 2 字节。

B型指令

B B B 型指令的指令编码与 S S S 型指令对比如下图所示:
在这里插入图片描述保持和 S S S 型指令中 o p c o d e    f u n c t 3    r s 1    r s 2 opcode \ \ funct3 \ \ rs1 \ \ rs2 opcode  funct3  rs1  rs2 位置相同。合理调整立即数各 b i t bit bit 的位置。
0:立即数 i m m e d i a t e immediate immediate 表示待跳转标签和当前 P C PC PC 内存地址的差值。以字节为单位。 B B B 型指令中跳转基本单元为 2 2 2 字节,故最低位不考虑,指令中不记录该位。
1:立即数的最高位永远位于指令中的最高有效位 M S B MSB MSB。主要原因:"In RISC-V the sign bit for all immediates is always held in bit 31 of the instruction to allow sign-extension to proceed in parallel with instruction decoding.",该标准原话告诉我们立即数的最高位永远位于指令的最高有效位方便在指令解码的同时进行符号扩展。
2:立即数编码奇怪的第二原因:" immediates is chosen to maximize overlap with the other formats and with each other.",立即数需要尽量和其余编码格式中立即数位置重合,方便逻辑的复用。
3: B B B 型指令中首先立即数最高位 i m m [ 12 ] imm[12] imm[12] 位于 i n s t [ 31 ] inst[31] inst[31],其次 i m m [ 10 : 5 ] imm[10:5] imm[10:5] 位于 i n s t [ 30 : 25 ] inst[30:25] inst[30:25] S S S 型保持一致。其次,立即数 i m m [ 4 : 1 ] imm[4:1] imm[4:1] 位于 i n s t [ 11 : 8 ] inst[11:8] inst[11:8] S S S型保持一致。最后一位填充到 i n s t [ 7 ] inst[7] inst[7]
4: B B B 型指令中记录 13 b i t 13bit 13bit 立即数的高 12 b i t 12bit 12bit,最低位一直为 0 0 0,跳转的地址空间范围: [ − ( 2 ∗ 2 11 ) , 2 ∗ ( 2 11 − 1 ) ] = [ − 4096 , 4094 ] [-(2*2^{11}),2*(2^{11}-1)]=[-4096,4094] [(2211),2(2111)]=[4096,4094]
5: B B B 型指令的 o p c o d e opcode opcode 0 b 1100011 0b1100011 0b1100011
所有 B B B 型指令编码及其字段值如下所示:

inst[31:25]inst[20:24]inst[19:15]inst[14:12]inst[11:7]inst[6:0]指令助记符
imm[12 |10:5]rs2rs1000imm[4:1 | 11]1100011beq
imm[12 |10:5]rs2rs1001imm[4:1 | 11]1100011bne
imm[12 |10:5]rs2rs1100imm[4:1 | 11]1100011blt
imm[12 |10:5]rs2rs1101imm[4:1 | 11]1100011bge
imm[12 |10:5]rs2rs1110imm[4:1 | 11]1100011bltu
imm[12 |10:5]rs2rs1111imm[4:1 | 11]1100011bgeu
简单举例

以下面RISCV代码为例,给出其分支指令的二进制表示:

Loop: beq x19,x10,End
add x18,x18,x10
addi x19,x19,-1
j Loop
End: # target instruction

假设当前 P C PC PC 指向分支指令 b e q   x 19 , x 10 , E n d beq \ x19,x10,End beq x19,x10,End 的地址, R V 32 I RV32I RV32I 指令定长 32 b i t 32bit 32bit,那么标签 E n d End End 的地址为 P C + 16 PC+16 PC+16。立即数以 2 2 2 字节为单元,所有 i m m = 8 imm=8 imm=8 r s 2 = 0 b 01010 = 1 0 10 rs2=0b01010=10_{10} rs2=0b01010=1010 r s 1 = 0 b 10011 = 1 9 10 rs1=0b10011=19_{10} rs1=0b10011=1910 f u n c t 3 = 0 b 000 funct3=0b000 funct3=0b000,综上,该指令二进制表示为: 0 b 0000000    01010    10011    000    01000    1100011 0b0000000 \ \ 01010 \ \ 10011 \ \ 000 \ \ 01000 \ \ 1100011 0b0000000  01010  10011  000  01000  1100011

U型指令

分支指令的跳转范围有限。考虑标准库 m m a p mmap mmap 的地址位置和当前文件距离较大时则需要更大的跳转范围。例如: b e q   x 10 , x 0 , f a r beq \ x10,x0,far beq x10,x0,far f a r far far 距离当前pc距离很大,则考虑以下形式改写指令:

bne x10,x0,next
j far
next:
# next instruction

上述含立即数类型的指令中立即数用 12 b i t 12bit 12bit 表示,对应的, U U U 型指令给出了控制立即数高 20 b i t 20bit 20bit 的指令。
U U U 型指令编码格式如下图所示,具体仅有指令 L U I LUI LUI A U I P C AUIPC AUIPC
在这里插入图片描述

LUI指令

L U I   ( l o a d   u p p e r   i m m e d i a t e ) LUI \ (load \ upper \ immediate) LUI (load upper immediate) 用于把立即数的值写入目的寄存器高 20 b i t 20bit 20bit,并将目的寄存器低 12 b i t 12bit 12bit 清零。
L U I LUI LUI 指令的 o p c o d e opcode opcode 由映射表可知为 0 b 0110111 0b0110111 0b0110111
结合 a d d i addi addi 指令写寄存器的低 12 b i t 12bit 12bit ,可以达到控制寄存器 32 b i t 32bit 32bit 的目的。例如:

lui x10, 0x87654      # x10 = 0x87654000
addi x10, x10, 0x321  # x10 = 0x87654321

其中, r d = 0 b 01010 rd=0b01010 rd=0b01010 i m m = 0 x 1000   0111   0110   0101   0100 imm=0x1000 \ 0111 \ 0110 \ 0101 \ 0100 imm=0x1000 0111 0110 0101 0100,故指令二进制及十六进制表示为: 0 b 10000111011001010100   01010   0110111 = 0 x 87654537 0b10000111011001010100 \ 01010 \ 0110111=0x87654537 0b10000111011001010100 01010 0110111=0x87654537

特殊的点,假如当前需求为设置 x 10 x10 x10 寄存器内容为 0 x D E A D B E E F 0xDEADBEEF 0xDEADBEEF

lui x10, 0xDEADB      # x10 = 0xDEADB000
addi x10, x10, 0xEEF  # x10 = 0xDEADAEEF

由于立即数在加法指令执行前会符号扩展,低 12 b i t 12bit 12bit 相加时直接相加,结果正确。高 20 b i t 20bit 20bit 相加时 0 x D E A D B 0xDEADB 0xDEADB 与符号扩展的全 1 1 1 补码表示为 − 1 -1 1 相加,故而高 20 b i t 20bit 20bit 比预期少 1 1 1
所以:在立即数低 12 b i t 12bit 12bit 的最高有效位为 1 1 1 时,设置高 20 b i t 20bit 20bit 时需要对立即数加 1 1 1 处理。如下所示:

lui x10, 0xDEAADC      # x10 = 0xDEADC000
addi x10, x10, 0xEEF  # x10 = 0xDEADBEEF
li伪指令

l i   ( l o a d   i m m e d i a t e ) li \ (load \ immediate) li (load immediate) 用于加载立即数到目的寄存器。
l i   x 10 , 0 x 87654321 li \ x10, 0x87654321 li x10,0x87654321 即把立即数 0 x 87654321 0x87654321 0x87654321 加载到寄存器 x 10 x10 x10 中。该伪指令最终借由指令 l u i   x 10 , 0 x 87654 lui \ x10, 0x87654 lui x10,0x87654 a d d i   x 10 , x 10 , 0 x 321 addi \ x10, x10, 0x321 addi x10,x10,0x321 实现。

AUIPC指令

1: A U I P C   ( a d d   u p p e r   i m m e d i a t e   t o   P C ) AUIPC \ (add \ upper \ immediate \ to \ PC) AUIPC (add upper immediate to PC) 用于把立即数左移 12 b i t 12bit 12bit,低位补 0 0 0 形成 o f f s e t offset offset,并将 o f f s e t + p c offset+pc offset+pc 放入目的寄存器, p c pc pc a u i p c auipc auipc 指令所在的地址。
2: A U I P C AUIPC AUIPC 指令用于辅助 P C PC PC 相对寻址。指令可以通过 Label: AUIPC x10, 0 拿到当前 l a b e l label label 的地址(位于 x 10 x10 x10 寄存器中)。
3: A U I P C AUIPC AUIPC 指令的 o p c o d e opcode opcode 由映射表可知为 0 b 0010111 0b0010111 0b0010111

4:指令 A U I P C   x 10 , 0 AUIPC \ x10, 0 AUIPC x10,0 r d = 0 b 01010 rd=0b01010 rd=0b01010 i m m = 0 x 0000   0000   0000   0000   0000 imm=0x0000 \ 0000 \ 0000 \ 0000 \ 0000 imm=0x0000 0000 0000 0000 0000,故指令二进制及十六进制表示为: 0 b 00000000000000000000   01010   0010111 = 0 x 00000517 0b00000000000000000000 \ 01010 \ 0010111=0x00000517 0b00000000000000000000 01010 0010111=0x00000517

J型指令(U型指令变体)

远距离跳转指令有: J A L JAL JAL J A L R JALR JALR,不同于分支指令, J J J J A L JAL JAL 指令拥有更远的跳转空间,配合 U U U 型指令可以更加灵活。

JAL指令

J A L JAL JAL 指令通过立即数并以 2 2 2 字节为单位形成有符号立即数和当前 p c pc pc 相加形成目的地址,用于远距离跳转并将跳转指令的下一条指令的地址放入目的寄存器 r d rd rd,方便函数返回。举例见下文。
J A L   ( J u m p   a n d   l i n k ) JAL \ (Jump \ and \ link) JAL (Jump and link) 指令编码对比 I I I 型和 U U U 型如下图所示:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述 J A L JAL JAL 指令 o p c o d e opcode opcode 由映射表可知为: 0 b 1101111 0b1101111 0b1101111。保持最高位位于指令 i n s t [ 31 ] inst[31] inst[31] 位置,立即数部分尽量与已有指令最大重合方便复用。 J A L JAL JAL 指令可用于函数调用,例如:

JAL ra, Func
# next instruction
...
Func:
addi sp, sp, -48 # 一个可能的函数栈帧结构开始位置
...

1: J A L JAL JAL 指令的寻址范围: 20 b i t 20bit 20bit 有符号立即数的 2 2 2 字节寻址单元,最低为为 0 0 0 ,则以字节为单位的寻址范围为: [ − ( 2 ∗ 2 19 ) , 2 ∗ ( 2 19 − 1 ) ] [-(2*2^{19}),2*(2^{19}-1)] [(2219),2(2191)],范围约为 ± 1 M i B \pm1MiB ±1MiB
2:伪指令 j   l a b e l j \ label j label 用于无条件跳转到 l a b e l label label 位置,同时不在意返回地址。最终实现方式为: j a l   x 0 , l a b e l jal \ x0, label jal x0,label 丢弃返回地址。

JALR指令(I型指令)

J A L R JALR JALR 指令通过立即数给出相对源寄存器rs的偏移量,符号扩展到 32 b i t 32bit 32bit,与 r s rs rs 的值相加之后作为跳转的目的地址,同时记录跳转指令下一条指令地址到目的寄存器 r d rd rd,方便函数返回。指令格式: j a l r   r d ,   r s ,   i m m e d i a t e jalr \ rd, \ rs, \ immediate jalr rd, rs, immediate,具体示例见下文。
J A L R   ( J u m p   a n d   l i n k   r e g i s t e r ) JALR \ (Jump \ and \ link \ register) JALR (Jump and link register) 指令编码对比 I I I 型指令如下图所示:
在这里插入图片描述在这里插入图片描述 J A L JAL JAL 指令 o p c o d e opcode opcode 由映射表可知为: 0 b 1100111 0b1100111 0b1100111。保持最高位位于指令 i n s t [ 31 ] inst[31] inst[31] 位置,立即数部分与 I I I 型指令一样。 J A L R JALR JALR 指令可用于 32 b i t 32bit 32bit 绝对地址函数调用,或已知的 32 b i t   P C 32bit \ PC 32bit PC 相对地址的值。例如,已知待跳转函数地址为 0 x 87654321 0x87654321 0x87654321

lui x5,0x87654    # x5 = 0x87654000
jalr ra,x5,0x321  # ra = address of next instruction, pc = 0x87654321
# next instruction

1:伪指令 j r   ( j u m p   r e g i s t e r ) jr \ (jump \ register) jr (jump register) 用于无条件跳转到目的寄存器地址。其具体实现方式: j r   x 5 = j a l r   x 0 , x 5 , 0 jr \ x5 = jalr \ x0, x5, 0 jr x5=jalr x0,x5,0
2:伪指令 r e t   ( r e t u r n ) ret \ (return) ret (return) 用于函数返回。其具体实现方式: r e t = j r   r a = j a l r   x 0 , r a , 0 ret = jr \ ra = jalr \ x0, ra, 0 ret=jr ra=jalr x0,ra,0
3:以指令 j a l r   r a , x 5 , 0 x 321 jalr \ ra,x5,0x321 jalr ra,x5,0x321 为例,其偏移量 o f f s e t = 0 x 321 = 0 b 001100100001 offset=0x321=0b001100100001 offset=0x321=0b001100100001 ,基地址寄存器 b a s e ( x 5 ) = 0 x 00101 base(x5)=0x00101 base(x5)=0x00101,目的寄存器 r d ( r a / x 1 ) = 0 b 00001 rd(ra/x1)=0b00001 rd(ra/x1)=0b00001,综上,其二进制表示为: 0 b 001100100001   00101   000   00001   1100111 0b001100100001 \ 00101 \ 000 \ 00001 \ 1100111 0b001100100001 00101 000 00001 1100111

另有指令 e c a l l   e b r e a k   f e n c e ecall \ ebreak \ fence ecall ebreak fence 未详细介绍,读者可详细参考指令集文档。

参考

R I S C V RISCV RISCV 指令集标准 unpriv-isa-asciidoc.pdf

完结撒花。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/607029.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

汽车IVI中控开发入门及进阶(十七):IVI的功耗管理

汽车人机界面(HMI)系统旨在使驾驶员能够在不分心的情况下与车辆互动。HMI可以通过触摸板、按钮或语音系统在人和机器之间建立更自然的互动。对连接解决方案、低成本HMI软件和增强的用户体验(UX)的需求不断增加,使得平视显示器(HUD)、后座娱乐系统、基于转向的控制、仪表…

第42天:WEB攻防-PHP应用MYSQL架构SQL注入跨库查询文件读写权限操作

第四十二天 一、PHP-MYSQL-SQL注入-常规查询 1.PHP-MYSQL-Web组成架构 MySQL(统一管理) ​ root(自带默认) ​ 网站A testA ​ 网站B testB MySQL(一对一管理) ​ testA用户 ​ 网站A testA ​ testB用户 ​ 网站B testB access无数据库用户 m…

使用海外云手机为亚马逊店铺引流

在全球经济一体化的背景下,出海企业与B2B外贸企业愈发重视海外市场的深耕,以扩大市场份额。本文旨在探讨海外云手机在助力亚马逊店铺提升引流效果方面的独特作用与优势。 海外云手机,一种基于云端技术的虚拟手机,能够在单一硬件上…

html--瀑布效果

<!doctype html> <html> <head> <meta charset"utf-8"> <title>瀑布效果</title><style> body {background: #222;color: white;overflow:hidden; }#container {box-shadow: inset 0 1px 0 #444, 0 -1px 0 #000;height: 1…

【Qt 学习笔记】Qt常用控件 | 输入类控件 | Slider的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 输入类控件 | Slider的使用及说明 文章编号&#xff1a;…

已经有 Prometheus 了,还需要夜莺?

谈起当下监控&#xff0c;Prometheus 无疑是最火的项目&#xff0c;如果只是监控机器、网络设备&#xff0c;Zabbix 尚可一战&#xff0c;如果既要监控设备又要监控应用程序、Kubernetes 等基础设施&#xff0c;Prometheus 就是最佳选择。甚至有些开源项目&#xff0c;已经内置…

QGraphicsView实现简易地图12『平移与偏移』

前文链接&#xff1a;QGraphicsView实现简易地图11『指定层级-定位坐标』 提供地图平移与偏移功能。地图平移是指将地图的中心点更改为给定的点&#xff0c;即移动地图到指定位置。地图偏移是指将当前视口内的地图向上/下/左/右/进行微调&#xff0c;这里偏移视口宽/高的四分之…

压缩机继电器EOCRDS-30NY7Q升级后型号:EOCRDS3-30S

EOCR-DS3系列型号&#xff1a; EOCRDS3-05S EOCRDS-05S EOCRDS1-05S EOCRDS3-30S EOCRDS-30S EOCRDS1-30S EOCRDS3-60S EOCRDS-60S EOCRDS1-60S EOCRDS3-05W EOCRDS-05W EOCRDS1-05W EOCRDS3-30W EOCRDS-30W EOCRDS1-30W EOCRDS3-60W EOCRDS-60W EOCRDS1-60W EOCR-DS3T-…

extern关键字的使用。keil中编译时,出现error:identifier xxx is undefined

问题 编译时&#xff0c;出现error&#xff1a; identifier “Reg_Flag” is undefined extern Reg_Flag reg_flag; 很奇怪&#xff0c;我明明已经定义了。无非就是定义是在extern的下面&#xff0c;会不会是这个原因&#xff1f; 解决 果然&#xff0c;把extern的部分放到…

3D模型如何实现拖拽打开?---模大狮模型网

在当今数字化时代&#xff0c;3D技术的应用已经深入到各行各业&#xff0c;为用户带来了更加丰富、生动的体验。然而&#xff0c;对于一些用户来说&#xff0c;打开和查看3D模型可能会面临一些困难&#xff0c;特别是在无法拖拽打开时。本文将为您揭示解决这一问题的方法&#…

智能商品计划系统:引领未来零售业的革新之路

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;和大数据技术已成为推动各行业革新的关键动力。在零售行业中&#xff0c;智能商品计划系统的出现&#xff0c;正逐步改变着传统的商品规划与管理方式&#xff0c;为品牌注入新的活力与竞争力。本文将对智能商…

TMS320F280049 CLB模块--总览(0)

CLB模块是可配置的逻辑块&#xff0c;和FPGA的CLB有些不同。 下图是CLB模块在系统中的交互&#xff0c;图中CLB XBAR和TILE是CLB。从049中有4个CLB&#xff0c;也就是TILE1-4。 下图是CPU和CLB交互的示意图。 下图是CLB的时钟。 参考文档&#xff1a; TMS320F28004x Real-Tim…

欢乐钓鱼大师内置辅助,游戏脚本!自动操作!

在《欢乐钓鱼大师》游戏中&#xff0c;探索珍稀鱼类成为钓鱼大师的过程充满了乐趣和挑战。下面是一些特殊鱼类的钓鱼技巧和详细攻略&#xff0c;助你在游戏中获得更好的成绩和丰厚的奖励。 一、碘化之齿 碘化之齿是游戏中一种珍稀的鱼类&#xff0c;它的出现需要一定的条件和技…

STC8增强型单片机开发 【GPIO的理解⭐⭐】

目录 一、引言 二、GPIO概述 三、GPIO的功能 1. 输入功能&#xff1a; 2. 输出功能 四、GPIO的配置方法 1. 选择GPIO端口和引脚&#xff1a; 2. 设置GPIO模式&#xff1a; 3. 配置GPIO参数&#xff1a; 五、GPIO应用实例 1. 硬件连接&#xff1a; 2. 编程实现&…

探索精酿啤酒:从经典到创新

Fendi club啤酒一直以来都以其卓着的品质和与众不同的口感深受消费者喜爱。而随着时代的变迁和消费者口味的不断变化&#xff0c;Fendi club啤酒也在不断地探索和创新&#xff0c;以满足市场的多样化需求。 在经典的口感和风味基础上&#xff0c;Fendi club啤酒不断地尝试新的原…

sql Server2015安装——参考的教程

1.sql Server安装包来自&#xff1a;https://mp.weixin.qq.com/s/Pe_YbWw_MgwjzzZhQWIYfA 2.需要的替换文件和补丁&#xff1a;https://blog.csdn.net/Auspicious_air/article/details/108315154 https://blog.csdn.net/m0_60477996/article/details/126748477 3.安装manger…

MybatisPlus 构造器wrapper的使用与原理

系列文章目录 MyBatis缓存原理 Mybatis plugin 的使用及原理 MyBatisSpringboot 启动到SQL执行全流程 数据库操作不再困难&#xff0c;MyBatis动态Sql标签解析 Mybatis的CachingExecutor与二级缓存 使用MybatisPlus还是MyBaits &#xff0c;开发者应该如何选择&#xff1f; My…

极简—springMVC工作流程

1、流程图 2、流程 发起请求&#xff1a;客户端通过 HTTP 协议向服务器发起请求。前端控制器&#xff1a;这个请求会先到前端控制器 DispatcherServlet&#xff0c;它是整个流程的入口点&#xff0c;负责接收请求并将其分发给相应的处理器。处理器映射&#xff1a;DispatcherS…

SDN和SD-WAN的对比

在数字化浪潮的推动下&#xff0c;SDN&#xff08;软件定义网络&#xff09;和SD-WAN&#xff08;软件定义广域网&#xff09;作为企业网络技术的两大支柱&#xff0c;正逐步引领网络架构的革新。尽管两者在理念和基础上有所共通&#xff0c;但在实际应用、功能特性和部署策略上…

视频号小店不直播怎么出单?这里面的秘密,一篇文章全曝光!

大家好&#xff0c;我是电商糖果 这两年关于视频号搞电商的话题度非常高&#xff0c;也吸引了很多商家入驻。 视频号因为背后巨大的私域流量池扶持&#xff0c;所以它的转化率非常高。 根据官方发出来的战报&#xff0c;我们也可以看出它的数据是翻倍增长。 在2024微信公开…