Compare commits
No commits in common. "e1f78b29275788975b30981f82b6b346c8ec90cf" and "b60ff7be12c0e5630311dce15aa1feb14f4f5ff1" have entirely different histories.
e1f78b2927
...
b60ff7be12
58
spicode.s65
58
spicode.s65
@ -3,7 +3,7 @@
|
|||||||
.include "lcd.h65"
|
.include "lcd.h65"
|
||||||
.include "math.h65"
|
.include "math.h65"
|
||||||
.include "keypad.h65"
|
.include "keypad.h65"
|
||||||
.include "keyboard_handler.h65"
|
.include "keyboard.h65"
|
||||||
.include "chars.h65"
|
.include "chars.h65"
|
||||||
.import homeloop:absolute
|
.import homeloop:absolute
|
||||||
.import home:absolute
|
.import home:absolute
|
||||||
@ -25,49 +25,47 @@ CODE_START:
|
|||||||
DEBUG_LED_OFF 1
|
DEBUG_LED_OFF 1
|
||||||
DEBUG_LED_OFF 2
|
DEBUG_LED_OFF 2
|
||||||
|
|
||||||
StoreDByte kb_irq1, ARG0
|
lda #<kb_irq1
|
||||||
StoreDByte $3000, ARG2
|
sta ARG0
|
||||||
; lda #<kb_irq1
|
lda #>kb_irq1
|
||||||
; sta ARG0
|
sta ARG1
|
||||||
; lda #>kb_irq1
|
lda #<$3000
|
||||||
; sta ARG1
|
sta ARG2
|
||||||
; lda #<$3000
|
lda #>$3000
|
||||||
; sta ARG2
|
sta ARG3
|
||||||
; lda #>$3000
|
|
||||||
; sta ARG3
|
|
||||||
ldy #10
|
ldy #10
|
||||||
jsr memcopy
|
jsr memcopy
|
||||||
|
|
||||||
StoreDByte kb_irq2, ARG0
|
lda #<kb_irq2
|
||||||
StoreDByte $3100, ARG2
|
sta ARG0
|
||||||
; lda #<kb_irq2
|
lda #>kb_irq2
|
||||||
; sta ARG0
|
sta ARG1
|
||||||
; lda #>kb_irq2
|
lda #<$3100
|
||||||
; sta ARG1
|
sta ARG2
|
||||||
; lda #<$3100
|
lda #>$3100
|
||||||
; sta ARG2
|
sta ARG3
|
||||||
; lda #>$3100
|
|
||||||
; sta ARG3
|
|
||||||
ldy #10
|
ldy #10
|
||||||
jsr memcopy
|
jsr memcopy
|
||||||
|
|
||||||
|
|
||||||
jsr ps2kb::init
|
; PrintNC $3000
|
||||||
|
|
||||||
|
jsr kb::init
|
||||||
|
|
||||||
stz kb::status
|
stz kb::status
|
||||||
StoreDByte process_scancode,ps2kb::scancode_handler
|
|
||||||
jsr ps2kb::begin_receive
|
|
||||||
|
|
||||||
lda #'%'
|
lda #'%'
|
||||||
jsr lcd::print_char
|
jsr lcd::print_char
|
||||||
|
|
||||||
stz kp::_DEBUG_VAL
|
stz kp::_DEBUG_VAL
|
||||||
ldy #0
|
ldy #0
|
||||||
|
|
||||||
@loop:
|
@loop:
|
||||||
wai
|
wai
|
||||||
lda ps2kb::scancode
|
lda kb::scancode
|
||||||
beq @noscancode
|
beq @noscancode
|
||||||
jsr process_scancode
|
jsr process_scancode
|
||||||
stz ps2kb::scancode
|
stz kb::scancode
|
||||||
lda char
|
lda char
|
||||||
beq @onlykeycode
|
beq @onlykeycode
|
||||||
Strf fmt_codechar,out_str,keycode,kb::status,char
|
Strf fmt_codechar,out_str,keycode,kb::status,char
|
||||||
@ -133,7 +131,7 @@ CODE_START:
|
|||||||
iny
|
iny
|
||||||
jmp @loop
|
jmp @loop
|
||||||
@lA:
|
@lA:
|
||||||
lda ps2kb::VIA + IO::SR
|
lda kb::KB_IO + IO::SR
|
||||||
jsr lcd::print_char
|
jsr lcd::print_char
|
||||||
jmp @loop
|
jmp @loop
|
||||||
@lB:
|
@lB:
|
||||||
@ -156,7 +154,7 @@ CODE_START:
|
|||||||
kb_irq1:
|
kb_irq1:
|
||||||
; lda #'!'
|
; lda #'!'
|
||||||
; jsr lcd::print_char
|
; jsr lcd::print_char
|
||||||
jsr ps2kb::_receive_irq_shift_reg_handler
|
jsr kb::irq_shift_reg_handler
|
||||||
; lda #':'
|
; lda #':'
|
||||||
; jsr lcd::print_char
|
; jsr lcd::print_char
|
||||||
rts
|
rts
|
||||||
@ -165,7 +163,7 @@ kb_irq2:
|
|||||||
; lda #'?'
|
; lda #'?'
|
||||||
; jsr lcd::print_char
|
; jsr lcd::print_char
|
||||||
; jsr kb::on_timer_irq
|
; jsr kb::on_timer_irq
|
||||||
jsr ps2kb::_receive_irq_timer_handler
|
jsr kb::irq_timer_handler
|
||||||
; lda #';'
|
; lda #';'
|
||||||
; jsr lcd::print_char
|
; jsr lcd::print_char
|
||||||
rts
|
rts
|
||||||
@ -174,7 +172,7 @@ kb_irq2:
|
|||||||
.proc process_scancode
|
.proc process_scancode
|
||||||
; DEBUG_LED_OFF 1
|
; DEBUG_LED_OFF 1
|
||||||
; check how this scancode needs to be interpreted
|
; check how this scancode needs to be interpreted
|
||||||
ldx ps2kb::scancode
|
ldx kb::scancode
|
||||||
bit kb::status
|
bit kb::status
|
||||||
jmi release_key ; bit 7 set
|
jmi release_key ; bit 7 set
|
||||||
bvs @twobytecode ; bit 6 set
|
bvs @twobytecode ; bit 6 set
|
||||||
|
@ -109,24 +109,5 @@ INCLUDE_IOW65C22 = 1
|
|||||||
IRQ = %10000000
|
IRQ = %10000000
|
||||||
.endenum
|
.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
|
.endscope ; IO
|
||||||
.endif ; guard
|
.endif ; guard
|
||||||
|
@ -1,17 +1,25 @@
|
|||||||
;;********************************************************************************
|
;;********************************************************************************
|
||||||
;; @module keyboard_handler
|
;; @module keyboard
|
||||||
;; @type system
|
;; @type drive
|
||||||
;; @details:
|
;; @details:
|
||||||
;; This module processes keyboard scancodes from the ps2_keyboard module.
|
;; 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.
|
||||||
;;********************************************************************************
|
;;********************************************************************************
|
||||||
.ifndef INCLUDE_KEYBOARD
|
.ifndef INCLUDE_KEYBOARD
|
||||||
INCLUDE_KEYBOARD = 1
|
INCLUDE_KEYBOARD = 1
|
||||||
|
.include "system.h65"
|
||||||
.include "ps2_keyboard.h65"
|
|
||||||
|
|
||||||
.scope kb
|
.scope kb
|
||||||
|
Import kb,init,irq_shift_reg_handler,irq_timer_handler,scancode,key_read
|
||||||
Import kb, CHARS_NOMOD, CHARS_MODSHIFT
|
Import kb, CHARS_NOMOD, CHARS_MODSHIFT
|
||||||
ImportZp kb,status
|
ImportZp kb,status
|
||||||
|
KB_IO = IO1
|
||||||
|
|
||||||
.enum STATUS
|
.enum STATUS
|
||||||
RELEASE = %10000000
|
RELEASE = %10000000
|
||||||
@ -137,5 +145,7 @@ K_RELEASE = $F0
|
|||||||
PAGEUP = $7D
|
PAGEUP = $7D
|
||||||
.endenum
|
.endenum
|
||||||
|
|
||||||
|
|
||||||
.endscope
|
.endscope
|
||||||
|
|
||||||
.endif ; guard
|
.endif ; guard
|
138
system/keyboard.s65
Normal file
138
system/keyboard.s65
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
.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,28 +0,0 @@
|
|||||||
.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"
|
|
@ -1,51 +0,0 @@
|
|||||||
;;********************************************************************************
|
|
||||||
;; @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
|
|
@ -1,313 +0,0 @@
|
|||||||
.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
|
|
@ -1,35 +0,0 @@
|
|||||||
.ifndef INCLUDE_PARITY
|
|
||||||
INCLUDE_PARITY = 1
|
|
||||||
|
|
||||||
.import count_set_bits
|
|
||||||
|
|
||||||
;;********************************************************************************
|
|
||||||
;; @macro Calculate even parity
|
|
||||||
;; @modifies: A, X, Y
|
|
||||||
;; @returns A: 0 - even number of set bits, 1 - uneven number of set bits
|
|
||||||
;; @returns Y: The number of set bits in the byte
|
|
||||||
;;********************************************************************************
|
|
||||||
.macro CalculateEvenParity
|
|
||||||
jsr count_set_bits
|
|
||||||
tya
|
|
||||||
and #1
|
|
||||||
.endmacro
|
|
||||||
|
|
||||||
|
|
||||||
;;********************************************************************************
|
|
||||||
;; @macro Calculate odd parity
|
|
||||||
;; @details
|
|
||||||
;; Count the number of set bits in Y.
|
|
||||||
;;
|
|
||||||
;; @modifies: A, X, Y
|
|
||||||
;; @returns A: 1 - even number of set bits, 0 - uneven number of set bits
|
|
||||||
;; @returns Y: The number of set bits in the byte
|
|
||||||
;;********************************************************************************
|
|
||||||
.macro CalculateOddParity
|
|
||||||
jsr count_set_bits
|
|
||||||
tya
|
|
||||||
and #1
|
|
||||||
eor #1
|
|
||||||
.endmacro
|
|
||||||
|
|
||||||
.endif ; guard
|
|
@ -1,23 +0,0 @@
|
|||||||
.export count_set_bits
|
|
||||||
;;********************************************************************************
|
|
||||||
;; @function Initialize the PS2 keyboard
|
|
||||||
;; @details
|
|
||||||
;; Count the number of set bits in Y.
|
|
||||||
;;
|
|
||||||
;; @modifies: A, X, Y
|
|
||||||
;; @returns Y: The number of set bits in the byte
|
|
||||||
;;********************************************************************************
|
|
||||||
.proc count_set_bits
|
|
||||||
ldx #8
|
|
||||||
ldy #0 ; number of set bits
|
|
||||||
@loop:
|
|
||||||
dex
|
|
||||||
beq @done
|
|
||||||
ror
|
|
||||||
bcc @loop
|
|
||||||
@set:
|
|
||||||
iny
|
|
||||||
bra @loop
|
|
||||||
@done:
|
|
||||||
rts
|
|
||||||
.endproc
|
|
30
utility.h65
30
utility.h65
@ -36,35 +36,6 @@ INCLUDE_UTILITY = 1
|
|||||||
.endmacro
|
.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
|
;; @macro Update a byte in memory using a mask
|
||||||
;; @param addr Address of the byte to update
|
;; @param addr Address of the byte to update
|
||||||
@ -85,7 +56,6 @@ INCLUDE_UTILITY = 1
|
|||||||
.endmacro
|
.endmacro
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;********************************************************************************
|
;;********************************************************************************
|
||||||
;; @macro Jump to the subroutine and let the routine return at another location
|
;; @macro Jump to the subroutine and let the routine return at another location
|
||||||
;; @details
|
;; @details
|
||||||
|
Loading…
Reference in New Issue
Block a user