Fix handling of IRQs that occur when ROM is active
This commit is contained in:
@@ -64,6 +64,15 @@ L1: lda sp,x
|
|||||||
sta ENABLE_RAM
|
sta ENABLE_RAM
|
||||||
stx $FFFE ; Install interrupt handler
|
stx $FFFE ; Install interrupt handler
|
||||||
sty $FFFF
|
sty $FFFF
|
||||||
|
ldx IRQVec
|
||||||
|
ldy IRQVec+1
|
||||||
|
stx IRQInd+1
|
||||||
|
sty IRQInd+2
|
||||||
|
ldx #<IRQStub
|
||||||
|
ldy #>IRQStub
|
||||||
|
stx IRQVec
|
||||||
|
sty IRQVec+1
|
||||||
|
|
||||||
cli ; Allow interrupts
|
cli ; Allow interrupts
|
||||||
|
|
||||||
; Clear the BSS data.
|
; Clear the BSS data.
|
||||||
@@ -94,6 +103,13 @@ _exit: pha ; Save the return code
|
|||||||
lda #0
|
lda #0
|
||||||
sta irqcount ; Disable custom IRQ handlers
|
sta irqcount ; Disable custom IRQ handlers
|
||||||
|
|
||||||
|
sei
|
||||||
|
ldx IRQInd+1
|
||||||
|
ldy IRQInd+2
|
||||||
|
stx IRQVec
|
||||||
|
sty IRQVec+1
|
||||||
|
cli
|
||||||
|
|
||||||
; Copy back the zero-page stuff.
|
; Copy back the zero-page stuff.
|
||||||
|
|
||||||
ldx #zpspace-1
|
ldx #zpspace-1
|
||||||
@@ -121,9 +137,13 @@ L2: lda zpsave,x
|
|||||||
; IRQ handler. The handler in the ROM enables the Kernal, and jumps to
|
; IRQ handler. The handler in the ROM enables the Kernal, and jumps to
|
||||||
; $CE00, where the ROM code checks for a BRK or IRQ, and branches via the
|
; $CE00, where the ROM code checks for a BRK or IRQ, and branches via the
|
||||||
; indirect vectors at $314/$316.
|
; indirect vectors at $314/$316.
|
||||||
; To make our stub as fast as possible, we skip the whole part of the ROM
|
;
|
||||||
; handler, and jump to the indirect vectors directly. We do also call our
|
; When RAM is banked in, we skip the whole part of the ROM handler, and jump to
|
||||||
; own interrupt handlers if we have any; so, they need not use $314.
|
; the indirect vectors directly, after calling our own interrupt handlers.
|
||||||
|
;
|
||||||
|
; When ROM is banked in, a stub installed in the $314 indirect vector ensures
|
||||||
|
; that our interrupt handlers are still called (otherwise, interrupts that are
|
||||||
|
; not serviced by the ROM handler may cause a deadlock).
|
||||||
|
|
||||||
.segment "LOWCODE"
|
.segment "LOWCODE"
|
||||||
|
|
||||||
@@ -138,15 +158,6 @@ IRQ: cld ; Just to be sure
|
|||||||
and #$10 ; Test for BRK bit
|
and #$10 ; Test for BRK bit
|
||||||
bne dobreak
|
bne dobreak
|
||||||
|
|
||||||
; It's an IRQ; and, RAM is enabled. If we have handlers, call them. We will use
|
|
||||||
; a flag here instead of loading __INTERRUPTOR_COUNT__ directly, since the
|
|
||||||
; condes function is not reentrant. The irqcount flag will be set/reset from
|
|
||||||
; the main code, to avoid races.
|
|
||||||
|
|
||||||
ldy irqcount
|
|
||||||
beq @L1
|
|
||||||
jsr callirq_y ; Call the IRQ functions
|
|
||||||
|
|
||||||
; Since the ROM handler will end with an RTI, we have to fake an IRQ return
|
; Since the ROM handler will end with an RTI, we have to fake an IRQ return
|
||||||
; on the stack, so that we get control of the CPU after the ROM handler,
|
; on the stack, so that we get control of the CPU after the ROM handler,
|
||||||
; and can switch back to RAM.
|
; and can switch back to RAM.
|
||||||
@@ -160,7 +171,7 @@ IRQ: cld ; Just to be sure
|
|||||||
pha ; Push faked X register
|
pha ; Push faked X register
|
||||||
pha ; Push faked Y register
|
pha ; Push faked Y register
|
||||||
sta ENABLE_ROM ; Switch to ROM
|
sta ENABLE_ROM ; Switch to ROM
|
||||||
jmp (IRQVec) ; Jump indirect to Kernal IRQ handler
|
jmp (IRQVec) ; Jump indirect to IRQ stub
|
||||||
|
|
||||||
irq_ret:
|
irq_ret:
|
||||||
sta ENABLE_RAM ; Switch back to RAM
|
sta ENABLE_RAM ; Switch back to RAM
|
||||||
@@ -182,6 +193,20 @@ nohandler:
|
|||||||
sta ENABLE_ROM
|
sta ENABLE_ROM
|
||||||
jmp (BRKVec) ; Jump indirect to the break vector
|
jmp (BRKVec) ; Jump indirect to the break vector
|
||||||
|
|
||||||
|
|
||||||
|
; IRQ stub called by the Kernal IRQ handler, via $314.
|
||||||
|
; If we have handlers, call them. We will use a flag here instead of loading
|
||||||
|
; __INTERRUPTOR_COUNT__ directly, since the condes function is not reentrant.
|
||||||
|
; The irqcount flag will be set/reset from the main code, to avoid races.
|
||||||
|
IRQStub:
|
||||||
|
cld ; Just to be sure
|
||||||
|
sta ENABLE_RAM
|
||||||
|
ldy irqcount
|
||||||
|
beq @L1
|
||||||
|
jsr callirq_y ; Call the IRQ functions
|
||||||
|
@L1: sta ENABLE_ROM
|
||||||
|
jmp (IRQInd+1) ; Jump to the saved IRQ vector
|
||||||
|
|
||||||
; ------------------------------------------------------------------------
|
; ------------------------------------------------------------------------
|
||||||
; Data
|
; Data
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user