Compare commits
2 Commits
b60ff7be12
...
e1f78b2927
Author | SHA1 | Date | |
---|---|---|---|
|
e1f78b2927 | ||
|
7f909b4f75 |
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.h65"
|
.include "keyboard_handler.h65"
|
||||||
.include "chars.h65"
|
.include "chars.h65"
|
||||||
.import homeloop:absolute
|
.import homeloop:absolute
|
||||||
.import home:absolute
|
.import home:absolute
|
||||||
@ -25,47 +25,49 @@ CODE_START:
|
|||||||
DEBUG_LED_OFF 1
|
DEBUG_LED_OFF 1
|
||||||
DEBUG_LED_OFF 2
|
DEBUG_LED_OFF 2
|
||||||
|
|
||||||
lda #<kb_irq1
|
StoreDByte kb_irq1, ARG0
|
||||||
sta ARG0
|
StoreDByte $3000, ARG2
|
||||||
lda #>kb_irq1
|
; lda #<kb_irq1
|
||||||
sta ARG1
|
; sta ARG0
|
||||||
lda #<$3000
|
; lda #>kb_irq1
|
||||||
sta ARG2
|
; sta ARG1
|
||||||
lda #>$3000
|
; lda #<$3000
|
||||||
sta ARG3
|
; sta ARG2
|
||||||
|
; lda #>$3000
|
||||||
|
; sta ARG3
|
||||||
ldy #10
|
ldy #10
|
||||||
jsr memcopy
|
jsr memcopy
|
||||||
|
|
||||||
lda #<kb_irq2
|
StoreDByte kb_irq2, ARG0
|
||||||
sta ARG0
|
StoreDByte $3100, ARG2
|
||||||
lda #>kb_irq2
|
; lda #<kb_irq2
|
||||||
sta ARG1
|
; sta ARG0
|
||||||
lda #<$3100
|
; lda #>kb_irq2
|
||||||
sta ARG2
|
; sta ARG1
|
||||||
lda #>$3100
|
; lda #<$3100
|
||||||
sta ARG3
|
; sta ARG2
|
||||||
|
; lda #>$3100
|
||||||
|
; sta ARG3
|
||||||
ldy #10
|
ldy #10
|
||||||
jsr memcopy
|
jsr memcopy
|
||||||
|
|
||||||
|
|
||||||
; PrintNC $3000
|
jsr ps2kb::init
|
||||||
|
|
||||||
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 kb::scancode
|
lda ps2kb::scancode
|
||||||
beq @noscancode
|
beq @noscancode
|
||||||
jsr process_scancode
|
jsr process_scancode
|
||||||
stz kb::scancode
|
stz ps2kb::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
|
||||||
@ -131,7 +133,7 @@ CODE_START:
|
|||||||
iny
|
iny
|
||||||
jmp @loop
|
jmp @loop
|
||||||
@lA:
|
@lA:
|
||||||
lda kb::KB_IO + IO::SR
|
lda ps2kb::VIA + IO::SR
|
||||||
jsr lcd::print_char
|
jsr lcd::print_char
|
||||||
jmp @loop
|
jmp @loop
|
||||||
@lB:
|
@lB:
|
||||||
@ -154,7 +156,7 @@ CODE_START:
|
|||||||
kb_irq1:
|
kb_irq1:
|
||||||
; lda #'!'
|
; lda #'!'
|
||||||
; jsr lcd::print_char
|
; jsr lcd::print_char
|
||||||
jsr kb::irq_shift_reg_handler
|
jsr ps2kb::_receive_irq_shift_reg_handler
|
||||||
; lda #':'
|
; lda #':'
|
||||||
; jsr lcd::print_char
|
; jsr lcd::print_char
|
||||||
rts
|
rts
|
||||||
@ -163,7 +165,7 @@ kb_irq2:
|
|||||||
; lda #'?'
|
; lda #'?'
|
||||||
; jsr lcd::print_char
|
; jsr lcd::print_char
|
||||||
; jsr kb::on_timer_irq
|
; jsr kb::on_timer_irq
|
||||||
jsr kb::irq_timer_handler
|
jsr ps2kb::_receive_irq_timer_handler
|
||||||
; lda #';'
|
; lda #';'
|
||||||
; jsr lcd::print_char
|
; jsr lcd::print_char
|
||||||
rts
|
rts
|
||||||
@ -172,7 +174,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 kb::scancode
|
ldx ps2kb::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,5 +109,24 @@ 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,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
|
;; @module keyboard_handler
|
||||||
;; @type drive
|
;; @type system
|
||||||
;; @details:
|
;; @details:
|
||||||
;; Support for a PS2 Keyboard using the shift register of a 6522 VIA
|
;; This module processes keyboard scancodes from the ps2_keyboard module.
|
||||||
;; 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
|
||||||
@ -145,7 +137,5 @@ K_RELEASE = $F0
|
|||||||
PAGEUP = $7D
|
PAGEUP = $7D
|
||||||
.endenum
|
.endenum
|
||||||
|
|
||||||
|
|
||||||
.endscope
|
.endscope
|
||||||
|
|
||||||
.endif ; guard
|
.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
|
35
util/parity.h65
Normal file
35
util/parity.h65
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
.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
|
23
util/parity.s65
Normal file
23
util/parity.s65
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
.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,6 +36,35 @@ 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
|
||||||
@ -56,6 +85,7 @@ 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