From 608dbc2cec5e9cc7e9e9b96c139d838837c7df3b Mon Sep 17 00:00:00 2001
From: Christian Groessler <chris@groessler.org>
Date: Tue, 22 Apr 2014 15:48:49 +0200
Subject: [PATCH 1/4] Workaround for "phantom" key presses in the C128
 "joystick" mouse driver.

---
 libsrc/c128/mou/c128-joy.s | 79 ++++++++++++++++++++++++++++++++++++++
 libsrc/c128/mouseref.s     | 69 +++++++++++++++++++++++++++++++++
 2 files changed, 148 insertions(+)

diff --git a/libsrc/c128/mou/c128-joy.s b/libsrc/c128/mou/c128-joy.s
index be0cf227b..fb087c8fc 100644
--- a/libsrc/c128/mou/c128-joy.s
+++ b/libsrc/c128/mou/c128-joy.s
@@ -11,6 +11,8 @@
 
         .macpack        generic
 
+IRQInd  = $2FD
+
 ; ------------------------------------------------------------------------
 ; Header. Includes jump table
 
@@ -25,6 +27,7 @@ HEADER:
 
 ; Library reference
 
+libref:
         .addr   $0000
 
 ; Jump table
@@ -70,6 +73,15 @@ SCREEN_WIDTH    = 320
         FIRE    = $10
 .endenum
 
+;----------------------------------------------------------------------------
+; data segment
+
+.data
+
+chainIRQ:
+        .byte   $4c                     ; JMP opcode
+        .word   0                       ; pointer to ROM IRQ handler (will be set at runtime)
+
 ;----------------------------------------------------------------------------
 ; Global variables. The bounding box values are sorted so that they can be
 ; written with the least effort in the SETBOX and GETBOX routines, so don't
@@ -92,6 +104,10 @@ INIT_save:      .res    1
 
 Temp:           .res    1
 
+; Keyboard buffer fill level at start of interrupt
+
+old_key_count:  .res    1
+
 .rodata
 
 ; Default values for above variables
@@ -146,6 +162,35 @@ INSTALL:
         jsr     CMOVEY
         cli
 
+; Initialize our IRQ magic
+
+        lda     IRQInd+1
+        sta     chainIRQ+1
+        lda     IRQInd+2
+        sta     chainIRQ+2
+        lda     libref
+        sta     ptr3
+        lda     libref+1
+        sta     ptr3+1
+        ldy     #2
+        lda     (ptr3),y
+        sta     IRQInd+1
+        iny
+        lda     (ptr3),y
+        sta     IRQInd+2
+        iny
+        lda     #<(callback-1)
+        sta     (ptr3),y
+        iny
+        lda     #>(callback-1)
+        sta     (ptr3),y
+        iny
+        lda     #<(chainIRQ-1)
+        sta     (ptr3),y
+        iny
+        lda     #>(chainIRQ-1)
+        sta     (ptr3),y
+
 ; Done, return zero (= MOUSE_ERR_OK)
 
         ldx     #$00
@@ -157,6 +202,12 @@ INSTALL:
 ; No return code required (the driver is removed from memory on return).
 
 UNINSTALL:
+
+        lda     chainIRQ+1
+        sta     IRQInd+1
+        lda     chainIRQ+2
+        sta     IRQInd+2
+
         jsr     HIDE                    ; Hide cursor on exit
         lda     INIT_save
         sta     INIT_STATUS
@@ -320,6 +371,8 @@ IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioclts for now
 ;
 
 IRQ:    jsr     CPREP
+        lda     KEY_COUNT
+        sta     old_key_count
         lda     #$7F
         sta     CIA1_PRA
         lda     CIA1_PRB                ; Read joystick #0
@@ -436,3 +489,29 @@ IRQ:    jsr     CPREP
 @SkipY: jsr     CDRAW
         clc                             ; Interrupt not "handled"
         rts
