kickc/src/test/ref/test-keyboard.asm

286 lines
7.7 KiB
NASM

// Test keyboard input - in the keyboard matrix and mapping screen codes to key codes
// Commodore 64 PRG executable file
.file [name="test-keyboard.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.const KEY_3 = 8
.const KEY_W = 9
.const KEY_A = $a
.const KEY_4 = $b
.const KEY_Z = $c
.const KEY_S = $d
.const KEY_E = $e
.const KEY_5 = $10
.const KEY_R = $11
.const KEY_D = $12
.const KEY_6 = $13
.const KEY_C = $14
.const KEY_F = $15
.const KEY_T = $16
.const KEY_X = $17
.const KEY_7 = $18
.const KEY_Y = $19
.const KEY_G = $1a
.const KEY_8 = $1b
.const KEY_B = $1c
.const KEY_H = $1d
.const KEY_U = $1e
.const KEY_V = $1f
.const KEY_9 = $20
.const KEY_I = $21
.const KEY_J = $22
.const KEY_0 = $23
.const KEY_M = $24
.const KEY_K = $25
.const KEY_O = $26
.const KEY_N = $27
.const KEY_PLUS = $28
.const KEY_P = $29
.const KEY_L = $2a
.const KEY_MINUS = $2b
.const KEY_DOT = $2c
.const KEY_COLON = $2d
.const KEY_AT = $2e
.const KEY_COMMA = $2f
.const KEY_POUND = $30
.const KEY_ASTERISK = $31
.const KEY_SEMICOLON = $32
.const KEY_EQUALS = $35
.const KEY_ARROW_UP = $36
.const KEY_SLASH = $37
.const KEY_1 = $38
.const KEY_ARROW_LEFT = $39
.const KEY_2 = $3b
.const KEY_SPACE = $3c
.const KEY_Q = $3e
.const OFFSET_STRUCT_MOS6526_CIA_PORT_A_DDR = 2
.const OFFSET_STRUCT_MOS6526_CIA_PORT_B_DDR = 3
.const OFFSET_STRUCT_MOS6526_CIA_PORT_B = 1
/// $D012 RASTER Raster counter
.label RASTER = $d012
/// The CIA#1: keyboard matrix, joystick #1/#2
.label CIA1 = $dc00
.segment Code
main: {
.label sc = 7
.label screen = 3
.label row = 6
.label ch = 5
// Checks all specific chars $00-$3f
.label i = 2
lda #<$400
sta.z sc
lda #>$400
sta.z sc+1
// Clear screen
__b1:
// for(byte* sc = (char*)$400; sc<$400+1000;sc++)
lda.z sc+1
cmp #>$400+$3e8
bcs !__b2+
jmp __b2
!__b2:
bne !+
lda.z sc
cmp #<$400+$3e8
bcs !__b2+
jmp __b2
!__b2:
!:
// keyboard_init()
// Init keyboard
jsr keyboard_init
__b4:
// while (*RASTER!=$ff)
lda #$ff
cmp RASTER
bne __b4
lda #<$400
sta.z screen
lda #>$400
sta.z screen+1
lda #0
sta.z row
// Read & print keyboard matrix
__b5:
// byte row_pressed_bits = keyboard_matrix_read(row)
ldx.z row
jsr keyboard_matrix_read
// byte row_pressed_bits = keyboard_matrix_read(row)
tax
ldy #0
__b6:
// row_pressed_bits & $80
txa
and #$80
// if( (row_pressed_bits & $80) != 0)
cmp #0
bne __b7
// screen[col] = '0'
lda #'0'
sta (screen),y
__b8:
// row_pressed_bits = row_pressed_bits * 2
txa
asl
tax
// for(byte col : 0..7)
iny
cpy #8
bne __b6
// screen = screen + 40
lda #$28
clc
adc.z screen
sta.z screen
bcc !+
inc.z screen+1
!:
// for(byte row : 0..7)
inc.z row
lda #8
cmp.z row
bne __b5
// screen = screen + 40
lda #$28
clc
adc.z screen
sta.z screen
bcc !+
inc.z screen+1
!:
lda #0
sta.z i
sta.z ch
__b12:
// byte key = keyboard_get_keycode(ch)
ldx.z ch
jsr keyboard_get_keycode
// if(key!=$3f)
cmp #$3f
beq __b13
// keyboard_key_pressed(key)
tax
jsr keyboard_key_pressed
// if(keyboard_key_pressed(key)!=0)
cmp #0
beq __b13
// screen[i++] = ch
lda.z ch
ldy.z i
sta (screen),y
// screen[i++] = ch;
inc.z i
__b13:
// for( byte ch : 0..$3f )
inc.z ch
lda #$40
cmp.z ch
bne __b12
__b3:
// Add some spaces
// screen[i++] = ' '
lda #' '
ldy.z i
sta (screen),y
// screen[i++] = ' ';
inc.z i
// while (i<5)
lda.z i
cmp #5
bcc __b3
jmp __b4
__b7:
// screen[col] = '1'
lda #'1'
sta (screen),y
jmp __b8
__b2:
// *sc = ' '
lda #' '
ldy #0
sta (sc),y
// for(byte* sc = (char*)$400; sc<$400+1000;sc++)
inc.z sc
bne !+
inc.z sc+1
!:
jmp __b1
}
// Initialize keyboard reading by setting CIA#1 Data Direction Registers
keyboard_init: {
// CIA1->PORT_A_DDR = 0xff
// Keyboard Matrix Columns Write Mode
lda #$ff
sta CIA1+OFFSET_STRUCT_MOS6526_CIA_PORT_A_DDR
// CIA1->PORT_B_DDR = 0x00
// Keyboard Matrix Columns Read Mode
lda #0
sta CIA1+OFFSET_STRUCT_MOS6526_CIA_PORT_B_DDR
// }
rts
}
// Read a single row of the keyboard matrix
// The row ID (0-7) of the keyboard matrix row to read. See the C64 key matrix for row IDs.
// Returns the keys pressed on the row as bits according to the C64 key matrix.
// Notice: If the C64 normal interrupt is still running it will occasionally interrupt right between the read & write
// leading to erroneous readings. You must disable the normal interrupt or sei/cli around calls to the keyboard matrix reader.
// __register(A) char keyboard_matrix_read(__register(X) char rowid)
keyboard_matrix_read: {
// CIA1->PORT_A = keyboard_matrix_row_bitmask[rowid]
lda keyboard_matrix_row_bitmask,x
sta CIA1
// char row_pressed_bits = ~CIA1->PORT_B
lda CIA1+OFFSET_STRUCT_MOS6526_CIA_PORT_B
eor #$ff
// }
rts
}
// Get the keycode corresponding to a specific screen code character
// ch is the character to get the key code for ($00-$3f)
// Returns the key code corresponding to the passed character. Only characters with a non-shifted key are handled.
// If there is no non-shifted key representing the char $3f is returned (representing RUN/STOP) .
// __register(A) char keyboard_get_keycode(__register(X) char ch)
keyboard_get_keycode: {
// return keyboard_char_keycodes[ch];
lda keyboard_char_keycodes,x
// }
rts
}
// Determines whether a specific key is currently pressed by accessing the matrix directly
// The key is a keyboard code defined from the keyboard matrix by %00rrrccc, where rrr is the row ID (0-7) and ccc is the column ID (0-7)
// All keys exist as as KEY_XXX constants.
// Returns zero if the key is not pressed and a non-zero value if the key is currently pressed
// __register(A) char keyboard_key_pressed(__register(X) char key)
keyboard_key_pressed: {
// char colidx = key&7
txa
and #7
tay
// char rowidx = key>>3
txa
lsr
lsr
lsr
// keyboard_matrix_read(rowidx)
tax
jsr keyboard_matrix_read
// keyboard_matrix_read(rowidx)
// keyboard_matrix_read(rowidx) & keyboard_matrix_col_bitmask[colidx]
and keyboard_matrix_col_bitmask,y
// }
rts
}
.segment Data
// Keycodes for each screen code character from $00-$3f.
// Chars that do not have an unmodified keycode return $3f (representing RUN/STOP).
keyboard_char_keycodes: .byte KEY_AT, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, $3f, KEY_POUND, $3f, KEY_ARROW_UP, KEY_ARROW_LEFT, KEY_SPACE, $3f, $3f, $3f, $3f, $3f, $3f, $3f, $3f, $3f, KEY_ASTERISK, KEY_PLUS, KEY_COMMA, KEY_MINUS, KEY_DOT, KEY_SLASH, KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_COLON, KEY_SEMICOLON, $3f, KEY_EQUALS, $3f, $3f
// Keyboard row bitmask as expected by CIA#1 Port A when reading a specific keyboard matrix row (rows are numbered 0-7)
keyboard_matrix_row_bitmask: .byte $fe, $fd, $fb, $f7, $ef, $df, $bf, $7f
// Keyboard matrix column bitmasks for a specific keybooard matrix column when reading the keyboard. (columns are numbered 0-7)
keyboard_matrix_col_bitmask: .byte 1, 2, 4, 8, $10, $20, $40, $80