split into driver and handler
This commit is contained in:
parent
7f909b4f75
commit
e1f78b2927
58
spicode.s65
58
spicode.s65
@ -3,7 +3,7 @@
|
||||
.include "lcd.h65"
|
||||
.include "math.h65"
|
||||
.include "keypad.h65"
|
||||
.include "keyboard.h65"
|
||||
.include "keyboard_handler.h65"
|
||||
.include "chars.h65"
|
||||
.import homeloop:absolute
|
||||
.import home:absolute
|
||||
@ -25,47 +25,49 @@ CODE_START:
|
||||
DEBUG_LED_OFF 1
|
||||
DEBUG_LED_OFF 2
|
||||
|
||||
lda #<kb_irq1
|
||||
sta ARG0
|
||||
lda #>kb_irq1
|
||||
sta ARG1
|
||||
lda #<$3000
|
||||
sta ARG2
|
||||
lda #>$3000
|
||||
sta ARG3
|
||||
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
|
||||
|
||||
lda #<kb_irq2
|
||||
sta ARG0
|
||||
lda #>kb_irq2
|
||||
sta ARG1
|
||||
lda #<$3100
|
||||
sta ARG2
|
||||
lda #>$3100
|
||||
sta ARG3
|
||||
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
|
||||
|
||||
|
||||
; PrintNC $3000
|
||||
|
||||
jsr kb::init
|
||||
|
||||
jsr ps2kb::init
|
||||
stz kb::status
|
||||
StoreDByte process_scancode,ps2kb::scancode_handler
|
||||
jsr ps2kb::begin_receive
|
||||
|
||||
lda #'%'
|
||||
jsr lcd::print_char
|
||||
|
||||
stz kp::_DEBUG_VAL
|
||||
ldy #0
|
||||
|
||||
@loop:
|
||||
wai
|
||||
lda kb::scancode
|
||||
lda ps2kb::scancode
|
||||
beq @noscancode
|
||||
jsr process_scancode
|
||||
stz kb::scancode
|
||||
stz ps2kb::scancode
|
||||
lda char
|
||||
beq @onlykeycode
|
||||
Strf fmt_codechar,out_str,keycode,kb::status,char
|
||||
@ -131,7 +133,7 @@ CODE_START:
|
||||
iny
|
||||
jmp @loop
|
||||
@lA:
|
||||
lda kb::KB_IO + IO::SR
|
||||
lda ps2kb::VIA + IO::SR
|
||||
jsr lcd::print_char
|
||||
jmp @loop
|
||||
@lB:
|
||||
@ -154,7 +156,7 @@ CODE_START:
|
||||
kb_irq1:
|
||||
; lda #'!'
|
||||
; jsr lcd::print_char
|
||||
jsr kb::irq_shift_reg_handler
|
||||
jsr ps2kb::_receive_irq_shift_reg_handler
|
||||
; lda #':'
|
||||
; jsr lcd::print_char
|
||||
rts
|
||||
@ -163,7 +165,7 @@ kb_irq2:
|
||||
; lda #'?'
|
||||
; jsr lcd::print_char
|
||||
; jsr kb::on_timer_irq
|
||||
jsr kb::irq_timer_handler
|
||||
jsr ps2kb::_receive_irq_timer_handler
|
||||
; lda #';'
|
||||
; jsr lcd::print_char
|
||||
rts
|
||||
@ -172,7 +174,7 @@ kb_irq2:
|
||||
.proc process_scancode
|
||||
; DEBUG_LED_OFF 1
|
||||
; check how this scancode needs to be interpreted
|
||||
ldx kb::scancode
|
||||
ldx ps2kb::scancode
|
||||
bit kb::status
|
||||
jmi release_key ; bit 7 set
|
||||
bvs @twobytecode ; bit 6 set
|
||||
|
@ -109,5 +109,24 @@ INCLUDE_IOW65C22 = 1
|
||||
IRQ = %10000000
|
||||
.endenum
|
||||
|
||||
;;********************************************************************************
|
||||
;; @macro Enable an interrupt source
|
||||
;; @modifies: A
|
||||
;; @param flag: A flag of the interrupt flag register (IO:IRQ)
|
||||
;;********************************************************************************
|
||||
.macro IO_EnableIRQ ioaddr, flag
|
||||
lda #(IO::IRQ::IRQ | flag)
|
||||
sta ioaddr + IO::IER
|
||||
.endmacro
|
||||
;;********************************************************************************
|
||||
;; @macro Disable an interrupt source
|
||||
;; @modifies: A
|
||||
;; @param flag: A flag of the interrupt flag register (IO:IRQ)
|
||||
;;********************************************************************************
|
||||
.macro IO_DisableIRQ ioaddr, flag
|
||||
lda #flag
|
||||
sta ioaddr + IO::IER
|
||||
.endmacro
|
||||
|
||||
.endscope ; IO
|
||||
.endif ; guard
|
||||
|
@ -1,138 +0,0 @@
|
||||
.include "keyboard.h65"
|
||||
.include "string.h65"
|
||||
.include "lcd.h65"
|
||||
Export kb,init,irq_shift_reg_handler,irq_timer_handler,scancode,key_read
|
||||
Export kb, CHARS_NOMOD, CHARS_MODSHIFT
|
||||
ExportZp kb,status
|
||||
|
||||
.zeropage
|
||||
status:
|
||||
.bss
|
||||
key_read: .res 2
|
||||
scancode: .res 1
|
||||
|
||||
.code
|
||||
;;********************************************************************************
|
||||
;; @function Initialize the PS2 keyboard
|
||||
;; @modifies: A
|
||||
;;********************************************************************************
|
||||
.proc init
|
||||
; - use the shift register interrupts to read the first 8 bits
|
||||
; set shift register to shift in under external clock on CB1
|
||||
; - configure timer for timing the read of the last 3 bits
|
||||
; timer 2 one shot mode is sufficient, leaves T1 available
|
||||
lda #(IO::ACR::SR_SIN_PHIE | IO::ACR::T2_IRQ_LOAD)
|
||||
tsb kb::KB_IO + 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 #230
|
||||
sta kb::KB_IO + IO::T2CL
|
||||
stz key_read
|
||||
stz key_read+1
|
||||
stz scancode
|
||||
stz status
|
||||
|
||||
; enable SR interrupts
|
||||
lda #(IO::IRQ::IRQ | IO::IRQ::SR)
|
||||
sta kb::KB_IO + IO::IER
|
||||
; load SR to reset
|
||||
lda kb::KB_IO + IO::SR
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @function Read the first 8 bits an
|
||||
;; @modifies: A
|
||||
;; @details
|
||||
;; - read shift register
|
||||
;; - disable shift register interrupts
|
||||
;; - reset shift register
|
||||
;; - enable timer 2 interrupts
|
||||
;; - start timer 2
|
||||
;; IO::SR has to be read before the next bit is shifted in, which happens ~75us after the irq
|
||||
;; at 1MHz, handling this interrupt takes about 50us (without any additional debug code),
|
||||
;; so it should work
|
||||
;;********************************************************************************
|
||||
.proc irq_shift_reg_handler
|
||||
lda kb::KB_IO + IO::SR
|
||||
sta key_read
|
||||
stz kb::KB_IO + IO::SR
|
||||
|
||||
; disable SR interrupts
|
||||
lda #IO::IRQ::SR
|
||||
sta kb::KB_IO + IO::IER
|
||||
; enable timer interrupts
|
||||
lda #(IO::IRQ::IRQ | IO::IRQ::T2)
|
||||
sta kb::KB_IO + IO::IER
|
||||
; start timer, low order count already in latch after init
|
||||
lda #0
|
||||
sta kb::KB_IO + IO::T2CH
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @function Read the last 3 bits after after timer 2 is up
|
||||
;; @modifies: A
|
||||
;; @details
|
||||
;; - read shift register
|
||||
;; - disable timer 2 interrupts
|
||||
;; - enable shift register interrupts
|
||||
;; - reset shift register
|
||||
;;********************************************************************************
|
||||
.proc irq_timer_handler
|
||||
lda kb::KB_IO + IO::SR
|
||||
sta key_read + 1
|
||||
|
||||
lda kb::KB_IO + IO::T2CL ; clear interrupt flag
|
||||
|
||||
; disable timer interrupts
|
||||
lda #(IO::IRQ::T2)
|
||||
sta kb::KB_IO + IO::IER
|
||||
|
||||
; reset SR
|
||||
; disabling shifting in acr seems necessary to reset - otherwise
|
||||
; it continues counting and interrupts after the first 5 bits of the next keypress
|
||||
lda #(IO::ACR::SR_SIN_PHIE | IO::ACR::T2_IRQ_LOAD)
|
||||
trb kb::KB_IO + IO::ACR
|
||||
tsb kb::KB_IO + IO::ACR
|
||||
stz kb::KB_IO + IO::SR
|
||||
; enable shift register interrupts
|
||||
lda #(IO::IRQ::IRQ | IO::IRQ::SR)
|
||||
sta kb::KB_IO + IO::IER
|
||||
|
||||
lda key_read+1
|
||||
ror
|
||||
ror
|
||||
ror
|
||||
lda key_read ; not affecting carry
|
||||
rol ; rotate carry into byte, rotate startbit into carry
|
||||
Reverse A
|
||||
sta scancode
|
||||
|
||||
rts
|
||||
.endproc
|
||||
|
||||
.rodata
|
||||
.align 256
|
||||
CHARS_NOMOD:
|
||||
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00"
|
||||
.byte "\x00\x00\x00\x00\x00q1\x00\x00\x00ysaw2\x00"
|
||||
.byte "\x00cxde43\x00\x00 vftr5\x00"
|
||||
.byte "\x00nbhgz6\x00\x00\x00mju78\x00"
|
||||
.byte "\x00,kio09\x00\x00.-l\xEFp\xE2\x00"
|
||||
.byte "\x00\x00\xE1\x00\xF5`\x00\x00\x00\x00\x00\x00\x00#\x00\x00"
|
||||
.byte "\x00<\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
|
||||
.align 256
|
||||
CHARS_MODSHIFT:
|
||||
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xDF\x00"
|
||||
.byte "\x00\x00\x00\x00\x00Q!\x00\x00\x00YSAW\"\x00"
|
||||
.byte "\x00CXDE$\xED\x00\x00 VFTR%\x00"
|
||||
.byte "\x00NBHGZ&\x00\x00\x00MJU/(\x00"
|
||||
.byte "\x00;KIO=)\x00\x00:_L\xEFP\xE2\x00"
|
||||
.byte "\x00\x00\xE1\x00\xF5`\x00\x00\x00\x00\x00\x00\x00'\x00\x00"
|
||||
.byte "\x00>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
@ -1,25 +1,17 @@
|
||||
;;********************************************************************************
|
||||
;; @module keyboard
|
||||
;; @type drive
|
||||
;; @module keyboard_handler
|
||||
;; @type system
|
||||
;; @details:
|
||||
;; Support for a PS2 Keyboard using the shift register of a 6522 VIA
|
||||
;; Pressing a key causes 11 bits to be sent: 1 start - 8 scancode - 1 parity - 1 stop
|
||||
;; The VIA is set up to interrupt after 8 bits have been shifted into the shift register
|
||||
;; from the external clock pulses of the keyboard (additional hardware required to
|
||||
;; address the hardware bug of the VIA, where bit get lost when the external clock
|
||||
;; transition happens during falling edge of PHI2). After reading the shift register,
|
||||
;; the VIAs T2 timer is set to interrupt after the last 3 bits have been shifted in,
|
||||
;; which takes about ~230ms.
|
||||
;; This module processes keyboard scancodes from the ps2_keyboard module.
|
||||
;;********************************************************************************
|
||||
.ifndef INCLUDE_KEYBOARD
|
||||
INCLUDE_KEYBOARD = 1
|
||||
.include "system.h65"
|
||||
|
||||
.include "ps2_keyboard.h65"
|
||||
|
||||
.scope kb
|
||||
Import kb,init,irq_shift_reg_handler,irq_timer_handler,scancode,key_read
|
||||
Import kb, CHARS_NOMOD, CHARS_MODSHIFT
|
||||
ImportZp kb,status
|
||||
KB_IO = IO1
|
||||
|
||||
.enum STATUS
|
||||
RELEASE = %10000000
|
||||
@ -145,7 +137,5 @@ K_RELEASE = $F0
|
||||
PAGEUP = $7D
|
||||
.endenum
|
||||
|
||||
|
||||
.endscope
|
||||
|
||||
.endif ; guard
|
28
system/keyboard_handler.s65
Normal file
28
system/keyboard_handler.s65
Normal file
@ -0,0 +1,28 @@
|
||||
.include "keyboard_handler.h65"
|
||||
Export kb, CHARS_NOMOD, CHARS_MODSHIFT
|
||||
ExportZp kb,status
|
||||
.zeropage
|
||||
status: .res 1
|
||||
|
||||
.rodata
|
||||
.align 256
|
||||
CHARS_NOMOD:
|
||||
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00"
|
||||
.byte "\x00\x00\x00\x00\x00q1\x00\x00\x00ysaw2\x00"
|
||||
.byte "\x00cxde43\x00\x00 vftr5\x00"
|
||||
.byte "\x00nbhgz6\x00\x00\x00mju78\x00"
|
||||
.byte "\x00,kio09\x00\x00.-l\xEFp\xE2\x00"
|
||||
.byte "\x00\x00\xE1\x00\xF5`\x00\x00\x00\x00\x00\x00\x00#\x00\x00"
|
||||
.byte "\x00<\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
|
||||
.align 256
|
||||
CHARS_MODSHIFT:
|
||||
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xDF\x00"
|
||||
.byte "\x00\x00\x00\x00\x00Q!\x00\x00\x00YSAW\"\x00"
|
||||
.byte "\x00CXDE$\xED\x00\x00 VFTR%\x00"
|
||||
.byte "\x00NBHGZ&\x00\x00\x00MJU/(\x00"
|
||||
.byte "\x00;KIO=)\x00\x00:_L\xEFP\xE2\x00"
|
||||
.byte "\x00\x00\xE1\x00\xF5`\x00\x00\x00\x00\x00\x00\x00'\x00\x00"
|
||||
.byte "\x00>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
51
system/ps2_keyboard.h65
Normal file
51
system/ps2_keyboard.h65
Normal file
@ -0,0 +1,51 @@
|
||||
;;********************************************************************************
|
||||
;; @module ps2_keyboard
|
||||
;; @type driver
|
||||
;; @details:
|
||||
;; Support for a PS2 Keyboard using the shift register of a 6522 VIA
|
||||
;; @section Reading a scancode/command answer
|
||||
;; Pressing a key causes 11 bits to be sent: 1 start - 8 scancode - 1 parity - 1 stop
|
||||
;; The VIA is set up to interrupt after 8 bits have been shifted into the shift register
|
||||
;; from the external clock pulses of the keyboard (additional hardware required to
|
||||
;; address the hardware bug of the VIA, where bit get lost when the external clock
|
||||
;; transition happens during falling edge of PHI2). After reading the shift register,
|
||||
;; the VIAs T2 timer is set to interrupt after the last 3 bits have been shifted in,
|
||||
;; which takes about ~230ms.
|
||||
;; T2 is used because it leaves to more versatile T1 available for something else
|
||||
|
||||
;; @section Processing a scancode
|
||||
;; The scancode may be processed by storing the address of a handler subroutine in
|
||||
;; ps2kb::scancode_handler. This handler can load the scancode byte from ps2kb::scancode.
|
||||
;;
|
||||
;;
|
||||
;; To use a different layout, change the enum K and the CHARS_NOMOD and CHARS_MODSHIFT
|
||||
;; @warning
|
||||
;; The value with which the timer is loaded must depends on the clock frequency
|
||||
;; of the keyboard and the computer
|
||||
;;
|
||||
;;********************************************************************************
|
||||
.ifndef INCLUDE_PS2_KEYBOARD
|
||||
INCLUDE_PS2_KEYBOARD = 1
|
||||
.include "system.h65"
|
||||
|
||||
.scope ps2kb
|
||||
Import ps2kb,init,begin_receive,send_command,scancode,status,scancode_handler
|
||||
Import ps2kb, _receive_irq_shift_reg_handler, _receive_irq_timer_handler
|
||||
|
||||
VIA = IO1
|
||||
TIMER = 230 ; 230 ms (@1MHz)
|
||||
; use RA4 to pull the clock low
|
||||
CLK_PULL_MASK= %00001000
|
||||
CLK_PULL_R = IO::RANH
|
||||
CLK_PULL_DDR = IO::DDRA
|
||||
|
||||
|
||||
.enum STATUS
|
||||
RECEIVE_KEYS = %10000000
|
||||
RECEIVE_ANSWER = %01000000
|
||||
SEND_CMD = %00100000
|
||||
NONE = %00000000
|
||||
.endenum
|
||||
.endscope
|
||||
|
||||
.endif ; guard
|
313
system/ps2_keyboard.s65
Normal file
313
system/ps2_keyboard.s65
Normal file
@ -0,0 +1,313 @@
|
||||
.include "ps2_keyboard.h65"
|
||||
.include "string.h65"
|
||||
.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
|
||||
|
||||
.bss
|
||||
status: .res 1
|
||||
send_last_bits: .res 1
|
||||
send_data: .res 1
|
||||
send_cmd: .res 1
|
||||
key_read: .res 2
|
||||
scancode: .res 1
|
||||
scancode_handler: .res 2
|
||||
|
||||
.code
|
||||
|
||||
;;********************************************************************************
|
||||
;; @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::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
|
||||
.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::CLK_PULL_DDR
|
||||
ora #ps2kb::CLK_PULL_MASK
|
||||
sta ps2kb::VIA + ps2kb::CLK_PULL_DDR
|
||||
; set pin low
|
||||
lda ps2kb::VIA + ps2kb::CLK_PULL_R
|
||||
and #<~ps2kb::CLK_PULL_MASK
|
||||
sta ps2kb::VIA + ps2kb::CLK_PULL_R
|
||||
.endmacro
|
||||
|
||||
|
||||
.proc init
|
||||
stz key_read
|
||||
stz key_read+1
|
||||
stz scancode
|
||||
stz status
|
||||
; T2 oneshot mode, clear shift reg
|
||||
lda ps2kb::VIA + IO::ACR
|
||||
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:
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @function Start receiving data from the keyboard
|
||||
;; @details
|
||||
;; - use the shift register interrupts to read the first 8 bits
|
||||
;; - configure timer for timing the read of the last 3 bits
|
||||
;; @modifies: A
|
||||
;;********************************************************************************
|
||||
.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
|
||||
lda ps2kb::VIA + IO::ACR
|
||||
and #<~IO::ACR_MASK::SR
|
||||
ora #IO::ACR::SR_SIN_PHIE
|
||||
sta ps2kb::VIA + IO::ACR
|
||||
stz key_read
|
||||
stz key_read+1
|
||||
stz scancode
|
||||
bit status
|
||||
; set to RECEIVE_KEYS only if RECEIVE_ANSWER is not set
|
||||
bvs @receive_answer
|
||||
lda #ps2kb::STATUS::RECEIVE_KEYS
|
||||
sta status
|
||||
@receive_answer:
|
||||
|
||||
_EnableClock
|
||||
|
||||
; todo setup irq handlers
|
||||
|
||||
IO_EnableIRQ ps2kb::VIA, IO::IRQ::SR
|
||||
; reset and start SR
|
||||
stz ps2kb::VIA + IO::SR
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @function Read the first 8 bits an
|
||||
;; @modifies: A
|
||||
;; @details
|
||||
;; - read shift register
|
||||
;; - disable shift register interrupts
|
||||
;; - reset shift register
|
||||
;; - enable timer 2 interrupts
|
||||
;; - start timer 2
|
||||
;; IO::SR has to be read before the next bit is shifted in, which happens ~75us after the irq
|
||||
;; at 1MHz, handling this interrupt takes about 50us (without any additional debug code),
|
||||
;; so it should work
|
||||
;;********************************************************************************
|
||||
.proc _receive_irq_shift_reg_handler
|
||||
lda ps2kb::VIA + IO::SR
|
||||
sta key_read
|
||||
stz 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
|
||||
sta ps2kb::VIA + IO::T2CH
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @function Read the last 3 bits after after timer 2 is up
|
||||
;; @modifies: A
|
||||
;; @details
|
||||
;; - read shift register
|
||||
;; - disable timer 2 interrupts
|
||||
;; - enable shift register interrupts
|
||||
;; - reset shift register
|
||||
;; - jump to the subroutine pointed to by scancode_handler
|
||||
;;********************************************************************************
|
||||
.proc _receive_irq_timer_handler
|
||||
lda ps2kb::VIA + IO::SR
|
||||
sta key_read + 1
|
||||
|
||||
lda ps2kb::VIA + IO::T2CL ; clear interrupt flag
|
||||
|
||||
IO_DisableIRQ ps2kb::VIA, IO::IRQ::T2
|
||||
; reset SR
|
||||
; disabling shifting in acr seems necessary to reset - otherwise
|
||||
; it continues counting and interrupts after the first 5 bits of the next keypress
|
||||
lda #(IO::ACR::SR_SIN_PHIE | IO::ACR::T2_IRQ_LOAD)
|
||||
trb ps2kb::VIA + IO::ACR
|
||||
tsb ps2kb::VIA + IO::ACR
|
||||
stz ps2kb::VIA + IO::SR
|
||||
IO_EnableIRQ ps2kb::VIA, IO::IRQ::SR
|
||||
|
||||
lda key_read+1
|
||||
ror ; stop bit -> C
|
||||
sta key_read+1 ; parity in bit 0, D7 in bit 1
|
||||
ror ; parity -> C
|
||||
ror ; D7 -> C
|
||||
lda key_read ; not affecting carry
|
||||
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 what to do with the scancode
|
||||
bit status
|
||||
bcc @status_not_receive_keys
|
||||
jmp (scancode_handler)
|
||||
@status_not_receive_keys:
|
||||
bvc @status_ignore
|
||||
jmp _process_cmd_answer
|
||||
@status_ignore:
|
||||
rts
|
||||
@parity_error: ; TODO handle somehow
|
||||
lda #$ff
|
||||
sta scancode
|
||||
DEBUG_LED_ON 2
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @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
|
||||
;;********************************************************************************
|
||||
.proc send_command
|
||||
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
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @function Send a byte to the keyboard
|
||||
;; @modifies: A,X,Y
|
||||
;; @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
|
||||
;;********************************************************************************
|
||||
.proc _send_byte
|
||||
pha
|
||||
IO_DisableIRQ ps2kb::VIA, IO::IRQ::T2
|
||||
_DisableClock
|
||||
; (re)set shift register to shift out under external clock on CB1
|
||||
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
|
||||
pla
|
||||
pha
|
||||
; split into the 11 bits
|
||||
CalculateOddParity
|
||||
tax
|
||||
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
|
||||
_EnableClock
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @function Send the lasts 3 bits
|
||||
;; @modifies: A
|
||||
;; @details
|
||||
;; - load the remaining 3 bits of the transmission into the shift register
|
||||
;; - disable shift register interrupts
|
||||
;; - enable timer 2 interrupts
|
||||
;; - start timer 2
|
||||
;;********************************************************************************
|
||||
.proc _send_irq_shift_reg_handler
|
||||
lda 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
|
||||
; start timer, low order count already in latch after init
|
||||
lda #>ps2kb::TIMER
|
||||
sta ps2kb::VIA + IO::T2CH
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @function Send databyte or reveice the keyboards answer
|
||||
;; @modifies: A, X, Y
|
||||
;; @details
|
||||
;; - disable timer 2 interrupts
|
||||
;; - if send_data is zero:
|
||||
;; - begin_receive
|
||||
;; - set status RECEIVE_ANSWER
|
||||
;; - else
|
||||
;; - send_byte send_data
|
||||
;; - set send_data = 0
|
||||
;;********************************************************************************
|
||||
.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
|
||||
beq @receive
|
||||
stz send_data
|
||||
jmp _send_byte
|
||||
rts
|
||||
@receive:
|
||||
lda #ps2kb::STATUS::RECEIVE_ANSWER
|
||||
sta status
|
||||
jmp begin_receive
|
||||
.endproc
|
||||
|
||||
|
||||
.proc _process_cmd_answer
|
||||
@success:
|
||||
rts
|
||||
.endproc
|
30
utility.h65
30
utility.h65
@ -36,6 +36,35 @@ INCLUDE_UTILITY = 1
|
||||
.endmacro
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @macro Store a double byte (immediate) at an address
|
||||
;; @param addr Address, double byte will be loaded in LE to addr, addr+1
|
||||
;; @param dbyte Location or value
|
||||
;; @param reg Register, defaults to A
|
||||
;; @modifies
|
||||
;;********************************************************************************
|
||||
.macro StoreDByte dbyte,addr,reg
|
||||
; .out .sprintf("%x, %x", dbyte, addr)
|
||||
.if .blank(reg) .or .match(reg, A)
|
||||
lda #<dbyte
|
||||
sta addr
|
||||
lda #>dbyte
|
||||
sta addr+1
|
||||
.elseif .match(reg, X)
|
||||
ldx #<dbyte
|
||||
stx addr
|
||||
ldx #>dbyte
|
||||
stx addr+1
|
||||
.elseif .match(reg, Y)
|
||||
ldy #<dbyte
|
||||
sty addr
|
||||
ldy #>dbyte
|
||||
sty addr+1
|
||||
.else
|
||||
.fatal "Invalid reg given to StoreDByte"
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
;;********************************************************************************
|
||||
;; @macro Update a byte in memory using a mask
|
||||
;; @param addr Address of the byte to update
|
||||
@ -56,6 +85,7 @@ INCLUDE_UTILITY = 1
|
||||
.endmacro
|
||||
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @macro Jump to the subroutine and let the routine return at another location
|
||||
;; @details
|
||||
|
Loading…
Reference in New Issue
Block a user