PSX / MIPS r300 - Confusion about offsets and lw instructions.

Started by MeshGearFox, April 28, 2014, 09:42:44 PM

Previous topic - Next topic

MeshGearFox

This is what I have in my source code:

lui t8, 0x8003
lw t8, 0xe414(t8)

This is what it got turned into after I assembled it, according to no$psx:

lui t8, 0x8003
lw t8, -0x1BEC(t8)

What's going on here? That latter one ends up pointing to 8002E414. Are all offsets going to be treated as negative, meaning I'd need to five 0x8004 in the lui instructions..?

Also I'm using armips as my assembler if that matters.

Revenant

What you're seeing is a case of integer overflow with signed numbers. The offset in instructions like lw and sw is a 16-bit signed integer, meaning that 0x0000-7FFF represent positive values and 0x8000-FFFF represent negative ones.

If you just want to load the value at 0x8003E414, try this instead:

lui $t8, 0x8003
ori $t8, $t8, 0xE414
lw $t8, 0($t8)


The lui instruction causes the upper 16 bits of the target register to be loaded and the lower 16 bits to be zeroed out, so it's not uncommon for it to be loaded by an ori (bitwise OR immediate) instruction to load the lower 16 bits with the second part of a 32-bit value.

I don't know about armips, but several MIPS assemblers also support a pseudoinstruction called "li" (load immediate) which simplifies the above:

li $t8, 0x8003E414
lw $t8, 0($t8)


("li" isn't a real MIPS instruction, but an assembler that supports it will essentially convert it to the lui/ori form when you assemble the code.)

MeganGrass

The syntax is incorrect. Try this:

li $t8, 0x8003E414
lw $t8, 0($t8)


Ninja'd by Revenant.

...and yes, it will work with armips.

MeshGearFox

Would there be anything unsafe about just changing the first lui to 8004 instead, though?

Revenant

Not that I can think of, apart from being less intuitive to look at.

KC

Armips supports this pseudo opcode and automatically accounts for the negative value in the second instruction:

lw t8,0x8003E414

Alternatively, if you use a recent development version, you can also do

lw.u t8,0x8003E414
lw.l t8,0x8003E414

which would both encode one of the two opcodes. This is useful if the two opcodes aren't consecutive.