TrinityTonic
TrinityTonic

Reputation: 151

RiscV jumps (j, jal) to wrong address (off by offset 2)

I'm using a riscV processor (RV32). With some code I've written on it, I've noticed something strange. When I use the "JAL" instruction or the "J" instruction to jump to a specific address, it seems like the the offset is not calculated correctly.

Let's say I have some code (PRAM_ResetVector) located at address 0x00008080 I want to jump to.

The jump code looks as following in assembly "jal x1, PRAM_ResetVector" and is located at address 0x000085e8. The instruction encoding (risc32) looks as following 0xeff09fa9.

However what happens after executing the jump instruction is that I land at address 0x00008082 instead of the intended 0x00008080.

I can't seem to find the reason for this, could anyone help here?

Upvotes: 0

Views: 2438

Answers (3)

Erik Eidt
Erik Eidt

Reputation: 26766

I tried the following in RARS and it worked as we would expect.

I had to move the text section into the valid range for RARS, but otherwise the same.

    .text 0x00400000
    jal x0, label2     # RARS starts program here

    .text 0x00408080

label1:
    lw  x1, 0(x1)

    .text 0x004085e8
label2:
    jal x1, label1     # <--- here's your instruction
    lw  x2, 0(x2)

The noted branch works and transfers control to label1.

RARS assembles the noted instruction and reports the machine code word as:

a99ff0ef

which is the same as yours (but displayed in little endian, whereas you're showing it in big endian).


Looks like you're working with RV32IMC, so you have the compressed instructions extension that enable a pc to be a multiple of 2 without necessarily being a multiple of 4.

Upvotes: 0

old_timer
old_timer

Reputation: 71586

so:
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    jal x1,so
    nop
    j so
    nop


00000000 <so>:
   0:   00000013            nop
   4:   00000013            nop
   8:   00000013            nop
   c:   00000013            nop
  10:   00000013            nop
  14:   00000013            nop
  18:   00000013            nop
  1c:   fe5ff0ef            jal x1,0 <so>
  20:   00000013            nop
  24:   fddff06f            j   0 <so>
  28:   00000013            nop

fe5ff0ef
11111110010111111111000011101111

imm[20|10:1|11|19:12, rd, 110111

1 1111110010 1 11111111 000011101111

1 11111111 1 1111110010 0

0xFFFFFFE4

0x1C + 0xFFFFFFE4 = 0x00000000

gnu tools are debugged, so

0xeff09fa9

which is actually

0xa99ff0ef

10101001100111111111000011101111

imm[20|10:1|11|19:12, rd, 110111

1 0101001100 1 11111111 00001 1101111

1 11111111 1 0101001100

111111111 1010 1001 1000

0xFFFFFA98 + 0x000085e8 = 0x8080

Yep it all looks good so this goes back to the first comment, which IP is this? Sounds like it is untested and under development?

Or the code that surrounds this is such that it is not executing the instruction you think it is.

This is not two compressed instructions the lower two bits of the lower halfword are 2b11 which means it is a 32 bit instruction if the code is off by a halfword 0xfe5f is still going to be a 32 bit instruction, but I think it is undefined.

Upvotes: 1

Chris
Chris

Reputation: 3987

The instruction is "0xeff09fa9"? Those 32-bits are actually two different two-byte instructions, c.sd and c.addw.

Upvotes: 1

Related Questions