Tuesday, December 24, 2024

Avoid conflicts between C64 keyboard and joystick #1

 



The Commodore 64 keyboard may display unexpected characters when joystick #1 is used.  There is a solution!  Avoid the keyboard when scanning the joystick, and exclude the joystick data when scanning the keyboard.  But somewhat easier said than done.

Tracing the source of the issue is that PORTB of CIA1 is connected to the keyboard and first joystick simultaneously.  Normally the C64 KERNAL IRQ will write zero bits to PORTA to select a row, and read from PORTB to read the columns.  And reading the joystick also is read from PORTB.  So with two devices both read from PORTB there's bound to be conflicts.

Reading from the joystick without conflict from the keyboard is the easiest solution.  Write 0xFF (all ones) to PORTA to turn off reading any of the column lines from the keyboard, and read PORTB.   The result will only be the lines from the joystick.   Any of the lower 5 bits which are zeros will mean that the corresponding joystick line is pulled low (switch is connected), meaning a direction is held and/or the fire button is pressed.

Accommodating keyboard reads ignoring the joystick is not as easy because the joystick cannot be logically disconnected in the same way, it is always connected.  Th e approach I took was to read the joystick, and then read the keyboard ignoring any lines active on the joystick.   This solution gives the joystick priority (as it is always connected), and skips supporting some keystrokes which would otherwise conflict with the joystick.

As inputs can change suddenly, there is debounce logic consistent with how the Commodore KERNAL already handles the keyboard.  Any reads of PORTB are followed by a comparison with PORTB, reading it twice, and making sure the values are identical.  If there is a change in values, the process is repeated without limit.  Both the joystick and keyboard in this solution both have this debounce logic.  And additionally, the joystick is read before and after the keyboard is read, so if there is a change in the joystick values, the process as a whole is repeated for that keyboard row.  As the joystick is repeatedly read, only the last value for the last keyboard row will remain until the next scan.

To implement a general fix for the BASIC Editor (which accepts keystrokes and draws characters on the screen), the IRQ scan key handler would ideally be updated to incorporate these changes.  But the challenge is that the IRQ does other things as well, and the scan key routine is not vectored.  But the key log routine is vectored, which is called when any key is pressed, so the IRQ can be intercepted to scan the joysticks, and the key log routine is intercepted.

The key log routine is responsible for interpreting raw key matrix presses, handle character set swapping, keyboard repeating, and putting keys into the keyboard input buffer.   The new code vectored here effectively throws away the old scan key handler by doing its own new scan key routine avoiding conflict with joystick #1, writing its own results to the current key scan matrix value and shift flag memory locations, and then returning to the existing key log routine to handle these filtered key presses.

The effect is a cleaner keyboard input without conflict from joysticks, and joystick values stored in memory locations 253 and 254.  The joystick values are inverted so they are 0..31 based on positioning (1=up, 2=down, 4=left, 8=right) and fire (16).

Instructions: load the machine code at absolute address, and SYS 49152 to activate it.  Only titles, copyright, and links will be displayed.  Press STOP+RESTORE to deactivate it.   While active, keyboard and joystick #1 will avoid conflict, and joystick readings every jiffy will be available to peek from memory locations 253 and 254.  When deactivated, normal operation will occur.

Links: open source and d64