490 lines
11 KiB
Plaintext
490 lines
11 KiB
Plaintext
.include "system.h65"
|
|
.include "string.h65"
|
|
.include "lcd.h65"
|
|
.include "math.h65"
|
|
.include "keypad.h65"
|
|
.include "keyboard_handler.h65"
|
|
.include "chars.h65"
|
|
.include "parity.h65"
|
|
.include "sleep.h65"
|
|
.import homeloop:absolute
|
|
.import home:absolute
|
|
|
|
.segment "SPI"
|
|
.export CODE_START
|
|
|
|
.import memcopy
|
|
|
|
|
|
|
|
CODE_START:
|
|
.assert * = $5000, error, "SPI Code not at $5000"
|
|
jsr lcd::clear
|
|
lda #'$'
|
|
jsr lcd::print_char
|
|
; jmp homeloop
|
|
DEBUG_LED_OFF 0
|
|
DEBUG_LED_OFF 1
|
|
DEBUG_LED_OFF 2
|
|
|
|
StoreDByte _process_cmd_answer, $3200
|
|
|
|
|
|
jsr ps2kb::init
|
|
stz kb::status
|
|
StoreDByte process_scancode,ps2kb::scancode_handler
|
|
; 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
|
|
|
|
stz kp::_DEBUG_VAL
|
|
ldy #0
|
|
@loop:
|
|
wai
|
|
lda ps2kb::scancode
|
|
beq @noscancode
|
|
jsr process_scancode
|
|
stz ps2kb::scancode
|
|
lda char
|
|
beq @onlykeycode
|
|
Strf fmt_codechar,out_str,keycode,kb::status,char
|
|
PrintNC out_str
|
|
stz char
|
|
stz keycode
|
|
bra @noscancode
|
|
@onlykeycode:
|
|
lda keycode
|
|
beq @noscancode
|
|
Strf fmt_code,out_str,keycode,keycode_flags
|
|
PrintNC out_str
|
|
stz keycode
|
|
@noscancode:
|
|
bbr5 kb::status, @shift_off
|
|
@shift_on:
|
|
; DEBUG_LED_ON 0
|
|
bra @check_caps
|
|
@shift_off:
|
|
; DEBUG_LED_OFF 0
|
|
@check_caps:
|
|
bbr4 kb::status, @caps_off
|
|
@caps_on:
|
|
; DEBUG_LED_ON 2
|
|
bra @read_keypad
|
|
@caps_off:
|
|
; DEBUG_LED_OFF 2
|
|
@read_keypad:
|
|
lda kp::_DEBUG_VAL
|
|
jeq @loop
|
|
stz kp::_DEBUG_VAL
|
|
cmp #'*'
|
|
jeq homeloop
|
|
cmp #'1'
|
|
beq @l1
|
|
cmp #'2'
|
|
beq @l2
|
|
cmp #'3'
|
|
beq @l3
|
|
cmp #'A'
|
|
beq @lA
|
|
cmp #'B'
|
|
beq @lB
|
|
cmp #'C'
|
|
beq @lC
|
|
cmp #'D'
|
|
beq @lD
|
|
jsr lcd::print_char
|
|
jmp @loop
|
|
@l1:
|
|
; jsr irq_on_shift_reg
|
|
jsr $3000
|
|
lda #'*'
|
|
jsr lcd::print_char
|
|
jmp @loop
|
|
@l2:
|
|
; jsr irq_on_timer
|
|
jsr $3100
|
|
lda #'#'
|
|
jsr lcd::print_char
|
|
jmp @loop
|
|
@l3:
|
|
lda $3000,y
|
|
jsr lcd::print_char
|
|
iny
|
|
jmp @loop
|
|
@lA:
|
|
jsr ps2kb::begin_receive
|
|
; StoreDByte _receive_irq_timer_handler, $3100
|
|
jmp @loop
|
|
@lB:
|
|
; Printf "kc%x;", out_str, kb::scancode
|
|
jsr lcd::clear
|
|
ldx out_idx
|
|
lda #0
|
|
sta out_str,x
|
|
Print out_str
|
|
stz out_idx
|
|
|
|
jmp @loop
|
|
@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
|
|
|
|
.byte '@'
|
|
|
|
.proc process_scancode
|
|
; DEBUG_LED_OFF 1
|
|
; check how this scancode needs to be interpreted
|
|
ldx ps2kb::scancode
|
|
bit kb::status
|
|
jmi release_key ; bit 7 set
|
|
bvs @twobytecode ; bit 6 set
|
|
; DEBUG_LED_ON 1
|
|
|
|
; check mods
|
|
cpx #kb::K_RELEASE
|
|
beq @code_release
|
|
cpx #kb::K::LEFTSHIFT
|
|
beq @code_shift
|
|
cpx #kb::K::RIGHTSHIFT
|
|
beq @code_shift
|
|
cpx #kb::K_TWOBYTE
|
|
beq @code_twobytecode
|
|
cpx #kb::K::CAPSLOCK
|
|
beq @code_capslock
|
|
|
|
; a real keycode and not a released keycode, twobyte or release scancode
|
|
stz keycode_flags
|
|
stx keycode
|
|
cmp #$62 ; $61 is the largest ascii scancode
|
|
bcs @special
|
|
bbs5 kb::status,@modshift ; if shift active
|
|
@nomod:
|
|
lda kb::CHARS_NOMOD,x
|
|
beq @special
|
|
@char: ; order which is fastet most of the time (lowercase characters)
|
|
sta char
|
|
rts
|
|
@modshift:
|
|
lda kb::CHARS_MODSHIFT,x
|
|
bne @char
|
|
@special:
|
|
rts
|
|
|
|
@code_release: ; set release
|
|
smb7 kb::status
|
|
rts
|
|
@code_twobytecode: ; set twobytecode
|
|
smb6 kb::status
|
|
rts
|
|
@code_shift: ; process shift
|
|
bbs4 kb::status, @unset_shift ; unset shift when capslock is on
|
|
@set_shift:
|
|
smb5 kb::status
|
|
rts
|
|
@unset_shift:
|
|
rmb5 kb::status
|
|
rts
|
|
@code_capslock: ; toggle capslock & shift
|
|
bbs1 kb::status, @rts ; ignore if held
|
|
lda kb::status
|
|
ora #(kb::STATUS::CAPSLOCK_HELD)
|
|
; toggle and capslock shift
|
|
eor #(kb::STATUS::CAPSLOCK | kb::STATUS::SHIFT)
|
|
sta kb::status
|
|
rts
|
|
@code_rightalt: ; set rightalt
|
|
smb3 kb::status
|
|
rts
|
|
@code_numlock: ; set numlock
|
|
smb2 kb::status
|
|
rts
|
|
|
|
@twobytecode:
|
|
rmb6 kb::status ; unset twobytecode
|
|
; check mods
|
|
cpx #kb::K2::RIGHTALT
|
|
beq @code_rightalt
|
|
|
|
lda #kb::STATUS::TWOBYTE
|
|
sta keycode_flags
|
|
stx keycode
|
|
@rts:
|
|
rts
|
|
.endproc
|
|
|
|
;; @param S: The status register must be set through `bit kb::status`
|
|
;; @param X: The scancode
|
|
.proc release_key
|
|
bvs @twobytecode
|
|
rmb7 kb::status
|
|
|
|
; check mods
|
|
cpx #kb::K_TWOBYTE
|
|
beq @code_twobytecode
|
|
cpx #kb::K::LEFTSHIFT
|
|
beq @code_shift
|
|
cpx #kb::K::RIGHTSHIFT
|
|
beq @code_shift
|
|
cpx #kb::K::CAPSLOCK
|
|
beq @code_capslock
|
|
; no need to process capslock - it gets toggled when pressed
|
|
rts
|
|
@code_twobytecode: ; unset special
|
|
rmb6 kb::status
|
|
rts
|
|
@code_shift: ; process shift
|
|
bbs4 kb::status, @code_shift_caps ; set shift when capslock is on
|
|
rmb5 kb::status ; unset if capslock is off
|
|
rts
|
|
@code_shift_caps:
|
|
smb5 kb::status
|
|
rts
|
|
@code_capslock: ; unset CAPSLOCK_HELD
|
|
rmb1 kb::status
|
|
rts
|
|
@code_rightalt: ; unset rightalt
|
|
rmb3 kb::status
|
|
rts
|
|
@code_numlock: ; unset numlock
|
|
rmb2 kb::status
|
|
rts
|
|
|
|
@twobytecode:
|
|
rmb6 kb::status ; unset twobytecode
|
|
; check mods
|
|
cpx #kb::K2::RIGHTALT
|
|
beq @code_rightalt
|
|
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
|
|
keycode: .res 1
|
|
keycode_flags: .res 1
|
|
fmt_codechar: .asciiz "%x %x %c "
|
|
fmt_code: .asciiz "%x %x "
|
|
fmt_answer: .asciiz "%x-%x>%x"
|