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.

ASM > Problems With Code Converting

#174556 - nathanpc - Sat Jun 26, 2010 12:19 am

Hello,
I'm starting to study how to convert a C source code(for GBA of course) to ARM Assembly, then I got this simple example from TONC:
Code:
int main()
{
    *(unsigned int*)0x04000000 = 0x0403;

    ((unsigned short*)0x06000000)[120+80*240] = 0x001F;

    while(1);

    return 0;
}

Then I converted it into this:
Code:
.arm
.text
.align 2
.global main
main:
        mov r0, #0x4000000
        mov r1, #0x400
        add r1, r1, #3
        str r1, [r0]
       
        mov r0, #0x6000000
        mov r1, #0x1F
        mov r2, #0xBB00
        add r2, r2, #0x80
        str r1, [r0], r2

infin:
   b infin

The 0xBB80 value, I got from the expression [120+80*240] from the C source, what is 48000 in decimal, then I used a hexadecimal calculator to calculate what it's in hexadecimal. It compiles ok, but when I tried to run this on my emulator, I got nothing. As you can see here:
[Images not permitted - Click here to view it]
What I need to do?

Best Regards,
Nathan Paulino Campos
_________________
Reading Tonc and trying to remind my very old C knowledge.

Just bought a GameBoy Advance SP one of those cartridges to put the ROMs for onboard debug.

#174557 - Dwedit - Sat Jun 26, 2010 3:08 am

This piece of code should set DISPCNT to 0403 (mode 3, a 16-bit color layer, with layer 2 enabled), then it sets some pixel to color 1F (red).

What's calling main?
Are you using the standard makefiles and linkscripts? If so, then we know what's calling main (the crt0 file), and we know that main is located at 08xxxxxx.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#174558 - nathanpc - Sat Jun 26, 2010 3:27 am

Hello Dwedit,
Before I've tried this code, from the GBAGuy's tutorial, just to test if my compiler is ok, and my emulator displayed all red ok:
Code:
.arm
.text
.align 2
.global main
main:
        mov r0, #0x4000000
        mov r1, #0x400
        add r1, r1, #3
        str r1, [r0]
       
        mov r0, #0x6000000
        mov r1, #0xFF
        mov r2, #0x9600
loop1:
   strh r1, [r0], #2
   subs r2, r2, #1
   bne loop1
infin:
   b infin

And that code works, like it should: The entire screen filled with a red color. But as you can see on my C source code, what I want is just a pixel, located at 120x80.

What did you suggest me to do?

Best Regards,
Nathan Paulino Campos
_________________
Reading Tonc and trying to remind my very old C knowledge.

Just bought a GameBoy Advance SP one of those cartridges to put the ROMs for onboard debug.

#174559 - headspin - Sat Jun 26, 2010 4:06 am

First of all 120+80*240 equals 19320 (0x4B78). Secondly you should write a half word (use strh instead of str) for the second store. Also note it's casting to a short before it indexes the array.

Code:
((unsigned short*)0x06000000)[120+80*240] = 0x001F;


So the 120+80*240 is actually 19320 steps into the array in half words (2 bytes). So to convert that to bytes you would need to multiply it by 2. 19320*2 = 38640 or 0x96F0.
_________________
Warhawk DS | Manic Miner: The Lost Levels | The Detective Game

#174561 - Cearn - Sat Jun 26, 2010 8:15 am

You don't need to do the arithmetic yourself, the assembler can do it for you. This can save you some trouble (and it makes it easier to figure out what you meant six months from now). If you're using the template makefiles, you can also create macros for this. The assembler also has macro-capabilities of its own, look that up on the manual.

Code:

#define MODE3_PX(x, y)   (x+240*y)*2

   ldr      r2,=(120+80*240)*2         @ Offset for (120,80)
   ldr      r2,=MODE3_PX(120,80)      @ Offset via macro


Also, be aware of the differences between addressing modes.

Code:

   ldr      r0, [r1, r2]    @ Pre-indexed.             r0= *(u32*)(r1+r2)
   ldr      r0, [r1, r2]!   @ Pre-indexed,  writeback. r0= *(u32*)(r1 += r2)
   ldr      r0, [r1], r2    @ Post-indexed, writeback. r0= *(u32*)r1; r1 += r2;

The post-indexed with write-back that you used in `str r1, [r0], r2' adds the offset after the store, so the pixel is actually at (0,0). If you zoom in you'll see.

#174564 - nathanpc - Sat Jun 26, 2010 1:31 pm

Yeah, now I saw it at the 0x0: [Images not permitted - Click here to view it]
But as I saw, it is located at the 0x0, because of the instruction str r1, [r0], r2, but what I should do to make it appear at the place that it should(120x80)?
_________________
Reading Tonc and trying to remind my very old C knowledge.

Just bought a GameBoy Advance SP one of those cartridges to put the ROMs for onboard debug.

#174568 - Cearn - Sat Jun 26, 2010 5:15 pm

Use a pre-indexing mode: str r1, [r0, r2].

When choosing from the three possibilities, first know what you really want to do. The modes write-back will change the second operand (the first register between brackets). If you don't need that, use simple pre-indexing. If you do, decide whether it needs to be done before you access the memory or after. It's the difference between *ptr++ and *++ptr.

GBAGuy used writeback because he wanted the register to already point to the right spot for the next iteration of the loop. He used post-indexing because pre-indexing would have skipped over the first pixel.

#174576 - nathanpc - Sun Jun 27, 2010 3:49 pm

Thanks, now I understood. :)
_________________
Reading Tonc and trying to remind my very old C knowledge.

Just bought a GameBoy Advance SP one of those cartridges to put the ROMs for onboard debug.