Skip to content

Instantly share code, notes, and snippets.

@jfoucher
Created December 29, 2020 20:26
Show Gist options
  • Save jfoucher/d25ecf55c94f64f82b2308bac42d6653 to your computer and use it in GitHub Desktop.
Save jfoucher/d25ecf55c94f64f82b2308bac42d6653 to your computer and use it in GitHub Desktop.
; Copyright 2020 Jonathan Foucher
; Permission is hereby granted, free of charge, to any person obtaining a copy of this software
; and associated documentation files (the "Software"), to deal in the Software without restriction,
; including without limitation the rights to use, copy, modify, merge, publish, distribute,
; sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
; is furnished to do so, subject to the following conditions:
; The above copyright notice and this permission notice shall be included in all copies or
; substantial portions of the Software.
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
; INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
; PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
; FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
; OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
; DEALINGS IN THE SOFTWARE.
DATA = $80 ; Data is in bit 7 of PORTA
; clock is on CA2
SHIFT = $1
ALT = $2
KB_STATE_START = $0
KB_STATE_DATA = $1
KB_STATE_PARITY = $2
KB_STATE_STOP = $3
KB_INIT_STATE_RESET = $0
KB_INIT_STATE_RESET_ACK = $1
KB_INIT_STATE_LEDS = $2
KB_INIT_STATE_LEDS_ACK = $3
KB_INIT_STATE_LEDS_DATA = $4
KB_INIT_STATE_LEDS_DATA_ACK = $5
LSHIFT_KEY = $12
RSHIFT_KEY = $59
TIMER_DELAY = $C4
; Copyright 2020 Jonathan Foucher
; Permission is hereby granted, free of charge, to any person obtaining a copy of this software
; and associated documentation files (the "Software"), to deal in the Software without restriction,
; including without limitation the rights to use, copy, modify, merge, publish, distribute,
; sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
; is furnished to do so, subject to the following conditions:
; The above copyright notice and this permission notice shall be included in all copies or
; substantial portions of the Software.
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
; INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
; PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
; FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
; OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
; DEALINGS IN THE SOFTWARE.
ps2_init:
lda IER
ora #$88 ;enable interrupt on neg transition on CB2
sta IER
lda #0
sta PCR
sta KB_TEMP
sta KB_BIT
sta KB_STATE
sta to_send
sta KB_PARITY
sta KB_BUF_INDEX
sta KB_BUF_INDEX_R
sta KB_INIT_STATE
sta ready
sta ignore_next
sta character
sta init_trys
cli ;enable interrupts
; jsr kb_reset
; jsr kb_leds
; jsr kb_leds_data
; jmp done_init
lda #KB_INIT_STATE_RESET
sta KB_INIT_STATE
@wait:
lda to_send
bne @wait ; do nothing while sending
;jsr lcd_print
ldx KB_INIT_STATE
;stx PORTA
cpx #KB_INIT_STATE_RESET
beq @do_reset
cpx #KB_INIT_STATE_RESET_ACK
beq @reset_ack
cpx #KB_INIT_STATE_LEDS
beq @do_leds
cpx #KB_INIT_STATE_LEDS_ACK
beq @leds_ack
cpx #KB_INIT_STATE_LEDS_DATA
beq @_do_leds_data
cpx #KB_INIT_STATE_LEDS_DATA_ACK
beq @_leds_data_ack
; beq @self_test_ok ; Wait for 256 loops with nothing. if still nothing, reset keyboard
bra @wait ; nothing to show yet
;sta PORTA
; wait for keyboard self test (#$AA)
@_leds_data_ack:
jmp @leds_data_ack
@_do_leds_data:
jmp @do_leds_data
@do_reset: ; ready is in A
jsr kb_reset
lda #KB_INIT_STATE_RESET_ACK ; next state should be an acknowledgment
sta KB_INIT_STATE
bra @wait
@reset_ack:
jmp done_init ; key board works after reset, so return here
; The below is not used, my keyboard is happy with just a reset and starts sending keypresses
lda ready
beq @reset_ack
jsr binhex
jsr lcd_print
txa
jsr lcd_print
tya
cmp #$FA ; keyboard ack
beq @reset_ack_ok
bra @wait
@reset_ack_ok:
lda #KB_INIT_STATE_LEDS ; next state should be sending the LEDS data
sta KB_INIT_STATE
stz ready
jsr kb_leds
bra @wait
@do_leds:
lda #KB_INIT_STATE_LEDS_ACK ; next state should be an acknowledgment
sta KB_INIT_STATE
jsr kb_leds
jmp @wait
@leds_ack:
lda ready
beq @leds_ack
cmp #$FA ; keyboard ack
beq @leds_ack_ok
jmp @wait
@leds_ack_ok:
lda #KB_INIT_STATE_LEDS_DATA ; next state should be sending the LEDS data
sta KB_INIT_STATE
stz ready
jmp @wait
@do_leds_data:
lda #KB_INIT_STATE_LEDS_DATA_ACK ; back to start
sta KB_INIT_STATE
jsr kb_leds_data
jmp @wait
@leds_data_ack:
beq @leds_data_ack
lda ready
cmp #$FA ; keyboard ack
beq done_init
jmp @wait
done_init:
lda #0
sta DDRB
sta ignore_next
sta ready
sta control_keys
sta temp
sta to_send
sta ready
sta character
sta KB_TEMP
sta KB_INIT_STATE
sta KB_BIT
sta KB_STATE
sta KB_BUF_INDEX
sta KB_BUF_INDEX_R
cli ; enable interrupts again
rts
kb_reset:
sei ;disable interrupts
jsr prepare_send
lda #$FF
sta to_send
cli ; enable interrupts
@wait:
lda to_send
bne @wait
rts
kb_leds:
sei ;disable interrupts
jsr prepare_send
lda #$ED
sta to_send
cli ; enable interrupts
@wait:
lda to_send
bne @wait
rts
kb_leds_data:
sei ;disable interrupts
jsr prepare_send
lda #$02
sta to_send
cli ; enable interrupts
@wait:
lda to_send
bne @wait
rts
prepare_send:
pha
phy
; ready to send, pull clock low for a while
lda #$C0
sta PCR ;set CB2 low
;delay
ldy #$80
jsr delay
; delay end
; pull data low now
lda PORTB
and #(~DATA & $FF)
sta PORTB
lda DDRB
ora #DATA ;data as output to set it low
sta DDRB
ldy #$40
jsr delay
lda #KB_STATE_DATA ; no start bit when sending
sta KB_STATE
; release clock
lda #0
sta to_send
sta KB_PARITY
sta PCR ;set CB2 to negative edge input
ply
pla
rts
reset_ps2: ; routine called during a timer interrupt to check
pha
; if the elasped time since the last ps2 interrupt allows us to reset it
lda time+3
cmp last_ps2_time+3
bcc @reset
lda time+2
cmp last_ps2_time+2
bcc @reset
lda time+1
cmp last_ps2_time+1
bcc @reset
lda time
adc #$1
cmp last_ps2_time
bcc @reset
@exit:
pla
rts
@reset:
lda #0
sta KB_TEMP
sta KB_BIT
sta KB_STATE
sta KB_BUF_INDEX
sta KB_BUF_INDEX_R
beq @exit
.include "ps2_irq.s"
KB_BUF: .res 256
ASCIITBL:
.byte $00 ; 00 no key pressed
.byte $89 ; 01 F9
.byte $87 ; 02 relocated F7
.byte $85 ; 03 F5
.byte $83 ; 04 F3
.byte $81 ; 05 F1
.byte $82 ; 06 F2
.byte $8C ; 07 F12
.byte $00 ; 08
.byte $8A ; 09 F10
.byte $88 ; 0A F8
.byte $86 ; 0B F6
.byte $84 ; 0C F4
.byte $09 ; 0D tab
.byte $60 ; 0E `~
.byte $8F ; 0F relocated Print Screen key
.byte $03 ; 10 relocated Pause/Break key
.byte $A0 ; 11 left alt (right alt too)
.byte $00 ; 12 left shift
.byte $E0 ; 13 relocated Alt release code
.byte $00 ; 14 left ctrl (right ctrl too)
.byte $71 ; 15 qQ
.byte $31 ; 16 1!
.byte $00 ; 17
.byte $00 ; 18
.byte $00 ; 19
.byte $7A ; 1A zZ
.byte $73 ; 1B sS
.byte $61 ; 1C aA
.byte $77 ; 1D wW
.byte $32 ; 1E 2@
.byte $A1 ; 1F Windows 98 menu key (left side)
.byte $02 ; 20 relocated ctrl-break key
.byte $63 ; 21 cC
.byte $78 ; 22 xX
.byte $64 ; 23 dD
.byte $65 ; 24 eE
.byte $34 ; 25 4$
.byte $33 ; 26 3#
.byte $A2 ; 27 Windows 98 menu key (right side)
.byte $00 ; 28
.byte $20 ; 29 space
.byte $76 ; 2A vV
.byte $66 ; 2B fF
.byte $74 ; 2C tT
.byte $72 ; 2D rR
.byte $35 ; 2E 5%
.byte $A3 ; 2F Windows 98 option key (right click, right side)
.byte $00 ; 30
.byte $6E ; 31 nN
.byte $62 ; 32 bB
.byte $68 ; 33 hH
.byte $67 ; 34 gG
.byte $79 ; 35 yY
.byte $36 ; 36 6^
.byte $00 ; 37
.byte $00 ; 38
.byte $00 ; 39
.byte $6D ; 3A mM
.byte $6A ; 3B jJ
.byte $75 ; 3C uU
.byte $37 ; 3D 7&
.byte $38 ; 3E 8*
.byte $00 ; 3F
.byte $00 ; 40
.byte $2C ; 41 ,<
.byte $6B ; 42 kK
.byte $69 ; 43 iI
.byte $6F ; 44 oO
.byte $30 ; 45 0)
.byte $39 ; 46 9(
.byte $00 ; 47
.byte $00 ; 48
.byte $2E ; 49 .>
.byte $2F ; 4A /?
.byte $6C ; 4B lL
.byte $3B ; 4C ;:
.byte $70 ; 4D pP
.byte $2D ; 4E -_
.byte $00 ; 4F
.byte $00 ; 50
.byte $00 ; 51
.byte $27 ; 52 '"
.byte $00 ; 53
.byte $5B ; 54 [{
.byte $3D ; 55 =+
.byte $00 ; 56
.byte $00 ; 57
.byte $00 ; 58 caps
.byte $00 ; 59 r shift
.byte $0D ; 5A <Enter>
.byte $5D ; 5B ]}
.byte $00 ; 5C
.byte $5C ; 5D \|
.byte $00 ; 5E
.byte $00 ; 5F
.byte $00 ; 60
.byte $00 ; 61
.byte $00 ; 62
.byte $00 ; 63
.byte $00 ; 64
.byte $00 ; 65
.byte $08 ; 66 bkspace
.byte $00 ; 67
.byte $00 ; 68
.byte $31 ; 69 kp 1
.byte $2f ; 6A kp / converted from E04A in code
.byte $34 ; 6B kp 4
.byte $37 ; 6C kp 7
.byte $00 ; 6D
.byte $00 ; 6E
.byte $00 ; 6F
.byte $30 ; 70 kp 0
.byte $2E ; 71 kp .
.byte $32 ; 72 kp 2
.byte $35 ; 73 kp 5
.byte $36 ; 74 kp 6
.byte $38 ; 75 kp 8
.byte $1B ; 76 esc
.byte $00 ; 77 num lock
.byte $8B ; 78 F11
.byte $2B ; 79 kp +
.byte $33 ; 7A kp 3
.byte $2D ; 7B kp -
.byte $2A ; 7C kp *
.byte $39 ; 7D kp 9
.byte $8D ; 7E scroll lock
.byte $00 ; 7F
;
; Table for shifted scancodes
;
.byte $00 ; 80
.byte $C9 ; 81 F9
.byte $C7 ; 82 relocated F7
.byte $C5 ; 83 F5 (F7 actual scancode=83)
.byte $C3 ; 84 F3
.byte $C1 ; 85 F1
.byte $C2 ; 86 F2
.byte $CC ; 87 F12
.byte $00 ; 88
.byte $CA ; 89 F10
.byte $C8 ; 8A F8
.byte $C6 ; 8B F6
.byte $C4 ; 8C F4
.byte $09 ; 8D tab
.byte $7E ; 8E `~
.byte $CF ; 8F relocated Print Screen key
.byte $03 ; 90 relocated Pause/Break key
.byte $A0 ; 91 left alt (right alt)
.byte $00 ; 92 left shift
.byte $E0 ; 93 relocated Alt release code
.byte $00 ; 94 left ctrl (and right ctrl)
.byte $51 ; 95 qQ
.byte $21 ; 96 1!
.byte $00 ; 97
.byte $00 ; 98
.byte $00 ; 99
.byte $5A ; 9A zZ
.byte $53 ; 9B sS
.byte $41 ; 9C aA
.byte $57 ; 9D wW
.byte $40 ; 9E 2@
.byte $E1 ; 9F Windows 98 menu key (left side)
.byte $02 ; A0 relocated ctrl-break key
.byte $43 ; A1 cC
.byte $58 ; A2 xX
.byte $44 ; A3 dD
.byte $45 ; A4 eE
.byte $24 ; A5 4$
.byte $23 ; A6 3#
.byte $E2 ; A7 Windows 98 menu key (right side)
.byte $00 ; A8
.byte $20 ; A9 space
.byte $56 ; AA vV
.byte $46 ; AB fF
.byte $54 ; AC tT
.byte $52 ; AD rR
.byte $25 ; AE 5%
.byte $E3 ; AF Windows 98 option key (right click, right side)
.byte $00 ; B0
.byte $4E ; B1 nN
.byte $42 ; B2 bB
.byte $48 ; B3 hH
.byte $47 ; B4 gG
.byte $59 ; B5 yY
.byte $5E ; B6 6^
.byte $00 ; B7
.byte $00 ; B8
.byte $00 ; B9
.byte $4D ; BA mM
.byte $4A ; BB jJ
.byte $55 ; BC uU
.byte $26 ; BD 7&
.byte $2A ; BE 8*
.byte $00 ; BF
.byte $00 ; C0
.byte $3C ; C1 ,<
.byte $4B ; C2 kK
.byte $49 ; C3 iI
.byte $4F ; C4 oO
.byte $29 ; C5 0)
.byte $28 ; C6 9(
.byte $00 ; C7
.byte $00 ; C8
.byte $3E ; C9 .>
.byte $3F ; CA /?
.byte $4C ; CB lL
.byte $3A ; CC ;:
.byte $50 ; CD pP
.byte $5F ; CE -_
.byte $00 ; CF
.byte $00 ; D0
.byte $00 ; D1
.byte $22 ; D2 '"
.byte $00 ; D3
.byte $7B ; D4 [{
.byte $2B ; D5 =+
.byte $00 ; D6
.byte $00 ; D7
.byte $00 ; D8 caps
.byte $00 ; D9 r shift
.byte $0D ; DA <Enter>
.byte $7D ; DB ]}
.byte $00 ; DC
.byte $7C ; DD \|
.byte $00 ; DE
.byte $00 ; DF
.byte $00 ; E0
.byte $00 ; E1
.byte $00 ; E2
.byte $00 ; E3
.byte $00 ; E4
.byte $00 ; E5
.byte $08 ; E6 bkspace
.byte $00 ; E7
.byte $00 ; E8
.byte $91 ; E9 kp 1
.byte $2f ; EA kp / converted from E04A in code
.byte $94 ; EB kp 4
.byte $97 ; EC kp 7
.byte $00 ; ED
.byte $00 ; EE
.byte $00 ; EF
.byte $90 ; F0 kp 0
.byte $7F ; F1 kp .
.byte $92 ; F2 kp 2
.byte $95 ; F3 kp 5
.byte $96 ; F4 kp 6
.byte $98 ; F5 kp 8
.byte $1B ; F6 esc
.byte $00 ; F7 num lock
.byte $CB ; F8 F11
.byte $2B ; F9 kp +
.byte $93 ; FA kp 3
.byte $2D ; FB kp -
.byte $2A ; FC kp *
.byte $99 ; FD kp 9
.byte $CD ; FE scroll lock
; Copyright 2020 Jonathan Foucher
; Permission is hereby granted, free of charge, to any person obtaining a copy of this software
; and associated documentation files (the "Software"), to deal in the Software without restriction,
; including without limitation the rights to use, copy, modify, merge, publish, distribute,
; sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
; is furnished to do so, subject to the following conditions:
; The above copyright notice and this permission notice shall be included in all copies or
; substantial portions of the Software.
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
; INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
; PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
; FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
; OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
; DEALINGS IN THE SOFTWARE.
ps2_irq:
pha
phx
lda to_send
bne @sending
lda KB_STATE ; which state ?
cmp #KB_STATE_START
beq @start ; start bit
cmp #KB_STATE_DATA ; get data bits
beq @data
cmp #KB_STATE_PARITY ; this is the parity bit
beq @parity
cmp #KB_STATE_STOP ; stop bit
beq @stop
jmp @exit
@start:
lda #KB_STATE_DATA
sta KB_STATE ; next state will be to get data
lda #0
sta KB_TEMP
sta KB_BIT
bra @exit
@data:
lda PORTB ; get the bit of data from PORTB bit 7
and #$80
ora KB_TEMP ; OR it with existing temp data
sta KB_TEMP ; save it
inc KB_BIT ; prepare for next bit
lda KB_BIT
cmp #8 ; if this is the last bit, next state is parity
beq @next_state_parity
lsr KB_TEMP ; if not last bit, shift KB_TEMP right to prepare for next bit
bra @exit
@next_state_parity:
lda #KB_STATE_PARITY ;next state is parity
sta KB_STATE
bra @exit
@parity:
lda #KB_STATE_STOP ;next state is stop
sta KB_STATE
bra @exit
@stop:
lda #KB_STATE_START
sta KB_STATE
lda ignore_next
bne @ignored
; Save key to character buffer
ldx KB_TEMP
cpx #$AA
beq @init
cpx #$FA
beq @init
cpx #$F0
beq @ignore_next
;stx PORTA
lda ASCIITBL, x
ldx KB_BUF_INDEX
sta KB_BUF, x
;sta PORTA
inc KB_BUF_INDEX
@exit:
plx
pla
rts
@init:
stx ready
bra @exit
@ignore_next:
lda #1
sta ignore_next
bra @exit
@ignored:
lda #0
sta ignore_next
bra @exit
@sending:
; lda #1
; sta PORTA
; data pin of DDRB should be set as output by prepare_send
lda KB_STATE ; which state ?
cmp #KB_STATE_DATA ; send data bits
beq @sending_data
cmp #KB_STATE_PARITY ; this is the parity bit
beq @sending_parity
cmp #KB_STATE_STOP ; stop bit
beq @sending_stop
bra @exit
@sending_data:
; lda #4
; sta PORTA
lda to_send ; get the bit of data from memory
and #$01 ; get only bottom bit
beq @send_zero
@send_one:
lda PORTB
ora #$80
sta PORTB
inc KB_PARITY
bra @sending_done
@send_zero:
lda PORTB
and #$7F
sta PORTB
@sending_done:
; lda #2
; sta PORTA
inc KB_BIT ; prepare for next bit
lda KB_BIT
cmp #8 ; if this is the last bit, next state is parity
jmp @next_state_parity
lsr to_send
clc
bra @exit
@sending_parity:
; lda #5
; sta PORTA
lda KB_PARITY
and #$01
beq @odd_parity ; send zero if odd parity
lda PORTB
ora #$80 ; send one if even
sta PORTB
lda #KB_STATE_STOP ;next state is stop
sta KB_STATE
bra @exit
@odd_parity:
lda PORTB
and #$7F
sta PORTB
lda #KB_STATE_STOP ;next state is stop
sta KB_STATE
bra @exit
@sending_stop:
; lda #6
; sta PORTA
lda #KB_STATE_START ; set it back to start in case we are receivin next
sta KB_STATE
lda #0
sta to_send
sta KB_BIT
sta KB_PARITY
lda DDRB ; set PORTB back to input
and #$7F
sta DDRB
jmp @exit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment