-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkeyboard.asm
280 lines (243 loc) · 5.11 KB
/
keyboard.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
@define PORTB $6000
@define PORTA $6001
@define DDRB $6002
@define DDRA $6003
@define PCR $600c
@define IFR $600d
@define IER $600e
@define kb_wptr $0000
@define kb_rptr $0001
@define kb_flags $0002
@define RELEASE %00000001
@define SHIFT %00000010
@define kb_buffer $0200 ; 256-byte kb buffer 0200-02ff
@define E %01000000
@define RW %00100000
@define RS %00010000
.org $8000
reset:
mov %rx, #$ff
mov %rs, %rx
lda #$01
sta PCR
lda #$82
sta IER
cli
lda #%11111111 ; Set all pins on port B to output
sta DDRB
lda #%00000000 ; Set all pins on port A to input
sta DDRA
jsr lcd_init
lda #%00101000 ; Set 4-bit mode; 2-line display; 5x8 font
jsr lcd_instruction
lda #%00001110 ; Display on; cursor on; blink off
jsr lcd_instruction
lda #%00000110 ; Increment and shift cursor; don't shift display
jsr lcd_instruction
lda #%00000001 ; Clear display
jsr lcd_instruction
lda #$00
sta kb_flags
sta kb_wptr
sta kb_rptr
loop:
sei
lda kb_rptr
cmp kb_wptr
cli
bne key_pressed
jmp loop
key_pressed:
ldx kb_rptr
lda kb_buffer, x
cmp #$0a ; enter - go to second line
beq enter_pressed
cmp #$1b ; escape - clear display
beq esc_pressed
jsr print_char
inc kb_rptr
jmp loop
enter_pressed:
lda #%10101000 ; put cursor at position 40
jsr lcd_instruction
inc kb_rptr
jmp loop
esc_pressed:
lda #%00000001 ; Clear display
jsr lcd_instruction
inc kb_rptr
jmp loop
lcd_wait:
pha
lda #%11110000 ; LCD data is input
sta DDRB
lcdbusy:
lda #RW
sta PORTB
lda #(RW | E)
sta PORTB
lda PORTB ; Read high nibble
pha ; and put on stack since it has the busy flag
lda #RW
sta PORTB
lda #(RW | E)
sta PORTB
lda PORTB ; Read low nibble
pla ; Get high nibble off stack
and #%00001000
bne lcdbusy
lda #RW
sta PORTB
lda #%11111111 ; LCD data is output
sta DDRB
pla
rts
lcd_init:
lda #%00000010 ; Set 4-bit mode
sta PORTB
ora #E
sta PORTB
and #%00001111
sta PORTB
rts
lcd_instruction:
jsr lcd_wait
pha
lsr
lsr
lsr
lsr ; Send high 4 bits
sta PORTB
ora #E ; Set E bit to send instruction
sta PORTB
eor #E ; Clear E bit
sta PORTB
pla
and #%00001111 ; Send low 4 bits
sta PORTB
ora #E ; Set E bit to send instruction
sta PORTB
eor #E ; Clear E bit
sta PORTB
rts
print_char:
jsr lcd_wait
pha
lsr
lsr
lsr
lsr ; Send high 4 bits
ora #RS ; Set RS
sta PORTB
ora #E ; Set E bit to send instruction
sta PORTB
eor #E ; Clear E bit
sta PORTB
pla
and #%00001111 ; Send low 4 bits
ora #RS ; Set RS
sta PORTB
ora #E ; Set E bit to send instruction
sta PORTB
eor #E ; Clear E bit
sta PORTB
rts
; IRQ vector points here
keyboard_interrupt:
pha
txa
pha
lda kb_flags
and #RELEASE ; check if we're releasing a key
beq read_key ; otherwise, read the key
lda kb_flags
eor #RELEASE ; flip the releasing bit
sta kb_flags
lda PORTA ; read key value that's being released
cmp #$12 ; left shift
beq shift_up
cmp #$59 ; right shift
beq shift_up
jmp exit
shift_up:
lda kb_flags
eor #SHIFT ; flip the shift bit
sta kb_flags
jmp exit
read_key:
lda PORTA
cmp #$f0 ; if releasing a key
beq key_release ; set the releasing bit
cmp #$12 ; left shift
beq shift_down
cmp #$59 ; right shift
beq shift_down
tax
lda kb_flags
and #SHIFT
bne shifted_key
lda keymap, x ; map to character code
jmp push_key
shifted_key:
mov %ra, [keymap_shifted + %rx] ; map to character code
push_key:
ldx kb_wptr
sta kb_buffer, x
inc kb_wptr
jmp exit
shift_down:
lda kb_flags
ora #SHIFT
sta kb_flags
jmp exit
key_release:
lda kb_flags
ora #RELEASE
sta kb_flags
exit:
pla
tax
pla
rti
nmi:
rti
@org $fd00
keymap:
.byte "????????????? `?" ; 00-0F
.byte "?????q1???zsaw2?" ; 10-1F
.byte "?cxde43?? vftr5?" ; 20-2F
.byte "?nbhgy6???mju78?" ; 30-3F
.byte "?,kio09??./l;p-?" ; 40-4F
.byte "??'?[=????",$0a,"]?\??" ; 50-5F
.byte "?????????1?47???" ; 60-6F
.byte "0.2568",$1b,"??+3-*9??" ; 70-7F
.byte "????????????????" ; 80-8F
.byte "????????????????" ; 90-9F
.byte "????????????????" ; A0-AF
.byte "????????????????" ; B0-BF
.byte "????????????????" ; C0-CF
.byte "????????????????" ; D0-DF
.byte "????????????????" ; E0-EF
.byte "????????????????" ; F0-FF
keymap_shifted:
.byte "????????????? ~?" ; 00-0F
.byte "?????Q!???ZSAW@?" ; 10-1F
.byte "?CXDE#$?? VFTR%?" ; 20-2F
.byte "?NBHGY^???MJU&*?" ; 30-3F
.byte "?<KIO)(??>?L:P_?" ; 40-4F
.byte "??\"?{+?????}?|??" ; 50-5F
.byte "?????????1?47???" ; 60-6F
.byte "0.2568???+3-*9??" ; 70-7F
.byte "????????????????" ; 80-8F
.byte "????????????????" ; 90-9F
.byte "????????????????" ; A0-AF
.byte "????????????????" ; B0-BF
.byte "????????????????" ; C0-CF
.byte "????????????????" ; D0-DF
.byte "????????????????" ; E0-EF
.byte "????????????????" ; F0-FF
; Reset/IRQ vectors
.org $fffa
.word nmi
.word reset
.word keyboard_interrupt