2

I want to load a word from 0x0200bff8 address into t1 register. I tried the following;

 lui t0, 0x0200b; // Write Upper 20 bits into t0
 lw t1, 0xff8(t0);  //fetch a word from address in t0 offsetted by 0xff8 (12 bits)

I thought its syntactically right, but I see this error

Error: illegal operands `lw t1,0xff8(t0)'

What am I doing wrong and what is a good way in terms of less instructions to load a word from an immediate address?

Erik Eidt
  • 23,049
  • 2
  • 29
  • 53
RRON
  • 1,037
  • 3
  • 12
  • 32

2 Answers2

2

0xff8 is 4088 in decimal.  That value is out of range of the 12-bit signed immediate for lw (and all other I-Type instructions).

You could attempt syntax like -8(t0) instead, and, while that will translate into machine code of lw with immediate field of ff8, it will get the wrong address (0x200aff8) because of sign extension.

However, your li solution is much easier to use.  If you look closely at the 2-instruction expansion, you'll see that the lui uses 200c to mitigate the sign extension that happens to the 12-bit immediate on the I-Type instruction.

Also, let's note that your li pseudo instruction approach will probably work with lw directly (depending on the assembler):

lw t0, 0x200bff8

However, if that is in a tight loop, it represents 2 instructions, whereas the li form can be used to create the address into a register outside of the loop, then in side only a simple lw is needed.

For the best of both, optimizing compilers will place just an lui outside the loop (instead of the lui/addi pair) and then use the one instruction form of lw with rest of the offset.

Erik Eidt
  • 23,049
  • 2
  • 29
  • 53
  • Some assemblers allow something like `%hi(0x200bff8)` / `%lo(0x200bff8)` to split for you in a way that works with sign-extended `addi` or `lw` offsets, so you can manually hoist the high half out of a loop and still not waste instructions materializing the low half in a register. I don't know what GAS for RISC-V uses specifically, but it has this feature for other ISAs like MIPS. – Peter Cordes Sep 02 '21 at 18:55
0

I just found a pseudo instruction li t0, 0x200bff8; which does the work.

RRON
  • 1,037
  • 3
  • 12
  • 32
  • 1
    That doesn't load from the address, it only puts that constant into a register. But yes that's the standard way to construct a full constant in a register, which costs you an extra `add` instruction vs. taking advantage of the same immediate width that `lw` supports as offset bits in the addressing mode. – Peter Cordes Sep 05 '21 at 10:24