+
+;----------------------------------------------------------------------------
+; Called after ROM IRQ handler has been run.
+; Check if there was joystick activity before and/or after the ROM handler.
+; If there was activity, discard the key presses since they are most
+; probably "phantom" key presses.
+
+callback:
+        ldx     old_key_count
+        cpx     KEY_COUNT
+        beq     @nokey
+
+        lda     Temp                    ; keypress before?
+        bne     @discard_key            ; yes, discard key
+
+        lda     #$7F
+        sta     CIA1_PRA
+        lda     CIA1_PRB                ; Read joystick #0
+        and     #$1F
+        eor     #$1F                    ; keypress after
+        beq     @nokey                  ; no, probably a real key press
+
+@discard_key:
+        stx     KEY_COUNT               ; set old keyboard buffer fill level
+
+@nokey: rts
diff --git a/libsrc/c128/mouseref.s b/libsrc/c128/mouseref.s
index 90aeedf3a..290303075 100644
--- a/libsrc/c128/mouseref.s
+++ b/libsrc/c128/mouseref.s
@@ -4,6 +4,8 @@
 ; 2013-07-25, Greg King
 ;
 
+        .include        "c128.inc"
+
         .export         mouse_libref, _pen_adjuster
 
         .data
@@ -21,3 +23,70 @@ mouse_libref:                   ; generic label for mouse-kernel
 ;
 _pen_adjuster:
         .addr   $0000
+        .addr   IRQStub2
+callback:                       ; callback into mouse driver after ROM IRQ handler has been run
+        .addr   $0000           ; (filled in by mouse driver)
+jmp_rom_hdlr:                   ; "trampoline" to jump to ROM IRQ handler
+        .addr   $0000           ; (filled in by mouse driver)
+
+
+.segment        "LOWCODE"
+
+; Called from irq.s when it thinks it chains to the original handler.
+; ROM is banked in again. In order to call the callback we have to
+; bank it out one more time.
+
+IRQStub2:
+
+; Call ROM handler and prepare stack so that it will return to us.
+
+        ; setup fake IRQ stack frame which will return to "IRQCont"
+        lda     #>@IRQCont
+        pha
+        lda     #<@IRQCont
+        pha
+        php
+
+        ; mimic the contents saved on the stack by the ROM IRQ entry handler
+        pha                     ; A
+        pha                     ; X
+        pha                     ; Y
+        lda     #MMU_CFG_CC65   ; MMU configuration which will be active after the ROM handler returns
+        pha
+
+        ; push address of ROM handler on stack and jump to it
+        lda     jmp_rom_hdlr+1
+        pha
+        lda     jmp_rom_hdlr
+        pha
+        rts                     ; jump to ROM handler
+
+        ; our MMU configuration byte we pushed on the stack before (MMU_CFG_CC65) is now active
+
+@IRQCont:
+
+        ; call mouse driver callback routine
+        lda     #>(@IRQCont2-1)
+        pha
+        lda     #<(@IRQCont2-1)
+        pha
+        lda     callback+1
+        pha
+        lda     callback
+        pha
+        rts                     ; jump to callback routine
+
+@IRQCont2:
+        
+        ; return from interrupt
+        ; We could just jump to $FF33, but since I don't know whether this address is valid in all
+        ; ROM versions, duplicate that code here.
+
+        pla
+        sta     MMU_CR          ; MMU configuration register
+        pla
+        tay
+        pla
+        tax
+        pla
+        rti

From 4406307c2fee0e3e2369d03e38bf8c118c2393ac Mon Sep 17 00:00:00 2001
From: Christian Groessler <chris@groessler.org>
Date: Thu, 24 Apr 2014 00:27:06 +0200
Subject: [PATCH 2/4] Make the hooking and unhooking of the interrupt interrupt
 safe.

---
 libsrc/c128/mou/c128-joy.s | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/libsrc/c128/mou/c128-joy.s b/libsrc/c128/mou/c128-joy.s
index fb087c8fc..339fdc836 100644
--- a/libsrc/c128/mou/c128-joy.s
+++ b/libsrc/c128/mou/c128-joy.s
@@ -160,7 +160,6 @@ INSTALL:
         lda     YPos
         ldx     YPos+1
         jsr     CMOVEY
