|
| 1 | +; Copyright 2022 LLVM-MOS Project |
| 2 | +; |
| 3 | +; Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +; you may not use this file except in compliance with the License. |
| 5 | +; You may obtain a copy of the License at |
| 6 | +; |
| 7 | +; http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | +; |
| 9 | +; Unless required by applicable law or agreed to in writing, software |
| 10 | +; distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | +; See the License for the specific language governing permissions and |
| 13 | +; limitations under the License. |
| 14 | +; |
| 15 | +; This module is based on the corresponding cc65 osic1p kbhit.s module as of |
| 16 | +; commit 5aa75ae81f07724ef8c16d61e42b74a20296acae, and was modified for the |
| 17 | +; use in llvm-mos-sdk: |
| 18 | +; |
| 19 | +; https://github.com/cc65/cc65/blob/5aa75ae81f07724ef8c16d61e42b74a20296acae/libsrc/osic1p/kbhit.s. |
| 20 | +; |
| 21 | +; The original cc65 license was: |
| 22 | +; |
| 23 | +; This software is provided 'as-is', without any express or implied warranty. |
| 24 | +; In no event will the authors be held liable for any damages arising from |
| 25 | +; the use of this software. |
| 26 | +; |
| 27 | +; Permission is granted to anyone to use this software for any purpose, |
| 28 | +; including commercial applications, and to alter it and redistribute it |
| 29 | +; freely, subject to the following restrictions: |
| 30 | +; |
| 31 | +; 1. The origin of this software must not be misrepresented; you must not |
| 32 | +; claim that you wrote the original software. If you use this software in |
| 33 | +; a product, an acknowledgment in the product documentation would be |
| 34 | +; appreciated but is not required. |
| 35 | +; |
| 36 | +; 2. Altered source versions must be plainly marked as such, and must not |
| 37 | +; be misrepresented as being the original software. |
| 38 | +; |
| 39 | +; 3. This notice may not be removed or altered from any source distribution. |
| 40 | + |
| 41 | + |
| 42 | +; The method to detect a pressed key is based on the documentation in |
| 43 | +; "Section 3 Programmed Key Functions" in "The Challenger Character Graphics |
| 44 | +; Reference Manual" |
| 45 | +; We only want to return true for characters that can be returned by getchar(), |
| 46 | +; but not for keys like <Shift> or <Ctrl>. Therefore a special handling is |
| 47 | +; needed for the first row. This is implemented by a bit mask that is stored |
| 48 | +; in KBDTMP and that is set to zero after the first round. |
| 49 | + |
| 50 | +; Put keyboard state into dedicated zero-page storage. |
| 51 | +; |
| 52 | +; "za" attribute means: |
| 53 | +; "z": allocate in page zero |
| 54 | +; "a": section is "allocatable", must be allocated a runtime address |
| 55 | +.section .zp.kbd,"za",@nobits |
| 56 | + |
| 57 | +; Internal state that needs to be preserved across calls. |
| 58 | +; The getchar() function uses __CHARBUF to retrieve |
| 59 | +; the return value. |
| 60 | +.global __CHARBUF |
| 61 | +__CHARBUF: .ds.b 1 ; Character buffer |
| 62 | +LASTSCAN: .ds.b 1 ; Result of previous keyboard scan |
| 63 | +DBNCCNT: .ds.b 1 ; Debounce counter |
| 64 | +KBDTMP: .ds.b 1 ; Temporary values |
| 65 | +CTRLSHIFT: .ds.b 1 ; State of CTRL and SHIFT keys |
| 66 | + |
| 67 | +KBD = $DF00 ; Polled keyboard register |
| 68 | + |
| 69 | +; Initialize one-character buffer that is filled by kbhit(). |
| 70 | +; Must be called before main(). |
| 71 | +.section .text.initkbhit |
| 72 | +.global __initkbhit |
| 73 | +__initkbhit: |
| 74 | + lda #$00 |
| 75 | + sta __CHARBUF ; No character in buffer initially |
| 76 | + sta LASTSCAN ; Initialize keyboard state |
| 77 | + sta DBNCCNT |
| 78 | + sta KBDTMP |
| 79 | + sta CTRLSHIFT |
| 80 | + |
| 81 | + rts |
| 82 | + |
| 83 | +; Routine to get character from keyboard and return it in A. |
| 84 | +; Based on the OSI ROM routine at $FD00 but uses different |
| 85 | +; storage locations. |
| 86 | + |
| 87 | +.section .text.kbhit |
| 88 | +.global __kbhit |
| 89 | +__kbhit: |
| 90 | + lda __CHARBUF ; Check for previously saved character |
| 91 | + beq LFD05 |
| 92 | + rts ; A contains non-zero character code meaning true |
| 93 | +LFD05: lda #$80 ; Bit mask for initial keyboard row |
| 94 | +LFD06: jsr LFCBE ; Write keyboard row |
| 95 | + jsr LFCC6 ; Read keyboard column |
| 96 | + bne LFD13 ; Branch if a key in this column was pressed |
| 97 | + lsr a ; Otherwise shift mask to next row |
| 98 | + bne LFD06 ; If not done yet, check next row |
| 99 | + beq LFD3A ; Branch if last row reached and no key pressed |
| 100 | +LFD13: lsr a ; Have a key press. Shift LSB into carry |
| 101 | + bcc LFD1F ; Branch if no key pressed in column 0 |
| 102 | + txa ; Key pressed in row zero. Get the column data |
| 103 | + and #$20 ; Mask only the bit for <ESC> as it is the only key in row zero that returns key press |
| 104 | + beq LFD3A ; Branch if <ESC> was not the key |
| 105 | + lda #$1B ; Set character to <ESC> |
| 106 | + bne LFD50 ; Do more processing |
| 107 | +LFD1F: jsr LFE86 ; Shift to find bit that is set (in Y) |
| 108 | + tya ; Get bit |
| 109 | + sta KBDTMP ; Save it |
| 110 | + asl a ; Multiply by 7 by shifting left three times (X8)... |
| 111 | + asl a |
| 112 | + asl a |
| 113 | + sec ; ...then subtracting one |
| 114 | + sbc KBDTMP |
| 115 | + sta KBDTMP ; Save value*7 for later lookup in table |
| 116 | + txa ; Get the keyboard column |
| 117 | + lsr a ; Shift out bit zero (only key there is <SHIFT LOCK>) |
| 118 | + asl a ; And shift back |
| 119 | + jsr LFE86 ; Shift to find bit that is set (in Y) |
| 120 | + beq LFD47 ; Branch if no keys pressed |
| 121 | + lda #$00 |
| 122 | +LFD3A: sta CTRLSHIFT ; Save state of <CTRL> and shift keys |
| 123 | +LFD3D: sta LASTSCAN |
| 124 | + lda #$02 ; Count used for key debouncing |
| 125 | + sta DBNCCNT |
| 126 | + lda #$00 ; Return false |
| 127 | + sta __CHARBUF |
| 128 | + rts |
| 129 | +LFD47: clc |
| 130 | + tya ; Get bit number of pressed key |
| 131 | + adc KBDTMP ; Add previously calculated offset for keyboard row*7 |
| 132 | + tay |
| 133 | + lda LFF3B,y ; Read ASCII code for key from table |
| 134 | +LFD50: cmp LASTSCAN ; Debounce - same as last key scan? |
| 135 | + bne LFD3D ; If not, try again |
| 136 | + dec DBNCCNT ; Decrement debounce counter |
| 137 | + beq LFD5F ; Branch if done debouncing |
| 138 | + jsr LFCDF ; Wait for short delay to debounce keyboard |
| 139 | + beq __kbhit ; Go back and scan keyboard. |
| 140 | +LFD5F: ldx #$64 ; Was <CONTROL> key down? |
| 141 | + cmp CTRLSHIFT |
| 142 | + bne LFD68 ; Branch if not |
| 143 | + ldx #$0F |
| 144 | +LFD68: stx DBNCCNT |
| 145 | + sta CTRLSHIFT |
| 146 | + cmp #$21 |
| 147 | + bmi LFDD0 ; Done, return key |
| 148 | + cmp #$5F |
| 149 | + beq LFDD0 ; Done, return key |
| 150 | + lda #$01 |
| 151 | + jsr LFCBE ; Write keyboard row |
| 152 | + jsr LFCCF ; Read keyboard column |
| 153 | + sta KBDTMP |
| 154 | + tax |
| 155 | + and #$06 |
| 156 | + bne LFDA2 |
| 157 | + bit LASTSCAN |
| 158 | + bvc LFDBB |
| 159 | + txa |
| 160 | + eor #$01 |
| 161 | + and #$01 |
| 162 | + beq LFDBB |
| 163 | + lda #$20 |
| 164 | + bit KBDTMP |
| 165 | + bvc LFDC3 |
| 166 | + lda #$C0 |
| 167 | + bne LFDC3 |
| 168 | +LFDA2: bit LASTSCAN |
| 169 | + bvc LFDAA |
| 170 | + txa |
| 171 | + beq LFDBB |
| 172 | +LFDAA: ldy LASTSCAN |
| 173 | + cpy #$31 |
| 174 | + bcc LFDB9 |
| 175 | + cpy #$3C |
| 176 | + bcs LFDB9 |
| 177 | + lda #$F0 |
| 178 | + bne LFDBB |
| 179 | +LFDB9: lda #$10 |
| 180 | +LFDBB: bit KBDTMP |
| 181 | + bvc LFDC3 |
| 182 | + clc |
| 183 | + adc #$C0 |
| 184 | +LFDC3: clc |
| 185 | + adc LASTSCAN |
| 186 | + and #$7F |
| 187 | + bit KBDTMP |
| 188 | + bpl LFDD0 |
| 189 | + ora #$80 |
| 190 | +LFDD0: sta KBDTMP ; Save pressed key and return in __CHARBUF |
| 191 | + sta __CHARBUF |
| 192 | + rts |
| 193 | + |
| 194 | +; Write keyboard row with value in A. |
| 195 | +; Invert the bits before writing. |
| 196 | +; Returns original value of A. |
| 197 | + |
| 198 | +LFCBE: eor #$FF |
| 199 | + sta KBD |
| 200 | + eor #$FF |
| 201 | + rts |
| 202 | + |
| 203 | +; Read keyboard column and return in X. |
| 204 | +; Sets Z flag if no keys were pressed. |
| 205 | +; Saves current value of A. |
| 206 | + |
| 207 | +LFCC6: pha ; Save A |
| 208 | + jsr LFCCF ; Read keyboard column |
| 209 | + tax ; Save in X |
| 210 | + pla ; Restore A |
| 211 | + dex ; Decrement and then increment to |
| 212 | + inx ; preserve value of X but set flags |
| 213 | + rts |
| 214 | + |
| 215 | +; Read keyboard column. |
| 216 | +; Invert the bits (pressed key(s) will show up as ones). |
| 217 | + |
| 218 | +LFCCF: lda KBD ; Read keyboard hardware |
| 219 | + eor #$FF ; Invert the bits |
| 220 | + rts |
| 221 | + |
| 222 | +; Short fixed delay routine. |
| 223 | + |
| 224 | +LFCDF: ldy #$10 |
| 225 | +LFCE1: ldx #$40 |
| 226 | +LFCE3: dex |
| 227 | + bne LFCE3 |
| 228 | + dey |
| 229 | + bne LFCE1 |
| 230 | + rts |
| 231 | + |
| 232 | +; Shift A left until we find a 1 in the most significant bit. |
| 233 | +; Return the bit number in Y. |
| 234 | + |
| 235 | +LFE86: ldy #$08 |
| 236 | +LFE88: dey |
| 237 | + asl a |
| 238 | + bcc LFE88 |
| 239 | + rts |
| 240 | + |
| 241 | +; Lookup table of keyboard keys for each scan row. |
| 242 | +LFF3B: .byte $BD |
| 243 | + .byte 'P', ';', '/', ' ', 'Z', 'A', 'Q' |
| 244 | + .byte ',', 'M', 'N', 'B', 'V', 'C', 'X' |
| 245 | + .byte 'K', 'J', 'H', 'G', 'F', 'D', 'S' |
| 246 | + .byte 'I', 'U', 'Y', 'T', 'R', 'E', 'W' |
| 247 | + .byte $00, $00, $0D, $0A, 'O', 'L', '.' |
| 248 | + .byte $00, '_', '-', ':', '0', '9', '8' |
| 249 | + .byte '7', '6', '5', '4', '3', '2', '1' |
0 commit comments