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.

Coding > Code overlays

#5725 - jd - Wed May 07, 2003 1:16 am

I'm trying to learn how to use code overlays, but I'm struggling to find any
example code. Can someone point me in the direction of some GBA-specific examples or documentation?

Thanks for your help,
James.

#5735 - Touchstone - Wed May 07, 2003 10:54 am

Why would you want to do this? Code is normally executed from ROM so no overlay is needed unless your code is compressed and need to be decompressed in RAM.

If you want to load code to RAM for faster execution then it's simply a matter of copying the code from ROM to RAM, given that your code and required symbols is PC relative and not using absolute adresses. You would ofcourse have to define new function-pointers to point to your function in RAM instead of ROM.

If you want to overlay variables in RAM then you should write a linkerscript with multiple sections in the same memory-space and just assign your variables to the correct section. Be aware that you have to initialize your variables for the variable-attribute "section" to work.
_________________
You can't beat our meat

#5737 - torne - Wed May 07, 2003 1:37 pm

If you mean the iwram0-9 sections supported by the crtls linker script, then all you need to do is declare functions as being in a particular one of those sections. iwram0 will be copied into iwram for you at boot time (along with the normal iwram section); when you want to copy a different overlay into memory, then use a DMA copy. The linker's section variables (things like __iwram1_start) will give you the addresses you need to copy from/to.

ewram0-9 work exactly the same way.

I realise this isn't in a lot of detail; I've never actually USED the overlay support in crtls, but I do understand linker scripts. =)

If you have any specific questions about this ask again and I'll see what I can find out.

T.

#5745 - jd - Wed May 07, 2003 11:03 pm

torne wrote:
If you mean the iwram0-9 sections supported by the crtls linker script, then all you need to do is declare functions as being in a particular one of those sections. iwram0 will be copied into iwram for you at boot time (along with the normal iwram section); when you want to copy a different overlay into memory, then use a DMA copy. The linker's section variables (things like __iwram1_start) will give you the addresses you need to copy from/to.


Ah, I see. Thanks for the help! However, there is a slight complication in my case that I hope you can help me out with. I'd like to keep the sound mixer and interrupt handling in the same place in IWRAM in all cases, even when other routines are being swapped in and out. What's the best way to do that?

#5747 - torne - Thu May 08, 2003 12:03 am

Just define anything you want to *always* be in iwram in the 'iwram' section. The iwram section is never replaced. iwram0-9 are allocated 'after' iwram, so while they all overlay each other, none of them overlay the iwram section.

T

#5750 - jd - Thu May 08, 2003 1:31 am

torne wrote:
Just define anything you want to *always* be in iwram in the 'iwram' section. The iwram section is never replaced. iwram0-9 are allocated 'after' iwram, so while they all overlay each other, none of them overlay the iwram section.


I see. Thanks for the help!

#5785 - jd - Thu May 08, 2003 4:53 pm

I've run into another problem - when I try to compile the following code:

Code:

#define UBYTE unsigned char
#define IN_IWRAM1 __attribute__ ((section (".iwram1")))

UBYTE local_luminance_quant_table_idct[8][8] IN_IWRAM1;
UBYTE local_chrominance_quant_table_idct[8][8] IN_IWRAM1;


I get these errors:

Code:

AMV.arm.c:42: local_luminance_quant_table_idct causes a section type conflict
AMV.arm.c:43: local_chrominance_quant_table_idct causes a section type conflict
make: *** [AMV.o] Error 1


Help!

#5787 - torne - Thu May 08, 2003 5:27 pm

Two problems:

1) You are trying to put uninitialised data into a section other than bss. This is not possible with a C compiler, that I know of. Uninitialised globals always go into the bss section, where they will be filled with zeros at load time. The C compiler won't let you have 'undefined' data; either it is initialised, and goes by default into the .data section, or it's uninitialised and goes into .bss to be zero-filled.

2) You are trying to use data overlays, which is normally neither neccecary nor possible for non-constant data. The iwram0-9 and ewram0-9 sections are intended for code overlays. If the data is supposed to be uninitialised, i.e. you don't want to store initial values in ROM, then it would be easier to just malloc the memory when you needed it and free it when you're done, rather than using overlays. If you need the data to be initialised, i.e. you want to store an array of non-constant data in ROM until it's needed, then copy it into RAM to use it, then remember that you won't be able to write the values back when you load a different overlay (obviously). If that's really, genuinely what you want, then tell me and I'll see if I can work out how to make data overlays work on the GBA (because I like pain). It will probably involve modifying the linker script as Touchstone said.

Hope that's enough for now,
Torne

#5790 - Jason Wilkins - Thu May 08, 2003 6:08 pm

The problem is that DevKit Advance R4 does not support putting both code and data into a special section at the same time.

using DevKit Advance R5 Beta 2, you can specify .iwram.text and .iwram.data (or even .iwram.foobar) to prevent the conflict.

The C compiler determines the type of section based on the first declaration it sees with a section attribute. So, all the definitions that go into a section need to have the same combination of executability and writability or you get a conflict.

The ability to add 'sub-sections', that is the ability to put things in .iwram.data and .iwram.text seperates all these different properties out and prevents the conflict.
_________________
http://devkitadv.sourceforge.net

#5793 - torne - Thu May 08, 2003 6:34 pm

Convenient, thanks Jason. Though since I just program in asm mostly, I can do whatever I like with my sections. =)

T.

#5800 - Jason Wilkins - Thu May 08, 2003 9:03 pm

Yeah, with assembly you can make sure that the section attributes are always the same. If you program in C, the compiler sets these attributes based on what you are putting into that section.

Functions get an 'ax' for allocatable and executable, initialized data gets 'aw' for allocatable and writable, constant data gets 'a' for just allocatable (not writable).

If you specify a section attribute for uninitialized data, it gets treated as data initialized to zero ('ar'). Unfortunately, this means you cannot split the .bss section into an iwram part and a ewram part. True uninitialized data has no attributes set, not even allocatable.

Here is an example of how to do something like what the original poster wants to do with DKA5.

Code:

__attribute__ ((section(".iwram.data"))) int iwram_var;

__attribute__ ((section(".iwram.text"))) void my_interrupt_handler(void)
{
}

__attribute__ ((section(".iwram0.text"))) void my_movie_renderer(void)
{
}

__attribute__ ((section(".iwram1.text"))) void my_3d_renderer(void)
{
}

extern int __iwram_overlay_start[];
extern int __iwram_overlay_end[];
extern int __load_start_iwram0;
extern int __laod_stop_iwram0;
extern int __load_start_iwram1;
extern int __load_stop_iwram1;

void AgbMain(void)
{
   // go ahead and use iwram0 because it is already loaded
   my_movie_renderer();

   // switch to iwram overlay 1
   memcpy(__iwram_overlay_start, __load_start_iwram, __load_stop_iwram1 - __load_start_iwram1)

   my_3d_renderer();

   // switch back to iwram overlay 0
   memcpy(__iwram_overlay_start, __load_start_iwram, __load_stop_iwram0 - __load_start_iwram0)

   my_movie_renderer();
}



One caveat. I found a bug with overlays when getting ready for beta 3, so you may want to wait until I release beta 3 (very soon I hope) before you try this.

Another Caveat, it would be better to come up with macros for declaring attributes and switching overlays. The code above is hardly readable as it is.

Code:

#define IWRAM_FUN(decl) __attribute__ ((section(".iwram.text"))) decl
#define IWRAM_VAR(decl) __attribute__ ((section(".iwram.data"))) decl
#define CONST_IWRAM_VAR(decl) __attribute__ ((section(".iwram.rodata"))) decl

IWRAM_VAR(foobar) = 42;

CONST_IWRAM_VAR(awesome) = 69;

// a function declaration
IWRAM_FUN(my_external_function(void));

// a function definition
IWRAM_FUN(int my_awesome_function(int a, int b))
{
   return a + b + awesome;
}



You will need to compile using the -mlong-calls option in order to call the function from ROM. Or, you can add the long_call attribute to the IWRAM_FUN macro and make it like this.

Code:

#define IWRAM_FUN(decl) __attribute__ ((section(".iwram.text"), long_call))

_________________
http://devkitadv.sourceforge.net

#5809 - jd - Thu May 08, 2003 11:20 pm

Thanks for all the help. I've worked around the problem by just putting the arrays mentioned above in IWRAM all the time - after all, it's only 128 bytes.

However, I have spotted that the following declaration uses ~220K of ROM when really it should use virtually none:

Code:

#define ULONG unsigned int
#define IN_EWRAM1 __attribute__ ((section (".ewram1")))

ULONG amv_data[55360] IN_EWRAM1;


I guess this is related to what Jason was saying but I'd prefer not to switch to a new version of the devkit at such a late stage in development, but I really need that 220K back somehow. Is there any way to fix this problem without upgrading? Perhaps using a bit of assembler?


Last edited by jd on Fri May 09, 2003 12:00 am; edited 1 time in total

#5810 - tepples - Thu May 08, 2003 11:24 pm

jd wrote:
I have spotted that the following declaration uses ~220K of ROM when really it should use virtually nothing:

Code:

#define ULONG unsigned int
#define IN_EWRAM1 __attribute__ ((section (".ewram1")))

ULONG amv_data[55360] IN_EWRAM1;

To fix this, try malloc().
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#5813 - jd - Fri May 09, 2003 12:03 am

tepples wrote:

To fix this, try malloc().


I've rewritten my routines so they don't use malloc because I need all the IWRAM I can get.

There must be a way to declare the variable with it wasting all that ROM.

#5830 - Jason Wilkins - Fri May 09, 2003 3:34 pm

I have realized the problem of having large uninitialized ewram/iwram variables waste ROM space because they are 'allocated'

DevKit Advance R5 somewhat works around this problem by allowing you to easily choose to put normal read/write C variables into ewram or iwram. That will allow you to use bss to allocate large variables in ewram.

It is not fine grain, unfortunately.

A work around is to use dynamic memory. I do not mean you have to use malloc. I do not remember if these symbols exist in R4, but R5 provides __ewram_break and __iwram_break which point to the beginning of unallocated space. It is not hard to write a simple memory manager for these spaces.

Code:


extern char __ewram_break[];
char *ebreak;

void reset_ewram_break(void)
{
      end = __ewram_break;
}

char *set_ewram_break(size_t s)
{
   char *prev_ebreak;

   if (!end) {
      reset_ewram_break();
   }

   prev_ebreak = ebreak;
   ebreak += s;

   return prev_ebreak;
}

my_foo *foo;
my_bar *bar;

void AgbMain(void)
{
   foo = set_ewram_break(sizeof(*foo));
   bar = set_ewram_break(sizeof(*bar));

   // now, use foo and bar ...

   // unallocate everything
   reset_ewram_break();

   // can now reallocate
}

_________________
http://devkitadv.sourceforge.net