-        cli
 
 ; Initialize our IRQ magic
 
@@ -190,6 +189,7 @@ INSTALL:
         iny
         lda     #>(chainIRQ-1)
         sta     (ptr3),y
+        cli
 
 ; Done, return zero (= MOUSE_ERR_OK)
 
@@ -202,11 +202,12 @@ INSTALL:
 ; No return code required (the driver is removed from memory on return).
 
 UNINSTALL:
-
         lda     chainIRQ+1
+        sei
         sta     IRQInd+1
         lda     chainIRQ+2
         sta     IRQInd+2
+        cli
 
         jsr     HIDE                    ; Hide cursor on exit
         lda     INIT_save

From 54be6de9bc0afa61b4f15e1f651832a614176852 Mon Sep 17 00:00:00 2001
From: Christian Groessler <chris@groessler.org>
Date: Fri, 25 Apr 2014 00:21:41 +0200
Subject: [PATCH 3/4] Workaround for "phantom" key presses in the C128 "1351"
 mouse driver.

---
 libsrc/c128/mou/c128-1351.s  | 74 ++++++++++++++++++++++++++++++++----
 libsrc/c128/mou/c128-joy.s   | 27 +------------
 libsrc/c128/mou/callback.inc | 29 ++++++++++++++
 3 files changed, 97 insertions(+), 33 deletions(-)
 create mode 100644 libsrc/c128/mou/callback.inc

diff --git a/libsrc/c128/mou/c128-1351.s b/libsrc/c128/mou/c128-1351.s
index 8aec3b7b7..c81ad04d0 100644
--- a/libsrc/c128/mou/c128-1351.s
+++ b/libsrc/c128/mou/c128-1351.s
@@ -12,6 +12,8 @@
 
         .macpack        generic
 
+IRQInd  = $2FD
+
 ; ------------------------------------------------------------------------
 ; Header. Includes jump table
 
@@ -26,6 +28,7 @@ HEADER:
 
 ; Library reference
 
+libref:
         .addr   $0000
 
 ; Jump table
@@ -63,6 +66,15 @@ CMOVEY: jmp     $0000                   ; Move the cursor to Y coord
 SCREEN_HEIGHT   = 200
 SCREEN_WIDTH    = 320
 
+;----------------------------------------------------------------------------
+; data segment
+
+.data
+
+chainIRQ:
+        .byte   $4c                     ; JMP opcode
+        .word   0                       ; pointer to ROM IRQ handler (will be set at runtime)
+
 ;----------------------------------------------------------------------------
 ; Global variables. The bounding box values are sorted so that they can be
 ; written with the least effort in the SETBOX and GETBOX routines, so don't
@@ -85,6 +97,11 @@ OldValue:       .res    1               ; Temp for MoveCheck routine
 NewValue:       .res    1               ; Temp for MoveCheck routine
 
 INIT_save:      .res    1
+Buttons:        .res    1               ; Button mask
+
+; Keyboard buffer fill level at start of interrupt
+
+old_key_count:  .res    1
 
 .rodata
 
@@ -138,6 +155,35 @@ INSTALL:
         lda     YPos
         ldx     YPos+1
         jsr     CMOVEY
+
+; Initialize our IRQ magic
+
+        lda     IRQInd+1
+        sta     chainIRQ+1
+        lda     IRQInd+2
+        sta     chainIRQ+2
+        lda     libref
+        sta     ptr3
+        lda     libref+1
+        sta     ptr3+1
+        ldy     #2
+        lda     (ptr3),y
+        sta     IRQInd+1
+        iny
+        lda     (ptr3),y
+        sta     IRQInd+2
+        iny
+        lda     #<(callback-1)
+        sta     (ptr3),y
+        iny
+        lda     #>(callback-1)
+        sta     (ptr3),y
+        iny
+        lda     #<(chainIRQ-1)
+        sta     (ptr3),y
+        iny
+        lda     #>(chainIRQ-1)
+        sta     (ptr3),y
         cli
 
 ; Done, return zero (= MOUSE_ERR_OK)
