Fixed IRQ demo

This commit is contained in:
Mattias Hansson 2026-07-12 18:51:28 +02:00
parent 8293982246
commit 8087aafc32
4 changed files with 87 additions and 23 deletions

5
examples/irq_demo/cm.sh Executable file
View file

@ -0,0 +1,5 @@
#!/bin/sh
# Define filename as variable
PROGNAME="irq_demo"
# Compile and assemble directly
c65gm ${PROGNAME}.c65

View file

@ -0,0 +1,55 @@
//-----------------------------------------------------------
// Simple IRQ Handler Demo
//
// Installs a custom IRQ handler through the kernal vector at
// $0314. The kernal has already saved the registers for us
// before it calls the vector, so our handler does NOT push or
// pull A/X/Y. When we are done we jump into the kernal so it
// can finish the IRQ and RTI properly:
//
// jmp $ea31 - let the kernal do its full IRQ work
// (scan keyboard, blink cursor, update jiffy
// clock, ...) and then RTI
// jmp $ea81 - skip the kernal work, just restore the
// registers the kernal saved and RTI
//
// This handler chains to $ea31 so the machine stays usable.
//-----------------------------------------------------------
#INCLUDE <c64start.c65>
#INCLUDE <c64defs.c65>
GOTO start
WORD CONST IRQ_VECTOR = $0314
WORD handler = @myIRQ // Address of our IRQ handler
FUNC installIRQ
ASM
sei // Disable interrupts while we patch
ENDASM
POKEW IRQ_VECTOR, handler // Point the vector at our handler
ASM
cli // Re-enable interrupts
ENDASM
FEND
LABEL start
installIRQ()
SUBEND //exit back to basic
//-----------------------------------------------------------
// The IRQ handler.
//
// No register saving needed - the kernal did it. Do the work,
// then hand control back to the kernal at $ea31 which restores
// the registers and returns from the interrupt.
//-----------------------------------------------------------
LABEL myIRQ
ASM
inc $0400 // Bump the top-left screen character
jmp $ea31 // Let the kernal finish the IRQ
ENDASM

View file

@ -0,0 +1 @@
x64 -autostartprgmode 1 irq_demo.prg

View file

@ -925,46 +925,49 @@ FEND
### Interrupt Handlers
The C64 kernal calls the IRQ vector at `$0314` on every interrupt. Because
the kernal saves the CPU registers *before* calling the vector, your handler
does **not** need to push/pull A/X/Y itself. When finished, chain into the
kernal so it restores the registers and returns from the interrupt:
- `jmp $ea31` — let the kernal do its full IRQ work (scan keyboard, blink
cursor, update the jiffy clock, ...) and then `RTI`
- `jmp $ea81` — skip that work; just restore the saved registers and `RTI`
Once the vector is installed it keeps firing in the background, so the main
program can simply return to BASIC with `SUBEND` — the handler stays live.
```c65
WORD CONST IRQ_VECTOR = $0314
WORD oldIRQ
WORD handler = @myIRQ // Address of our IRQ handler
FUNC installIRQ
ASM
sei // Disable interrupts
sei // Disable interrupts while we patch
ENDASM
oldIRQ = PEEKW IRQ_VECTOR
POKEW IRQ_VECTOR, myIRQ
POKEW IRQ_VECTOR, handler // Point the vector at our handler
ASM
cli // Enable interrupts
cli // Re-enable interrupts
ENDASM
FEND
LABEL start
installIRQ()
SUBEND // Return to BASIC; the IRQ stays installed
// No register saving needed — the kernal already did it.
LABEL myIRQ
// IRQ handler code
ASM
// Save registers
pha
txa
pha
tya
pha
// Do IRQ work
inc $d020
// Restore and return
pla
tay
pla
tax
pla
rti
inc $0400 // Do the IRQ work
jmp $ea31 // Let the kernal finish the IRQ
ENDASM
```
See `examples/irq_demo/` for a complete, buildable version.
### Lookup Tables
Generate tables at compile time: