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.

Beginners > Putting code in IWRAM

#12320 - yaustar - Sat Nov 08, 2003 12:13 am

at the moment I have this chunk of code at the top of my main.cpp
Code:

#define IN_INRAM __attribute__ ((section (".iwram")))


put when I do:
Code:

void IN_INRAM function(){   }


i get this error:
Code:

relocation truncated to fit   R_ARM_PC24 func_drawRadar(short, short)


any help is appreciated
_________________
[Blog] [Portfolio]

#12323 - sajiimori - Sat Nov 08, 2003 12:33 am

Oh yeah, you have to use 'long_call':
Code:

#define IN_IWRAM __attribute__ ((section (".iwram"), long_call))

I think that's the syntax.

Edit: forgot the underscore.

#12324 - yaustar - Sat Nov 08, 2003 12:37 am

Cheers man.
edit: that didn't work either :/
_________________
[Blog] [Portfolio]

#12327 - yaustar - Sat Nov 08, 2003 1:50 am

Okay, after looking at some old posts, this should have work.

Is it a compliar error of some sort?
_________________
[Blog] [Portfolio]

#12329 - DekuTree64 - Sat Nov 08, 2003 3:29 am

I never could get long_call to work, but I think that's just cause I don't link any of the standard libs with my game.
There are other ways to call functinos in IWRAM though. You can use __FarProcedure((u32)funcName) which is in Jeff's Crt0, but it uses the first argument as the function to call, so if your function expects an arg in r0, it won't work. So my solution to that was to make a u32 variable and an ASM function (I just called the var farProc and the function FarProc) so you can set the var to the address of the function and then call FarProc with whatever arguments it needs. So in your C file you need
Code:

u32 farProc;
extern u32 FarProc(u32, ...);

That means it takes one u32 (everything can be treated as a plain 32 bit value) and any number more args. The compiler won't let you do the ... thing without at least one var before it, so if your function doesn't take any vars just give it a 0 or anything, it won't make any difference. Then in a .s file:
Code:

.global FarProc
.align
.arm
FarProc:
ldr r12, =farProc   @the address of the variable
ldr r12, [r12]   @the value stored in it, which is the address of your IWRAM function
bx r12   @and branch!

r12 is free to use so you don't have to worry about corrupting it, and your function won't know that it was called any differently than any other function, and will return to where you called FarProc() from.
So to use it, do like this:
Code:

IN_IWRAM u32 AddStuff(u32 a, u32 b)
{
   return a + b;
}

void main()
{
   farProc = (u32)AddStuff;
   u32 result = FarProc(4, 5);
//now result holds 9
}

_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#12330 - yaustar - Sat Nov 08, 2003 3:35 am

I am not too familar with ASM, would I need to do anything within my make.bat file or #include it anywhere?

edit: checked in the code, I am assuming I have to put a marco like so:
Code:

#define IN_IWRAM __FarProcedure((u32)funcName)


function
Code:

IN_IWRAM void func_drawRadar(s16 var_x, s16 var_y)


in main
Code:

//help asm
//func_drawRadar(var_x, var_y);
farProc = (u32)func_drawRadar;
FarProc(var_x, var_y);


and getting this error from the function
Code:

97 C:\DOCUME~1\YAUSTA~1\MYDOCU~1\MYPROJ~1\Code\BG_DMA\main.cpp
`funcName' was not declared in this scope
97 C:\DOCUME~1\YAUSTA~1\MYDOCU~1\MYPROJ~1\Code\BG_DMA\main.cpp
ISO C++ forbids declaration of `__FarProcedure' with no type



why is nothing simple anymore :/
_________________
[Blog] [Portfolio]

#12333 - DekuTree64 - Sat Nov 08, 2003 4:44 am

Oh yeah, you do need to declare __FarProcedure to use it.
Code:
extern void __FarProcedure(u32, ...);

Then use it like
Code:
__FarProcedure((u32)func_drawRadar);

__FarProcedure is not in IWRAM, it's to call a function that is in IWRAM from ROM. Also, funcName was what you were supposed to replace with the name of your function, not some magic word or anything (sorry I didn't make any that very clear before).

And the FarProc thing is something else entirely that I made up myself, so if you want to use it, you'll have to write it yourself too. But since your functino does take arguments, I think you will need it. All the info on how to do it was in that last post. Just declare a variable called farProc somewhere like any other variable, declare FarProc() as an extern function, and paste that ASM into a .s file and compile/link it with gcc exactly like you would a C file. Then set farProc to the address of your function and call FarProc() with the same arguments you would give to your function if you were calling it directly.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#12334 - DekuTree64 - Sat Nov 08, 2003 4:48 am

Hmm, just thinking about it, you could use __FarProcedure with arguments if you give the function you're calling a pointless first argument to fill the slot that the address takes when calling __FarProcedure. So just declare it like
Code:
IN_IWRAM void func_drawRadar(u32 dummy, s16 var_x, s16 var_y)

and call it like
Code:
__FarProcedure((u32)func_drawRadar, x, y);

and everything should be fine.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#12335 - yaustar - Sat Nov 08, 2003 4:56 am

okay, recap
declare
Code:

#define IN_IWRAM __attribute__ ((section (".iwram"))//functions only
extern void __FarProcedure(u32, ...);

I dont think I need:
Code:

//u32 farProc;
//extern u32 FarProc(u32, ...);

or the .s file since we are not using them

declare function
Code:

