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 > Strange sprite problems with -O3 Tag

#32374 - identitycrisisuk - Tue Dec 21, 2004 5:17 pm

I'm getting problems after starting to compile code in DevKitARM with the -O3 tag. I've checked for the standard mistakes listed in the FAQ and I have my Vcount and key registers set up as volatile but it's likely I need it for some other things I haven't thought of.

The problem is only with my sprites, the backgrounds seem to be fine as they are only loaded once at the beginning but the sprites are DMA transferred in each time a different frame of animation is needed so the OAM data should always be pointing to the same place in VRAM.

Looking at the VBA debug stuff the problem seems to be in a few areas, firstly using the tile viewer I can see that the sprites section is filled with nonsense, kinda like when you use map data as tiles by mistake. If I leave it on Automatic update I can see that sometimes the right sprite appears to be in VRAM but only for a brief second and then it's back to nonsense again. On top of this the OAM data seems to change too, later entries I don't use seem to change position, size etc. and my sprites move too, sometimes ending up at 0, 0 and becoming 8x8 instead of 32x32.

All in all a bit of a scary prospect but at least it must be with the sprites since the backgrounds and gamelogic seem fine. I've also checked that it is the same on VBA and hardware, which it is. I'm guessing my problems might be with more registers needing to be made volatile or perhaps I'm relying on some data to be initialised as zero when in non optimised mode. Any suggestions?
_________________
Code:
CanIKickIt(YES_YOU_CAN);

#32391 - pan69 - Wed Dec 22, 2004 8:12 am

Can it be an alignment problem? Maybe some struct's gets missaligned because of the -O3 compiler switch.

- Pan

#32396 - FluBBa - Wed Dec 22, 2004 10:59 am

I've seen DMA start code mangled by -O3, often the assembler code writes to the start register before source and/or destination register, thus screwing up the transfer.
_________________
I probably suck, my not is a programmer.

#32401 - identitycrisisuk - Wed Dec 22, 2004 11:36 am

FluBBa wrote:
I've seen DMA start code mangled by -O3, often the assembler code writes to the start register before source and/or destination register, thus screwing up the transfer.


Ooh, that sounds like a possibility, there's a way around that isn't there by using an asm command? I've not used any asm yet, I know that the preferred way of doing it is putting it into a separate .s file but is this something I might get away with having a single asm command in the midst of some C++ code? Both my OAM data transfer and sprite loading are done by DMA3 so it fits the things that are going wrong.

Not sure about the alignment idea, could you be more specific? Do you mean some things might need the ALIGN4 tag at its declaration or that I might be relying on the offset of some variables within the struct?I don't think I do anything like that at the moment, I have my map and sprite data with ALIGN4, don't really know what else needs it.
_________________
Code:
CanIKickIt(YES_YOU_CAN);

#32419 - isildur - Wed Dec 22, 2004 3:54 pm

If you need a DMA3 function that writes to the registers with a single stmia instruction, here is mine:

Code:


.GLOBAL Dma3A

.section .iwram, "xw", %progbits
.arm
.align 2

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@
@ void Dma3A(u32 flgs, u32 srcAddress, u32 dstAddress, u32 Count)

Dma3A:
   
    orr r3, r3, r0, lsl #16
    ldr   r0, =0x040000d4
    stmia   r0, {r1-r3}
    bx   lr

    .pool



This should prevent -O3 from messing it up.

#32421 - identitycrisisuk - Wed Dec 22, 2004 4:31 pm

I've tried to write something like that on my own but it doesn't seem to be working, I've gone for the inline C method. Here's my code:
Code:
void SafeDMA3(u32 from, u32 to, u32 ctrl)
{
   asm volatile ("   ldr   a1, =0x040000d4\n\
                     stmia   a1, {r0-r2}\n");
}

And I'd use it like:
Code:
SafeDMA3((u32)SpriteData, (u32)VRAM, SPRITE_ENTRIES|DMA_16NOW);

Anything blindingly wrong with that? Sorry, I know little to no ASM. It seemed to be copying some sprite data into tile data when I tried to use it to copy the OAM data so it's obviously doing something but not quite right.
_________________
Code:
CanIKickIt(YES_YOU_CAN);

#32458 - tepples - Thu Dec 23, 2004 1:50 am

identitycrisisuk wrote:
Here's my code:
Code:
void SafeDMA3(u32 from, u32 to, u32 ctrl)
{
   asm volatile ("   ldr   a1, =0x040000d4\n\
                     stmia   a1, {r0-r2}\n");
}

And I'd use it like:
Code:
SafeDMA3((u32)SpriteData, (u32)VRAM, SPRITE_ENTRIES|DMA_16NOW);

Anything blindingly wrong with that? Sorry, I know little to no ASM. It seemed to be copying some sprite data into tile data when I tried to use it to copy the OAM data so it's obviously doing something but not quite right.

AAS uses something like this to do DMA3.

But three things: First of all, you're only supposed to use r0-r3 and ip without saving them beforehand; otherwise the calling function gets confused. Easy fix:
Code:
void SafeDMA3(u32 from, u32 to, u32 ctrl)
{
   asm volatile ("   ldr   r3, =0x040000d4\n\
                     stmia   r3, {r0-r2}\n");
}

Second, you have to remember to divide the length by 2 or 4 when using 16-bit or 32-bit DMA respectively. Finally, the 'VRAM' macro in GBA header files usually means the address of the part of VRAM containing background tile data. Here's a macro to find the address of sprite cel data starting at a given tile number (copying from the latest version of my custom header):
Code:
#define SPR_VRAM(x) ((u32 *)(0x06010000 | ((x) << 5)))

Some of the confusion may be due to a faulty tutorial that incorrectly used "OAMData" as a name for sprite cel VRAM.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#32542 - identitycrisisuk - Thu Dec 23, 2004 7:12 pm

Kay, finally got that assembler DMA copy working, tested it without the -O3 tag to make sure it worked (should have done that a lot earlier). Sprites seem okay but I've now lost all my background tiles, the maps seem to be updated (from what I can recognise of the funny coloured tiles where my maps are in the tile viewer) so it just looks like the tiles aren't loaded in, this only happens once whereas the update of sprites and map data is much more frequent.

I'll have a trawl through my code and see if there's anything more that could possibly do with a volatile tag. Also, I think I remember this from a thread a while back - if I'm copying data from arrays with DMA_16NOW do I need to put ALIGN16 after the declaration instead of ALIGN4? At the moment they all have ALIGN4.

Sorry to keep on bugging you about this, would be nice to get it working though. It's weird, I can't seem to find any source code for other tutorials with sprites, BGs etc. that will compile with -O3, They all have weird problems similar to mine without modifications. Means I don't really have a cast iron example that I can look at and say right this works with -O3, what does it do that mine doesn't and vice versa.
_________________
Code:
CanIKickIt(YES_YOU_CAN);

#32559 - tepples - Thu Dec 23, 2004 9:36 pm

All macros referring to memory-mapped registers (anything in the 0x04000000 region, or cart bankswitch registers in the 0x08000000 region) need a volatile tag.

ALIGN4 refers to bytes, so you can use ALIGN4 with DMA_32NOW.

To solve your background loading problem, you might need to load your tiles, set the palette, wait for 30 vblanks (so that you can pause the game and check the tile viewer), and then load sprite cels.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.