6502-OS/system/ps2_keyboard.h65
2024-01-02 23:37:07 +01:00

63 lines
2.5 KiB
Plaintext

;;********************************************************************************
;; @module ps2_keyboard
;; @type driver
;; @details:
;; Support for a PS2 Keyboard using the shift register of a 6522 VIA
;; @section Reading a scancode/command answer
;; Pressing a key causes 11 bits to be sent: 1 start - 8 scancode - 1 parity - 1 stop
;; The VIA is set up to interrupt after 8 bits have been shifted into the shift register
;; from the external clock pulses of the keyboard (additional hardware required to
;; address the hardware bug of the VIA, where bit get lost when the external clock
;; transition happens during falling edge of PHI2). After reading the shift register,
;; the VIAs T2 timer is set to interrupt after the last 3 bits have been shifted in,
;; which takes about ~230ms.
;; T2 is used because it leaves to more versatile T1 available for something else
;; @section Processing a scancode
;; The scancode may be processed by storing the address of a handler subroutine in
;; ps2kb::scancode_handler. This handler can load the scancode byte from ps2kb::scancode.
;;
;;
;; To use a different layout, change the enum K and the CHARS_NOMOD and CHARS_MODSHIFT
;; @warning
;; The value with which the timer is loaded must depends on the clock frequency
;; of the keyboard and the computer
;;
;;********************************************************************************
.ifndef INCLUDE_PS2_KEYBOARD
INCLUDE_PS2_KEYBOARD = 1
.include "system.h65"
.scope ps2kb
Import ps2kb,init,begin_receive,send_command,scancode,status,scancode_handler
Import ps2kb, _receive_irq_shift_reg_handler, _receive_irq_timer_handler, _send_byte, _send_irq_shift_reg_handler, _send_irq_timer_handler,
Import ps2kb, send_last_bits, send_cmd, send_data, key_read, prev_status
VIA = IO1
; Enough time must pass for 3 bits to be shifted in.
TIMER_RECV = 230 ; 230 ms (@1MHz)
; Enough time must pass for one bit must be shifted out (parity),
; but at most two (parity+stop).
; After that, the interrupt must have happened because the keyboard will pull data low.
; At that point, the SR needs to be set to input again
TIMER_SEND = 230 ; 180 ms (@1MHz)
; use RA4 to pull the clock low
PULL_REG = IO::RANH
PULL_DDR = IO::DDRA
PULL_MASK_CLK = %00010000
; PULL_MASK_DAT = %00001000
NO_DATA = $ff ; indicates that no data byte should be send
.enum STATUS
RECEIVE_KEYS = %10000000
RECEIVE_ANSWER = %01000000
SEND_CMD = %00100000
SEND_DATA = %00010000
SEND_CMD_WAIT = %00001000
NONE = %00000000
.endenum
.endscope
.endif ; guard