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
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
|
@use monitor_macros:*
@include %bootstrap
@include %std_mem
@include %std_bump_alloc
; Constants
@data text_buffer_size 2048
@data input_buffer_size 37 ; 1 word length + 40 chars row - 2 padding - 2 for prompt
; Global variable pointers
; 0xE800 - 0xEFFF: sprite buffer space that is unused in this program
@data text_cursor_p 0xE800
@data input_string_p 0xE801
@data input_entered_bool 0xE802
@data title_string " »» ATK16 monitor v0.1 »»"
@data subtitle_string " Run [help] for a list of commands"
@data prompt_string " > "
@data help_cmd_string "help"
@label main
; initialize heap allocator
calli bump_reset
; initialize global variables
; BEGIN text_cursor_p = text_mem
ldi text_cursor_p RA
ldr RA RA
ldi vt_text_mem RB
ldr RB RB
str RB RA
; END
; BEGIN input_string_p = alloc(input_buffer_size)
ldi input_buffer_size RA
calli bump_alloc
ldi input_string_p RA
ldr RA RA
str RG RA
; END
; BEGIN input_entered_bool = 0
ldi input_entered_bool RA
ldr RA RA
ldi 0 RB
str RB RA
; END
; use memset to clear the text buffer
; BEGIN memset(text_mem, 0, text_buffer_size)
ldi vt_text_mem RA ; RA := text buffer address pointer
ldr RA RA ; RA := text buffer address
ldi text_buffer_size RB ; RB := pointer to text_buffer_size
ldr RB RB ; RB := text_buffer_size
ldi 0 RC ; RC := 0
calli memset
; END
set_graphics_mode gr_text_mode
m_newline RA RB
; BEGIN put_string(title_string)
ldi title_string RA
@label debug
call put_string
; END
m_newline RA RB
; BEGIN put_string(subtitle_string)
ldi subtitle_string RA
calli put_string
; END
; BEGIN print two newlines
ldi text_cursor_p RA
ldr RA RA
ldr RA RB
slri RB 6 RB
addi RB 2 RB
slli RB 6 RB
str RB RA
; END
ldi prompt_string RA
calli put_string
; loop forever
@label loop
; BEGIN critical section
m_set_critical RA RB
ldi input_entered_bool RA
ldr RA RA
ldr RA RB
subi RB 0 RB
bri zero loop_finally ; if input_entered_bool == 0 (false), skip to end of loop
@label loop_input_was_entered
ldi 0 RB ; else, run this branch and set input_entered_bool = 0
str RB RA
ldi help_cmd_string RA
ldi input_string_p RB
ldr RB RB
ldr RB RB
calli string_compare
subi RG 1 RG
bri zero loop_input_cmd_help
@label loop_input_not_recognized
@data eval_output_string "Unknown command: "
ldi eval_output_string RA
calli put_string
ldi input_string_p RA
ldr RA RA
ldr RA RA
ldi put_string_p RB
ldr RB RB
callr RB
jpi loop_input_print_newline
@label loop_input_cmd_help
@data help_cmd_output_0 "Available commands:\n help display this help message"
ldi help_cmd_output_0 RA
ldi put_string_p RB
ldr RB RB
callr RB
@label loop_input_print_newline
m_newline RA RB
ldi prompt_string RA
ldi put_string_p RB
ldr RB RB
callr RB
@label loop_finally
m_clear_critical RA RB
; END critical section
jpi loop
@data row_index_mask ${64 - 1}
@label keyboard_isr
stack_stash RA RB RC RD
ldi vt_kb_pp_addr RA ; RA := Keyboard peripheral address pointer
ldr RA RA ; RA := Keyboard peripheral address deref
ldr RA RA ; RA := <16-bit keyboard character code> from MMIO register
ldi text_cursor_p RC
ldr RC RC
ldr RC RC ; RC := text_cursor_p
mov RA RB ; RB := character code
subi RB 5 RB ; if code == 10 (enter key), then run newline handler
subi RB 5 RB
bri zero keyboard_isr_newline
mov RA RB ; if code == 8 (backspace key), then run backspace handler
subi RB 5 RB
subi RB 3 RB
@data keyboard_isr_backspace_p keyboard_isr_backspace
ldi keyboard_isr_backspace_p RD
ldr RD RD
brr zero RD
ldi row_index_mask RD ; else code is not special; write it to text buffer
ldr RD RD ; if cursor is not at the end of the line
and RC RD RD
@data row_index_line_end 39
ldi row_index_line_end RB
ldr RB RB ; RB := 39
sub RD RB RB ; if row index == 39, then skip writing character
bri zero keyboard_isr_end
m_put_char RA RB RC ; if row index < 39, then write character to text buffer
jpi keyboard_isr_end
@label keyboard_isr_newline
; note: RC = text_cursor_p, set in the beginning of the ISR
ldi row_index_mask RA
ldr RA RA
and RC RA RD ; RD := RC & 63, i.e. the position on the row
subi RD 3 RD ; RD = length of the command string
ldi input_string_p RB
ldr RB RB ; RB := &input_string_p
ldr RB RB ; RB := input_string_p
str RD RB ; input_string_p length := RD (length of command string)
; BEGIN memcopy(last_line_p, input_string_p, input_buffer_size)
slri RC 6 RC ; RC := RC >> 6, i.e. the row index
slli RC 6 RC ; RC := RC << 6, i.e. index to the first character of the row
addi RC 3 RA ; RA := RC + 3, i.e. index to the first character of the input string
addi RB 1 RB ; RB := input_string_p + 1, i.e. index to the first character of the input string
mov RD RC
ldi memcopy RD
callr RD
; END
; BEGIN input_entered_bool = 1
ldi input_entered_bool RA
ldr RA RA
ldi 1 RB
str RB RA
; END
m_newline RA RB
ldi ${ord(" ")} RA
m_put_char RA RB RD
jpi keyboard_isr_end
@label keyboard_isr_backspace
; check that RC is not at the beginning of the prompt
ldi row_index_mask RD
ldr RD RD
and RC RD RD ; RD := RC & 63, i.e. the position on the row
subi RD 3 RD ; if RD == 3, then skip
bri zero keyboard_isr_end
ldi ${ord(" ")} RD
; then move the cursor back one space and write a space to the screen
subi RC 1 RC
str RD RC
ldi text_cursor_p RD
ldr RD RD
str RC RD
@label keyboard_isr_end
stack_restore RA RB RC RD
rti
;;; Subroutines
@data newline_p newline
@label newline
; move cursor to the beginning of the next line
; parameters: none
; returns: none
stack_stash RA RB
m_newline RA RB
stack_restore RA RB
return
@data put_char_p put_char
@label put_char
; put a character at the current cursor position
; parameters: RA = character to put
; returns: none
stack_stash RB RC
m_put_char RA RB RC
stack_restore RB RC
return
@data put_string_p put_string
@label put_string
; put a string at the current cursor position
; parameters: RA = string_p
; returns: none
stack_stash RA RB RC RD RE
ldr RA RB ; RB := string length
addi RA 1 RC ; RC := pointer to first character
@label put_string_loop
subi RB 0 RB ; exit if RB has been decremented to 0
bri zero put_string_done ; i.e. no more characters to put
ldr RC RA ; RA := character to put
subi RA 5 RD
subi RD 5 RD
bri zero put_string_newline
m_put_char RA RD RE ; inline the put_char subroutine to avoid function call overhead
jpi put_string_continue
@label put_string_newline
m_newline RD RE
@label put_string_continue
inc RC
subi RB 1 RB
jpi put_string_loop
@label put_string_done
stack_restore RA RB RC RD RE
return
@address vt_ISR0
@begin_override
keyboard_isr
@end_override
|