@@ -151,6 +197,13 @@ INSTALL:
 ; No return code required (the driver is removed from memory on return).
 
 UNINSTALL:
+        lda     chainIRQ+1
+        sei
+        sta     IRQInd+1
+        lda     chainIRQ+2
+        sta     IRQInd+2
+        cli
+
         jsr     HIDE                    ; Hide cursor on exit
         lda     INIT_save
         sta     INIT_STATUS
@@ -250,14 +303,8 @@ MOVE:   sei                             ; No interrupts
 ; BUTTONS: Return the button mask in a/x.
 
 BUTTONS:
-        lda     #$7F
-        sei
-        sta     CIA1_PRA
-        lda     CIA1_PRB                ; Read joystick #0
-        cli
-        ldx     #0
-        and     #$1F
-        eor     #$1F
+        lda     Buttons
+        ldx     #$00
         rts
 
 ;----------------------------------------------------------------------------
@@ -320,6 +367,15 @@ IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioclts for now
 ;
 
 IRQ:    jsr     CPREP
+        lda     KEY_COUNT
+        sta     old_key_count
+        lda     #$7F
+        sta     CIA1_PRA
+        lda     CIA1_PRB                ; Read joystick #0
+        and     #$1F
+        eor     #$1F                    ; Make all bits active high
+        sta     Buttons
+
         lda     SID_ADConv1             ; Get mouse X movement
         ldy     OldPotX
         jsr     MoveCheck               ; Calculate movement vector
@@ -450,3 +506,5 @@ MoveCheck:
         clc
         rts
 
+.define  OLD_BUTTONS Buttons            ; tells callback.inc where the old port status is stored
+.include "callback.inc"
diff --git a/libsrc/c128/mou/c128-joy.s b/libsrc/c128/mou/c128-joy.s
index 339fdc836..83255b64e 100644
--- a/libsrc/c128/mou/c128-joy.s
+++ b/libsrc/c128/mou/c128-joy.s
@@ -491,28 +491,5 @@ IRQ:    jsr     CPREP
         clc                             ; Interrupt not "handled"
         rts
 
-;----------------------------------------------------------------------------
-; Called after ROM IRQ handler has been run.
-; Check if there was joystick activity before and/or after the ROM handler.
-; If there was activity, discard the key presses since they are most
-; probably "phantom" key presses.
-
-callback:
-        ldx     old_key_count
-        cpx     KEY_COUNT
-        beq     @nokey
-
-        lda     Temp                    ; keypress before?
-        bne     @discard_key            ; yes, discard key
-
-        lda     #$7F
-        sta     CIA1_PRA
-        lda     CIA1_PRB                ; Read joystick #0
-        and     #$1F
-        eor     #$1F                    ; keypress after
-        beq     @nokey                  ; no, probably a real key press
-
-@discard_key:
-        stx     KEY_COUNT               ; set old keyboard buffer fill level
-
-@nokey: rts
+.define  OLD_BUTTONS Temp               ; tells callback.inc where the old port status is stored
+.include "callback.inc"
diff --git a/libsrc/c128/mou/callback.inc b/libsrc/c128/mou/callback.inc
new file mode 100644
index 000000000..ea64b8913
--- /dev/null
+++ b/libsrc/c128/mou/callback.inc
@@ -0,0 +1,29 @@
+;
+; Callback routine called from the IRQ handler after the ROM IRQ handler
+; had been run.
+;
+; Christian Groessler, 24.04.2014
+;
+; Check if there was joystick activity before and/or after the ROM handler.
+; If there was activity, discard the key presses since they are most
+; probably "phantom" key presses.
+
+callback:
+        ldx     old_key_count
+        cpx     KEY_COUNT
+        beq     @nokey
+
+        lda     OLD_BUTTONS             ; keypress before?
+        bne     @discard_key            ; yes, discard key
+
+        lda     #$7F
+        sta     CIA1_PRA
+        lda     CIA1_PRB                ; Read joystick #0
+        and     #$1F
+        eor     #$1F                    ; keypress after
+        beq     @nokey                  ; no, probably a real key press
+
+@discard_key:
+        stx     KEY_COUNT               ; set old keyboard buffer fill level
+
+@nokey: rts

