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.

Coding > Interrupt/stack question

#2545 - jd - Thu Feb 06, 2003 5:38 am

Hi,

I'm using interrupts in my code and most of the time it works fine. However, I have begun noticing occasional random problems. I've just been looking at the CowBite spec, and it says that the first thing the BIOS does when it is called by an interrupt is put r0-r3, r12 and LR_irq on the stack.

I believe this might be the source of the problems because inside some of my routines I'm storing the stack (r13) and then using it as a general purpose register. Of course, I restore the stack before returning or calling another function so there's not normally a problem. However, if an interrupt were to occur whilst r13 contained something other than the stack then random areas of memory would be corrupted.

First of all, is my understanding correct? If it is, is there any way to change this behaviour? In other words, I need chance to set r13 to a suitable value before the BIOS is called. Or, failing that, if I switch off interrupts whilst r13 is mangled will any interrupts that would have occured whilst interrupts were switched off be called instantly or will they be missed completely? If the latter is the case, can anyone suggest a way around this problem (apart from rewriting the code so that r13 is always the stack)?

Any help would be greatly appreciated!


Last edited by jd on Thu Feb 06, 2003 6:33 am; edited 1 time in total

#2546 - imikeyi - Thu Feb 06, 2003 6:09 am

If you set sp to point to invalid memory, then when an interrupt is called the cpu will store r0-r3 etc into this invalid area. Unfortunately, you have no control until the bios jumps to the interrupt vector (which is of course too late).

The easiest solution is to not mess with the SP. It isn't really good programming practice to change it, unless your coding something unorthodox. There are 13 other registers you could use! :)

Otherwise you could switch off interrupts before changing sp. Any interrupts that _would have occurred_, would just be ignored (eg timer).
_________________
microkernel advance

#2547 - jd - Thu Feb 06, 2003 6:31 am

imikeyi wrote:
If you set sp to point to invalid memory, then when an interrupt is called the cpu will store r0-r3 etc into this invalid area. Unfortunately, you have no control until the bios jumps to the interrupt vector (which is of course too late).


Is there no way to make it call some other code first instead?

imikeyi wrote:

The easiest solution is to not mess with the SP. It isn't really good programming practice to change it, unless your coding something unorthodox.


Unfortunately, I've already written ~7,000 lines of assembler that do mess with SP and I'm not very keen to rewrite them.

imikeyi wrote:

There are 13 other registers you could use! :)


14 surely? (Leaf functions are allowed to corrupt LR.) 14 registers is nice, but 15 is nicer. :)

imikeyi wrote:

Otherwise you could switch off interrupts before changing sp. Any interrupts that _would have occurred_, would just be ignored (eg timer).


Unfortunately, I can't afford to miss them completely. It would be ok if there was a slight delay in dealing with them, though. Is there any way to find out if an interrupt would have occured?

#2548 - imikeyi - Thu Feb 06, 2003 6:49 am

Quote:
Is there no way to make it call some other code first instead?

Not that I know of, because its an inbuilt function of the actual CPU. No matter how you write your code, it won't influence how the CPU does a stock action.

BUT
The Cowbite spec says sp gets bank swapped to sp_irq. It may very well be the case that sp_irq is loaded with a different value immediately (although I don't know what it is), hence not causing the problem you think it is..

Out of curiosity, what are you programming that means you need to use so many registers?
_________________
microkernel advance

#2550 - jd - Thu Feb 06, 2003 7:15 am

imikeyi wrote:
Not that I know of, because its an inbuilt function of the actual CPU. No matter how you write your code, it won't influence how the CPU does a stock action.


My understanding was that writing the registers to the stack was done by the BIOS, not automatically by the CPU. I was hoping there was some way to make the CPU call my own code rather than the BIOS. (Or has it been hard-wired by Nintendo?)

imikeyi wrote:
The Cowbite spec says sp gets bank swapped to sp_irq. It may very well be the case that sp_irq is loaded with a different value immediately (although I don't know what it is), hence not causing the problem you think it is..


I'm not sure how it could set sp to a valid value, which makes me think this is unlikely.

imikeyi wrote:
Out of curiosity, what are you programming that means you need to use so many registers?


Mainly texture mappers but you can pretty much always speed up code by using more registers.

#2551 - Splam - Thu Feb 06, 2003 7:25 am

There isn't a way to stop the BIOS from calling its code BUT the stack pointer is indeed swapped to the IRQ Stack so you shouldn't be seeing any problems. I've got code running using the SP as a work register and interrupts running (hblank so a lot of them) and it works fine.

#2552 - imikeyi - Thu Feb 06, 2003 7:30 am

Quote:
My understanding was that writing the registers to the stack was done by the BIOS, not automatically by the CPU.

Yep you're right, sorry about that, but it doesnt really change my point. You only gain control after the BIOS has done its thing.

The closest I've ever gotten is when writing some code for my attempt at a microkernel for the GBA. Basically my context switching code could get the process state to the very beginning of the interrupt being called. The problem in your case though is that you still have to wait for the interrupt to load before 'undoing' everything it has done. I don't see any solution this way.

Quote:
Unfortunately, I can't afford to miss them completely. It would be ok if there was a slight delay in dealing with them, though. Is there any way to find out if an interrupt would have occured?

That possibly depends on what type of interrupt it was.

EDIT: or what Splam said ;)
_________________
microkernel advance

#2554 - Splam - Thu Feb 06, 2003 8:57 am

How many interrupts are you running? If you're doing say a vblank and some dma triggered ones you may well be hitting 2 at the same time in which case you need to code for re-entrant interrupts because normal crt0's tend to set the stack (and other things) for a 1 shot handler and if another interrupt occurs (ie you let it by not clearing IME) everything will tend to go a bit pear shaped.

#2582 - jd - Fri Feb 07, 2003 8:19 pm

Splam wrote:
How many interrupts are you running?


Just the one. Thanks to the help of the people in this forum and on the gbadev list the problem has now been fixed. As you said, there is a seperate stack for interrupts (although only if you're not using devkitadv's "multiple interrupts" option) so that wasn't the source of the errors. It was actually the user stack overflowing elsewhere in my code that was the cause of the problems. D'oh!