6502-OS/system/ps2_keyboard.h65

195 lines
5.3 KiB
Plaintext
Raw Normal View History

2024-01-01 14:56:11 +01:00
;;********************************************************************************
;; @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
2024-01-07 00:41:12 +01:00
Import ps2kb, init, begin_receive, scancode, status, scancode_handler
2024-01-02 23:37:07 +01:00
Import ps2kb, _receive_irq_shift_reg_handler, _receive_irq_timer_handler, _send_byte, _send_irq_shift_reg_handler, _send_irq_timer_handler,
2024-01-07 00:41:12 +01:00
Import ps2kb, send_command, send_cmd, send_data, cmd_response, response_length, FMT_CMD_FAIL
2024-01-01 14:56:11 +01:00
VIA = IO1
2024-01-02 23:37:07 +01:00
; Enough time must pass for 3 bits to be shifted in.
2024-01-11 20:51:07 +01:00
; TIMER_RECV = 230 ; 230 ms (@1MHz)
TIMER_RECV = 400 ; 230 ms (@1MHz)
2024-01-02 23:37:07 +01:00
; 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
2024-01-11 20:51:07 +01:00
; TIMER_SEND = 230 ; 180 ms (@1MHz)
TIMER_SEND = 400 ; 180 ms (@1MHz)
2024-01-07 00:41:12 +01:00
2024-01-02 23:37:07 +01:00
PULL_REG = IO::RANH
PULL_DDR = IO::DDRA
2024-01-07 00:41:12 +01:00
; use RA4 to pull the clock low
2024-01-02 23:37:07 +01:00
PULL_MASK_CLK = %00010000
2024-01-07 00:41:12 +01:00
; using ff because 0 is a possible data byte (set led)
NO_DATA = $ff ; indicates that no data byte should be send
NO_RESPONSE = $ff ; indicates a command did not receive a response (yet)
ACK = $fa ; successful transmission
RESEND = $fe ; unsuccessful transmission
2024-01-01 14:56:11 +01:00
.enum STATUS
2024-01-07 00:41:12 +01:00
RECEIVE_KEYS = %10000000 ; keyboard sends scancodes
RECEIVE_ANSWER = %01000000 ; keyboard replies to a command
SEND_CMD = %00100000 ; host sends/sent the command byte
SEND_DATA = %00010000 ; host sends/sent the data byte
SEND_RECV = %00001000 ; keyboard sends additional data byte
SEND = SEND_CMD | SEND_DATA | SEND_RECV ; host is sending something, only used for checking status
2024-01-01 14:56:11 +01:00
NONE = %00000000
.endenum
2024-01-07 00:41:12 +01:00
.enum TYPEMATIC
REPEAT_MASK = %00011111 ; 00000 = 30Hz, ..., 11111 = 2Hz
DELAY250 = %00000000
DELAY500 = %00100000
DELAY750 = %01000000
DELAY1000 = %01100000
.endenum
2024-01-01 14:56:11 +01:00
.endscope
2024-01-07 00:41:12 +01:00
; see https://wiki.osdev.org/PS/2_Keyboard
.macro ps2kb_CmdEcho
lda #$ee
ldx #ps2kb::NO_DATA
ldy #0
jsr ps2kb::send_command
.endmacro
.macro ps2kb_CmdSetLeds mask
lda #$ed
.ifnblank mask
ldx #mask
.endif
ldy #0
jsr ps2kb::send_command
.endmacro
.macro ps2kb_CmdGetScancodeSet
lda #$f0
ldx #0
ldy #1
jsr ps2kb::send_command
.endmacro
.macro ps2kb_CmdSetScancodeSet set
.assert set = 1 .or set = 2 .or set = 3, warning, "ps2kb_CmdSetScancodeSet: invalid scancode set"
lda #$f0
ldx #set
ldy #0
jsr ps2kb::send_command
.endmacro
.macro ps2kb_CmdIdentify
lda #$f2
ldx #ps2kb::NO_DATA
ldy #2
jsr ps2kb::send_command
.endmacro
.macro ps2kb_CmdTypematicSettings settings
lda #$f3
ldx #settings
ldy #0
jsr ps2kb::send_command
.endmacro
.macro ps2kb_CmdEnable
lda #$f4
ldx #ps2kb::NO_DATA
ldy #0
jsr ps2kb::send_command
.endmacro
.macro ps2kb_CmdDisable
lda #$f5
ldx #ps2kb::NO_DATA
ldy #0
jsr ps2kb::send_command
.endmacro
.macro ps2kb_CmdSetTypematic scancode
ldy #0
.ifblank scancode
lda #$f7
ldx #ps2kb::NO_DATA
.else
lda #$fb
ldx #scancode
.endif
jsr ps2kb::send_command
.endmacro
.macro ps2kb_CmdSetMakeRelease scancode
ldy #0
.ifblank scancode
lda #$f8
ldx #ps2kb::NO_DATA
.else
lda #$fc
ldx #scancode
.endif
jsr ps2kb::send_command
.endmacro
.macro ps2kb_CmdSetMake scancode
ldy #0
.ifblank scancode
lda #$f9
ldx #ps2kb::NO_DATA
.else
lda #$fd
ldx #scancode
.endif
jsr ps2kb::send_command
.endmacro
.macro ps2kb_CmdSelfTest
lda #$ff
ldx #ps2kb::NO_DATA
ldy #1
jsr ps2kb::send_command
.endmacro
.macro ps2kb_WaitFinishCmd
:
wai
lda ps2kb::status
and #ps2kb::STATUS::SEND
bne :-
.endmacro
.macro ps2kb_PrintCmdFailed
Printf ps2kb::FMT_CMD_FAIL,ps2kb::send_cmd,ps2kb::send_data,ps2kb::cmd_response,ps2kb::cmd_response+1,ps2kb::cmd_response+2
.endmacro
2024-01-01 14:56:11 +01:00
.endif ; guard