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

View File

@ -5,6 +5,8 @@
.include "keypad.h65"
.include "keyboard_handler.h65"
.include "chars.h65"
.include "parity.h65"
.include "sleep.h65"
.import homeloop:absolute
.import home:absolute
@ -25,37 +27,30 @@ CODE_START:
DEBUG_LED_OFF 1
DEBUG_LED_OFF 2
StoreDByte kb_irq1, ARG0
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
StoreDByte _process_cmd_answer, $3200
jsr ps2kb::init
stz kb::status
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 #'%'
jsr lcd::print_char
@ -84,17 +79,17 @@ CODE_START:
@noscancode:
bbr5 kb::status, @shift_off
@shift_on:
DEBUG_LED_ON 0
; DEBUG_LED_ON 0
bra @check_caps
@shift_off:
DEBUG_LED_OFF 0
; DEBUG_LED_OFF 0
@check_caps:
bbr4 kb::status, @caps_off
@caps_on:
DEBUG_LED_ON 2
; DEBUG_LED_ON 2
bra @read_keypad
@caps_off:
DEBUG_LED_OFF 2
; DEBUG_LED_OFF 2
@read_keypad:
lda kp::_DEBUG_VAL
jeq @loop
@ -113,6 +108,8 @@ CODE_START:
beq @lB
cmp #'C'
beq @lC
cmp #'D'
beq @lD
jsr lcd::print_char
jmp @loop
@l1:
@ -133,8 +130,8 @@ CODE_START:
iny
jmp @loop
@lA:
lda ps2kb::VIA + IO::SR
jsr lcd::print_char
jsr ps2kb::begin_receive
; StoreDByte _receive_irq_timer_handler, $3100
jmp @loop
@lB:
; Printf "kc%x;", out_str, kb::scancode
@ -149,26 +146,23 @@ CODE_START:
@lC:
jsr lcd::clear
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 '@'
.proc process_scancode
@ -297,6 +291,194 @@ kb_irq2:
rts
.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_str: .res 40
char: .res 1
@ -304,3 +486,4 @@ keycode: .res 1
keycode_flags: .res 1
fmt_codechar: .asciiz "%x %x %c "
fmt_code: .asciiz "%x %x "
fmt_answer: .asciiz "%x-%x>%x"

View File

@ -30,20 +30,31 @@ INCLUDE_PS2_KEYBOARD = 1
.scope ps2kb
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
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
CLK_PULL_MASK= %00001000
CLK_PULL_R = IO::RANH
CLK_PULL_DDR = IO::DDRA
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

View File

