From f8e57f1cf26a486371e7090d395827169c622081 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 4 Jun 2020 22:19:10 +0200 Subject: [PATCH] safer NMI handling --- c64/basic/wedge_tape.s | 5 +- .../interrupts/ea81.return_from_interrupt.s | 4 ++ c64/kernal/interrupts/hw_entry_nmi.s | 9 ++- c64/kernal/interrupts/nmi_lock.s | 60 +++++++++++++++++++ c64/kernal/memory/vector_real.s | 5 +- c64/kernal/panic.s | 13 +++- c64/kernal/tape/load_tape_normal.s | 3 + c64/kernal/tape/load_tape_turbo.s | 3 + c64/kernal/tape/tape_common.s | 14 ++++- c64/kernal/tape/tape_head_align.s | 17 ++++-- 10 files changed, 114 insertions(+), 19 deletions(-) create mode 100644 c64/kernal/interrupts/nmi_lock.s diff --git a/c64/basic/wedge_tape.s b/c64/basic/wedge_tape.s index 705e41ad..13dee5aa 100644 --- a/c64/basic/wedge_tape.s +++ b/c64/basic/wedge_tape.s @@ -56,7 +56,10 @@ wedge_arrow_L: wedge_arrow_H: jsr tape_head_align - jmp basic_main_loop + + jsr print_return + ldx #B_ERR_BREAK + jmp do_basic_error #endif diff --git a/c64/kernal/interrupts/ea81.return_from_interrupt.s b/c64/kernal/interrupts/ea81.return_from_interrupt.s index 4a834206..9372d84d 100644 --- a/c64/kernal/interrupts/ea81.return_from_interrupt.s +++ b/c64/kernal/interrupts/ea81.return_from_interrupt.s @@ -20,4 +20,8 @@ return_from_interrupt: plx_trash_a pla + // FALLTROUGH + +return_from_interrupt_rti: + rti diff --git a/c64/kernal/interrupts/hw_entry_nmi.s b/c64/kernal/interrupts/hw_entry_nmi.s index 2ed19829..225f9397 100644 --- a/c64/kernal/interrupts/hw_entry_nmi.s +++ b/c64/kernal/interrupts/hw_entry_nmi.s @@ -5,17 +5,16 @@ hw_entry_nmi: - sei // do not allow IRQ to interfere, see https://www.c64-wiki.com/wiki/Interrupt + sei // do not allow IRQ to interfere, see https://www.c64-wiki.com/wiki/Interrupt #if CONFIG_CPU_MOS_6502 && CONFIG_BCD_SAFE_INTERRUPTS - cld // clear decimal flag to allow using it without disabling interrupts + cld // clear decimal flag to allow using it without disabling interrupts #endif // Call interrupt routine (only if initialised) pha - lda NMINV - ora NMINV+1 - beq !+ + lda NMINV+1 // consider zeropage NMI address as uninitialized vector + beq !+ // this allows safer interrupt vector modifications pla jmp (NMINV) !: diff --git a/c64/kernal/interrupts/nmi_lock.s b/c64/kernal/interrupts/nmi_lock.s new file mode 100644 index 00000000..0b1462ee --- /dev/null +++ b/c64/kernal/interrupts/nmi_lock.s @@ -0,0 +1,60 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * KERNAL_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Routine to lock NMI interrupts, using a trick described here: +// - https://codebase64.org/doku.php?id=base:nmi_lock +// + + +#if CONFIG_TAPE_HEAD_ALIGN + + +// XXX consider broader usage of this method to make IO safer + + +nmi_lock: + + // We will have to change NMI vector to point empty routine, + // which will not acknowledge the interrupt - thus preventing + // the NMI to be triggered again + + // Our code considers zeropage address invalid, so put + // it there as a preparation + + ldx #$00 + stx NMINV+1 + + // We can now safelly replace the vector + + lda #return_from_interrupt_rti + sta NMINV+1 + + // Stop timer A + + stx CIA2_CRA // $DD0E + + // Set timer A to 0, after starting NMI will occur immediately + + stx CIA2_TIMALO // $DD04 + stx CIA2_TIMAHI // $DD05 + + // Set timer A as source for NMI + + lda #$81 + sta CIA2_ICR // $DD0D + + // Start timer A to trigger the NMI + + lda #$01 + sta CIA2_CRA // $DD0E + + // All done. Unmaskable interrupts are now masked. + + rts + + +#endif diff --git a/c64/kernal/memory/vector_real.s b/c64/kernal/memory/vector_real.s index 1d5e379b..9440fa34 100644 --- a/c64/kernal/memory/vector_real.s +++ b/c64/kernal/memory/vector_real.s @@ -23,6 +23,9 @@ vector_real: sty MEMUSS + 1 stx MEMUSS + 0 + lda #$00 + sta NMINV + 1 // our routine considers this a disabled interrupt + // Select routine variant - store or restore vectors ldy #$1F bcc vector_restore @@ -30,7 +33,7 @@ vector_real: lda CINV, y sta (MEMUSS), y - bcs vector_end_loop // branch always + bcs vector_end_loop // branch always vector_restore: lda (MEMUSS), y diff --git a/c64/kernal/panic.s b/c64/kernal/panic.s index aa37b876..7e2ef9c4 100644 --- a/c64/kernal/panic.s +++ b/c64/kernal/panic.s @@ -22,11 +22,18 @@ panic: jsr setup_vicii jsr clear_screen - // Disable NMIs - our routine checks for NULL vector + // Disable NMIs + +#if CONFIG_TAPE_HEAD_ALIGN + + jsr nmi_lock + +#else lda #$00 - sta NMINV+0 - sta NMINV+1 + sta NMINV + 1 // our routine does not allow zeropage vectors + +#endif // Display KERNAL PANIC message diff --git a/c64/kernal/tape/load_tape_normal.s b/c64/kernal/tape/load_tape_normal.s index c53dabdb..c1ecd776 100644 --- a/c64/kernal/tape/load_tape_normal.s +++ b/c64/kernal/tape/load_tape_normal.s @@ -45,6 +45,9 @@ load_tape_normal: // Start playing jsr tape_common_prepare_cia jsr tape_ask_play +#if CONFIG_TAPE_HEAD_ALIGN + jsr tape_prepare_reading +#endif // FALLTROUGH diff --git a/c64/kernal/tape/load_tape_turbo.s b/c64/kernal/tape/load_tape_turbo.s index 7c421e90..fe20438e 100644 --- a/c64/kernal/tape/load_tape_turbo.s +++ b/c64/kernal/tape/load_tape_turbo.s @@ -32,6 +32,9 @@ load_tape_auto: // Start playing jsr tape_common_prepare_cia jsr tape_ask_play +#if CONFIG_TAPE_HEAD_ALIGN + jsr tape_prepare_reading +#endif // FALLTROUGH diff --git a/c64/kernal/tape/tape_common.s b/c64/kernal/tape/tape_common.s index fa813aef..f254dc43 100644 --- a/c64/kernal/tape/tape_common.s +++ b/c64/kernal/tape/tape_common.s @@ -104,6 +104,17 @@ tape_wait_first_pulse: tape_wait_play_done: + lda #$01 + sta CAS1 // set the interlock + +#if CONFIG_TAPE_HEAD_ALIGN + + rts + +tape_prepare_reading: + +#endif // CONFIG_TAPE_HEAD_ALIGN + #if CONFIG_MB_MEGA_65 // Display confirmation @@ -115,9 +126,6 @@ tape_wait_play_done: // Prepare for reading - lda #$01 - sta CAS1 // set the interlock - jsr print_return jmp tape_screen_off_motor_on diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index b0d38594..756d9ec0 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -12,9 +12,7 @@ // XXX for Mega65 it can be done more easily, by just disabling the badlines -// XXX consider "PRESS PLAY ON TAPE" before start, with option to stop // XXX document CONFIG_TAPE_HEAD_ALIGN option -// XXX block NMIs // XXX fix Mega65 build compilation issues @@ -50,12 +48,22 @@ tape_head_align: #else + // Make sure user really wants to launch the tool + + jsr tape_ask_play + // Disable interrupts, set proper I/O values jsr CLALL + sei + jsr IOINIT - jsr cint_legacy + jsr CINT + + jsr nmi_lock + + // Prepare CIA timers ldx #$02 // set timer A to 3 ticks jsr tape_common_prepare_cia_by_x @@ -111,8 +119,6 @@ tape_head_align: dey bne !- - - // Set graphics mode lda #$28 // graphics start at $2000, color at $0800 @@ -252,7 +258,6 @@ tape_head_align_drawn: beq tape_head_align_loop_1 - tape_head_align_quit: // It makes no sense to return to system, as we already destroyed