RISCV-LEARN

B-type

1744957662496

我们注意到,B-type类型的指令中,imm是一个12位的立即数,在指令中只指出了imm的1到12位,第0位默认为0。

跳转的目标地址计算方法:根据B-type指令的机器码得到imm的第1-12位,将第0位添为0,而后加上当前PC值,即得到目标地址。

例子

这里有一个C语言程序:

#include <stdio.h>
int main()
{
    int a = 3;
    if (a > 2)
    {
        a = 2;
    }
    else
    {
        a = 1;
    }
    return 0;
}

利用gcc和objdump来查看汇编代码,其中包含每条指令的地址以及机器码:

gcc -g -c btype.c -o btype.o
objdump -S byte.o

得到如下:

btype.o:     file format elf64-littleriscv


Disassembly of section .text:

0000000000000000 <main>:
#include <stdio.h>
int main()
{
   0:   1101                    add     sp,sp,-32
   2:   ec22                    sd      s0,24(sp)
   4:   1000                    add     s0,sp,32
    int a = 3;
   6:   478d                    li      a5,3
   8:   fef42623                sw      a5,-20(s0)
    if (a > 2)
   c:   fec42783                lw      a5,-20(s0)
  10:   0007871b                sext.w  a4,a5
  14:   4789                    li      a5,2
  16:   00e7d663                bge     a5,a4,22 <.L2>
    {
        a = 2;
  1a:   4789                    li      a5,2
  1c:   fef42623                sw      a5,-20(s0)
  20:   a021                    j       28 <.L3>

0000000000000022 <.L2>:
    }
    else
    {
        a = 1;
  22:   4785                    li      a5,1
  24:   fef42623                sw      a5,-20(s0)

0000000000000028 <.L3>:
    }
    return 0;
  28:   4781                    li      a5,0
  2a:   853e                    mv      a0,a5
  2c:   6462                    ld      s0,24(sp)
  2e:   6105                    add     sp,sp,32
  30:   8082                    ret

这里聚焦于bge指令,可以看到其机器码是00e7d663,该指令的地址是0x16,跳转的目标地址是0x22,那么我们看看是怎么计算得到目标跳转地址的:

所以说,对于B-type类型指令,跳转的目标地址即当前PC值(B-type指令的地址)加上imm的值(第0为填充为0)。


其实这对于J-type类型的指令也类似:

17449612420941744961254965

B-type是先比较,后跳转;J-type是先记录下一条指令的PC,再跳转。

二者跳转的部分类似,都会保证跳转偏移值第0位是0,且需要加上当前PC值。