-
Notifications
You must be signed in to change notification settings - Fork 2
Interrupts
The Language Reference - Interrupts
Interrupts are an important kind of software routine which are triggered when special events occur. These events include a system reset, non-maskable interrupt (NMI, called when NES's vblank interval is reached), or interrupt request (IRQ, which has miscellaneous uses). There is a jump table located at the high memory addresses 0xFFFA .. 0xFFFF which determine what code is called by each event.
Code will contain a snippet like this to setup the interrupt table:
in prg, 0xFFFA:
word: nmi, reset, irq
This must be done in a PRG ROM bank, or else there is no way to start the ROM or handle necessary interrupts. Some code will point irq to 0, because they don't use interrupts, but you need to be extremely careful to ensure that interrupts are off if you do that (or else it could start running code based on RAM values, which is probably not a good idea).
Here is a stripped down example layout of a program:
in prg, 0xC000:
def reset:
p: unset decimal, set interrupt
x: get #0xFF, put s, inc
// ... clear ram, setup PPU and other things
local loop:
// ... main loop code goes here
goto loop
def nmi:
a: push, get x, push, get y, push
// ... vblank handler code goes here
a: pull, put y, pull, put x, pull
resume
def irq:
a: push, get x, push, get y, push
// ... IRQ handler code goes here.
a: pull, put y, pull, put x, pull
resume
in prg, 0xE000:
// ... some ROM data, etc.
in prg, 0xFFFA:
word: nmi, reset, irq
There are a few important things to notice here. reset
is the "main program" which do setup and then have an infinite loop where all the processing code goes, and it is interrupted by the nmi
and irq
handlers which handle events and then resume to the main program. To prevent corruption of registers in the main program, the nmi
and irq
will save all the registers by pushing them on the stack, do something, and then restore all the registers by pulling the values off the stack. nmi
and irq
then use a statement called rti
to resume the main program.
resume
(Opcode 0x40, 6502 mnemonic rti
) is responsible for resuming code where it left off before an interrupt, and will restore processor flags and retreive the old program counter off of the stack.
Subroutines use call
and return
, but interrupts are triggered by external factors and use resume
. The restoration of processor flags makes resume
different, and this way branching and calculations performed in the main code is not as screwed up (although you still need to push/pull the other registers which you use in your interrupts manually). Also, unlike return
which expects to get (program counter - 1), resume
expects the program counter unsubtracted.