Fixed IRQ demo
This commit is contained in:
parent
8293982246
commit
8087aafc32
4 changed files with 87 additions and 23 deletions
5
examples/irq_demo/cm.sh
Executable file
5
examples/irq_demo/cm.sh
Executable file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# Define filename as variable
|
||||||
|
PROGNAME="irq_demo"
|
||||||
|
# Compile and assemble directly
|
||||||
|
c65gm ${PROGNAME}.c65
|
||||||
55
examples/irq_demo/irq_demo.c65
Normal file
55
examples/irq_demo/irq_demo.c65
Normal 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
|
||||||
1
examples/irq_demo/start_in_vice.sh
Executable file
1
examples/irq_demo/start_in_vice.sh
Executable file
|
|
@ -0,0 +1 @@
|
||||||
|
x64 -autostartprgmode 1 irq_demo.prg
|
||||||
49
language.md
49
language.md
|
|
@ -925,46 +925,49 @@ FEND
|
||||||
|
|
||||||
### Interrupt Handlers
|
### 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
|
```c65
|
||||||
WORD CONST IRQ_VECTOR = $0314
|
WORD CONST IRQ_VECTOR = $0314
|
||||||
WORD oldIRQ
|
WORD handler = @myIRQ // Address of our IRQ handler
|
||||||
|
|
||||||
FUNC installIRQ
|
FUNC installIRQ
|
||||||
ASM
|
ASM
|
||||||
sei // Disable interrupts
|
sei // Disable interrupts while we patch
|
||||||
ENDASM
|
ENDASM
|
||||||
|
|
||||||
oldIRQ = PEEKW IRQ_VECTOR
|
POKEW IRQ_VECTOR, handler // Point the vector at our handler
|
||||||
POKEW IRQ_VECTOR, myIRQ
|
|
||||||
|
|
||||||
ASM
|
ASM
|
||||||
cli // Enable interrupts
|
cli // Re-enable interrupts
|
||||||
ENDASM
|
ENDASM
|
||||||
FEND
|
FEND
|
||||||
|
|
||||||
|
LABEL start
|
||||||
|
installIRQ()
|
||||||
|
SUBEND // Return to BASIC; the IRQ stays installed
|
||||||
|
|
||||||
|
// No register saving needed — the kernal already did it.
|
||||||
LABEL myIRQ
|
LABEL myIRQ
|
||||||
// IRQ handler code
|
|
||||||
ASM
|
ASM
|
||||||
// Save registers
|
inc $0400 // Do the IRQ work
|
||||||
pha
|
jmp $ea31 // Let the kernal finish the IRQ
|
||||||
txa
|
|
||||||
pha
|
|
||||||
tya
|
|
||||||
pha
|
|
||||||
|
|
||||||
// Do IRQ work
|
|
||||||
inc $d020
|
|
||||||
|
|
||||||
// Restore and return
|
|
||||||
pla
|
|
||||||
tay
|
|
||||||
pla
|
|
||||||
tax
|
|
||||||
pla
|
|
||||||
rti
|
|
||||||
ENDASM
|
ENDASM
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See `examples/irq_demo/` for a complete, buildable version.
|
||||||
|
|
||||||
|
|
||||||
### Lookup Tables
|
### Lookup Tables
|
||||||
|
|
||||||
Generate tables at compile time:
|
Generate tables at compile time:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue