From e7bd5096cda455513b45e3882bcaac024f390837 Mon Sep 17 00:00:00 2001 From: "matthias@arch" Date: Tue, 2 Jan 2024 23:37:07 +0100 Subject: [PATCH] wip: keyboard send --- main.s65 | 25 ++-- spicode.s65 | 289 ++++++++++++++++++++++++++++++++-------- system/ps2_keyboard.h65 | 21 ++- system/ps2_keyboard.s65 | 177 ++++++++++++++---------- 4 files changed, 374 insertions(+), 138 deletions(-) diff --git a/main.s65 b/main.s65 index 97b6753..748d5e7 100644 --- a/main.s65 +++ b/main.s65 @@ -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 + bbr7 irq_via_ifr,@irq_io2 ; skip + 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 diff --git a/spicode.s65 b/spicode.s65 index d40c549..037e9d7 100644 --- a/spicode.s65 +++ b/spicode.s65 @@ -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 ARG1 - ; lda #<$3000 - ; sta ARG2 - ; lda #>$3000 - ; sta ARG3 - ldy #10 - jsr memcopy - - StoreDByte kb_irq2, ARG0 - StoreDByte $3100, ARG2 - ; 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,10 +291,199 @@ 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 # 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_codechar: .asciiz "%x %x %c " +fmt_code: .asciiz "%x %x " +fmt_answer: .asciiz "%x-%x>%x" diff --git a/system/ps2_keyboard.h65 b/system/ps2_keyboard.h65 index f8f5a52..6ebabc3 100644 --- a/system/ps2_keyboard.h65 +++ b/system/ps2_keyboard.h65 @@ -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 diff --git a/system/ps2_keyboard.s65 b/system/ps2_keyboard.s65 index 664f7d7..a54eab6 100644 --- a/system/ps2_keyboard.s65 +++ b/system/ps2_keyboard.s65 @@ -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 # 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 + 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 # 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