wip: keyboard send

This commit is contained in:
matthias@arch 2024-01-02 23:37:07 +01:00
parent aebd813a55
commit e7bd5096cd
4 changed files with 374 additions and 138 deletions

View File

@ -42,10 +42,13 @@ irq:
; DEBUG_LED_ON 2 ; DEBUG_LED_ON 2
@irq_io1: @irq_io1:
lda IO1 + IO::IFR lda IO1 + IO::IFR
and IO1 + IO::IER ; sometimes CB1/2 IFR set even though not enabled in IER
sta irq_via_ifr sta irq_via_ifr
bbr7 irq_via_ifr,@irq_io2 ; skip bbr7 irq_via_ifr,@irq_io2 ; skip
bbs2 irq_via_ifr,@irq_kb1 ; shit reg -> first 8 bits bbs2 irq_via_ifr,@irq_kb_sr
bbs5 irq_via_ifr,@irq_kb2 ; timer -> last 3 bits bbs3 irq_via_ifr,@irq_kb_cb2
bbs4 irq_via_ifr,@irq_kb_cb1
bbs5 irq_via_ifr,@irq_kb_t2
bra @irq_unknown bra @irq_unknown
@irq_io2: @irq_io2:
lda IO2 + IO::IFR lda IO2 + IO::IFR
@ -56,7 +59,6 @@ irq:
@irq_unknown: @irq_unknown:
; this SHOULD never be reached ; this SHOULD never be reached
jsr lcd::clear
Print "Unknown IRQ" Print "Unknown IRQ"
; force reset interrupt flags ; force reset interrupt flags
lda #$ff lda #$ff
@ -71,14 +73,15 @@ irq:
bra @irq_return bra @irq_return
; jmp (spi_p::irq_handler) ; jmp (spi_p::irq_handler)
; JsrIndirect (spi_p::irq_handler), @irq_return ; JsrIndirect (spi_p::irq_handler), @irq_return
@irq_kb1: @irq_kb_sr:
; Print "$3000" ; Print "$3000"
jsr $3000 JsrIndirect ($3000), @irq_return
bra @irq_return @irq_kb_cb2:
@irq_kb2: JsrIndirect ($3020), @irq_return
; Print "$3100" @irq_kb_cb1:
jsr $3100 JsrIndirect ($3040), @irq_return
bra @irq_return @irq_kb_t2:
JsrIndirect ($3060), @irq_return
; @irq_dht: ; @irq_dht:
; lda IO1 + IO::T1CL ;T1L2 ; clear interrupt flag ; lda IO1 + IO::T1CL ;T1L2 ; clear interrupt flag
; bra @irq_return ; bra @irq_return

View File

