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.

C/C++ > ARM vs THUMB instructions

#7396 - Darkain - Tue Jun 17, 2003 12:09 am

im using DKA/GCC. i was wondering how i specify if a section of code (ike a function, or maybe a specific section within a function) to be in THUMB mode or ARM mode, this way i can better optimize my code depending on what it may be doing.
_________________
-=- Darkain Dragoon -=-
http://www.darkain.com
DarkStar for Nintendo DS

#7401 - tepples - Tue Jun 17, 2003 6:58 am

Put all your time-critical stuff that should be compiled as ARM code and placed in IWRAM in a separate file, tell GCC to compile it as ARM instead of Thumb, and give it a name that tells the link script to put it in IWRAM. Do something like this:
Code:
gcc -Mthumb -Mthumb-interwork -O3 -o 1.o -c main.c
gcc -Mthumb -Mthumb-interwork -O3 -o 2.o -c stuff.c
gcc -Mthumb -Mthumb-interwork -O3 -o 3.o -c morestuff.c
gcc -Marm -Mthumb-interwork -O3 -o 4.text.iwram.o -c timecriticalstuff.c
gcc -Marm -Mthumb-interwork -O3 -o 5.o -c asmstuff.s
gcc -Mthumb-interwork -o game.elf 1.o 2.o 3.o 4.text.iwram.o

_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#7419 - Jason Wilkins - Tue Jun 17, 2003 4:45 pm

You forgot to mention that the code in ROM which calls functions defined in timecriticalstuff.c will need to be compiled with -mlong-calls or there will be linker errors.

You don't have to worry about it if you are making multiboot images, apparently, EWRAM and IWRAM are close enough to each other (logically) that short calls will work. This means that code in EWRAM which calls code in IWRAM does not need -mlong-calls, just code in ROM which calls code in RAM or visa versa.
_________________
http://devkitadv.sourceforge.net

#7420 - Lupin - Tue Jun 17, 2003 5:04 pm

I *think* this will work too:

extern __attribute__ ((long_call)) s32 MyFunc(s32 a, s32 b);

#7428 - Darkain - Tue Jun 17, 2003 7:43 pm

Lupin wrote:
I *think* this will work too:

extern __attribute__ ((long_call)) s32 MyFunc(s32 a, s32 b);



the long_call attribute as far as i know only lets you call functions between IWRAM, EWRAM, and ROM. this will force it to use a 32-bit pointer, because normally i think it uses a 24-bit? pointer, to help load things faster.
_________________
-=- Darkain Dragoon -=-
http://www.darkain.com
DarkStar for Nintendo DS

#7431 - Jason Wilkins - Tue Jun 17, 2003 9:13 pm

The long_call attribute effects only the functions which call the function with the attribute, not the function itself, so you use it with declarations that appear with functions which need to call that function long.

Functions which do not need call the function long, such as other functions in the same memory, do not need the attribute, and will be faster without it.

Also, if you put the long_call attribute on the declaration, you also need to add it to the definition or it will complain about the declaration and definition being different. But, since a function doesn't need to call itself long, there is no need for the function definition to see the version of its declaration which has the attribute.

This leads to a slightly annoying situation where some functions need to see the long_call version of the declaration, and some functions do not. The way I handle this is to use a macro to declare the function in its header file.

long-calls.h:
Code:

#ifdef WRAM_LOCAL_CALLS
#define __WRAM_CALL_LENGTH
#else
#define __WRAM_CALL_LENGTH __attribute__ ((long_call))
#endif

#define IWRAM_FUN(decl) __WRAM_CALL_LENGTH __attribute__ (section(".iwram.text"))) decl
#define EWRAM_FUN(decl) __WRAM_CALL_LENGTH __attribute__ (section(".ewram.text"))) decl


iwram-functions.h:
Code:

#include "long-calls.h"

IWRAM_FUN(int my_iwram_fun(int, int, int));
IWRAM_FUN(int my_iwram_fun2(int));


iwram-functions.c:
Code:

#define WRAM_LOCAL_CALLS
#include "iwram-functions.h"

int my_iwram_fun(int x, int y, int z)
{
   return x + y + z;
}

int my_iwram_fun2(int x)
{
   // because of the WRAM_LOCAL_CALLS define, this will be a short call
   return my_iwram_fun(x, x, x);
}


main.c
Code:

#include "iwram-functions.h"

int main(void)
{
   // because of the lack of the WRAM_LOCAL_CALLS define, these functions will both be called long
   return my_iwram_fun2(my_iwram_fun(1, 2, 3));
}

_________________
http://devkitadv.sourceforge.net

#7554 - Lupin - Thu Jun 19, 2003 7:30 pm

For me it's hard to understand this stuff :(