From 6307815ada83e09589864fe218baab2c907e1641 Mon Sep 17 00:00:00 2001
From: Christian Groessler <chris@groessler.org>
Date: Sat, 26 Apr 2014 11:55:24 +0200
Subject: [PATCH 4/4] Correctly map out ROM when needed in the "phantom keys"
 workaround.

---
 libsrc/c128/mou/c128-1351.s | 40 ++++++++++++++++++++++---------------
 libsrc/c128/mou/c128-joy.s  | 40 ++++++++++++++++++++++---------------
 libsrc/c128/mouseref.s      |  8 +++++++-
 3 files changed, 55 insertions(+), 33 deletions(-)

diff --git a/libsrc/c128/mou/c128-1351.s b/libsrc/c128/mou/c128-1351.s
index c81ad04d0..e55c1d01b 100644
--- a/libsrc/c128/mou/c128-1351.s
+++ b/libsrc/c128/mou/c128-1351.s
@@ -66,15 +66,6 @@ CMOVEY: jmp     $0000                   ; Move the cursor to Y coord
 SCREEN_HEIGHT   = 200
 SCREEN_WIDTH    = 320
 
-;----------------------------------------------------------------------------
-; data segment
-
-.data
-
-chainIRQ:
-        .byte   $4c                     ; JMP opcode
-        .word   0                       ; pointer to ROM IRQ handler (will be set at runtime)
-
 ;----------------------------------------------------------------------------
 ; Global variables. The bounding box values are sorted so that they can be
 ; written with the least effort in the SETBOX and GETBOX routines, so don't
@@ -103,6 +94,10 @@ Buttons:        .res    1               ; Button mask
 
 old_key_count:  .res    1
 
+; original IRQ vector
+
+old_irq:        .res    2
+
 .rodata
 
 ; Default values for above variables
@@ -158,20 +153,27 @@ INSTALL:
 
 ; Initialize our IRQ magic
 
-        lda     IRQInd+1
-        sta     chainIRQ+1
+        ; remember ROM IRQ continuation address
         lda     IRQInd+2
-        sta     chainIRQ+2
+        sta     old_irq+1
+        lda     IRQInd+1
+        sta     old_irq
+
         lda     libref
         sta     ptr3
         lda     libref+1
         sta     ptr3+1
+
+        ; set ROM IRQ continuation address to point to the provided routine
         ldy     #2
         lda     (ptr3),y
         sta     IRQInd+1
         iny
         lda     (ptr3),y
         sta     IRQInd+2
+
+        ; set address of our IRQ callback routine
+        ; since it's called via "rts" we have to use "address-1"
         iny
         lda     #<(callback-1)
         sta     (ptr3),y
@@ -179,10 +181,16 @@ INSTALL:
         lda     #>(callback-1)
         sta     (ptr3),y
         iny
-        lda     #<(chainIRQ-1)
+
+        ; set ROM entry point vector
+        ; since it's called via "rts" we have to decrement it by one
+        lda     old_irq
+        sec
+        sbc     #1
         sta     (ptr3),y
         iny
-        lda     #>(chainIRQ-1)
+        lda     old_irq+1
+        sbc     #0
         sta     (ptr3),y
         cli
 
@@ -197,10 +205,10 @@ INSTALL:
 ; No return code required (the driver is removed from memory on return).
 
 UNINSTALL:
-        lda     chainIRQ+1
+        lda     old_irq
         sei
         sta     IRQInd+1
-        lda     chainIRQ+2
+        lda     old_irq+1
         sta     IRQInd+2
         cli
 
