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 > Please help!

#50390 - triton - Tue Aug 09, 2005 3:01 am

Hi folks, I'm new to gba programming and when I finished what was available w/ gbaguy's new tutorials, I tried putting together a game myself. I just wanted to see if i could incorporate a sprite, background and music together. It compiled successfully but unfortunately it didn't run on VBA. I checked the i/o reader and apparently the display contoller is set to forced blank. I don't know why that is and hopes someone can figure things out from my code. "main" , "palette" and "sprite" are all linked from C arrays.
@beginning
.arm
.text
.global main
start:
ldr r10, =0x40000bc @dma_1 for soundfifo
ldr r11, =0x40000c0 @dma 1 dest
ldr r12, =0x40000c4 @dma word count

ldr r7, =0x40000d4 @dma3 for convenient use later
ldr r8, =0x40000d8
ldr r9, =0x40000dc

ldr r0, =0x4000000
ldrh r1, =0x1400 @sprites and bg1
strh r1, [r0]
bg_setup:
ldr r0, =0x400000c
ldrh r1, =0x1480 @600a000 screnbase 6000000 char base block
strh r1, [r0] @256 *256 text background
SND:
ldr r1, =0x4000084 @enable all circuits
ldrh r0, =0x0080
strh r0, [r1]
snd_cnt:
ldr r0, =0x4000080
ldr r1, =0x0b040000 @snd_cnt_l + h fifo a, timer0/reset
str r1, [r0] @ disable snd channels 1-4
snd_timer:
ldr r0, =0x4000100
ldrh r1, =0xfd06 @22050 hz
strh r1, [r0]
ldr r4, =0x4000102
ldrh r3, =0x0080
snd_dma:
ldr r0, =main
str r0, [r10]
ldr r1, =0x40000a0
str r1, [r11]
ldr r1, =0xb2000000
tim_dma:
str r1, [r12]
strh r3, [r4]

BG:
bg_pal:
ldr r0, =bgpal
str r0, [r7] @dma
ldr r0, =0x5000000
str r0, [r8]
ldr r0, =0x94000080 @128 words during vblank
str r0, [r9]
bg_data:
ldr r0, =bg1
str r0, [r7]
ldr r0, =0x6000000
str r0, [r8]
ldr r0, =0x94002000 @vblank 8192 words/ tiledata
bg_map:
ldr r0, =bgmap
str r0, [r7]
ldr r0, =0x600a000
str r0, [r8]
ldr r0, =0x94000200 @512 words on vblank bits 12, 13
str r0, [r9]

SPR:
ldr r0, =0x7000000
ldr r1, =0x200ac00a @att 0 & 1 10y + x
str r1, [r0], #4 @oam
ldrh r1, =0x0000
strh r1, [r0]
.ltorg
spr_pal:
ldr r0, =palette
str r0, [r7]
ldr r0, =0x5000200
str r0, [r8]
ldr r0, =0x94000080 @ 128 words
str r0, [r9]
charmem:
ldr r0, =sprite
str r0, [r7]
ldr r0, =0x6010000
str r0, [r8]
ldr r0, =0x94000200 @512 words
str r0, [r9]
inf:
b inf

.ltorg

bg1:
.incbin "bg1.bin"
bgmap:
.incbin "bg1.map"
bgpal:
.incbin "bg1.pal"
@end of file

#50397 - poslundc - Tue Aug 09, 2005 5:22 am

First rule of debugging: refactor code that doesn't work into the smallest segment of code you can that does work.

Application of rule: don't try to throw three untested, unproven and disparate systems into the mix at once and expect to be able to debug it; you are asking for a world of hurt. First write code that displays a background. Get it working. Then write code that displays a sprite. Get it working. Then write code that combines those two, and get it working. Then write code that plays sound and get it working, then finally combine all three.

It's important to realize that a mistake in one of these systems can easily clobber the other two, and it's next to impossible to debug when you can't tell who's causing the problem.

Finally, consider coding in a higher level language (C/C++) instead of assembly. Assembly is useful for writing small, custom routines that need to be fast, but for general engine purposes it takes far too long and results in code that's infinitely harder to maintain. If you're doing it for academic purposes (ie. to learn how) then that's fine... but believe me, there will still be plenty of challenges awaiting you in C.

Good luck,

Dan.

