Page 1 of 2
Inline asm calls ignored in devkitARM r43
Posted: Thu Jan 08, 2015 12:59 am
by Chano
Hi!
This code used to work devkitARM r42 without problems:
Code: Select all
void biosDivision(s32 numerator, s32 denominator, s32* result, s32* remainder)
{
asm volatile
(
"mov r0, %2 \n"
"mov r1, %3 \n"
"swi 6 \n" // Put 6 here for Thumb C Compiler mode.
"ldr r2, %0 \n" // Put 0x60000 there for ARM C Compiler mode.
"str r0, [r2] \n"
"ldr r2, %1 \n"
"str r1, [r2] \n"
: "=m" (result), "=m" (remainder)
: "r" (numerator), "r" (denominator)
: "r0","r1","r2","r3"
);
}
However, with r43 it only works if the gcc optimizations are disabled (-O0).
Any ideas?
Re: Inline asm calls ignored in devkitARM r43
Posted: Thu Jan 08, 2015 11:06 am
by WinterMute
Seems to be working for me, what compiler flags are you using?
You can detect thumb/arm mode at compile time - here's the code I used to test.
Code: Select all
#include <stdint.h>
typedef int32_t s32;
void biosDivision(s32 numerator, s32 denominator, s32* result, s32* remainder) {
asm volatile (
"\tmov r0, %2 \n"
"\tmov r1, %3 \n"
#if defined ( __thumb__ )
"\tswi 6 \n" // Put 6 here for Thumb C Compiler mode.
#else
"\tswi 6<<16 \n" // Put 0x60000 there for ARM C Compiler mode.
#endif
"\tldr r2, %0 \n"
"\tstr r0, [r2] \n"
"\tldr r2, %1 \n"
"\tstr r1, [r2] \n"
: "=m" (result), "=m" (remainder)
: "r" (numerator), "r" (denominator)
: "r0","r1","r2","r3"
);
}
I like to put \t in the assembly mainly because it makes the output from -save-temps a little more readable. Some people like to not do that because it makes it more obvious which parts are inline assembly & which parts are generated.
Re: Inline asm calls ignored in devkitARM r43
Posted: Thu Jan 08, 2015 7:08 pm
by Chano
I have copypasted the template project in the example folder.
The code below with the default flags shows "5 / 2 = 0".
However, with -O0 it shows "5 / 2 = 2":
Code: Select all
#include <gba_console.h>
#include <gba_video.h>
#include <gba_interrupt.h>
#include <gba_systemcalls.h>
#include <gba_input.h>
#include <stdio.h>
#include <stdlib.h>
void biosDivision(s32 numerator, s32 denominator, s32* result, s32* remainder)
{
asm volatile (
"\tmov r0, %2 \n"
"\tmov r1, %3 \n"
#if defined ( __thumb__ )
"\tswi 6 \n" // Put 6 here for Thumb C Compiler mode.
#else
"\tswi 6<<16 \n" // Put 0x60000 there for ARM C Compiler mode.
#endif
"\tldr r2, %0 \n"
"\tstr r0, [r2] \n"
"\tldr r2, %1 \n"
"\tstr r1, [r2] \n"
: "=m" (result), "=m" (remainder)
: "r" (numerator), "r" (denominator)
: "r0","r1","r2","r3"
);
}
//---------------------------------------------------------------------------------
// Program entry point
//---------------------------------------------------------------------------------
int main(void) {
//---------------------------------------------------------------------------------
// the vblank interrupt must be enabled for VBlankIntrWait() to work
// since the default dispatcher handles the bios flags no vblank handler
// is required
irqInit();
irqEnable(IRQ_VBLANK);
consoleDemoInit();
s32 numerator = 5;
s32 denominator = 2;
s32 result = 0;
s32 remainder = 0;
biosDivision(numerator, denominator, &result, &remainder);
// ansi escape sequence to set print co-ordinates
// /x1b[line;columnH
iprintf("\x1b[10;10H%d / %d = %d\n", numerator, denominator, result);
while (1) {
VBlankIntrWait();
}
}
Re: Inline asm calls ignored in devkitARM r43
Posted: Sat Jan 10, 2015 1:33 am
by Chano
I have tried to replace the function with a macro, but the result is the same:
Code: Select all
#include <gba_console.h>
#include <gba_video.h>
#include <gba_interrupt.h>
#include <gba_systemcalls.h>
#include <gba_input.h>
#include <stdio.h>
#include <stdlib.h>
#define BIOS_DIVISION(numerator, denominator, result, remainder) \
do { \
asm volatile \
( \
"mov r0, %2 \n" \
"mov r1, %3 \n" \
"swi 6 \n" \
"ldr r2, %0 \n" \
"str r0, [r2] \n" \
"ldr r2, %1 \n" \
"str r1, [r2] \n" \
: "=m" (result), "=m" (remainder) \
: "r" (numerator), "r" (denominator) \
: "r0","r1","r2","r3" \
); \
} while(0)
//---------------------------------------------------------------------------------
// Program entry point
//---------------------------------------------------------------------------------
int main(void) {
//---------------------------------------------------------------------------------
// the vblank interrupt must be enabled for VBlankIntrWait() to work
// since the default dispatcher handles the bios flags no vblank handler
// is required
irqInit();
irqEnable(IRQ_VBLANK);
consoleDemoInit();
s32 numerator = 5;
s32 denominator = 2;
s32 result = 0;
s32 remainder = 0;
s32* resultPtr = &result;
s32* remainderPtr = &remainder;
BIOS_DIVISION(numerator, denominator, resultPtr, remainderPtr);
// ansi escape sequence to set print co-ordinates
// /x1b[line;columnH
iprintf("\x1b[10;10H%d / %d = %d\n", numerator, denominator, result);
while (1) {
VBlankIntrWait();
}
}
Re: Inline asm calls ignored in devkitARM r43
Posted: Sat Jan 10, 2015 1:30 pm
by Chano
Well, it works with -O3 if I put the bios call inside a .s file... it seems like a GCC bug, right?
Code: Select all
@ DECL: s32 biosDivisionAsm(s32 numerator, s32 denominator);
@ DESC:
.align
.thumb_func
.global biosDivisionAsm
biosDivisionAsm:
swi 0x06
bx lr
Re: Inline asm calls ignored in devkitARM r43
Posted: Sat Jan 10, 2015 5:27 pm
by WinterMute
Chano wrote:Well, it works with -O3 if I put the bios call inside a .s file... it seems like a GCC bug, right?
Possibly, I'm not really sure.
I've never entirely got inline assembly to work consistently so I tend to avoid it for anything more complex than getting access to conditions codes or arm registers. There's a good write up at
http://www.ethernut.de/en/documents/arm-inline-asm.html which can be immensely helpful sometimes.
I got your code to work at -O1 by telling the compiler that result & remainder are inputs as well as outputs. Once the function gets inlined things start going strange though.
Code: Select all
//---------------------------------------------------------------------------------
// BIOS divison function
//---------------------------------------------------------------------------------
void biosDivision(s32 numerator, s32 denominator, s32* result, s32* remainder) {
//---------------------------------------------------------------------------------
asm volatile (
"mov r0, %[numerator] \n\t"
"mov r1, %[denominator] \n\t"
#if defined ( __thumb__ )
"swi 6 \n\t" // Put 6 here for Thumb C Compiler mode.
#else
"swi 6<<16 \n\t" // Put 0x60000 there for ARM C Compiler mode.
#endif
"mov r2, %[result]\n\t"
"str r0, [r2]\n\t"
"mov r2, %[remainder]\n\t"
"str r1, [r2] \n\t"
: [result] "+l" (result), [remainder] "+l" (remainder)
: [numerator] "l" (numerator), [denominator] "l" (denominator)
: "r0","r1","r2","r3"
);
}
I was mainly just playing around to see what happens. "l" is a low register (r0-7), the "+" modifier says this operand is read as well as written
Re: Inline asm calls ignored in devkitARM r43
Posted: Sun Jan 11, 2015 2:28 pm
by Chano
Oh well, I'll try to put all asm code on .s files from now on.
Is there any way to get the result and the remainder of a division with only one bios call without using inline asm?
I am not able to get both values without two bios calls (yes, I'm an ARM asm noob u_u)
Anyways, thanks a lot for your help.
Re: Inline asm calls ignored in devkitARM r43
Posted: Sun Jan 11, 2015 6:10 pm
by Chano
By the way, I have more instances where functions are not called if -O0 is not enabled.
It wouldn't be possible to roll back to a previous version of GCC of devkitARM?
Nothing of this happened with r42...
Re: Inline asm calls ignored in devkitARM r43
Posted: Mon Jan 12, 2015 9:29 pm
by Chano
The issues I has having were related with more ignored inline asm calls.
It's weird, because some of them work fine and some not...
Re: Inline asm calls ignored in devkitARM r43
Posted: Tue Jan 27, 2015 10:20 pm
by WinterMute
I played around with this some more and discovered that using temp variables for the outputs gets the code working at -O2 and above.
Code: Select all
//---------------------------------------------------------------------------------
// BIOS divison function
//---------------------------------------------------------------------------------
void biosDivision(s32 numerator, s32 denominator, s32* result, s32* remainder) {
//---------------------------------------------------------------------------------
s32 __result, __remainder;
asm volatile (
"mov r0, %[numerator] \n\t"
"mov r1, %[denominator] \n\t"
#if defined ( __thumb__ )
"swi 6 \n\t" // Put 6 here for Thumb C Compiler mode.
#else
"swi 6<<16 \n\t" // Put 0x60000 there for ARM C Compiler mode.
#endif
"mov %[result], r0\n\t"
"mov %[remainder], r1\n\t"
: [result] "=l" (__result), [remainder] "=l" (__remainder)
: [numerator] "l" (numerator), [denominator] "l" (denominator)
: "r0","r1","r2","r3"
);
*result = __result;
*remainder = __remainder;
}
I still don't really 100% understand why but I think you'll agree that this version of the code is much clearer & easier to understand.