diff --git a/libsrc/c128/mou/c128-joy.s b/libsrc/c128/mou/c128-joy.s
index 83255b64e..c1dc2e019 100644
--- a/libsrc/c128/mou/c128-joy.s
+++ b/libsrc/c128/mou/c128-joy.s
@@ -73,15 +73,6 @@ SCREEN_WIDTH    = 320
         FIRE    = $10
 .endenum
 
-;----------------------------------------------------------------------------
-; data segment
-
-.data
-
-chainIRQ:
-        .byte   $4c                     ; JMP opcode
-        .word   0                       ; pointer to ROM IRQ handler (will be set at runtime)
-
 ;----------------------------------------------------------------------------
 ; Global variables. The bounding box values are sorted so that they can be
 ; written with the least effort in the SETBOX and GETBOX routines, so don't
@@ -108,6 +99,10 @@ Temp:           .res    1
 
 old_key_count:  .res    1
 
+; original IRQ vector
+
+old_irq:        .res    2
+
 .rodata
 
 ; Default values for above variables
@@ -163,20 +158,27 @@ INSTALL:
 
 ; Initialize our IRQ magic
 
-        lda     IRQInd+1
-        sta     chainIRQ+1
+        ; remember ROM IRQ continuation address
         lda     IRQInd+2
-        sta     chainIRQ+2
+        sta     old_irq+1
+        lda     IRQInd+1
+        sta     old_irq
+
         lda     libref
         sta     ptr3
         lda     libref+1
         sta     ptr3+1
+
+        ; set ROM IRQ continuation address to point to the provided routine
         ldy     #2
         lda     (ptr3),y
         sta     IRQInd+1
         iny
         lda     (ptr3),y
         sta     IRQInd+2
+
+        ; set address of our IRQ callback routine
+        ; since it's called via "rts" we have to use "address-1"
         iny
         lda     #<(callback-1)
         sta     (ptr3),y
@@ -184,10 +186,16 @@ INSTALL:
         lda     #>(callback-1)
         sta     (ptr3),y
         iny
-        lda     #<(chainIRQ-1)
+
+        ; set ROM entry point vector
+        ; since it's called via "rts" we have to decrement it by one
+        lda     old_irq
+        sec
+        sbc     #1
         sta     (ptr3),y
         iny
-        lda     #>(chainIRQ-1)
+        lda     old_irq+1
+        sbc     #0
         sta     (ptr3),y
         cli
 
@@ -202,10 +210,10 @@ INSTALL:
 ; No return code required (the driver is removed from memory on return).
 
 UNINSTALL:
-        lda     chainIRQ+1
+        lda     old_irq
         sei
         sta     IRQInd+1
-        lda     chainIRQ+2
+        lda     old_irq+1
         sta     IRQInd+2
         cli
 
diff --git a/libsrc/c128/mouseref.s b/libsrc/c128/mouseref.s
index 290303075..630ff573f 100644
--- a/libsrc/c128/mouseref.s
+++ b/libsrc/c128/mouseref.s
@@ -26,7 +26,7 @@ _pen_adjuster:
         .addr   IRQStub2
 callback:                       ; callback into mouse driver after ROM IRQ handler has been run
         .addr   $0000           ; (filled in by mouse driver)
-jmp_rom_hdlr:                   ; "trampoline" to jump to ROM IRQ handler
+jmp_rom_hdlr:                   ; original ROM indirect IRQ handler address
         .addr   $0000           ; (filled in by mouse driver)
 
 
@@ -54,11 +54,17 @@ IRQStub2:
         lda     #MMU_CFG_CC65   ; MMU configuration which will be active after the ROM handler returns
         pha
 
+        ; map out ROM
+        ldy     MMU_CR
+        sta     MMU_CR
+
         ; push address of ROM handler on stack and jump to it
         lda     jmp_rom_hdlr+1
         pha
         lda     jmp_rom_hdlr
         pha
+
+        sty     MMU_CR          ; map in ROM
         rts                     ; jump to ROM handler
 
         ; our MMU configuration byte we pushed on the stack before (MMU_CFG_CC65) is now active