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.

DS development > Resetting interrupts, and VBLANK_INTR_WAIT_FLAGS

#152078 - krozen - Sun Mar 09, 2008 2:43 pm

Hi,
I'm working through some interrupt examples. I pretty much understand interrupts, except for one thing: VBLANK_INTR_WAIT_FLAGS. I have the following function, which is called on every VBLANK:

Code:

void irq()
{
   REG_IF = IRQ_VBLANK;
   VBLANK_INTR_WAIT_FLAGS = IRQ_VBLANK;
}


Why does VBLANK_INTR_WAIT_FLAGS have to be reset similiar to REG_IF? Is this just to "reset" the interrupt on the REG_DISPSTAT "side" in the same way as we are resetting the interrupting on REG_IF?
Cheers

#152080 - tepples - Sun Mar 09, 2008 3:12 pm

krozen wrote:
Why does VBLANK_INTR_WAIT_FLAGS have to be reset similiar to REG_IF?

This location tells the BIOS that the interrupt has happened and that your ISR has handled it.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#152084 - krozen - Sun Mar 09, 2008 4:10 pm

Okay - cheers for that Tepples. So, does something similiar have to be performed for every interrupt - or does VBLANK_INTR_WAIT_FLAGS have to be set regardless of what time of interrupt fires? (by type I mean vblank, hblank, dma etc.)

#152088 - eKid - Sun Mar 09, 2008 7:48 pm

I think it should really be called INTR_WAIT_FLAGS. Since it can be used for more than just the vblank interrupt. It's for the IntrWait SWI. During that SWI the cpu goes to sleep until awoken by any interrupt. After your interrupt routine is finished it checks the flags against which interrupts you told it to wait for. The flags only has to be set for whatever you call IntrWait with. (ie, swiWaitForVBlank calls IntrWait with the vblank interrupt specified)

#152096 - Cydrak - Sun Mar 09, 2008 9:45 pm

Yup. IntrWait waits for a match, but it doesn't check IRQ registers. It couldn't, because a proper handler already acknowledged the IRQ! So if you don't set INTR_WAIT_FLAGS, it will sleep forever.

Beware that REG_IF and INTR_WAIT_FLAGS have to be set differently.
- REG_IF is a register and setting the bits actually *clears* them.
- INTR_WAIT_FLAGS is just a variable; bits *stay set* (until IntrWait clears them).
Code:
irqsPending = REG_IE & REG_IF;
INTR_WAIT_FLAGS |= irqsPending; // note: "or" required to not lose multiple IRQs
REG_IF = irqsToHandle;          // plain "=" since "or" would clear everything
... now go handle those ...

This is roughly what libnds does. I can't think why one *wouldn't* set INTR_WAIT_FLAGS to all the pending IRQs, as this lets you wait for any interrupt. Though, AFAIK you must eventually ack REG_IF, to get out of the ISR, and back to IntrWait in the first place.

#152106 - tepples - Mon Mar 10, 2008 2:42 am

eKid wrote:
I think it should really be called INTR_WAIT_FLAGS.

I called it BIOS_IF in my own header, which I used until the FAT libraries came out.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#152122 - wintermute - Mon Mar 10, 2008 12:00 pm

krozen wrote:
Hi,
I'm working through some interrupt examples. I pretty much understand interrupts, except for one thing: VBLANK_INTR_WAIT_FLAGS. I have the following function, which is called on every VBLANK:

Code:

void irq()
{
   REG_IF = IRQ_VBLANK;
   VBLANK_INTR_WAIT_FLAGS = IRQ_VBLANK;
}



It's also worth noting that any tutorial which teaches you interrupts in this manner is leading you down a road of eventual pain and suffering.

The ARM has separate user and interrupt stacks and, generally, the interrupt stack is quite small, 256 bytes with the standard setup. If you start using local variables in your interrupt handlers then it's very likely that you will overflow the interrupt stack and end up with some rather difficult bugs to track down. On the GBA and the DS ARM7 the interrupt dispatcher itself must be ARM code, not thumb.

The libnds and libgba dispatchers avoid these issues by switching the processor back to user mode before calling the user supplied interrupt handlers and allowing the code to be thumb. This particular trickery is not possible in C.

In my opinion an ARM interrupt dispatcher should never be written in C and trying to write a single function to handle all of your interrupts is going to cause you a world of hurt.
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog

#152154 - krozen - Mon Mar 10, 2008 8:04 pm

Cheers for the feedback guys.
Wintermute: I was under the impression that you could only have one ISR. Is it possible to write as ISR for each different interrupt type?

#152165 - wintermute - Mon Mar 10, 2008 11:26 pm

There's only one master ISR, known as a dispatcher. In libnds this handles all the mode switching & flag setting before handing off to the user defined handlers.

Have a look at http://tinyurl.com/yprc5h to see how it's done.

Trying to do that in C just adds unnecessary complexity you really don't need. It's possible but honestly, just don't.
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog