Reputation: 151
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
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
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
Reputation: 3987
The instruction is "0xeff09fa9"? Those 32-bits are actually two different two-byte instructions, c.sd and c.addw.
Upvotes: 1