In a RISC/MIPS-32bit architecture, how does an instruction target a remote memory address that falls out of the offset?

From what I understand, RISC architecture like MIPS, uses a fixed-length instruction. For branching and jumping between memory, and respectively J or I type – we are given a section inside to allocate 16 or 26 bits to offsets from the current memory (instruction offsets – multiples of 4 byte memory offsets). if this offsets cannot emcompass all possible 2^32 bits byte-address, how does it do it when it needs to?

>Solution :

Generate the address in a register with one or more extra instructions. That’s the tradeoff in limiting what one instruction can do (RISC), it’s the cost of doing business.

Look at compiler output for MIPS or RISC-V:

int foo(char *arr){
    return arr[0x12345678];
}

Godbolt for RISC-V and MIPS

# rv32gc clang -O2
foo:
        lui     a1, 74565     # 0x12345 into the upper 20 bits
        add     a0, a0, a1    # add high part of the offset to the incoming ptr
        lbu     a0, 1656(a0)  # offset 0x678 with the 12-bit immediate
        ret

RISC-V has a 20:12 split between LUI and I-type instructions. Costs less coding space.
MIPS has a 16:16 split, with LUI being an I-type instruction. So there are fewer opcode bits in each I-type instruction in MIPS than RISC-V.

But the strategy is identical; split the offset into high/low parts, do the low part as part of the load.

# MIPS gcc 11.2 -O2 -march=mips3 -fno-delayed-branch
foo:
        li      $2,305397760                        # 0x12340000
        addu    $4,$4,$2                 # add large offset to pointer
        lb      $2,22136($4)             # sign-extending byte load
        jr      $31                      # return
        nop

(Note that RISC-V is a specific architecture, a more recent design led by one of the architects of MIPS, David Patterson. In some ways it’s a cleaned-up re-spin of MIPS. Both are RISCs, like AArch64 or SPARC.)

Leave a Reply