#50439 - triton - Tue Aug 09, 2005 6:38 pm

Gotcha! But how much slower is C over assembly?

#50444 - poslundc - Tue Aug 09, 2005 7:54 pm

C code is compiled into assembly code... so it depends on how good your compiler is. Compiled code is usually at least an order of magnitude slower than well-written assembly code, but the compiler can easily outperform you if you don't know what you're doing.

None of that really matters for the general case, though. At 16.78 million cycles per second, you are far better off prioritizing your development time over your execution time. Optimize only where you need to. If you write clean, efficient C code then you won't have to often.

Dan.

#51079 - LOst? - Tue Aug 16, 2005 5:10 am

triton wrote:
Gotcha! But how much slower is C over assembly?

I can only give an example on the I386 platform. Doing something like this will result in the following assembler:
Code:

a += 4;
a -= 3;


Quote:

move value from memory where a is located into an empty register.
add 4 to that register.
move register back to memory where a is located.

move value from memory where a is located into an empty register.
subtrack 4 to that register.
move register back to memory where a is located.


I think the solution to skip as much memory to register moves can be avoided by doing all the calculations in one step:

Code:

a = a + 4 - 3;


Quote:

move value from memory where a is located into an empty register.
add 4 to that register.
subtrack 4 to that register.
move register back to memory where a is located.


Imagine having a in a C++ class as private, and accessing it with methods. That's a lot of code that is stupid in the end result and slows down everything:
Code:

class cA
{
private:
 int a;

public:
 void do_calculation (int add, int sub)
 {
   a += add;
   a -= sub;
 }
};


Quote:

-load a cA class into a register.
-call offset where method do_calculation is located from that register.
initialize C++ function.
load class onto the stack.

get a pointer to class cA + offset where a is located in the stack and put it into an empty register.
move the value from where that register is pointing to into yet another empty register.
add the value from stack where add is located to this register holding the value of a.
get a pointer to a where it is located in the stack and put it into a new empty register.
move the value with the sum of a and add into the location the new register is pointing at: (class cA + a in stack).

get a pointer to class cA + offset where a is located in the stack and put it into an empty register.
move the value from where that register is pointing to into yet another empty register.
subtrack the value from stack where sub is located to this register holding the value of a.
get a pointer to a where it is located in the stack and put it into a new empty register.
move the value with the difference of a and sub into the location the new register is pointing at: (class cA + a in stack).

unload class onto the stack.
uninitialize C++ function.
return to caller


Makes you wanna forget all about the power of C++ classes and OOP and just undo all this crap.

I can do these steps in assembler much easier and faster, and I could even handle my own object in memory and point to it directly, and never change the pointers, and never unload the registers when I am about to use them twice, and skip the stack. So you see what you get by trusting a C++ compilator like MSVC++. I have no idea if GCC handles classes better. Also with a RISC CPU with more register, it must be a little bit faster to handle all this, but it makes me think.
_________________
Exceptions are fun


Last edited by LOst? on Tue Aug 16, 2005 7:18 pm; edited 1 time in total

#51106 - FluBBa - Tue Aug 16, 2005 12:44 pm

A small suggestion if you really want to code in ARM assembler.
Use offsets & defines when writing to the HW registers.
Code:

 ldr r0, =0x400000c
ldrh r1, =0x1480 @600a000 screnbase 6000000 char base block
strh r1, [r0] @256 *256 text background

Could easily be changed into:
Code:

mov r0,#REG_BASE
ldr r1,=0x1480 @This should probably also use defines
strh r1,[r0,REG_BG2CNT]

But seeing how your code looks and that it is run from ROM I think Thumb compiled C code will be faster.
_________________
I probably suck, my not is a programmer.

#51140 - DekuTree64 - Tue Aug 16, 2005 7:22 pm

FluBBa wrote:
Use offsets & defines when writing to the HW registers.

Yep, yep, this makes things much easier to understand. Just because it's not C doesn't mean you should write bad code with magic numbers all over.
Also handy is named stack offsets, if you have more variables than you can fit in registers.

Sometimes I even name my registers if I'm planning to keep specific variables in them.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#51164 - sajiimori - Tue Aug 16, 2005 10:12 pm

Lost, check your compiler settings. If you've enabled optimizations and the compiler doesn't optimize a simple inline method like the one you posted, then you might need to upgrade.