gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

ASM > Invalid constant - why?

#71374 - HyperHacker - Sun Feb 12, 2006 6:07 am

I'm trying to put some ASM code into a C program for DS:
Code:
__asm(".arm\n"
   "mov r2,#8000\n");

(Not complete, obviously.)

The problem is if I specify a number above 8000 (decimal) in any instruction, the assembler/gcc says it's an invalid constant. What's so invalid about it?

#71378 - chishm - Sun Feb 12, 2006 7:01 am

ARM ASM constants can only be an 8bit shifted constant. For instance, 0xff0000 (0xff << 16) is valid, 0x1f40 (0xfa << 5) is valid, while 0x1f41 is not. You'll notice that 8000 = 0x1f40 and is therefore valid, however 8001 = 0x1f41 and is therefore invalid.

On another note, THUMB ASM constants can only be an unshifted 8 bit value.
_________________
http://chishm.drunkencoders.com
http://dldi.drunkencoders.com

#71379 - HyperHacker - Sun Feb 12, 2006 7:08 am

Hm, so then how do I load something arbitrary like 0x12345? Do I have to break it down into a series of shifts, like (0x12 << 12) | (0x34 << 4) | 5? Seems rather difficult to write efficient code doing that...

#71382 - DekuTree64 - Sun Feb 12, 2006 8:02 am

The common way is to store the constant somewhere near to the current instruction, and use a pc-relative load. In fact, it's so common that the assembler has a shortcut for it:
Code:
ldr r0, =8001
// ...do more stuff, return from function

.pool

The .pool directive tells the assembler that it can place such constants for loading there. Usually it's best to put it before the start or after the end of your function, so your code doesn't have to jump over it. You can have multiple pools too, if your function gets larger than the range of a pc-relative load (although that's pretty rare).
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#71385 - HyperHacker - Sun Feb 12, 2006 8:48 am

Ah, that explains quite a bit. Thanks! Unfortunately, the code isn't working... I'm trying to load whatever app is on the GBA cart, as WifiMe would.

On ARM7, I do this:
Code:
void (*Reboot)(void) = (void(*)())0x080000C0;
Reboot();


On ARM9:
Code:
void Reboot()
{
   IPC->arm7desc = A7_REBOOT; //Tell ARM7 to reboot
   (*(vuint32*)0x027FFE24) = (vuint32)Reboot2;
   Reboot2();
}


/*
Used by Reboot().
*/
void Reboot2()
{
   __asm(".arm\n"
   "ldr r1,=0x027FFE24\n"
   "ldr r0,[r1]\n"
   "mov pc,r0\n"
   ".pool\n");
}


According to this thread, this is what WifiMe does, but it's just freezing the system.