@ -5,6 +5,8 @@
.include "keypad.h65" .include "keypad.h65"
.include "keyboard_handler.h65" .include "keyboard_handler.h65"
.include "chars.h65" .include "chars.h65"
.include "parity.h65"
.include "sleep.h65"
.import homeloop:absolute .import homeloop:absolute
.import home:absolute .import home:absolute
@ -25,37 +27,30 @@ CODE_START:
DEBUG_LED_OFF 1 DEBUG_LED_OFF 1
DEBUG_LED_OFF 2 DEBUG_LED_OFF 2
StoreDByte kb_irq1, ARG0 StoreDByte _process_cmd_answer, $3200
StoreDByte $3000, ARG2
; lda #<kb_irq1
; sta ARG0
; lda #>kb_irq1
; sta ARG1
; lda #<$3000
; sta ARG2
; lda #>$3000
; sta ARG3
ldy #10
jsr memcopy
StoreDByte kb_irq2, ARG0
StoreDByte $3100, ARG2
; lda #<kb_irq2
; sta ARG0
; lda #>kb_irq2
; sta ARG1
; lda #<$3100
; sta ARG2
; lda #>$3100
; sta ARG3
ldy #10
jsr memcopy
jsr ps2kb::init jsr ps2kb::init
stz kb::status stz kb::status
StoreDByte process_scancode,ps2kb::scancode_handler StoreDByte process_scancode,ps2kb::scancode_handler
jsr ps2kb::begin_receive ; jsr ps2kb::begin_receive
JsrIndirect @a1, @a2
stp
stp
stp
stp
stp
@a1:
lda #'1'
jsr lcd::print_char
rts
stp
stp
stp
stp
@a2:
lda #'2'
jsr lcd::print_char
lda #'%' lda #'%'
jsr lcd::print_char jsr lcd::print_char
@ -84,17 +79,17 @@ CODE_START:
@noscancode: @noscancode:
bbr5 kb::status, @shift_off bbr5 kb::status, @shift_off
@shift_on: @shift_on:
DEBUG_LED_ON 0 ; DEBUG_LED_ON 0
bra @check_caps bra @check_caps
@shift_off: @shift_off:
DEBUG_LED_OFF 0 ; DEBUG_LED_OFF 0
@check_caps: @check_caps:
bbr4 kb::status, @caps_off bbr4 kb::status, @caps_off
@caps_on: @caps_on:
DEBUG_LED_ON 2 ; DEBUG_LED_ON 2
bra @read_keypad bra @read_keypad
@caps_off: @caps_off:
DEBUG_LED_OFF 2 ; DEBUG_LED_OFF 2
@read_keypad: @read_keypad:
lda kp::_DEBUG_VAL lda kp::_DEBUG_VAL
jeq @loop jeq @loop
@ -113,6 +108,8 @@ CODE_START:
beq @lB beq @lB
cmp #'C' cmp #'C'
beq @lC beq @lC
cmp #'D'
beq @lD
jsr lcd::print_char jsr lcd::print_char
jmp @loop jmp @loop
@l1: @l1:
@ -133,8 +130,8 @@ CODE_START:
iny iny
jmp @loop jmp @loop
@lA: @lA:
lda ps2kb::VIA + IO::SR jsr ps2kb::begin_receive
jsr lcd::print_char ; StoreDByte _receive_irq_timer_handler, $3100
jmp @loop jmp @loop
@lB: @lB:
; Printf "kc%x;", out_str, kb::scancode ; Printf "kc%x;", out_str, kb::scancode
@ -149,26 +146,23 @@ CODE_START:
@lC: @lC:
jsr lcd::clear jsr lcd::clear
jmp @loop jmp @loop
@lD:
lda ps2kb::STATUS::SEND_CMD
sta ps2kb::status
; lda #$ed
; ldx #%00000111
; lda #$f6
; lda #$ff
lda #$ee
; ldx #$ee
; ldx #0
ldx #ps2kb::NO_DATA
sta ps2kb::send_cmd
stx ps2kb::send_data
jsr _send_byte
; jsr ps2kb::send_command;
jmp @loop
; key_read: .res 2
; scancode: .res 1
kb_irq1:
; lda #'!'
; jsr lcd::print_char
jsr ps2kb::_receive_irq_shift_reg_handler
; lda #':'
; jsr lcd::print_char
rts
.byte '='
kb_irq2:
; lda #'?'
; jsr lcd::print_char
; jsr kb::on_timer_irq
jsr ps2kb::_receive_irq_timer_handler
; lda #';'
; jsr lcd::print_char
rts
.byte '@' .byte '@'
.proc process_scancode .proc process_scancode
@ -297,10 +291,199 @@ kb_irq2:
rts rts
.endproc .endproc
;;********************************************************************************
;; @macro Enable the clock signal from the keyboard
;; @modifies: A
;; @details
;; Stop pulling the keyboards clock low
;;********************************************************************************
.macro _EnableClock
; set pin to input
lda ps2kb::VIA + ps2kb::PULL_DDR
and #<~ps2kb::PULL_MASK_CLK
sta ps2kb::VIA + ps2kb::PULL_DDR
.endmacro
;;********************************************************************************
;; @macro Disable the clock signal from the keyboard
;; @modifies: A
;; @details
;; Pulls the keyboards clock low
;;********************************************************************************
.macro _DisableClock
; set pin to output
lda ps2kb::VIA + ps2kb::PULL_DDR
ora #ps2kb::PULL_MASK_CLK
sta ps2kb::VIA + ps2kb::PULL_DDR
; set pin low
lda ps2kb::VIA + ps2kb::PULL_REG
and #<~ps2kb::PULL_MASK_CLK
sta ps2kb::VIA + ps2kb::PULL_REG
.endmacro
.proc _send_byte
pha
IO_DisableIRQ ps2kb::VIA, (IO::IRQ::T2 | IO::IRQ::SR)
_DisableClock
lda #'X'
jsr lcd::print_char
; set shift register to output
lda ps2kb::VIA + IO::ACR
and #<~IO::ACR_MASK::SR
ora #IO::ACR::SR_SOUT_PHIE
sta ps2kb::VIA + IO::ACR
stz ps2kb::VIA + IO::SR
; shift out the startbit = data low
_EnableClock
_DisableClock
; reset shift register to start the count at 0 again
lda #IO::ACR::SR_SOUT_PHIE
trb ps2kb::VIA + IO::ACR
tsb ps2kb::VIA + IO::ACR
; setup the low timer byte
lda #<ps2kb::TIMER_SEND
sta ps2kb::VIA + IO::T2CL
; setup interrupt handlers
StoreDByte ps2kb::_send_irq_shift_reg_handler, $3000
; StoreDByte _send_irq_cb2_handler, $3020
; StoreDByte _send_irq_cb1_handler, $3040
StoreDByte _send_irq_timer_handler, $3060
pla
Reverse A
pha
CalculateOddParity
ror ; Parity -> C
lda #$ff
ror ; Parity -> bit 7, rest = 1
sta ps2kb::send_last_bits ; loaded into SR by irq handler
pla
sta ps2kb::VIA + IO::SR
IO_EnableIRQ ps2kb::VIA, IO::IRQ::SR
_EnableClock
rts
.endproc
; .proc _send_irq_shift_reg_handler
; lda ps2kb::send_last_bits
; sta ps2kb::VIA + IO::SR
; IO_DisableIRQ ps2kb::VIA, IO::IRQ::SR
; IO_EnableIRQ ps2kb::VIA, IO::IRQ::T2
; ; start timer, low order count already in latch after init
; lda #>ps2kb::TIMER_SEND
; sta ps2kb::VIA + IO::T2CH
; rts
; .endproc
.proc _send_irq_timer_handler
lda ps2kb::VIA + IO::T2CL ; clear interrupt flag
IO_DisableIRQ ps2kb::VIA, IO::IRQ::T2
; disable shift register
lda ps2kb::VIA + IO::ACR
and #<~IO::ACR_MASK::SR
sta ps2kb::VIA + IO::ACR
bra _send_done
; lda ps2kb::VIA + IO::IFR
; jsr str::uint8_to_hex_str
; jsr lcd::print_char
; txa
; jsr lcd::print_char
rts
.endproc
; @details
; Set the SEND_CMD_WAIT status bit the first time
; and jump to _send_done the second time it is called
; .proc _send_irq_cb1_handler
; ; clear the flag and disable interrupts
; ; DEBUG_LED_ON 1
; lda #'i'
; jsr lcd::print_char
; stp
; lda #IO::IRQ::CB1
; sta ps2kb::VIA + IO::IFR
; sta ps2kb::VIA + IO::IER
; ; DEBUG_LED_OFF 1
; bra _check_done
; .endproc
; .proc _send_irq_cb2_handler
; ; DEBUG_LED_ON 0
; ; lda #'I'
; ; jsr lcd::print_char
; lda #IO::IRQ::CB2
; sta ps2kb::VIA + IO::IFR
; sta ps2kb::VIA + IO::IER
; ; DEBUG_LED_OFF 0
; bra _send_done
; bra _check_done
; .endproc
; .proc _check_done
; ; check if done, by checking if SEND_CMD_WAIT bit is set
; lda #ps2kb::STATUS::SEND_CMD_WAIT
; tsb ps2kb::status
; bne _send_done ; SEND_CMD_WAIT was already set
; rts
; .endproc
.proc _send_done
_DisableClock ; disable keyboard while setting up receive
lda #'D'
jsr lcd::print_char
; Sleep 1
lda ps2kb::status
and #ps2kb::STATUS::SEND_CMD
beq @status_send_data ; data byte already sent
@status_send_cmd:
lda #ps2kb::STATUS::SEND_DATA
lda ps2kb::status
; check if a data byte needs to be sent
lda ps2kb::send_data
beq @send_data ; if 0
cmp #ps2kb::NO_DATA
beq @receive_answer ; if not NO_DATA
@send_data:
jmp _send_byte ; send the data
@status_send_data:
@receive_answer:
_DisableClock ; disable keyboard while setting up receive
DEBUG_LED_ON 0
lda #ps2kb::STATUS::RECEIVE_ANSWER
sta ps2kb::status
jmp ps2kb::begin_receive
.endproc
.proc _process_cmd_answer
Strf fmt_answer, out_str, ps2kb::send_cmd, ps2kb::send_data, ps2kb::scancode
PrintNC out_str
DEBUG_LED_ON 1
stz ps2kb::scancode
lda ps2kb::prev_status
sta ps2kb::status
; set pin to input
; lda ps2kb::VIA + ps2kb::CLK_PULL_DDR
; and #<~ps2kb::CLK_PULL_MASK
; sta ps2kb::VIA + ps2kb::CLK_PULL_DDR
rts
.endproc
out_idx: .res 1 out_idx: .res 1
out_str: .res 40 out_str: .res 40
char: .res 1 char: .res 1
keycode: .res 1 keycode: .res 1
keycode_flags: .res 1 keycode_flags: .res 1
fmt_codechar: .asciiz "%x %x %c " fmt_codechar: .asciiz "%x %x %c "
fmt_code: .asciiz "%x %x " fmt_code: .asciiz "%x %x "
fmt_answer: .asciiz "%x-%x>%x"

