From b7fef8abe68810a07f6e0ccb7a9f28e5d2c5c6ce Mon Sep 17 00:00:00 2001 From: Christian Werner Date: Sun, 18 Oct 2026 08:57:01 +0200 Subject: [PATCH] feat(arnitech): handlers for a 65816's native-mode interrupts on a Blade A Blade reads the 65816's native-mode vectors from the RAM under the KERNAL at $FFE4-$FFEF. native_vectors_init puts handlers' addresses there: IRQ and NMI save A, X, and Y at full width, the direct page, and the data bank, push the frame an emulation-mode interrupt makes, and run the KERNAL's handlers through CINV and NMINV in 8-bit native mode, whose RTI comes back to restore everything. BRK, COP, and ABORT go to the BRK handler, which on a Blade first sets the direct page and data bank to 0 and returns to emulation mode. --- src/aliases/,aliases_hardware_arnitech.s | 7 ++ src/kernal/arnitech/arnitech_native.s | 106 ++++++++++++++++++ .../interrupts/fe66.default_brk_handler.s | 14 ++- 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 src/kernal/arnitech/arnitech_native.s diff --git a/src/aliases/,aliases_hardware_arnitech.s b/src/aliases/,aliases_hardware_arnitech.s index 134ceb15..4013b724 100644 --- a/src/aliases/,aliases_hardware_arnitech.s +++ b/src/aliases/,aliases_hardware_arnitech.s @@ -33,3 +33,10 @@ !addr RRNET_TX_CMD = $DE0C ; write-only !addr RRNET_TX_LENGTH = $DE0E ; write-only } + +!ifdef CONFIG_ARNITECH_BLADE { + + ; The 65816's native-mode vectors, which a Blade reads from the RAM under the KERNAL (ADR 0029) + + !addr NATIVE_VECTORS = $FFE4 ; COP, BRK, ABORT, NMI, reserved, IRQ +} diff --git a/src/kernal/arnitech/arnitech_native.s b/src/kernal/arnitech/arnitech_native.s new file mode 100644 index 00000000..92bdebcb --- /dev/null +++ b/src/kernal/arnitech/arnitech_native.s @@ -0,0 +1,106 @@ +;; #LAYOUT# STD * #TAKE +;; #LAYOUT# * * #IGNORE + +; +; The 65816's native-mode interrupts on a Blade (mc64blade only, arnitech's ADR 0029 and 0030) +; +; In native mode the 65816 fetches its vectors from $FFE4-$FFEF, where the KERNAL's jump table +; has its JMPs, so a Blade reads them from the RAM under the KERNAL, which CINT fills. A program +; that switches to native mode with interrupts on keeps running: the IRQ and NMI handlers save +; the registers, the direct page, and the data bank, run the KERNAL's handlers through CINV and +; NMINV in 8-bit native mode on direct page 0 and data bank 0, and return with RTI. BRK, COP, and +; ABORT go to the BRK handler, which returns to emulation mode and to READY. The code here runs +; only on a 65816, so its own opcodes are bytes. +; + +!ifdef CONFIG_ARNITECH_BLADE { + +native_vectors_init: + + ldx #(__native_vector_table_end - native_vector_table - 1) +@1: + lda native_vector_table, x + sta NATIVE_VECTORS, x ; with the KERNAL banked in, the write reaches the RAM under it + dex + bpl @1 + rts + +native_vector_table: + + !word default_brk_handler ; COP + !word default_brk_handler ; BRK + !word default_brk_handler ; ABORT + !word native_nmi ; NMI + !word default_brk_handler ; reserved + !word native_irq ; IRQ + +__native_vector_table_end: + +; +; IRQ and NMI in native mode, with any register widths: the registers go on the stack whole, +; then a frame as an IRQ or NMI makes it in emulation mode, whose RTI comes back to native_return. +; + +native_irq: + + !byte $C2, $30 ; REP #$30: 16-bit A, X, and Y + pha + !byte $A9 ; LDA #: the handler's address, less one, for RTS + !word native_irq_kernal - 1 + !byte $80 ; BRA native_save + !byte native_save - (* + 1) + +native_nmi: + + !byte $C2, $30 ; REP #$30 + pha + !byte $A9 ; LDA # + !word hw_entry_nmi - 1 + + ; FALLTROUGH + +native_save: + + !byte $DA ; PHX + !byte $5A ; PHY + !byte $8B ; PHB + !byte $0B ; PHD + tax ; the handler's address, 16 bits + !byte $F4, $00, $00 ; PEA $0000 + !byte $2B ; PLD: direct page 0 + !byte $E2, $20 ; SEP #$20: 8-bit A + lda #$00 + pha + !byte $AB ; PLB: data bank 0 + + ; The frame the KERNAL's handler returns through: program bank, address, status (8-bit A, + ; X, and Y, interrupts off) + + pha + !byte $F4 ; PEA native_return + !word native_return + lda #$34 + pha + !byte $DA ; PHX: the handler's address, for RTS + !byte $E2, $30 ; SEP #$30: 8-bit X and Y + rts + +native_irq_kernal: + + ; The KERNAL's IRQ handlers end by pulling Y, X, and A, as hw_entry_irq pushes them + + pha + pha + pha + jmp (CINV) + +native_return: + + !byte $C2, $30 ; REP #$30 + !byte $2B ; PLD + !byte $AB ; PLB + !byte $7A ; PLY + !byte $FA ; PLX + pla + rti +} diff --git a/src/kernal/interrupts/fe66.default_brk_handler.s b/src/kernal/interrupts/fe66.default_brk_handler.s index 94a5e1d0..a956cd6a 100644 --- a/src/kernal/interrupts/fe66.default_brk_handler.s +++ b/src/kernal/interrupts/fe66.default_brk_handler.s @@ -9,7 +9,19 @@ default_brk_handler: sei ; disable IRQs, to be sure they wont interfere -!ifdef CONFIG_PLATFORM_COMMODORE_64 { +!ifdef CONFIG_ARNITECH_BLADE { + + ; A Blade's 65816 comes here from BRK, COP, and ABORT in native mode too (arnitech_native.s): + ; direct page 0, data bank 0, and back to emulation mode + + !byte $F4, $00, $00 ; PEA $0000 + !byte $2B ; PLD + !byte $4B ; PHK + !byte $AB ; PLB + sec + !byte $FB ; XCE + +} else ifdef CONFIG_PLATFORM_COMMODORE_64 { ldx #$00 sta VIC_SCROLX ; turn the display off - we want as little screen artifacts as possible