IN_IWRAM void func_drawRadar(u32 dummy, s16 var_x, s16 var_y)
{
bool even_odd;//false is even, true is odd
u8 var_newX, var_newY, var_diffY, var_diffX;//temp variables
s16 var_curX, var_curY;//temp variables
......
}

and in main
Code:

__FarProcedure((u32)func_drawRadar, var_x, var_y);


in that case i begin to get errors, mainly in the function like
Code:
108 C:\DOCUME~1\YAUSTA~1\MYDOCU~1\MYPROJ~1\Code\BG_DMA\main.cpp
ISO C++ forbids declaration of `var_curX' with no type


btw, I appreciate the help you have given me.
_________________
[Blog] [Portfolio]

#12336 - Burton Radons - Sat Nov 08, 2003 4:56 am

__FarProcedure is just for calling the function and calling from it; use the attribute syntax for declaring it.

Leveraging GCC features (and idiosyncracies) allows a nicer far call:

Code:

#define FarCall(FUNCTION) \
    ({ \
        typeof (FUNCTION) *volatile _POINTER; \
        \
        _POINTER = &(FUNCTION); \
    })

FarCall (LongBoat) ();

#12337 - yaustar - Sat Nov 08, 2003 5:04 am

I assume that FarCall is called in main so would it be something like this?
Code:

FarCall (function name) (function arguments);

_________________
[Blog] [Portfolio]

#12338 - Burton Radons - Sat Nov 08, 2003 5:07 am

Yeah.

#12339 - yaustar - Sat Nov 08, 2003 5:11 am

re-recap
declare
Code:

#define IN_IWRAM __attribute__ ((section (".iwram"))//functions only
#define FarCall(FUNCTION) \
    ({ \
        typeof (FUNCTION) *volatile _POINTER; \
        \
        _POINTER = &(FUNCTION); \
    })


function
Code:

IN_IWRAM void func_drawRadar(s16 var_x, s16 var_y)
{
    bool even_odd;//false is even, true is odd
    u8 var_newX, var_newY, var_diffY, var_diffX;//temp variables
    s16 var_curX, var_curY;//temp variables
   
    var_curX = ((var_x + 120) >> 3) - 18;
    var_curY = (((var_y + 80) >> 3) - 18) << 6;
    ........
}

in main
Code:

FarCall (drawRadar)(var_x, var_y);


some errors;
Code:

107 C:\DOCUME~1\YAUSTA~1\MYDOCU~1\MYPROJ~1\Code\BG_DMA\main.cpp
syntax error before `void'
113 C:\DOCUME~1\YAUSTA~1\MYDOCU~1\MYPROJ~1\Code\BG_DMA\main.cpp
ISO C++ forbids declaration of `var_curX' with no type
113 C:\DOCUME~1\YAUSTA~1\MYDOCU~1\MYPROJ~1\Code\BG_DMA\main.cpp
conflicting types for `int var_curX'


help.....
_________________
[Blog] [Portfolio]

#12340 - Burton Radons - Sat Nov 08, 2003 5:25 am

Add a closing parenthesis in your IN_IWRAM definition.

#12341 - yaustar - Sat Nov 08, 2003 5:27 am

I could kiss you guys.. guess I have another two in the credits :)
_________________
[Blog] [Portfolio]

#12360 - Paul Shirley - Sat Nov 08, 2003 9:24 pm

removed

Last edited by Paul Shirley on Sun Mar 28, 2004 8:51 pm; edited 1 time in total

#12361 - yaustar - Sat Nov 08, 2003 11:00 pm

Side note: how do I work out how much room this code takes in IWRAM? Is it actual text/file size or does it work it out differently?
_________________
[Blog] [Portfolio]

#12362 - Paul Shirley - Sun Nov 09, 2003 1:35 am

removed

Last edited by Paul Shirley on Sun Mar 28, 2004 8:52 pm; edited 1 time in total

#12364 - yaustar - Sun Nov 09, 2003 3:05 am

May I ask how is that done? (the c++ filt)
_________________
[Blog] [Portfolio]

#12376 - Paul Shirley - Sun Nov 09, 2003 4:24 pm

removed

Last edited by Paul Shirley on Sun Mar 28, 2004 8:52 pm; edited 1 time in total

#12377 - DekuTree64 - Sun Nov 09, 2003 4:54 pm

I use the -Map option when linking to check where/how big everything is. If you have a line in your makefile like
LDFLAGS = -T lnkscript
then just put a -Map and then a name for your map file so it looks something like
-T lnkscript -Map game.txt
and that will tell you everything you need to know.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#12387 - Drago - Mon Nov 10, 2003 2:00 pm

Paul Shirley wrote:
Your IN_IWRAM is in the wrong place. It needs to follow the function prototype and only the prototype.

Does it really matters? I ask because I use it this way:

Code:
 int _IWRAM_ func(int arg);


and it works fine.

#23133 - krozen - Mon Jul 05, 2004 9:14 am

Hey guys,
i tried this in C and it worked perfectly. Now im trying to code in C++, but am having trouble implementing this. I have a method in an object called Render. I create an instance of this object called screen, and so want to make a call to screen.Draw(x,y), from the main method. Is there any particular care needed for this?
Thanks
Damien
Edit

The errors im getting are like so
Code:
main.c:28: type of `screen.Render::Draw(int, int)' is unknown
main.c:28: ISO C++ forbids declaration of `_POINTER' with no type
main.c:28: ISO C++ forbids taking the address of a bound member function to
   form a pointer to member function.  Say `&Render::Draw'
main.c:28: cannot convert `void (Render::*)(int, int)' to `int* volatile' in
   assignment