@ -3,10 +3,12 @@
.include "lcd.h65"
.include "parity.h65"
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
status: .res 1
prev_status: .res 1
send_last_bits: .res 1
send_data: .res 1
send_cmd: .res 1
@ -24,16 +26,9 @@ scancode_handler: .res 2
;;********************************************************************************
.macro _EnableClock
; set pin to input
lda ps2kb::VIA + ps2kb::CLK_PULL_DDR
and #<~ps2kb::CLK_PULL_MASK
sta ps2kb::VIA + ps2kb::CLK_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
lda ps2kb::VIA + ps2kb::PULL_DDR
and #<~ps2kb::PULL_MASK_CLK
sta ps2kb::VIA + ps2kb::PULL_DDR
.endmacro
;;********************************************************************************
@ -44,17 +39,45 @@ scancode_handler: .res 2
;;********************************************************************************
.macro _DisableClock
; set pin to output
lda ps2kb::VIA + ps2kb::CLK_PULL_DDR
ora #ps2kb::CLK_PULL_MASK
sta ps2kb::VIA + ps2kb::CLK_PULL_DDR
lda ps2kb::VIA + ps2kb::PULL_DDR
ora #ps2kb::PULL_MASK_CLK
sta ps2kb::VIA + ps2kb::PULL_DDR
; set pin low
lda ps2kb::VIA + ps2kb::CLK_PULL_R
and #<~ps2kb::CLK_PULL_MASK
sta ps2kb::VIA + ps2kb::CLK_PULL_R
lda ps2kb::VIA + ps2kb::PULL_REG
and #<~ps2kb::PULL_MASK_CLK
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
.proc init
_DisableClock
stz key_read
stz key_read+1
stz scancode
@ -64,10 +87,6 @@ scancode_handler: .res 2
and #<~IO::ACR_MASK::SR
ora #IO::ACR::T2_IRQ_LOAD
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
StoreDByte @rts, scancode_handler
@rts:
@ -85,25 +104,32 @@ scancode_handler: .res 2
.proc begin_receive
; disable timer interrupts (this might be called while waiting on the last 3 bits)
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
and #<~IO::ACR_MASK::SR
sta ps2kb::VIA + IO::ACR ; important, disabling SR resets the count
ora #IO::ACR::SR_SIN_PHIE
sta ps2kb::VIA + IO::ACR
stz key_read
stz key_read+1
stz scancode
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
bvs @receive_answer
bvs @status_set
lda #ps2kb::STATUS::RECEIVE_KEYS
sta status
@receive_answer:
@status_set:
; todo setup irq handlers
StoreDByte _receive_irq_shift_reg_handler, $3000
StoreDByte _receive_irq_timer_handler, $3060
_EnableClock
; todo setup irq handlers
IO_EnableIRQ ps2kb::VIA, IO::IRQ::SR
; reset and start SR
stz ps2kb::VIA + IO::SR
@ -132,7 +158,7 @@ scancode_handler: .res 2
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
lda #>ps2kb::TIMER_RECV
sta ps2kb::VIA + IO::T2CH
rts
.endproc
@ -150,7 +176,7 @@ scancode_handler: .res 2
;;********************************************************************************
.proc _receive_irq_timer_handler
lda ps2kb::VIA + IO::SR
sta key_read + 1
sta key_read+1
lda ps2kb::VIA + IO::T2CL ; clear interrupt flag
@ -173,10 +199,13 @@ scancode_handler: .res 2
rol ; C -> bit 0, startbit -> C
Reverse A
sta scancode
CalculateOddParity
eor key_read+1 ; if bit 0 is 1 - parity error
and #1 ; bit 1 is still D7
bne @parity_error
; check parity
; CalculateOddParity
; 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
bit status
bcc @status_not_receive_keys
@ -198,15 +227,15 @@ scancode_handler: .res 2
;; @function Send a command to the keyboard
;; @modifies: A,X,Y
;; @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
ldy status
sty prev_status
ldy #ps2kb::STATUS::SEND_CMD
sty status
sta send_cmd ; store if it needs to be resent
cpx #0
beq @jmp_send_byte
@store_data:
stx send_data
@jmp_send_byte:
jmp _send_byte
.endproc
@ -217,36 +246,51 @@ scancode_handler: .res 2
;; @param A: The byte to send
;; @details
;; - pull clock low to stop keyboard transmissions
;; - setup shift register to shift out
;; - put startbit + D0-6 in shift register
;; - store D7 + parity + stopbit in memory
;; - TODO setup SR and T2 interrupt handlers
;; - setup SR to shift out
;; - pull data low (by shifting out a zero)
;; - reset SR
;; - put (reversed) byte in SR
;; - put parity + stopbit(s) in send_last_bits variable
;; - setup interrupt handlers
;; - enable clock
;;********************************************************************************
.proc _send_byte
pha
IO_DisableIRQ ps2kb::VIA, IO::IRQ::T2
IO_DisableIRQ ps2kb::VIA, (IO::IRQ::T2 | IO::IRQ::SR)
_DisableClock
; (re)set shift register to shift out under external clock on CB1
; 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
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
Reverse A
pha
; split into the 11 bits
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
clc ; C = 0 (startbi)
rol ; C -> bit 0, D7 -> C
sta ps2kb::VIA + IO::SR
txa
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
IO_EnableIRQ ps2kb::VIA, IO::IRQ::SR
_EnableClock
rts
.endproc
@ -262,17 +306,13 @@ scancode_handler: .res 2
;; - start timer 2
;;********************************************************************************
.proc _send_irq_shift_reg_handler
lda send_last_bits
lda ps2kb::send_last_bits
sta ps2kb::VIA + IO::SR
; disable SR interrupts
lda #IO::IRQ::SR
sta ps2kb::VIA + IO::IER
; enable timer interrupts
lda #(IO::IRQ::IRQ | IO::IRQ::T2)
sta ps2kb::VIA + IO::IER
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
lda #>ps2kb::TIMER_SEND
sta ps2kb::VIA + IO::T2CH
rts
.endproc
@ -293,21 +333,20 @@ scancode_handler: .res 2
.proc _send_irq_timer_handler
lda ps2kb::VIA + IO::T2CL ; clear interrupt flag
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
stz send_data
stz ps2kb::send_data
jmp _send_byte
rts
@receive:
_DisableClock ; disable keyboard while setting up receive
lda #ps2kb::STATUS::RECEIVE_ANSWER
sta status
jmp begin_receive
sta ps2kb::status
jmp ps2kb::begin_receive
.endproc
.proc _process_cmd_answer
@success:
rts
jmp ($3200)
.endproc