.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 # 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"