-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathbfloader.S
430 lines (329 loc) · 7.07 KB
/
bfloader.S
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
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
# bfloader - Brainfuck made to fit in 512 bytes.
#
# Reserved registers:
# BP = debug flag (Ctrl+F5)
# DI = current pointer
# SI = current char
MAX_ROW = 0x15
MAX_COL = 0x4F
MAX_CHAR = 0x154F
BF_INITIAL_POINTER = 0xF000
BF_SEPARATOR = (MAX_ROW + 1) * 0x100
BF_INITIAL_OUT = BF_SEPARATOR + 0x100
BF_ABOUT = BF_INITIAL_OUT + 0x100
MAX_OUT_CHAR = BF_INITIAL_OUT + MAX_COL
MEMORY_OFFSET = 0xFFD0
MEMORY_OUT_CHAR = MEMORY_OFFSET
KEY_EXECUTE = 0x3F00 # F5
KEY_DEBUG = 0x6200 # Ctrl+F5
KEY_TERMINATE = 0x2E03 # Ctrl+C
KEY_RESET = 0x8A00 # Ctrl+F12
KEY_UP = 0x48
KEY_DOWN = 0x50
KEY_LEFT = 0x4B
KEY_RIGHT = 0x4D
KEY_BACKSPACE = 0x08
KEY_HOME = 0x47
KEY_END = 0x4F
KEY_ENTER = 0x0D
CHAR_POINTER_RIGHT = 0x3E # >
CHAR_POINTER_LEFT = 0x3C # <
CHAR_INC = 0x2B # +
CHAR_DEC = 0x2D # -
CHAR_OUT = 0x2E # .
CHAR_IN = 0x2C # ,
CHAR_LOOP_START = 0x5B # [
CHAR_LOOP_END = 0x5D # ]
CHAR_BORDER = 0xCD
.code16
.global init
init:
# Set text mode, 80x25.
mov $0x0002, %ax
int $0x10
restart:
# Set cursor shape. (Insert style)
mov $0x01, %ah
mov $0x000f, %cx
int $0x10
# Set cursor position.
mov $BF_SEPARATOR, %dx
call set_cursor_pos
# Clear output.
mov $0x0900, %ax
mov $0x000F, %bx
mov $0x06FF, %cx
int $0x10
# Print output separator.
mov $0xCD, %al
mov $0x0050, %cx
int $0x10
# Clear memory.
mov $BF_INITIAL_POINTER, %bx
clear_memory:
movb %ch, (%bx)
inc %bx
cmp $0xF0FF, %bx
jne clear_memory
restart_cont:
# Set cursor position.
mov $BF_ABOUT, %dx
call set_cursor_pos
# Print about background.
mov $0x0900, %ax
mov $0x001F, %bx
mov $0x0050, %cx
int $0x10
mov $about, %si
mov $0x0e, %ah
print_about:
lodsb
test %al, %al
jz restart_finish
int $0x10
jmp print_about
restart_finish:
# Set cursor position.
xor %dx, %dx
call set_cursor_pos
# Initialize
xor %bp, %bp # BP = debug flag
movw $BF_INITIAL_POINTER, %di # DI = current pointer
movw $BF_INITIAL_OUT, (MEMORY_OUT_CHAR)
xor %si, %si # SI = current char
push $-1
jmp keyboard
keyboard:
cmp $KEY_BACKSPACE, %al
je clear_char
# Read cursor position.
mov $0x03, %ah
int $0x16
xor %ah, %ah
int $0x16
# Start executing if KEY_EXECUTE is pressed.
cmp $KEY_EXECUTE, %ax
je execute
# Start debugging if KEY_DEBUG is pressed.
cmp $KEY_DEBUG, %ax
je debug
# Move cursor
cmp $KEY_HOME, %ah
je move_first
# Move cursor
cmp $KEY_END, %ah
je move_last
# Move cursor
cmp $KEY_UP, %ah
je move_up
# Move cursor
cmp $KEY_DOWN, %ah
je move_down
# Move cursor
cmp $KEY_LEFT, %ah
je move_prev
# Handle backspace
cmp $KEY_BACKSPACE, %al
je move_prev
# Move cursor
cmp $KEY_RIGHT, %ah
je move_next
# Handle Enter
cmp $KEY_ENTER, %al
je move_next_line
call check_keys
# Print last character.
mov $0x09, %ah
mov $0x0007, %bx
mov $0x0001, %cx
int $0x10
jmp move_next
# Get more keys.
jmp keyboard
clear_char:
mov $0x0900, %ax
mov $0x0007, %bx
mov $0x0001, %cx
int $0x10
jmp keyboard
move_first:
xor %dl, %dl
jmp move_finish
move_last:
mov $MAX_COL, %dl
jmp move_finish
move_next:
cmp $MAX_COL, %dl
je move_next_line
inc %dl
jmp move_finish
move_next_line:
cmp $MAX_ROW, %dh
je keyboard
xor %dl, %dl
inc %dh
jmp move_finish
move_prev:
test %dl, %dl
jz move_prev_line
dec %dl
jmp move_finish
move_prev_line:
test %dh, %dh
jz keyboard
mov $MAX_COL, %dl
dec %dh
jmp move_finish
move_up:
test %dh, %dh
jz keyboard
dec %dh
jmp move_finish
move_down:
cmp $MAX_ROW, %dh
je keyboard
inc %dh
move_finish:
# Set cursor position.
call set_cursor_pos
jmp keyboard
debug:
inc %bp # BP = debug flag
execute:
# Set cursor shape. (Default)
mov $0x01, %ah
mov $0x0001, %cx
int $0x10
loop:
test %bp, %bp # BP = debug flag
jnz loop_wait
# Get pressed key.
mov $0x01, %ah
int $0x16
jz step
loop_wait:
# Wait for pressed key.
xor %ah, %ah
loop_should_terminate:
int $0x16
call check_keys
cmp $KEY_EXECUTE, %ax
jne step
xor %bp, %bp # BP = debug flag
step:
# Set cursor position.
mov %si, %dx # SI = current char
call set_cursor_pos
# Read character. (to %al)
mov $0x08, %ah
int $0x10
cmp $CHAR_INC, %al
je cmd_inc
cmp $CHAR_DEC, %al
je cmd_dec
cmp $CHAR_LOOP_START, %al
je cmd_loop_start
cmp $CHAR_LOOP_END, %al
je cmd_loop_end
cmp $CHAR_POINTER_LEFT, %al
je cmd_pointer_left
cmp $CHAR_POINTER_RIGHT, %al
je cmd_pointer_right
cmp $CHAR_OUT, %al
je cmd_out
cmp $CHAR_IN, %al
je cmd_in
# Unsupported character.
jmp next
cmd_in:
# Read key.
xor %ah, %ah
int $0x16
call check_keys
# Save character.
mov %al, (%di) # DI = current pointer
jmp next
cmd_out:
# Set cursor position.
mov (MEMORY_OUT_CHAR), %dx
call set_cursor_pos
# Print last character.
mov (%di), %al
mov $0x0e, %ah
int $0x10
cmpw $MAX_OUT_CHAR, (MEMORY_OUT_CHAR)
je reset_out_char
incw (MEMORY_OUT_CHAR)
jmp next
reset_out_char:
movw $BF_INITIAL_OUT, (MEMORY_OUT_CHAR)
mov (MEMORY_OUT_CHAR), %dx
call set_cursor_pos
jmp next
cmd_loop_start:
# Push cursor position to stack.
push %si # SI = current char
jmp next
cmd_loop_end:
# Copy stack value to %ax.
pop %ax
push %ax
# Go back to loop start if current value is not equal to 0.
mov (%di), %bx # DI = current pointer
test %bl, %bl
jnz cmd_loop_end_back
# Remove loop from stack otherwise.
pop %ax
jmp next
cmd_loop_end_back:
# Go back to loop start.
mov %ax, %si # SI = current char
jmp next
cmd_pointer_left:
# Switch current pointer to left.
dec %di # DI = current pointer
jmp next
cmd_pointer_right:
# Switch current pointer to right.
inc %di # DI = current pointer
jmp next
cmd_inc:
# Increment value of current pointer.
incb (%di) # DI = current pointer
jmp next
cmd_dec:
# Decrement value of current pointer.
decb (%di) # DI = current pointer
next:
# Increment value of current character.
inc %si # SI = current char
mov %si, %ax # SI = current char
# Check if it's past the last character (if it is, end program).
cmpw $MAX_CHAR, %ax
jg end
# Check if it's last column, if yes, go to next row.
cmp $0x50, %al
je next_row
jmp loop
next_row:
xor %al, %al
inc %ah
mov %ax, %si # SI = current char
jmp loop
end:
jmp loop_wait
set_cursor_pos:
mov $0x02, %ah
xor %bh, %bh
int $0x10
ret
check_keys:
cmp $KEY_TERMINATE, %ax
je restart
# Handle reset
cmp $KEY_RESET, %al
je init
ret
about: .asciz "bfloader F5 Run Ctrl+F5 Debug"
.fill 510-(.-init), 1, 0
.word 0xaa55