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 > Interrupt Problem

#89303 - ProblemBaby - Sat Jun 24, 2006 3:11 am

Hi

I think my interrupt service routine isn't correct when it comes to nested interrupts. It looks like this:

Code:

   u32 i;
   for (i = 0; i < 25; i++)
   {
      if (REG_IF & BIT(i))
      {
         g_Interrupt[i].pFunction();


      }
   }
   INTERRUPT_WAITFLAGS |= REG_IE & REG_IF;
   REG_IF |= REG_IE & REG_IF;


I tried to use the one provided my libnds but it seems to handle just the VBLANK with my irqSet, irqInit etc routines. I've looked thorugh the code a few times and can't see anything that is different from my own. Is it something like memory placement that Ive missed from the things in interrupt.c? my table is also Identical with the routine and then a mask, so I cant understand why it just takes care about the vblank (and not a timer that is enabled, for example).

My question is, would it be easy to fix my own routine to make it correct or do you have any ideas why the IntrMain function doesnt works for me?

thanks

#89315 - DekuTree64 - Sat Jun 24, 2006 4:51 am

If you really mean nested interrupts, as in like allowing hblank to interrupt your vblank handler if it happens to run over, then you'll have to use a bit of assembly.

If you just want normal interrupt handling, try this instead:

Code:
   u32 flags = REG_IF | REG_IE;
   u32 i;
   for (i = 0; i < 25; i++)
   {
      if (flags & BIT(i))
      {
         g_Interrupt[i].pFunction();
      }
   }

   // BIOS flags, really just a variable. OR in the ones we handled.
   INTERRUPT_WAITFLAGS |= flags;
   // Hardware flags. Write 1 to each bit that we handled to clear them.
   REG_IF = flags;


Note that it only writes to REG_IF. ORing with it is bad, because if something happened to set a bit in IF between the time you read it to decide which handlers to call, and the time you acknowledge them, that interrupt would then be missed.

Personally I prefer this way though:

Code:
   u32 flags = REG_IF | REG_IE;
   u32 i;
   for (i = 0; i < 25; i++)
   {
      if (flags & BIT(i))
      {
         INTERRUPT_WAITFLAGS |= BIT(i);
         REG_IF = BIT(i);
         g_Interrupt[i].pFunction();
         return; // Only handle the first one we found
      }
   }

Differences being that it only handles the first interrupt it found, leaving the rest to fire off after it finishes (saves time iterating over all the bits every time), and that it acknowledges the interrupt BEFORE calling the handler. Then for example if have an enormous VBlank handler that takes over an entire frame to finish, the VBlank bit in IF will be set again even while you're blocking things up. Then as soon as you return, the next VBlank will fire off, rather than being missed entirely.

Either way works though, it's up to your personal preference.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#89339 - ProblemBaby - Sat Jun 24, 2006 11:51 am

Thanks Deku! The second method solves my problems perfectly.