now, how do I have to call my functions in IWRAM? The functions are in math.text.iwram.s, how does the function prototype for the functions in my file have to look like (I'm calling from the normal memory (wherever this is :)))?

#7558 - Jason Wilkins - Thu Jun 19, 2003 8:02 pm

The code example I provided is exactly what you need to do to call functions in IWRAM from a function in ROM. What part do you not understand?
_________________
http://devkitadv.sourceforge.net

#7560 - Lupin - Thu Jun 19, 2003 8:28 pm

now, do I still need __attribute__ ((long_call)) for my IWRAM-functions? why did you specifiy the section attribute? it also works without it i think

#7595 - Jason Wilkins - Fri Jun 20, 2003 3:19 pm

Originally, the feature of naming a file '*.iwram.o' in order to have it in iwram was, in my opinion (the opinion of the creator of the feature), for files which you did not have control of the source code but needed to force to be in a certain place. Perhaps you just have an object file, or you do not want to edit a piece of source code you have found.

Recently I have come to think of it as a trick or short cut, which beginners can use, but it is like a sledgehammer. Using an __attribute__ to set a section is more surgical.

In DevKit Advance R5, I have reigned in the feature to make it more predictable. I have no idea precisely how it works in DKA4. It was the first draft of a feature that I did not finish implementing. It has no polish. The documentation, like Jeff's FAQ on devrs, is not completely correct about how it works. That is my fault. But in DKA5 I polished it up and made it more consistent.

The presence of the variables __gba_multiboot and __gba_ewram_data are used to set the overall default location of variables and code for the whole final executable image. __gba_multiboot does a lot more than that, but I'll save an explanation of all it does for another day.

Naming an object file *.iwram.o, *.ewram.o, or *.cartrom.o will override the default set of the presence or absence of the __gba_* variables and place the functions, data, and constants into sections based on the file name. This is a novel use of a linkscript feature which I have never seen anyone else use for a general toolchain like DKA.

Using a section attribute overrides the above two methods and allows you to set the section on a function by function, variable by variable basis.

You will need a long_call attribute on the prototype of the callee when calling a function in ram from rom or visa versa because the numerical distance between the addresses is too big for a normal (short) call. iwram to ewram calls (and visa versa) seem to be fine because they are close enough to each other.

However, you should not have a long_call attribute on the prototype seen by the file that contains the callee, because that wouldl require that you put the attribute on the function definition as well so that the type of the prototype and definition will match. Putting the attribute on the function definition is ugly and totally unnecessary because a function does not need to call itself long (unless it was a VERY VERY BIG function) and rarely call themselves anyway.

Another case where it is desirable to not have the long_call attribute is when compiling other functions, which call the function in ram, which are also located in ram. These functions do not need to call each other with a long call because they are all close enough to each other.

Because of these cases, and the number 1 software construction principle that you should only write something once, and have it in one place, (i.e., you shouldn't have two versions of the prototype) it is good to create the prototype in such a way that you can easily switch between the long and short call versions. That is what my sample code above demonstrates using macros.

The reason it also sets the section is that use of long_call and setting the section are intimately related. long_call has no other use except to allow proper linking of functions between ram and rom, so a macro setting the long_call attribute would also naturally set the section.

If you use the *.iwram.o/*.ewram.o method of placing stuff in ram, then the natural partner of that method is using -mlong-calls option when compiling the clients of the functions in those files. "Clients" means files which contain calls to the functions defined in the *.iwram.o/*.ewram.o files (except the *.iwram.o/*.ewram.o files themselves). If the *.iwram.o/*.ewram.o files call functions in ROM, then they will need the -mlong-calls option as well. Simply returning to ROM does not count, just if they make actual calls.

The -mlong-calls option is the sledgehammer counterpart to the *.iwram.o/*.ewram.o sledgehammer because it will make all function calls in the compiled file be long calls, even ones that do not need it. The result is slower code because of the overhead of the unecessary long calls.

Of course, you can mix the two options, but it may become more difficult to understand what is happening.

I use the *.iwram.o/*.ewram.o feature when I do not want to edit the source code of the file I am compiling. One example is when I compiled some benchmark code I didn't write. I didn't want to go through the code and add a bunch of DKA5 specific stuff to it, so I just had the makefile give the file the name queens.iwram.o. This had the intended effect of putting all the time critical code and data in the benchmark into iwram, and was very easy. It is intended to be a quick and dirty solution, and there is nothing wrong with that, but if you have total control over your source, you should be more careful and use attributes.

The __gba_* variables are for controlling the location of variables and code you have little control over, like the standard C library. I am working on a way to more precisely control even where the standard library are located. Stay tuned.

I hope this is a thorough enough explanation, I will be using this as a rough draft for documenting this feature on the DKA web site. What is needed is a couple of code samples and I'm set.
_________________
http://devkitadv.sourceforge.net

#7619 - Lupin - Sat Jun 21, 2003 2:55 pm

hmm, thanks for your explanation about that, I think I have to get rid of this .iwram.o extension and somehow try to put the functions into iwram myself.

#7631 - Drago - Sat Jun 21, 2003 6:52 pm

Until now I've been mixing the two methods, file naming to place functions into iwram and macros to specify the type of jump, and it has been working fine for both C and C++. After reading the posts I've tried to make use of the section attribute to place functions into iwram. C modules worked fine, but I'm having problems with C++. Are there any special considerations about placing class methods into iwram by using the section attribute instead of file naming?

#7701 - Jason Wilkins - Mon Jun 23, 2003 6:32 am

I have never tried to use attributes with C++ methods, so I dunno. I would assume that you CANNOT use the section attribute on member variables in the class declaration, but that you can use it on the member functions. attribute long_call would seem to be useless for virtual functions because all virtual function calls are done through pointers and thus are already long calls, but it should not give you an error.

Could you explain your problems more? Please provide a code sample of what you are trying to do and the errors you are getting. Also, which version of DKA are you using?

From you explaination, I do not even know if your problems are syntax errors, semantic errors, or linker errors.
_________________
http://devkitadv.sourceforge.net

#7719 - Drago - Mon Jun 23, 2003 2:40 pm

Well, I gave no details because I wanted to know if I was missing something obvious before messing up with specific code.
Now, while writing a simple example to post I found the source of the error, and it has to do with ARM/Thumb compilation, and not with ROM/IWRAM code placing. Thus, the section attribute is now working fine with C++.

Anyway, I tried the section attribute method in order to avoid splitting my modules into three files, module.h, module.c/cpp and module.text.iwram.c/cpp. But I realized that I need to keep doing it because I want my IWRAM code to be ARM, and my ROM code to be Thumb.