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 > Timers, etc.

#29478 - AlbaTalpa - Sat Nov 20, 2004 11:27 pm

Hi guys,

I'm a student at UMass Amherst, and I'm programming the GBA as a project for an architecture and assembly course I'm taking this semester. It has to be entirely in assembly, but the usual tutorials for beginners are in C, so it's been a little difficult to find information. Right now, the GBAGuy tutorial and the Cowbite spec are my main sources.

Anyway, I've managed to print pixels to the screen and read buttons in. What I'm working on right now is timers, and it's not going so well. Here's my code:

Code:

.arm
.text

;=====================================================
; Place a pixel on screen every second (give or take).
;=====================================================

countStore   @DCD   0

main:
;------------------
;Black out screen
;------------------
      mov   r0, #0x4000000
      mov   r1, #0x400
      add   r1, r1, #3
      str   r1, [r0]
      mov   r0, #0x6000000
      mov   r1, #0x0000   ;color = black
      mov   r2, #0x9600
loop1:
      strh   r1, [r0], #2
      subs   r2, r2, #1
      bne   loop1

;------------------------
;Prepare Interrupt Regs
;------------------------

      ldr   r0,=0x4000208      ;0x4000208 is REG_IME
      mov   r1,#0x1
      str   r1,[r0]         ;enable interrupt master

      ldr   r0,=0x3007FFC      ;0x3007FFC is REG_INTADDR, mem to jump to
      ldr   r1,=doPixel      ;get address of doPixel
      str   r1,[r0]         ;jump to doPixel on interrupt

      ldr   r0,=0x4000200      ;0x4000200 is REG_IE
      mov   r1,#0x20      ;bit 5 is Timer 2
      str   r1,[r0]         ;Select Timer 2 Interrupt

      ldr   r0,=0x400010A      ;0x400010A is REG_TM2CNT
      mov   r1,#0x82      ;Pattern 1000 0010
      str   r1,[r0]         ;freq about 1 sec, enable

      mov   r1,#0
      mov   r2,#0
      mov   r3,#0xFF      ;reddish color

      b   infin

;-------------------
;Interrupt Code
;-------------------
doPixel:   ldr   r4,=0x4000208
      mov   r5,#0
      str   r5,[r4]         ;disable interrupt master

      bl   pixel
      add   r1,r1,#1
      ldr   r4,=countStore
      str   r1,[r4]         ;save changes in r1

      ldr   r4,=0x4000208
      mov   r5,#1
      str   r5,[r4]         ;re-enable interrupt master

      bx   lr

;----------------------
;Loop Until Interrupt
;----------------------
infin:
      ldr   r0,=countStore
      ldr   r1,[r0]         ;preserve any changes in r1 during interrupt
      b   infin

;----------------------------------
;Place a color (r3) at x=r1, y=r2
;----------------------------------

pixel:
      str   r0,[sp,#-4]!
      str   r1,[sp,#-4]!
      str   r2,[sp,#-4]!
      mov   r0, #0x6000000      ;start of buffer
      rsb   r2,r2,r2,LSL #4      ;pos = 16y - y
      mov   r2,r2,LSL #5      ;pos = 2*16(16y - y) = 2*240y
      add   r2,r2,r1,LSL #1      ;pos = 2*240y + 2*x
      add   r0,r0,r2
      strh   r3,[r0]
      ldr   r2,[sp],#4
      ldr   r1,[sp],#4
      ldr   r0,[sp],#4
      mov   pc,lr


This is supposed to fill in the screen, from top left to bottom right, one pixel at a time. Nothing happens. It's probably just a stupid mistake somewhere. I hope you guys can help me out.

You might also notice something weird about my pixel subroutine. I figured the formula for the offset to place a pixel would just be 240y+x. When I coded it that way, though, the co-ordinates were half what they were supposed to be. If I told it x=80, y=120, it would end up at (40,60). I multiplied everything by two to fix it, but that's kind of hackish. What's the deal? :-/

Thanks, and please forgive my n00bery.
-AlbaTalpa

#29484 - getch - Sun Nov 21, 2004 12:13 am

AlbaTalpa wrote:
You might also notice something weird about my pixel subroutine. I figured the formula for the offset to place a pixel would just be 240y+x. When I coded it that way, though, the co-ordinates were half what they were supposed to be. If I told it x=80, y=120, it would end up at (40,60). I multiplied everything by two to fix it, but that's kind of hackish. What's the deal? :-/


Sorry, I dont know a think about ASM, but I think the reason your coords are halved might be because each 16-bit word in VRAM has 2 pixels stored in little-endian (?) mode.
_________________
-pb

#29490 - keldon - Sun Nov 21, 2004 1:30 am

if you're in 16-bit BG mode then screenX = x*2 because each pixel is 2 bytes.

#29529 - poslundc - Sun Nov 21, 2004 4:21 pm

With regards to why your interrupt doesn't work:

1. doPixel (and its subroutine pixel) needs to behave like a proper subroutine. This means you can't expect any of the registers to contain values from your main program, and you need to preserve any register changes you make across the function call (with some exceptions). To share data between your program and your ISR or to preserve the state of your pixel program you need to store those values in a global memory location that both the main program and your interrupt can access. The only registers you can freely modify are r0-r3 and r12; any other registers must be saved to the stack at the beginning of your routine and popped off the stack at the end.

2. At the end of the ISR you need to acknowledge that the interrupt has been completed by writing to the appropriate bit in REG_IF.

Dan.

#29610 - ozahid - Mon Nov 22, 2004 4:05 pm

Yah VERTS! WHOOOO!

... i'm in his class
_________________
http://people.umass.edu/ozahid