From e2007d074312c2f8600d8da87b2c55a724f4b128 Mon Sep 17 00:00:00 2001
From: Jeff Tranter <tranter@pobox.com>
Date: Thu, 4 Jan 2018 19:04:13 -0500
Subject: [PATCH 069/125] New OSI input routine based on disassembly of ROM
code.
---
libsrc/osic1p/cgetc.s | 189 ++++++++++++++++++++++++++++++++++++++-
libsrc/osic1p/kbhit.s | 3 +-
libsrc/osic1p/osic1p.inc | 1 -
3 files changed, 190 insertions(+), 3 deletions(-)
diff --git a/libsrc/osic1p/cgetc.s b/libsrc/osic1p/cgetc.s
index f05ad33e..d99f69a7 100644
--- a/libsrc/osic1p/cgetc.s
+++ b/libsrc/osic1p/cgetc.s
@@ -4,17 +4,34 @@
.constructor initcgetc
.export _cgetc
+ .export inputc
.import cursor
.include "osic1p.inc"
.include "extzp.inc"
.include "zeropage.inc"
+; Internal state that needs to be preserved across calls.
+; These variables are named after the original memory locations used by the
+; 65V PROM MONITOR, until the actual meaning is determined.
+.segment "EXTZP" : zeropage
+
+KB0213: .res 1
+KB0214: .res 1
+KB0215: .res 1
+KB0216: .res 1
+
; Initialize one-character buffer that is filled by kbhit()
.segment "ONCE"
initcgetc:
lda #$00
sta CHARBUF ; No character in buffer initially
+
+ sta KB0213 ; Initialize keyboard state
+ sta KB0214
+ sta KB0215
+ sta KB0216
+
rts
; Input routine from 65V PROM MONITOR, show cursor if enabled
@@ -35,7 +52,7 @@ nobuffer:
lda #$A1 ; full white square
sta (SCREEN_PTR),y ; store at cursor position
nocursor:
- jsr INPUTC ; get input character in A
+ jsr inputc ; get input character in A
ldx cursor
beq done ; was cursor on?
tax ; save A in X
@@ -48,3 +65,173 @@ restorex:
done:
ldx #$00 ; high byte of int return value
rts
+
+; Routine to get character from keyboard and return it in A.
+; Based on the OSI ROM routine at $FD00 but uses different
+; storage locations to avoid corrupting CC65 run-time code.
+
+inputc: txa ; Save X on stack.
+ pha
+ tya ; Save Y on stack.
+ pha
+LFD04: lda #$80 ; Bit mask for initial keyboard row
+LFD06: jsr LFCBE ; Write keyboard row
+ jsr LFCC6 ; Read keyboard column
+ bne LFD13 ; Branch if a key in this column was pressed
+ lsr a ; Otherwise shift mask to next row
+ bne LFD06 ; If not done yet, check next row
+ beq LFD3A ; Branch if last row reached and no key pressed
+LFD13: lsr a ; Have a key press. Shift LSB into carry
+ bcc LFD1F ; Branch if no key pressed in column 0
+ txa ; Key pressed in row zero. Get the column data
+ and #$20 ; Mask only the bit for <ESC> as it is the only key in row zero that returns key press
+ beq LFD3A ; Branch if <ESC> was not the key
+ lda #$1B ; Set character to <ESC>
+ bne LFD50 ; Do more processing
+LFD1F: jsr LFE86 ; Shift to find bit that is set (in Y)
+ tya ; Get bit
+ sta KB0215 ; Save it
+ asl a ; Multiply by 7 by shifting left three times (X8)...
+ asl a
+ asl a
+ sec ; ...then subtracting one
+ sbc KB0215
+ sta KB0215 ; Save value*7 for later lookup in table
+ txa ; Get the keyboard column
+ lsr a ; Shift out bit zero (only key there is <SHIFT LOCK>)
+ asl a ; And shift back
+ jsr LFE86 ; Shift to find bit that is set (in Y)
+ beq LFD47 ; Branch if no keys pressed
+ lda #$00
+LFD3A: sta KB0216 ; Save state of <CTRL> and shift keys
+LFD3D: sta KB0213
+ lda #$02 ; Count used for key debouncing
+ sta KB0214
+ bne LFD04 ; Go back and scan keyboard again
+LFD47: clc
+ tya ; Get bit number of pressed key
+ adc KB0215 ; Add previously calculated offset for keyboard row*7
+ tay
+ lda LFF3B,y ; Read ASCII code for key from table
+LFD50: cmp KB0213 ; Debounce - same as last key scan?
+ bne LFD3D ; If not, try again
+ dec KB0214 ; Decrement debounce counter
+ beq LFD5F ; Branch if done debouncing
+ jsr LFCDF ; Wait for short delay to debounce keyboard
+ beq LFD04 ; Go back and scan keyboard.
+LFD5F: ldx #$64 ; Was <CONTROL> key down?
+ cmp KB0216
+ bne LFD68 ; Branch if not
+ ldx #$0F
+LFD68: stx KB0214
+ sta KB0216
+ cmp #$21
+ bmi LFDD0 ; Done, return key
+ cmp #$5F
+ beq LFDD0 ; Done, return key
+ lda #$01
+ jsr LFCBE ; Write keyboard row
+ jsr LFCCF ; Read keyboard column
+ sta KB0215
+ and #$01
+ tax
+ lda KB0215
+ and #$06
+ bne LFDA2
+ bit KB0213
+ bvc LFDBB
+ txa
+ eor #$01
+ and #$01
+ beq LFDBB
+ lda #$20
+ bit KB0215
+ bvc LFDC3
+ lda #$C0
+ bne LFDC3
+LFDA2: bit KB0213
+ bvc LFDAA
+ txa
+ beq LFDBB
+LFDAA: ldy KB0213
+ cpy #$31
+ bcc LFDB9
+ cpy #$3C
+ bcs LFDB9
+ lda #$F0
+ bne LFDBB
+LFDB9: lda #$10
+LFDBB: bit KB0215
+ bvc LFDC3
+ clc
+ adc #$C0
+LFDC3: clc
+ adc KB0213
+ and #$7F
+ bit KB0215
+ bpl LFDD0
+ ora #$80
+LFDD0: sta KB0215 ; Save pressed key
+ pla
+ tay ; Restore saved Y value
+ pla
+ tax ; Restore saved Y value
+ lda KB0215 ; Get pressed key and return in A
+ rts
+
+; Write keyboard row with value in A.
+; Invert the bits before writing.
+; Returns original value of A.
+
+LFCBE: eor #$FF
+ sta KBD
+ eor #$FF
+ rts
+
+; Read keyboard column and return in X.
+; Sets Z flag if no keys were pressed.
+; Saves current value of A.
+
+LFCC6: pha ; Save A
+ jsr LFCCF ; Read keyboard column
+ tax ; Save in X
+ pla ; Restore A
+ dex ; Decrement and then increment to
+ inx ; preserve value of X but set flags
+ rts
+
+; Read keyboard column.
+; Invert the bits (pressed key(s) will show up as ones).
+
+LFCCF: lda KBD ; Read keyboard hardware
+ eor #$FF ; Invert the bits
+ rts
+
+; Short fixed delay routine.
+
+LFCDF: ldy #$10
+LFCE1: ldx #$40
+LFCE3: dex
+ bne LFCE3
+ dey
+ bne LFCE1
+ rts
+
+; Shift A left until we find a 1 in the most significant bit.
+; Return the bit number in Y.
+
+LFE86: ldy #$08
+LFE88: dey
+ asl a
+ bcc LFE88
+ rts
+
+; Lookup table of keyboard keys for each scan row.
+LFF3B: .byte $BD
+ .byte 'P', ';', '/', ' ', 'Z', 'A', 'Q'
+ .byte ',', 'M', 'N', 'B', 'V', 'C', 'X'
+ .byte 'K', 'J', 'H', 'G', 'F', 'D', 'S'
+ .byte 'I', 'U', 'Y', 'T', 'R', 'E', 'W'
+ .byte $00, $00, $0D, $0A, 'O', 'L', '.'
+ .byte $00, '_', '-', ':', '0', '9', '8'
+ .byte '7', '6', '5', '4', '3', '2', '1'
diff --git a/libsrc/osic1p/kbhit.s b/libsrc/osic1p/kbhit.s
index b616b4a3..1ecfa104 100644
--- a/libsrc/osic1p/kbhit.s
+++ b/libsrc/osic1p/kbhit.s
@@ -11,6 +11,7 @@
;
.export _kbhit
+ .import inputc
.include "osic1p.inc"
.include "extzp.inc"
.include "zeropage.inc"
@@ -40,7 +41,7 @@ scan:
sta CHARBUF ; No character in buffer
rts
keypressed:
- jsr INPUTC ; Get input character in A
+ jsr inputc ; Get input character in A
sta CHARBUF ; Save in buffer
ldx #$00 ; High byte of return is always zero
lda #$01 ; Return true
diff --git a/libsrc/osic1p/osic1p.inc b/libsrc/osic1p/osic1p.inc
index aaa03ba6..9f8620dc 100644
--- a/libsrc/osic1p/osic1p.inc
+++ b/libsrc/osic1p/osic1p.inc
@@ -1,4 +1,3 @@
; Addresses
-INPUTC := $FD00 ; Input character from keyboard
RESET := $FF00 ; Reset address, show boot prompt
KBD := $DF00 ; Polled keyboard register
--
2.23.0