#43280 - zorpax - Sat May 21, 2005 1:08 pm
Hi, I', just getting started with GBA programming and am a little confused about double buffering. I have code which in screen mode 3 uses
u16* buffer = (u16*)0x2000000;
to create the background buffer in EWRAM. And then it copies the memory into VRAM
Surely this is going to be at the beginning of the stack or heap (i don;t know which) and it may be allocated by the compiler to other variables, which can then overwrite the memory?
Am I missing something here? do you need to tell the compiler not to alocate that part of memory?
Any information would be great
Thanks
Dan
#43282 - strager - Sat May 21, 2005 2:15 pm
Like this (if I remember):
Code: |
u16 buffer[240 * 160 / 2] __attribute__ ((section (".ewram"))); |
Looks messy, but should work.
#43287 - tepples - Sat May 21, 2005 3:58 pm
If it's uninitialized, put it in section .sbss instead of section .ewram; otherwise, it'll bloat your ROM.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#43347 - Quirky - Sun May 22, 2005 4:06 pm
tepples wrote: |
If it's uninitialized, put it in section .sbss instead of section .ewram; otherwise, it'll bloat your ROM. |
Yikes! As in the following?
Code: |
u16 buffer[240 * 160 / 2] __attribute__ ((section (".sbss"))); |
That is very handy to know. A Devkit ARM addition, I assume? I'm off to try it now...
#43644 - Cearn - Wed May 25, 2005 9:34 am
Quote: |
Code: |
u16 buffer[240 * 160 / 2] __attribute__ ((section (".sbss"))); |
|
... wouldn't that make the buffer only half the proper size for mode 3?
#43764 - zorpax - Thu May 26, 2005 12:35 pm
basically though, what you are saying is that the tutorial i was reading that gave me that code, was lying to me?
#43775 - poslundc - Thu May 26, 2005 5:32 pm
zorpax wrote: |
basically though, what you are saying is that the tutorial i was reading that gave me that code, was lying to me? |
No, there's nothing wrong with what you were doing, but you need to delve into the guts of the GBA a bit more to explain why.
0x02000000 is the beginning of EWRAM, which goes unused by default for any GBA programs you write (all non-const variables go into IWRAM by default, as does the stack). The exceptions are as follows:
- Multiboot games are loaded into EWRAM, so you would have a conflict there if your game was multiboot.
- The heap in most configurations go into EWRAM, but this only affects you if you are using new or malloc, and in either case the heap usually begins at the end of EWRAM and works it way down towards the beginning, so as long as you're careful you can use both at once. (It is generally unwise to use dynamic allocation on the GBA anyway, though.)
So as long as that memory isn't being used for anything, there's nothing preventing you from grabbing a pointer to it and using it, which is what you're doing.
You should probably be cautioned that the mode you're using with the EWRAM/VRAM page-flipping style is one of the least used on the GBA, and EWRAM is pretty slow overall, so you might be limited in how much drawing you have time for in a single frame.
Dan.
#43862 - zorpax - Fri May 27, 2005 11:14 am
Thanks for that explanation.
Why is it unwise to use dynamic memory allocation on the GBA?
Cheers
#43865 - tepples - Fri May 27, 2005 1:55 pm
How are you going to handle the out-of-memory situation? On a machine with a large amount of rewritable storage, you can swap things to disk, but on the GBA you generally can't.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#43881 - poslundc - Fri May 27, 2005 4:13 pm
Also, the GBA has such a small amount of memory and such a slow processor that a heap is very difficult to manage effectively. The risks of fragmentation are comparatively high - especially if you can't determine the order in which objects will be deallocated - and if your heap gets fragged it's all over, man.
You can simulate dynamic allocation by creating your own static memory pools and allocating entries out of those as you need them. By restricting yourself to two or three structures that actually really do need this kind of behaviour, and making sure that they are allocated from their own, separate partitions of the appropriate length (size of structure * maximum number of entries you will ever conceivably need), you can ensure that things will never overflow or get fragmented.
Dan.
#43885 - wintermute - Fri May 27, 2005 5:43 pm
poslundc wrote: |
- The heap in most configurations go into EWRAM, but this only affects you if you are using new or malloc, and in either case the heap usually begins at the end of EWRAM and works it way down towards the beginning, so as long as you're careful you can use both at once. (It is generally unwise to use dynamic allocation on the GBA anyway, though.)
|
Newlib malloc ( and new which uses the same allocation scheme) return pointers from the bottom of heap and working upwards. Dynamic allocation isn't a particular problem on the GBA although over liberal use of malloc and free are unwise ( such as excessive new & delete ). It's perfectly feasible to allocate a large chunk at the start of a game & return it when the game has completed. Alternatively the .sbss section can be used for large static allocations.
On the other hand, manually typing addresses to buffers is a recipe for disaster. You should *always* let the compiler do as much work as possible.
#43887 - poslundc - Fri May 27, 2005 6:05 pm
wintermute wrote: |
Newlib malloc ( and new which uses the same allocation scheme) return pointers from the bottom of heap and working upwards. Dynamic allocation isn't a particular problem on the GBA although over liberal use of malloc and free are unwise ( such as excessive new & delete ). It's perfectly feasible to allocate a large chunk at the start of a game & return it when the game has completed. Alternatively the .sbss section can be used for large static allocations. |
I stand corrected then... I'd heard it operated like the stack, from the end of WRAM.
And yes, it's fine to use those functions for large grabs that amount to static allocation anyway... but fluctuating systems are the ones that are most likely to use malloc/new, and those are the ones that need to be careful not to cause fragmentation.
Quote: |
On the other hand, manually typing addresses to buffers is a recipe for disaster. You should *always* let the compiler do as much work as possible. |
I agree that you shouldn't use a magic number in regular code, but a setup like the following in a file called "EWRAM.h":
Code: |
typedef struct EWRAM_Struct
{
Player playerData[MAX_PLAYERS];
Level level;
...
}
EWRAM_Struct;
#define EWRAM (*(EWRAM_Struct *)0x02000000) |
... Has served me well in the past. This way you can just refer to EWRAM.playerData[n], etc. and it keeps things clean, if not necessarily portable/modular.
Dan.
#43890 - sajiimori - Fri May 27, 2005 6:20 pm
Quote: |
How are you going to handle the out-of-memory situation? |
Don't run out of memory. :P
That may sound like a joke, but one could as easily as how you are going to handle the out-of-statically-allocated-objects situation.
#43891 - DekuTree64 - Fri May 27, 2005 6:32 pm
My preferred way of using EWRAM is like a stack:
Code: |
u8 *eWram = (u8*)0x2000000;
void main()
{
u32 *someTemporaryData;
eWram -= 1000;
someTemporaryData = (u32*)eWram;
DoStuff(someTemporaryData);
eWram += 1000;
...
} |
Lets you ex. claim a large chunk of memory during a particular menu (or even just a function), and then free it up when you're done.
Same thing could be done with malloc/free though, since you wouldn't get fragmentation if you went in stack-like order anyway. It's a heck of a lot slower though :)
Actually I do like Dan's struct for static data. A combination would be best.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#43892 - poslundc - Fri May 27, 2005 6:37 pm
DekuTree64 wrote: |
Actually I do like Dan's struct for static data. |
(Credit where it's due: I got the idea from tepples.)
Dan.
#43898 - sajiimori - Fri May 27, 2005 7:49 pm
Look out, here come a bunch of scary things to say:
If you make lots of tiny allocations and no big ones (or make special reservations for big ones), fragmentation can't become severe.
It saves memory in the average case because you don't have to have lots of unused objects sitting around just in case you need them. There's a little memory overhead for each object due to record keeping.
It's a CPU hit compared to a static structure, but our bottlenecks are rendering and collision (by very, very far), neither of which do any allocation.
#43902 - DekuTree64 - Fri May 27, 2005 8:29 pm
All very true. Back on my old GBA game where I actually used that EWRAM stack, I had a memory manager too, just not a single giant heap. I'd grab a hunk of EWRAM and set it up for dynamic allocating for a particular purpose. Good for things like sprite movement scripts, which are pretty random in length, or my crazy semi-object-oriented battle system that would allocate little structures for anything that would need updating every frame.
Looking back on it though, the battle system would have been better to do with a static array of objects, with a union for all the different vars for each type. Then dynamically allocate if one particular type needed a huge lump of memory.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#43906 - poslundc - Fri May 27, 2005 10:23 pm
sajiimori wrote: |
If you make lots of tiny allocations and no big ones (or make special reservations for big ones), fragmentation can't become severe. |
I dunno... the general case for most game algorithms probably isn't so bad, but it's possible to fragment your way out of a heap of any size with the tiniest of allocations, so long as one is bigger than the allocation block size. With only 256K, it's something worth being careful over, I believe.
Quote: |
It saves memory in the average case because you don't have to have lots of unused objects sitting around just in case you need them. There's a little memory overhead for each object due to record keeping. |
*shrug* Saving memory in the average case seems like a relatively pointless thing to do on a console, where you must design to handle the worst case anyway, and memory isn't being shared with other programs that might benefit from your average-case generosity.
Quote: |
It's a CPU hit compared to a static structure, but our bottlenecks are rendering and collision (by very, very far), neither of which do any allocation. |
I have no beef with the CPU hit, really, or even the memory cost of managing a heap. I just think that on the GBA it saves trouble down the road to use static allocation, and do any necessarily dynamic allocation out of static pools that are sized to the specific structure, so you are always operating in the worst-case and can't fragment.
Dan.
#44457 - strager - Thu Jun 02, 2005 12:03 am
I am having a problem relating to this topic:
I tried using .sbss, and it mad my ROM a whopping 90MB!! ***!!!MEGABYTES!!!*** Then I tried .ewram, and that worked a little better, but there was a big section in my ROM full of zeros (total ROM size is 80KB). Is there any other method I could use to allocate memory in EWRAM?
#44472 - tepples - Thu Jun 02, 2005 3:10 am
strager wrote: |
I am having a problem relating to this topic:
I tried using .sbss, and it mad my ROM a whopping 90MB!! ***!!!MEGABYTES!!!*** |
What version of the linker are you using? If you're still using DevKit Advance r5 beta 3, .sbss isn't a recognized section in the default link script. You need to upgrade to devkitARM r8 or later (I suggest using r11 until updated r12 packages are available to fix a crt0 bug) in order to get .sbss to work.
Quote: |
Then I tried .ewram, and that worked a little better, but there was a big section in my ROM full of zeros (total ROM size is 80KB). |
Expected.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#44517 - strager - Thu Jun 02, 2005 1:59 pm
tepples wrote: |
If you're still using DevKit Advance r5 beta 3, .sbss isn't a recognized section in the default link script. You need to upgrade to devkitARM r8 or later (I suggest using r11 until updated r12 packages are available to fix a crt0 bug) in order to get .sbss to work. |
I use my own crt0 script to fit my needs, so I don't care about that. I downloaded r11, and I couldn't find the lnkscript. Maybe I downloaded DKA from the wrong place. Where's a direct link (I could never seem to find one)?
Edit: Never mind, I got the lnkscript. But now it doesn't work, and the .sbss method now blows it up to 100 Megs! EWRAM now has 150 KB, also. What am I doing wrong?! :-(