View File

@ -30,20 +30,31 @@ INCLUDE_PS2_KEYBOARD = 1
.scope ps2kb .scope ps2kb
Import ps2kb,init,begin_receive,send_command,scancode,status,scancode_handler Import ps2kb,init,begin_receive,send_command,scancode,status,scancode_handler
Import ps2kb, _receive_irq_shift_reg_handler, _receive_irq_timer_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 VIA = IO1
TIMER = 230 ; 230 ms (@1MHz) ; 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 ; use RA4 to pull the clock low
CLK_PULL_MASK= %00001000 PULL_REG = IO::RANH
CLK_PULL_R = IO::RANH PULL_DDR = IO::DDRA
CLK_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 .enum STATUS
RECEIVE_KEYS = %10000000 RECEIVE_KEYS = %10000000
RECEIVE_ANSWER = %01000000 RECEIVE_ANSWER = %01000000
SEND_CMD = %00100000 SEND_CMD = %00100000
SEND_DATA = %00010000
SEND_CMD_WAIT = %00001000
NONE = %00000000 NONE = %00000000
.endenum .endenum
.endscope .endscope

View File

@ -3,10 +3,12 @@
.include "lcd.h65" .include "lcd.h65"
.include "parity.h65" .include "parity.h65"
Export ps2kb,init,begin_receive,send_command,scancode,status,scancode_handler Export ps2kb,init,begin_receive,send_command,scancode,status,scancode_handler
Export ps2kb, _receive_irq_shift_reg_handler, _receive_irq_timer_handler Export ps2kb, _receive_irq_shift_reg_handler, _receive_irq_timer_handler, _send_byte, _send_irq_shift_reg_handler, _send_irq_timer_handler,
Export ps2kb, send_last_bits, send_cmd, send_data, key_read, prev_status
.bss .bss
status: .res 1 status: .res 1
prev_status: .res 1
send_last_bits: .res 1 send_last_bits: .res 1
send_data: .res 1 send_data: .res 1
send_cmd: .res 1 send_cmd: .res 1
@ -24,16 +26,9 @@ scancode_handler: .res 2
;;******************************************************************************** ;;********************************************************************************
.macro _EnableClock .macro _EnableClock
; set pin to input ; set pin to input
lda ps2kb::VIA + ps2kb::CLK_PULL_DDR lda ps2kb::VIA + ps2kb::PULL_DDR
and #<~ps2kb::CLK_PULL_MASK and #<~ps2kb::PULL_MASK_CLK
sta ps2kb::VIA + ps2kb::CLK_PULL_DDR sta ps2kb::VIA + ps2kb::PULL_DDR
.endmacro
.macro _DisableTimerIRQ
; set pin to input
lda ps2kb::VIA + ps2kb::CLK_PULL_DDR
and #<~ps2kb::CLK_PULL_MASK
sta ps2kb::VIA + ps2kb::CLK_PULL_DDR
.endmacro .endmacro
;;******************************************************************************** ;;********************************************************************************
@ -44,17 +39,45 @@ scancode_handler: .res 2
;;******************************************************************************** ;;********************************************************************************
.macro _DisableClock .macro _DisableClock
; set pin to output ; set pin to output
lda ps2kb::VIA + ps2kb::CLK_PULL_DDR lda ps2kb::VIA + ps2kb::PULL_DDR
ora #ps2kb::CLK_PULL_MASK ora #ps2kb::PULL_MASK_CLK
sta ps2kb::VIA + ps2kb::CLK_PULL_DDR sta ps2kb::VIA + ps2kb::PULL_DDR
; set pin low ; set pin low
lda ps2kb::VIA + ps2kb::CLK_PULL_R lda ps2kb::VIA + ps2kb::PULL_REG
and #<~ps2kb::CLK_PULL_MASK and #<~ps2kb::PULL_MASK_CLK
sta ps2kb::VIA + ps2kb::CLK_PULL_R sta ps2kb::VIA + ps2kb::PULL_REG
.endmacro
;;********************************************************************************
;; @macro Stop pulling the keyboard data pin low
;; @modifies: A
;;********************************************************************************
.macro _StopPullDataLow
; set pin to input
lda ps2kb::VIA + ps2kb::PULL_DDR
and #<~ps2kb::PULL_MASK_DAT
sta ps2kb::VIA + ps2kb::PULL_DDR
.endmacro
;;********************************************************************************
;; @macro Pull the keyboard data pin low
;; @modifies: A
;;********************************************************************************
.macro _PullDataLow
; set pin to output
lda ps2kb::VIA + ps2kb::PULL_DDR
ora #ps2kb::PULL_MASK_DAT
sta ps2kb::VIA + ps2kb::PULL_DDR
; set pin low
lda ps2kb::VIA + ps2kb::PULL_REG
and #<~ps2kb::PULL_MASK_DAT
sta ps2kb::VIA + ps2kb::PULL_REG
.endmacro .endmacro
.proc init .proc init
_DisableClock
stz key_read stz key_read
stz key_read+1 stz key_read+1
stz scancode stz scancode
@ -64,10 +87,6 @@ scancode_handler: .res 2
and #<~IO::ACR_MASK::SR and #<~IO::ACR_MASK::SR
ora #IO::ACR::T2_IRQ_LOAD ora #IO::ACR::T2_IRQ_LOAD
sta ps2kb::VIA + IO::ACR sta ps2kb::VIA + IO::ACR
; the 3 last bits take about 230us, at @1MHz => wait 230 cycles and then the shift register
; (this could be shorter since the it takes a few cycles after the interrupt)
lda #<ps2kb::TIMER
sta ps2kb::VIA + IO::T2CL
; load this rts as scancode_handler ; load this rts as scancode_handler
StoreDByte @rts, scancode_handler StoreDByte @rts, scancode_handler
@rts: @rts:
@ -85,25 +104,32 @@ scancode_handler: .res 2
.proc begin_receive .proc begin_receive
; disable timer interrupts (this might be called while waiting on the last 3 bits) ; disable timer interrupts (this might be called while waiting on the last 3 bits)
IO_DisableIRQ ps2kb::VIA, IO::IRQ::T2 IO_DisableIRQ ps2kb::VIA, IO::IRQ::T2
; set shift register to shift in under external clock on CB1 ; (re)set shift register to shift in under external clock on CB1
lda ps2kb::VIA + IO::ACR lda ps2kb::VIA + IO::ACR
and #<~IO::ACR_MASK::SR and #<~IO::ACR_MASK::SR
sta ps2kb::VIA + IO::ACR ; important, disabling SR resets the count
ora #IO::ACR::SR_SIN_PHIE ora #IO::ACR::SR_SIN_PHIE
sta ps2kb::VIA + IO::ACR sta ps2kb::VIA + IO::ACR
stz key_read stz key_read
stz key_read+1 stz key_read+1
stz scancode stz scancode
bit status bit status
; the 3 last bits take about 230us, at @1MHz => wait 230 cycles and then the shift register
; (this could be shorter since the it takes a few cycles after the interrupt)
lda #<ps2kb::TIMER_RECV
sta ps2kb::VIA + IO::T2CL
; set to RECEIVE_KEYS only if RECEIVE_ANSWER is not set ; set to RECEIVE_KEYS only if RECEIVE_ANSWER is not set
bvs @receive_answer bvs @status_set
lda #ps2kb::STATUS::RECEIVE_KEYS lda #ps2kb::STATUS::RECEIVE_KEYS
sta status sta status
@receive_answer: @status_set:
; todo setup irq handlers
StoreDByte _receive_irq_shift_reg_handler, $3000
StoreDByte _receive_irq_timer_handler, $3060
_EnableClock _EnableClock
; todo setup irq handlers
IO_EnableIRQ ps2kb::VIA, IO::IRQ::SR IO_EnableIRQ ps2kb::VIA, IO::IRQ::SR
; reset and start SR ; reset and start SR
stz ps2kb::VIA + IO::SR stz ps2kb::VIA + IO::SR
@ -132,7 +158,7 @@ scancode_handler: .res 2
IO_DisableIRQ ps2kb::VIA, IO::IRQ::SR IO_DisableIRQ ps2kb::VIA, IO::IRQ::SR
IO_EnableIRQ ps2kb::VIA, IO::IRQ::T2 IO_EnableIRQ ps2kb::VIA, IO::IRQ::T2
; start timer, low order count already in latch after init ; start timer, low order count already in latch after init
lda #>ps2kb::TIMER lda #>ps2kb::TIMER_RECV
sta ps2kb::VIA + IO::T2CH sta ps2kb::VIA + IO::T2CH
rts rts
.endproc .endproc
@ -150,7 +176,7 @@ scancode_handler: .res 2
;;******************************************************************************** ;;********************************************************************************
.proc _receive_irq_timer_handler .proc _receive_irq_timer_handler
lda ps2kb::VIA + IO::SR lda ps2kb::VIA + IO::SR
sta key_read + 1 sta key_read+1
lda ps2kb::VIA + IO::T2CL ; clear interrupt flag lda ps2kb::VIA + IO::T2CL ; clear interrupt flag
@ -173,10 +199,13 @@ scancode_handler: .res 2
rol ; C -> bit 0, startbit -> C rol ; C -> bit 0, startbit -> C
Reverse A Reverse A
sta scancode sta scancode
CalculateOddParity
eor key_read+1 ; if bit 0 is 1 - parity error ; check parity
and #1 ; bit 1 is still D7 ; CalculateOddParity
bne @parity_error ; eor key_read+1 ; if bit 0 is 1 - parity error
; and #1 ; bit 1 is still D7
; bne @parity_error
; check what to do with the scancode ; check what to do with the scancode
bit status bit status
bcc @status_not_receive_keys bcc @status_not_receive_keys
@ -198,15 +227,15 @@ scancode_handler: .res 2
;; @function Send a command to the keyboard ;; @function Send a command to the keyboard
;; @modifies: A,X,Y ;; @modifies: A,X,Y
;; @param A: The command byte ;; @param A: The command byte
;; @param X: The data byte or 0 if only the command byte should be sent ;; @param X: The data byte or NO_DATA if only the command byte should be sent
;;******************************************************************************** ;;********************************************************************************
.proc send_command .proc send_command
ldy status
sty prev_status
ldy #ps2kb::STATUS::SEND_CMD
sty status
sta send_cmd ; store if it needs to be resent sta send_cmd ; store if it needs to be resent
cpx #0
beq @jmp_send_byte
@store_data:
stx send_data stx send_data
@jmp_send_byte:
jmp _send_byte jmp _send_byte
.endproc .endproc
@ -217,36 +246,51 @@ scancode_handler: .res 2
;; @param A: The byte to send ;; @param A: The byte to send
;; @details ;; @details
;; - pull clock low to stop keyboard transmissions ;; - pull clock low to stop keyboard transmissions
;; - setup shift register to shift out ;; - setup SR to shift out
;; - put startbit + D0-6 in shift register ;; - pull data low (by shifting out a zero)
;; - store D7 + parity + stopbit in memory ;; - reset SR
;; - TODO setup SR and T2 interrupt handlers ;; - put (reversed) byte in SR
;; - put parity + stopbit(s) in send_last_bits variable
;; - setup interrupt handlers
;; - enable clock
;;******************************************************************************** ;;********************************************************************************
.proc _send_byte .proc _send_byte
pha pha
IO_DisableIRQ ps2kb::VIA, IO::IRQ::T2 IO_DisableIRQ ps2kb::VIA, (IO::IRQ::T2 | IO::IRQ::SR)
_DisableClock _DisableClock
; (re)set shift register to shift out under external clock on CB1
; set shift register to output
lda ps2kb::VIA + IO::ACR lda ps2kb::VIA + IO::ACR
and #<~IO::ACR_MASK::SR and #<~IO::ACR_MASK::SR
ora #IO::ACR::SR_SOUT_PHIE ora #IO::ACR::SR_SOUT_PHIE
sta ps2kb::VIA + IO::ACR sta ps2kb::VIA + IO::ACR
IO_EnableIRQ ps2kb::VIA, IO::IRQ::SR stz ps2kb::VIA + IO::SR
; shift out the startbit = data low
_EnableClock
_DisableClock
; reset shift register to start the count at 0 again
lda #IO::ACR::SR_SOUT_PHIE
trb ps2kb::VIA + IO::ACR
tsb ps2kb::VIA + IO::ACR
; setup the low timer byte
lda #<ps2kb::TIMER_SEND
sta ps2kb::VIA + IO::T2CL
StoreDByte _send_irq_shift_reg_handler, $3000
StoreDByte _send_irq_timer_handler, $3006
pla pla
Reverse A
pha pha
; split into the 11 bits
CalculateOddParity CalculateOddParity
tax ror ; Parity -> C
lda #$ff
ror ; Parity -> bit 7, rest = 1
sta ps2kb::send_last_bits ; loaded into SR by irq handler
pla pla
clc ; C = 0 (startbi)
rol ; C -> bit 0, D7 -> C
sta ps2kb::VIA + IO::SR sta ps2kb::VIA + IO::SR
txa IO_EnableIRQ ps2kb::VIA, IO::IRQ::SR
ror ; C -> bit 0 (D7)
ora #%00000100 ; set stopbit
; A = 000001P7 where 7 = D7, P = Parity
sta send_last_bits ; loaded into SR by irq handler
; stop pulling clk low, which causes the startbit to be shifted out
_EnableClock _EnableClock
rts rts
.endproc .endproc
@ -262,17 +306,13 @@ scancode_handler: .res 2
;; - start timer 2 ;; - start timer 2
;;******************************************************************************** ;;********************************************************************************
.proc _send_irq_shift_reg_handler .proc _send_irq_shift_reg_handler
lda send_last_bits lda ps2kb::send_last_bits
sta ps2kb::VIA + IO::SR sta ps2kb::VIA + IO::SR
; disable SR interrupts IO_DisableIRQ ps2kb::VIA, IO::IRQ::SR
lda #IO::IRQ::SR IO_EnableIRQ ps2kb::VIA, IO::IRQ::T2
sta ps2kb::VIA + IO::IER
; enable timer interrupts
lda #(IO::IRQ::IRQ | IO::IRQ::T2)
sta ps2kb::VIA + IO::IER
; start timer, low order count already in latch after init ; start timer, low order count already in latch after init
lda #>ps2kb::TIMER lda #>ps2kb::TIMER_SEND
sta ps2kb::VIA + IO::T2CH sta ps2kb::VIA + IO::T2CH
rts rts
.endproc .endproc
@ -293,21 +333,20 @@ scancode_handler: .res 2
.proc _send_irq_timer_handler .proc _send_irq_timer_handler
lda ps2kb::VIA + IO::T2CL ; clear interrupt flag lda ps2kb::VIA + IO::T2CL ; clear interrupt flag
IO_DisableIRQ ps2kb::VIA, IO::IRQ::T2 IO_DisableIRQ ps2kb::VIA, IO::IRQ::T2
; no SR reset necessary, will be done in begin_receive or send_byte
lda send_data lda ps2kb::send_data
beq @receive beq @receive
stz send_data stz ps2kb::send_data
jmp _send_byte jmp _send_byte
rts rts
@receive: @receive:
_DisableClock ; disable keyboard while setting up receive
lda #ps2kb::STATUS::RECEIVE_ANSWER lda #ps2kb::STATUS::RECEIVE_ANSWER
sta status sta ps2kb::status
jmp begin_receive jmp ps2kb::begin_receive
.endproc .endproc
.proc _process_cmd_answer .proc _process_cmd_answer
@success: jmp ($3200)
rts
.endproc .endproc