diff --git a/STATUS.md b/STATUS.md
index 4195a6ba..7b320fe7 100644
--- a/STATUS.md
+++ b/STATUS.md
@@ -96,53 +96,53 @@ NOTE: Even the 'DONE' routines won't support features described as missing in on
-| Address | Unofficial | Name | Status | Remarks |
-| :-------: | :--------: | :---------- | :------: | :------------------------------------------------: |
-| `($028F)` | | `KEYLOG` | DONE | |
-| `$FF81` | `$FF5B` | `CINT` | DONE | |
-| `$FF84` | `$FDA3` | `IOINIT` | PARTIAL | CIA initialization incomplete |
-| `$FF87` | `$FD50` | `RAMTAS` | DONE | |
-| `$FF8A` | `$FD15` | `RESTOR` | DONE | |
-| `$FF8D` | `$FD1A` | `VECTOR` | DONE | |
-| `$FF90` | | `SETMSG` | DONE | |
-| `$FF93` | | `SECOND` | DONE | |
-| `$FF96` | | `TKSA` | DONE | |
-| `$FF99` | | `MEMTOP` | DONE | |
-| `$FF9C` | | `MEMBOT` | DONE | |
-| `$FF9F` | | `SCNKEY` | PARTIAL | future complete version has compatibility problems |
-| `$FFA2` | | `SETTMO` | DONE | |
-| `$FFA5` | | `ACPTR` | DONE | |
-| `$FFA8` | | `CIOUT` | DONE | |
-| `$FFAB` | | `UNTLK` | DONE | |
-| `$FFAE` | | `UNLSN` | DONE | |
-| `$FFB1` | | `LISTEN` | DONE | |
-| `$FFB4` | | `TALK` | DONE | |
-| `$FFB7` | | `READST` | DONE | |
-| `$FFBA` | | `SETFLS` | DONE | |
-| `$FFBD` | | `SETNAM` | DONE | |
-| `$FFC0` | `$F34A` | `OPEN` | DONE | |
-| `$FFC3` | `$F291` | `CLOSE` | DONE | |
-| `$FFC6` | `$F20E` | `CHKIN` | DONE | |
-| `$FFC9` | `$F250` | `CKOUT` | PARTIAL | |
-| `$FFCC` | `$F333` | `CLRCHN` | DONE | |
-| `$FFCF` | `$F157` | `CHRIN` | PARTIAL | |
-| `$FFD2` | `$F1CA` | `CHROUT` | PARTIAL | |
-| `$FFD5` | `$F49E` | `LOAD` | PARTIAL | not yet clear what's this entry doing |
-| `($0330)` | `$F4A5` | `LOAD` | PARTIAL | no VERIFY support, no STOP key, check $F49E addr |
-| `$FFD8` | `$F5DD` | `SAVE` | NOT DONE | |
-| `($0332)` | `$F5ED` | `SAVE` | NOT DONE | |
-| `$FFDB` | | `SETTIM` | DONE | |
-| `$FFDE` | | `RDTIM` | DONE | |
-| `$FFE1` | `$F6ED` | `STOP` | DONE | |
-| `$FFE4` | `$F13E` | `GETIN` | PARTIAL | only some devices supported |
-| `$FFE7` | `$F32F` | `CLALL` | DONE | |
-| `$FFEA` | | `UDTIM` | DONE | |
-| `$FFED` | | `SCREEN` | DONE | |
-| `$FFF0` | `$E50A` | `PLOT` | DONE | |
-| `$FFF3` | | `IOBASE` | DONE | |
-| `($FFFA)` | | NMI vec | PARTIAL | |
-| `($FFFC)` | | RESET vec | PARTIAL | |
-| `($FFFE)` | | IRQ/BRK vec | PARTIAL | |
+| Address | Unofficial | Name | Status | Remarks |
+| :-------: | :--------: | :---------- | :------: | :--------------------------------------------------: |
+| `($028F)` | | `KEYLOG` | DONE | works differently on purpose, to improve kb scanning |
+| `$FF81` | `$FF5B` | `CINT` | DONE | |
+| `$FF84` | `$FDA3` | `IOINIT` | PARTIAL | CIA initialization incomplete |
+| `$FF87` | `$FD50` | `RAMTAS` | DONE | |
+| `$FF8A` | `$FD15` | `RESTOR` | DONE | |
+| `$FF8D` | `$FD1A` | `VECTOR` | DONE | |
+| `$FF90` | | `SETMSG` | DONE | |
+| `$FF93` | | `SECOND` | DONE | |
+| `$FF96` | | `TKSA` | DONE | |
+| `$FF99` | | `MEMTOP` | DONE | |
+| `$FF9C` | | `MEMBOT` | DONE | |
+| `$FF9F` | | `SCNKEY` | PARTIAL | future complete version has compatibility problems |
+| `$FFA2` | | `SETTMO` | DONE | |
+| `$FFA5` | | `ACPTR` | DONE | |
+| `$FFA8` | | `CIOUT` | DONE | |
+| `$FFAB` | | `UNTLK` | DONE | |
+| `$FFAE` | | `UNLSN` | DONE | |
+| `$FFB1` | | `LISTEN` | DONE | |
+| `$FFB4` | | `TALK` | DONE | |
+| `$FFB7` | | `READST` | DONE | |
+| `$FFBA` | | `SETFLS` | DONE | |
+| `$FFBD` | | `SETNAM` | DONE | |
+| `$FFC0` | `$F34A` | `OPEN` | DONE | |
+| `$FFC3` | `$F291` | `CLOSE` | DONE | |
+| `$FFC6` | `$F20E` | `CHKIN` | DONE | |
+| `$FFC9` | `$F250` | `CKOUT` | PARTIAL | |
+| `$FFCC` | `$F333` | `CLRCHN` | DONE | |
+| `$FFCF` | `$F157` | `CHRIN` | PARTIAL | |
+| `$FFD2` | `$F1CA` | `CHROUT` | PARTIAL | |
+| `$FFD5` | `$F49E` | `LOAD` | PARTIAL | not yet clear what's this entry doing |
+| `($0330)` | `$F4A5` | `LOAD` | PARTIAL | no VERIFY support, no STOP key, check $F49E addr |
+| `$FFD8` | `$F5DD` | `SAVE` | NOT DONE | |
+| `($0332)` | `$F5ED` | `SAVE` | NOT DONE | |
+| `$FFDB` | | `SETTIM` | DONE | |
+| `$FFDE` | | `RDTIM` | DONE | |
+| `$FFE1` | `$F6ED` | `STOP` | DONE | |
+| `$FFE4` | `$F13E` | `GETIN` | PARTIAL | only some devices supported |
+| `$FFE7` | `$F32F` | `CLALL` | DONE | |
+| `$FFEA` | | `UDTIM` | DONE | |
+| `$FFED` | | `SCREEN` | DONE | |
+| `$FFF0` | `$E50A` | `PLOT` | DONE | |
+| `$FFF3` | | `IOBASE` | DONE | |
+| `($FFFA)` | | NMI vec | PARTIAL | |
+| `($FFFC)` | | RESET vec | PARTIAL | |
+| `($FFFE)` | | IRQ/BRK vec | PARTIAL | |
diff --git a/c64/,,config_generic.s b/c64/,,config_generic.s
index de70aaac..60c34491 100644
--- a/c64/,,config_generic.s
+++ b/c64/,,config_generic.s
@@ -58,7 +58,9 @@
#define CONFIG_PANIC_SCREEN
#define CONFIG_DOS_WEDGE
#define CONFIG_BCD_SAFE_INTERRUPTS
-#define CONFIG_SCNKEY_TWW_CTR // for now has to be enabled
+// #define CONFIG_SCNKEY_TWW_CTR // XXX document this
+#define CONFIG_JOY1_CURSOR // XXX document this
+#define CONFIG_JOY2_CURSOR // XXX document this
// Debug options
diff --git a/c64/,,config_mega65.s b/c64/,,config_mega65.s
index 8cd04b0e..8f94243e 100644
--- a/c64/,,config_mega65.s
+++ b/c64/,,config_mega65.s
@@ -60,7 +60,9 @@
#define CONFIG_PANIC_SCREEN
#define CONFIG_DOS_WEDGE
#define CONFIG_BCD_SAFE_INTERRUPTS
-#define CONFIG_SCNKEY_TWW_CTR // for now has to be enabled
+#define CONFIG_SCNKEY_TWW_CTR // XXX document this
+#define CONFIG_JOY1_CURSOR // XXX document this
+#define CONFIG_JOY2_CURSOR // XXX document this
// Debug options
diff --git a/c64/,,config_ultimate64.s b/c64/,,config_ultimate64.s
index 7578d183..6a1a0e5b 100644
--- a/c64/,,config_ultimate64.s
+++ b/c64/,,config_ultimate64.s
@@ -58,7 +58,9 @@
#define CONFIG_PANIC_SCREEN
#define CONFIG_DOS_WEDGE
#define CONFIG_BCD_SAFE_INTERRUPTS
-#define CONFIG_SCNKEY_TWW_CTR // for now has to be enabled
+// #define CONFIG_SCNKEY_TWW_CTR // XXX document this
+#define CONFIG_JOY1_CURSOR // XXX document this
+#define CONFIG_JOY2_CURSOR // XXX document this
// Debug options
diff --git a/c64/kernal/interrupts/udtim.s b/c64/kernal/interrupts/udtim.s
index 2d8aac00..34528613 100644
--- a/c64/kernal/interrupts/udtim.s
+++ b/c64/kernal/interrupts/udtim.s
@@ -25,18 +25,17 @@ udtim_update_stkey: // entry to be used when interrupts are disabled
// Another action we have to perform is to copy the last row of keyboard to RAM,
// so that various routines can detect the STOP key press
- // XXX scnkey contains similar sequence - deduplicate this!
- lda #$FF
- sta CIA1_DDRA // output
- lda #$00
- sta CIA1_DDRB // input
lda #$7F
sta CIA1_PRA // select the last row (bit to 0)
lda CIA1_PRB // read the row
sta STKEY
- rts
+
+ // Finish by disconnecting the keyboard, this will prevent
+ // interference when scanning joystick in port 1
+
+ jmp keyboard_disconnect
udtim_clock_rollover:
diff --git a/c64/kernal/keyboard/kb_matrix_lookup.s b/c64/kernal/keyboard/kb_matrix_lookup.s
index 53f55497..93477737 100644
--- a/c64/kernal/keyboard/kb_matrix_lookup.s
+++ b/c64/kernal/keyboard/kb_matrix_lookup.s
@@ -1,21 +1,23 @@
//
-// Work out if normal, shifted, control or Vendor modified keyboard.
-// Table contains the offsets into keyboard_matrixes that should be used
-// for different values of the bottom 3 bits of key_bucky_state XXX
-// Interaction is simple to work out when playing with a C64:
-// CTRL trumps SHIFT or VENDOR
-// VENDOR + SHIFT = DOES NOTHING
-// All 3 does CONTROL
+// Helper table for determining keyboard matrix decoding table on the C64 keyboard
//
+// When more than one bucky keey is pressed, decoding keys is asking for trouble,
+// so never allow this.
+//
+
+
+#if !CONFIG_SCNKEY_TWW_CTR
kb_matrix_lookup:
- .byte (__kb_matrix_normal - kb_matrix) // Normal
- .byte (__kb_matrix_shift - kb_matrix) // SHIFT
- .byte (__kb_matrix_ctrl - kb_matrix) // CTRL
- .byte (__kb_matrix_ctrl - kb_matrix) // CTRL + SHIFT
- .byte (__kb_matrix_vendor - kb_matrix) // VENDOR
- .byte (__kb_matrix_vendor - kb_matrix) // VENDOR + SHIFT
- .byte (__kb_matrix_ctrl - kb_matrix) // VENDOR + CTRL
- .byte (__kb_matrix_ctrl - kb_matrix) // VENDOR + CTRL + SHIFT
+ .byte (__kb_matrix_normal - kb_matrix) // %000 Normal
+ .byte (__kb_matrix_shift - kb_matrix) // %001 SHIFT
+ .byte (__kb_matrix_vendor - kb_matrix) // %010 VENDOR
+ .byte $FF // %011 SHIFT+VENDOR
+ .byte (__kb_matrix_ctrl - kb_matrix) // %100 CTRL
+ .byte $FF // %101 SHIFT+CTRL
+ .byte $FF // %110 VENDOR+CTRL
+ .byte $FF // %111 SHIFT+VENDOR+CTRL
+
+#endif
diff --git a/c64/kernal/keyboard/kb_matrix_lookup_tww_ctr.s b/c64/kernal/keyboard/kb_matrix_lookup_tww_ctr.s
new file mode 100644
index 00000000..cc7d6e09
--- /dev/null
+++ b/c64/kernal/keyboard/kb_matrix_lookup_tww_ctr.s
@@ -0,0 +1,28 @@
+
+//
+// Work out if normal, shifted, control or Vendor modified keyboard.
+// Table contains the offsets into keyboard_matrixes that should be used
+// for different values of the bottom 3 bits of key_bucky_state XXX
+// Interaction is simple to work out when playing with a C64:
+// CTRL trumps SHIFT or VENDOR
+// VENDOR + SHIFT = DOES NOTHING
+// All 3 does CONTROL
+//
+
+// This lookup table is used by TWW/CTR keyboard routine only!
+
+
+#if CONFIG_SCNKEY_TWW_CTR
+
+kb_matrix_lookup_tww_ctr:
+
+ .byte $00 // Normal
+ .byte $40 // Shifted
+ .byte $80 // Control
+ .byte $80 // Control + SHIFT
+ .byte $C0 // Vendor
+ .byte $C0 // Vendor + SHIFT
+ .byte $80 // Vendor + CTRL
+ .byte $80 // Vendor + CTRL + SHIFT
+
+#endif // CONFIG_SCNKEY_TWW_CTR
diff --git a/c64/kernal/keyboard/keyboard_disconnect.s b/c64/kernal/keyboard/keyboard_disconnect.s
new file mode 100644
index 00000000..12708fb6
--- /dev/null
+++ b/c64/kernal/keyboard/keyboard_disconnect.s
@@ -0,0 +1,12 @@
+
+//
+// Helper routine - disconnects the keyboard from CIA1_PRB,
+// leaves $FF in .X (behavior needed in some places)
+
+
+keyboard_disconnect:
+
+ ldx #$FF
+ stx CIA1_PRA // disconnect all the rows
+
+ rts
diff --git a/c64/kernal/keyboard/scnkey.s b/c64/kernal/keyboard/scnkey.s
index 4c8689a5..d79f183f 100644
--- a/c64/kernal/keyboard/scnkey.s
+++ b/c64/kernal/keyboard/scnkey.s
@@ -23,8 +23,9 @@
// XXX add Commodore 128 keyboard support
// XXX add Commodore 65 keybopard support
-// XXX add support for using joystick to move sursor keys
-// XXX explicitly prevent joystick port 1 interference
+// XXX add support for using joysticks to move cursor keys
+// XXX add support for keys which are repeated always
+
#if !CONFIG_SCNKEY_TWW_CTR
@@ -46,7 +47,7 @@ SCNKEY:
// Check for any activity
lda #$00
- sta CIA1_PRA // connect all the rows
+ sta CIA1_PRA // connect all the rows
ldx #$FF
cpx CIA1_PRB
beq scnkey_no_keys
@@ -71,18 +72,44 @@ scnkey_bucky_loop:
jsr via_keylog // XXX for some CPUs we have indirect jsr
- // Check if we have free space in the keyboard buffer
+ // Check if KEYTAB is not 0 (happens if more than one bucky key is pressed)
+ // High byte equal to 0 = table considered invalid
+ lda KEYTAB+1
+ beq scnkey_no_keys
- lda NDX
- cmp XMAX
- bcs scnkey_no_keys // no space in keyboard buffer - do not waste time
+#if CONFIG_JOY2_CURSOR
- // XXX check for joystick activity
+ // XXX why this does not work???
+
+ // Check for control port 2 activity
+
+ // ldx #$00
+ // stx CIA1_DDRA // set port to input to read joystick
+
+ // lda CIA1_PRA // read the joystick 2 status
+
+ // dex
+ // stx CIA1_DDRA // set port back to output
+
+ // and #%00001111 // filter out anything but joystick movement
+ // bne scnkey_joystick_a_filtered
+
+#endif
+
+ // Check for control port 1 activity (can interfere with keyboard)
+
+ jsr keyboard_disconnect // disconnect all the rows, .X will be $FF
+ cpx CIA1_PRB // only control port activity will be reported
+#if CONFIG_JOY1_CURSOR
+ bne scnkey_joystick_x // use joystick for cursor keys
+#else
+ bne scnkey_no_keys // if activity detected do not scan the keyboard
+#endif
// Scan the keyboard matrix
+ ldy #$FF // offset in key matrix table, $FF for not found yet
ldx #$07 // XXX adapt for C128 and C65 keyboards
- ldy #$FF // offset in key matrix table, $FF for not found yet
scnkey_matrix_loop:
lda kb_matrix_row_keys, x
sta CIA1_PRA
@@ -110,9 +137,16 @@ scnkey_matrix_loop_next:
dex
bpl scnkey_matrix_loop
- // Scanning complete
+ // Scanning complete - check if we got a key
+
cpy #$FF
- bne scnkey_got_key
+ beq scnkey_no_keys
+
+ // To be extra sure, check for possible control port 1 interference once again
+
+ jsr keyboard_disconnect // disconnect all the rows, .X will be $FF
+ cpx CIA1_PRB // only control port activity will be reported
+ beq scnkey_got_key // branch if joystick activity NOT detected
// FALLTROUGH
@@ -125,6 +159,25 @@ scnkey_no_keys:
rts
+#if CONFIG_JOY1_CURSOR || CONFIG_JOY2_CURSOR
+
+scnkey_joystick_x:
+
+ // Handle joystick activity (in .X) as cursor keys
+
+ txa
+ and #%00001111 // filter out anything but movement
+
+ // FALLTROUGH
+
+scnkey_joystick_a_filtered:
+
+ // XXX finish the implementation
+
+ rts
+
+#endif
+
scnkey_got_key: // .Y should now contain the key offset in matrix pointed by KEYTAB
cpy LSTX
@@ -148,6 +201,12 @@ scnkey_got_key: // .Y should now contain the key offset in matrix pointed by KEY
scnkey_output_key:
+ // Check if we have free space in the keyboard buffer
+
+ lda NDX
+ cmp XMAX
+ bcs scnkey_early_repeat // no space in buffer XXX set timer to trigger repeat the next time
+
// Reinitialize secondary counter
lda #$03
@@ -170,12 +229,10 @@ scnkey_handle_repeat:
// Check whether we should repeat keys
- // XXX some keys should be repeat always!
-
lda RPTFLG
bpl scnkey_done // branch if we should do no repeat
- // First countdown (for the first repeat)
+ // Countdown before first repeat
lda DELAY
beq !+
@@ -183,7 +240,7 @@ scnkey_handle_repeat:
rts
!:
- // Second countdown (for both first and subsequential repeats)
+ // Countdown before subsequent repeats
lda KOUNT
beq scnkey_output_key // if second counter is also 0, we can repeat the key
@@ -191,6 +248,17 @@ scnkey_handle_repeat:
rts
+scnkey_early_repeat:
+
+ // Keyboard buffer was full - at least make sure the key
+ // will be repeated as soon as possible
+
+ lda #$00
+ sta DELAY
+ sta KOUNT
+
+ rts
+
via_keylog:
jmp (KEYLOG)
diff --git a/c64/kernal/keyboard/scnkey_set_keytab.s b/c64/kernal/keyboard/scnkey_set_keytab.s
index 27fcfef1..4f9781aa 100644
--- a/c64/kernal/keyboard/scnkey_set_keytab.s
+++ b/c64/kernal/keyboard/scnkey_set_keytab.s
@@ -5,8 +5,17 @@
// - [CM64] Compute's Mapping the Commodore 64 - pages 220, 221
//
+
scnkey_set_keytab:
+
+#if CONFIG_SCNKEY_TWW_CTR // routine not compatible with legacy SCNKEY
+
+ rts
+
+#else
+
+
// Set initial KEYTAB value
lda #