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 > DS Interrupts

#177133 - sverx - Fri Dec 16, 2011 11:10 am

I'm not really sure I understood completely how to work with interrupts :|

I have an ARM7 code where I'm managing interrupts with many handlers: VBlank, VCount, Timer0, wi-fi... then, in the VBlank handler, I have to call some PowerManagement functions, but I read that it is unsafe to leave interrupts enabled while doing that...

So first I disabled the interrupts:
Code:
REG_IME = IME_DISABLE;

do the PowerManagement function calls, and re-enable the interrupts:
Code:
REG_IME = IME_ENABLE;


well, sometimes it happens that after doing that, the ARM7 stops managing the interrupts: for instance I'm sure that the Timer0 interrupt handler doesn't get called because it is the music timer, and I hear that the music get stuck.

Any suggestions? What does happen to the interrupts that happen when IME is disabled? Do they get queued or what?

Thanks!
_________________
libXM7|NDS programming tutorial (Italiano)|Waimanu DS / GBA|A DS Homebrewer's Diary

#177134 - Miked0801 - Fri Dec 16, 2011 4:59 pm

Make sure the clear the interrupt flag field as well.

#177135 - sverx - Fri Dec 16, 2011 5:02 pm

You mean REG_IF, right? I really don't get why should I clear that... if interrupts are disabled (IME=0), why should they raise flags in there? :|
_________________
libXM7|NDS programming tutorial (Italiano)|Waimanu DS / GBA|A DS Homebrewer's Diary

#177136 - Dwedit - Fri Dec 16, 2011 5:36 pm

Interrupts are disabled from being processed, not from triggering. So IF can change.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#177144 - sverx - Mon Dec 19, 2011 9:41 am

I see... and of course if IF isn't reset, the interrupts won't be triggered even when IME is re-enabled, right?

BTW I'm also missing how interrupts take precedence one on the other... I mean, would an interrupt interrupt another interrupt in servicing if this second one has priority? (I know how interrupt works on x86 hardware, I never deeply read how do they work on ARM...)
_________________
libXM7|NDS programming tutorial (Italiano)|Waimanu DS / GBA|A DS Homebrewer's Diary

#177145 - Miked0801 - Mon Dec 19, 2011 5:15 pm

Or you get a whole bunch as each is triggered - can't quite remember how that works.

Nested interrupts are quite possible on the DS/GBA. All you need is to not turn off interrupts (or turn them back on) at the beginning of your vector. We had VBlank, HBlank, and serial being allowed to interrupt timer interrupts.

#177147 - Dwedit - Mon Dec 19, 2011 7:23 pm

Here's what the LibGBA interrupt handler does: (I rewrote it later for my own project)

Before executing it, the BIOS pushes 6 words onto the stack (libgba handler later pushes 4 words).

* Sets REG_IME to 0 (interrupt master enable)
* Mixes with BIOS's copy of interrupt flags so BIOS wait functions work (GBA and NDS7 only)
* Linear search through the interrupt list, handlers that get added earlier are handled slightly faster. Handlers added sooner have priority over handlers added later.
If handler found:
* Acknowledges the interrupt by clearing its interrupt flag
* Switches to System mode so code runs with the normal stack. REG_IME is still at zero, so interrupts are disabled that way.
* When returning from the handler, disables interrupts again, switches to IRQ mode to return from the interrupt handler.
* Returns to the interrupt handler code, which switches back to IRQ mode so it can return to BIOS.
If no handler found:
* Acknowledges the interrupt by clearing its interrupt flag
* Returns to BIOS

After executing it, the BIOS pops its 6 words from the stack and and returns to the previous CPU mode.

10 words get put on the IRQ stack every time it handles an interrupt (when using the libgba/libnds interrupt handler).
On the GBA, the IRQ stack is 160 bytes large, so you can have up to 4 nested interrupts before it clobbers the system stack.
On NDS7, suggested size is 172 bytes large (4 nested interrupts max), on NDS9 it's 224 bytes large (5 nested interrupts max).
Make interrupt handlers can't retrigger before they are finished being handled, otherwise you can get an infinite stack overflow crash.

When I rewrote the IRQ handling code, I defined some types of interrupts as "high priority", so they jumped directly to the handler with the CPU still in IRQ mode. When they finish, they simply return to the BIOS's return code. Other handlers were not priority, and they executed in System mode (and could be interrupted).
I also replaced the linear search with fast Log 2 which always completes within 11 instructions, but I'm not sure if that's much faster.

One problem I encountered is that VCOUNT and HBLANK interrupts can be lost forever if interrupts are disabled for too long.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#177148 - sverx - Tue Dec 20, 2011 10:41 am

Thanks for the answers!
I'm using
Code:
irqSet(IRQ_VBLANK, myVblankHandler);
in my (ARM7) code, and I never had to explicitly reset REG_IF myself, it always worked fine without that, and even never had to mask REG_IE or clear REG_IME or such... so I guess other interrupts (one is TIMER0 for instance) were able to interrupt my VBlank handler without causing any problem...

Then I added that 'critical' section where I'm reading/writing PM registers, clearing REG_IME before that and setting it again when the job is done and... well, problems started. :|

Now I'll run some more tests explicitly resetting REG_IF after re-enabling REG_IME and see...

Thanks again anyway :)
_________________
libXM7|NDS programming tutorial (Italiano)|Waimanu DS / GBA|A DS Homebrewer's Diary

#177150 - sverx - Thu Dec 29, 2011 12:06 pm

for completeness, I have to add that functions that access PM registers already have been made 'safe' in libnds, since almost 3 years ago

http://sourceforge.net/apps/trac/devkitpro/browser/trunk/libnds/source/arm7/spi.c?rev=3533

so there's no need to disable and re-enable interrupts 'around' PM function calls
_________________
libXM7|NDS programming tutorial (Italiano)|Waimanu DS / GBA|A DS Homebrewer's Diary