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 > need help getting TONCs intterrupt handler to work in vham

#86606 - Ant6n - Thu Jun 08, 2006 6:31 am

Hey,

I am disturbing the peace and quietness in these forums again to bring up a question of the past...
I am trying to get a little library working (to be used in some class); I would like it to be standalone, so libga is not much of an option.
For the time being I would like to use tonc's intterrupt handler,
http://user.chem.tue.nl/jakvijn/tonc/interrupts.htm, because as I understand it can handle multiple interrupts, but they are not nested (i.e. they are run one after another).
It doesnt seem to do anything. Right now I am using visual ham (as far as I know it shouldnt make much of a difference what compiler to use).

I have the handler, 'irqhandler.S'

Code:
   .extern interrupttable

    .section .iwram,"ax",%progbits
    .code   32
    .align  2
    .global interrupthandler
interrupthandler:
@ (1)
    @ Single interrupts support
    mov     r3, #0x04000000         @ REG_BASE
    ldr     r2, [r3, #0x200]        @ Read REG_IE and REG_IF
    and     r1, r2, r2, lsr #16     @ r1 =  REG_IE & REG_IF
@ (2)
    ldrh    r2, [r3, #-8]           @\mix up with BIOS irq flags at 3007FF8h,
    orr     r2, r2, r1              @ aka mirrored at 3FFFFF8h, this is required
    strh    r2, [r3, #-8]           @/when using the (VBlank)IntrWait functions

@ (3)
    add     r3, r3, #0x200
    ldr     r2, =interrupttable
@ V-Blank Interrupt
    ands    r0, r1, #0x0001
    bne     .Ljump_intr
    add     r2, r2, #4
@ H-Blank Interrupt
    ands    r0, r1, #0x0002
    bne     .Ljump_intr
    add     r2, r2, #4
@ V Counter Interrupt
    ands    r0, r1, #0x0004
    bne     .Ljump_intr
    add     r2, r2, #4
@ Timer 0 Interrupt
    ands    r0, r1, #0x0008
    bne     .Ljump_intr
    add     r2, r2, #4
    @ Timer 1 Interrupt
    ands    r0, r1, #0x0010
    bne     .Ljump_intr
    add     r2, r2, #4
@ Timer 2 Interrupt
    ands    r0, r1, #0x0020
    bne     .Ljump_intr
    add     r2, r2, #4
@ Timer 3 Interrupt
    ands    r0, r1, #0x0040
    bne     .Ljump_intr
    add     r2, r2, #4
@ Serial Communication  Interrupt
    ands    r0, r1, #0x0080
    bne     .Ljump_intr
    add     r2, r2, #4
@ DMA0 Interrupt
    ands    r0, r1, #0x0100
    bne     .Ljump_intr
    add     r2, r2, #4
@ DMA1 Interrupt
    ands    r0, r1, #0x0200
    bne     .Ljump_intr
    add     r2, r2, #4
@ DMA2 Interrupt
    ands    r0, r1, #0x0400
    bne     .Ljump_intr
    add     r2, r2, #4
@ DMA3 Interrupt
    ands    r0, r1, #0x0800
    bne     .Ljump_intr
    add     r2, r2, #4
@ Key Interrupt
    ands    r0, r1, #0x1000
    bne     .Ljump_intr
    add     r2, r2, #4
@ Cart Interrupt
    ands    r0, r1, #0x2000
    strneb  r0, [r3, #0x84-0x200] @ Stop  sound if cart removed (REG_SOUNDCNT_X)
.Lloop:
    bne     .Lloop                  @ Infinite  loop if cart removed
@ (4)
.Ljump_intr:
    strh    r0, [r3, #2]            @ Acknowlegde int (will clear REG_IF)
    ldr     r0, [r2]                @ Jump  to user IRQ process
    bx      r0


    .align  2
    .pool


and the lib_interrupt.c

Code:
#include "lib_interrupt.h"
#include "lib_type.h"


fnptr interrupttable[14];
extern fnptr interrupthandler;
extern fnptr hblank;

void irq_set(int flags, fnptr irq_handle, int priority)
{
   int i;
   for(i = 0; i < 14; i++)
   {
      if(flags & BIT(i))
         interrupttable[i] = irq_handle;
   }
   REG_IRQ_HANDLER = interrupthandler;
   REG_IME  = 0;
   REG_IE |= flags;
   REG_IME = 1;
}

void irq_disable(int flags)
{
   REG_IME = 0;
   REG_IE &= ~flags;
   REG_IME = 1;
}


and some main.c

Code:

#include "lib_math.h"
#include "lib_time.h"
#include "lib_register.h"
#include "lib_interrupt.h"

fnptr* IntrTable;


void WaitForVblank(void)
{
   while(!(REG_DISPSTAT & 1));
   while(REG_DISPSTAT & 1);
}

void hblank(void)
{
   *(vu16*)0x05000000 ^= 0x7FFF;
}


int main(void)
{
    unsigned char x,y;
    REG_DISPCNT = (4 | 1024);
   *(vu16*)0x05000000 = 31*32;
    for(x = 0; x < 240; x++)
        for(y = 0; y < 160; y++)
            ((vu16*)0x06000000)[x+ y * 240] = 0;
    //set up our interrupt
   REG_DISPSTAT = 32 | (80 << 8);
   irq_set(4,hblank,0);
    while(1)
   {
      WaitForVblank();
      //*(vu16*)0x05000000 = 31*32;
   }
   return 0;
}



this code should basicly invert the backdrop coloer in mode 4 every 80th scanline, so it should flash a lot. It doesnt. If I set the little 'hblank' function directly as the handler, then it does. I somehow suspect there might be a general problem here. As far as i know ham supports interworking, so I am kind of stuck... any ideas?

thank you
Anton Dubrau

#86621 - Cearn - Thu Jun 08, 2006 9:22 am

Ant6n wrote:
Code:
fnptr interrupttable[14];
extern fnptr interrupthandler;
extern fnptr hblank;

void irq_set(int flags, fnptr irq_handle, int priority)
{
   int i;
   for(i = 0; i < 14; i++)
   {
      if(flags & BIT(i))
         interrupttable[i] = irq_handle;
   }
   REG_INTMAIN = interrupthandler;
   REG_IME  = 0;
   REG_IE |= flags;
   REG_IME = 1;
}
interrupthandler is not a function pointer, it is a function. The way it's set up now, interrupthandler is seen as a variable containing an address of a function, where in fact it's an instruction. Use the proper declaration, with attributes:
Code:
__attribute__((section(".iwram"), long_call)) void interrupthandler(void);

Do the same for hblank().

As a side note, it may be better to use libgba's or pern's irq-handler; while this one can do multiple interrupts, it's not exactly safe. And, yes, the obligatory note on
Code:
    unsigned char x,y;
Ints please. Anything else just slows things down unnecessarily.

#86724 - Ant6n - Thu Jun 08, 2006 8:11 pm

thank you; it works beautifully now. I also switched to perns handler.
Btw, is there information (i.e. a tutorial) on the ominous __attribute__'s
or things like the inline assembler (I still try to figure out whether
they can be dependent on whether the code around it is thumb or arm...) ?
thx
anton