-
Notifications
You must be signed in to change notification settings - Fork 0
/
console_sub.asm
655 lines (655 loc) · 12.2 KB
/
console_sub.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
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
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
%ifndef _CONSLE_SUB_ASM_
%define _CONSLE_SUB_ASM_
; NOTE : YOU MUST CONSOLE_INIT BEFORE USING ANYTHING IN THIS MODULE
; --- modules ---
%include "list16_sub.asm"
%include "mem_sub.asm"
; --- macro ---
%define CONSOLE_VIDEO_MODE 0x03
%define CONSOLE_DUMP_SEG 0xB800
%define CONSOLE_WIDTH 80
%define CONSOLE_HEIGHT 25
%define BLACK 0x00
%define BLUE 0x01
%define GREEN 0x02
%define CYAN 0x03
%define RED 0x04
%define MAGENTA 0x05
%define YELLOW 0x06
%define GREY 0x07
%define BRIGHT 0x08
%define WHITE (BRIGHT + GREY)
; BRIGHT + COLOR = BRIGHT COLOR
; BRIGHT itself is light grey
%define KEY_ESC 0x011b
%define KEY_1 0x0231
%define KEY_2 0x0232
%define KEY_3 0x0233
%define KEY_4 0x0234
%define KEY_5 0x0235
%define KEY_6 0x0236
%define KEY_7 0x0237
%define KEY_8 0x0238
%define KEY_9 0x0239
%define KEY_MINUS 0x0c2d
%define KEY_EQUAL 0x0d3d
%define KEY_BS 0x0e08
%define KEY_TAB 0x0f09
%define KEY_ENTER 0x1c0d
%define KEY_UP 0x4800
%define KEY_LEFT 0x4b00
%define KEY_RIGHT 0x4d00
%define KEY_DOWN 0x5000
%define CONSOLE_READ_LINE_DEFAULT_COLOR YELLOW
; initialize console
%macro CONSOLE_INIT 0
pusha
mov ah, 0x00
mov al, CONSOLE_VIDEO_MODE
int 0x10
popa
%endmacro
; read keyboard input (wait for keystroke)
; al -> ascii character code
; ah -> scan code
%macro CONSOLE_READ_CHAR 0
mov ah, 0x00
int 0x16
%endmacro
; set cursor
; dh <- row
; dl <- column
%macro SET_CURSOR 0
pusha
mov ah, 0x02
mov bh, 0
int 0x10
popa
%endmacro
; get cursor
; dh -> row
; dl -> column
; ch -> cursor pixel Y-address
; cl -> cursor pixel X-address
%macro GET_CURSOR 0
push ax
push bx
mov ah, 0x03
mov bh, 0
int 0x10
pop bx
pop ax
%endmacro
; move cursor backward
%macro CURSOR_BACKWARD 0
pusha
GET_CURSOR
cmp dl, 0
je %%retract_row
dec dl
jmp %%retract_end
%%retract_row :
cmp dh, 0
je %%skip_advance
dec dh
%%skip_advance :
mov dl, (CONSOLE_WIDTH - 1)
%%retract_end :
SET_CURSOR
popa
%endmacro
; mov cursor forward
%macro CURSOR_FORWARD 0
pusha
GET_CURSOR
cmp dl, (CONSOLE_WIDTH-1)
je %%advance_row
inc dl
jmp %%advance_end
%%advance_row :
cmp dh, (CONSOLE_HEIGHT-1)
je %%skip_advance
inc dh
%%skip_advance :
mov dl, 0
%%advance_end :
SET_CURSOR
popa
%endmacro
; mov cursor upward
%macro CURSOR_UPWARD 0
pusha
GET_CURSOR
cmp dh, 0
je %%end
dec dh
%%end :
SET_CURSOR
popa
%endmacro
; convert row and column to index for video dump
; %1 <- row {1-2B, !bx}
; %2 <- col {1-2B, !ax}
; bx -> index
%macro CONSOLE_RC2IDX 2
push ax
movzx bx, %1
mov al, CONSOLE_WIDTH
mul bl
mov bx, ax
movzx ax, %2
add bx, ax
pop ax
%endmacro
; convert index for video dump to row and column
; %1 <- index {2B, !cx}
; dh -> row
; dl -> column
%macro CONSOLE_IDX2RC 1
push cx
xor dx, dx
mov cx, %1
%%counter_loop :
cmp cx, CONSOLE_WIDTH
jb %%counter_loop_end
sub cx, CONSOLE_WIDTH
inc dh
jmp %%counter_loop
%%counter_loop_end :
mov dl, cl
pop cx
%endmacro
; --- subroutine ---
; scroll console upward
; bl <- displacelment
consoleScrollUp :
pusha
push ds
push es
mov al, CONSOLE_WIDTH * 2
mul bl
mov si, ax
xor di, di
mov cx, (CONSOLE_WIDTH * CONSOLE_HEIGHT * 2)
sub cx, ax
mov ax, CONSOLE_DUMP_SEG
mov es, ax
mov ds, ax
rep movsb
; clear the rest of the row
mov al, CONSOLE_HEIGHT
sub al, bl
mov dl, (2 * CONSOLE_WIDTH)
mul dl
mov si, ax ; si = begining of slots to be cleared
mov al, bl
mov dl, (2 * CONSOLE_WIDTH)
mul dl
mov cx, si ; cx = number of slots to be cleared
mov bx, si
xor ax, ax
call wordset
pop es
pop ds
popa
ret
; write character & attribute to location using index
; al <- character
; ah <- attribute
; bx <- index
consoleWriteIndex :
pusha
cmp bx, (CONSOLE_WIDTH * CONSOLE_HEIGHT - 1)
ja .end ; exceed video dump
push es
shl bx, 1 ; multiply by 2, skipping attribute
mov cx, CONSOLE_DUMP_SEG
mov es, cx
mov word [es : bx], ax
pop es
.end :
popa
ret
; write character & attribute to location
; al <- character
; ah <- attribute
; cl <- row
; ch <- column
consoleWrite :
pusha
CONSOLE_RC2IDX cl, ch
call consoleWriteIndex
popa
ret
; write only character to location using index
; al <- character
; bx <- index
consoleWriteCharIndex :
pusha
cmp bx, (CONSOLE_WIDTH * CONSOLE_HEIGHT - 1)
ja .end ; exceed video dump
push es
shl bx, 1 ; multiply by 2, skipping attribute
mov cx, CONSOLE_DUMP_SEG
mov es, cx
mov byte [es : bx], al
pop es
.end :
popa
ret
; write only character to location
; al <- character
; cl <- row
; ch <- column
consoleWriteChar :
pusha
CONSOLE_RC2IDX cl, ch
call consoleWriteCharIndex
popa
ret
; set the attribute of the character
; ah <- attribute
; bx <- index
consolePaintIndex :
pusha
cmp bx, (CONSOLE_WIDTH * CONSOLE_HEIGHT - 1)
ja .end ; exceed video dump
push es
shl bx, 1 ; multiply by 2, skipping attribute
mov cx, CONSOLE_DUMP_SEG
mov es, cx
inc bx
mov byte [es : bx], ah
pop es
.end :
popa
ret
; write only character to location
; ah <- attribute
; cl <- row
; ch <- column
consolePaint :
pusha
CONSOLE_RC2IDX cl, ch
call consolePaintIndex
popa
ret
; write list 16 to location using index
; bx <- index
; si <- address of list 16
consoleWriteList16Index :
pusha
LIST16_GET_COUNT ; cx = count
mov ax, bx
add ax, cx
cmp ax, (CONSOLE_WIDTH * CONSOLE_HEIGHT)
jb .within_video_dump
mov cx, (CONSOLE_WIDTH * CONSOLE_HEIGHT)
sub cx, bx
.within_video_dump :
push es
mov dx, CONSOLE_DUMP_SEG
mov es, dx
mov di, bx ; di = offset for video dump
shl di, 1
add si, 2 ; si = start of string
rep movsw
pop es
popa
ret
; write list 16 to location
; cl <- row
; ch <- column
; si <- address of list 16
consoleWriteList16 :
pusha
CONSOLE_RC2IDX cl, ch
call consoleWriteList16Index
popa
ret
; write subset of list 16 to location using index
; al <- start (inclusive)
; ah <- end (exclusive)
; bx <- index
; si <- address of list 16
consoleWriteSubList16Index :
pusha
cmp bx, (CONSOLE_WIDTH * CONSOLE_HEIGHT - 1)
ja .end
LIST16_GET_INFO ; cl = max ; ch = length
sub ah, al
cmp ah, ch
jbe .valid_length
mov ah, ch ; the end exceed length, use length instead
sub ah, al
.valid_length :
movzx cx, ah
add cx, bx
cmp cx, (CONSOLE_WIDTH * CONSOLE_HEIGHT)
jb .within_video_dump
mov cx, (CONSOLE_WIDTH * CONSOLE_HEIGHT)
.within_video_dump :
sub cx, bx ; cx = length of character to be print
mov di, bx
shl di, 1 ; di = offset for console dump
movzx bx, al
shl bx, 1
add si, 2
add si, bx ; si = begining of substring
push es
mov dx, CONSOLE_DUMP_SEG
mov es, dx
rep movsw
pop es
.end :
popa
ret
; write subset of list 16 to location
; al <- start (inclusive)
; ah <- end (exclusive)
; cl <- row
; ch <- column
; si <- address of list 16
consoleWriteSubList16 :
pusha
CONSOLE_RC2IDX cl, ch
call consoleWriteSubList16Index
popa
ret
; write attributed c string to location using index
; bx <- index
; si <- attributed c string
consoleWriteAttributedCStringIndex :
pusha
push es
mov ax, CONSOLE_DUMP_SEG
mov es, ax
shl bx, 1
.loop :
mov word ax, [si]
cmp ax, 0
je .loop_end
mov word [es : bx], ax
add bx, 2
add si, 2
jmp .loop
.loop_end :
pop es
popa
ret
; write attributed c string to location
; cl <- row
; ch <- column
; si <- attributed c string
consoleWriteAttributedCString :
pusha
CONSOLE_RC2IDX cl, ch
call consoleWriteAttributedCStringIndex
popa
ret
; write uint (always 5 digits) to location by index
; ah <- attribute
; bx <- index
; dx <- number
consoleWriteUintIndex :
pusha
cmp bx, (CONSOLE_WIDTH * CONSOLE_HEIGHT - 1)
ja .end
xchg ax, dx ; ax = number ; dh = attribute
push es
mov cx, CONSOLE_DUMP_SEG
mov es, cx
add bx, 4 ; displace to index for the last digit
shl bx, 1
mov cx, 5
.loop :
push cx
push dx
xor dx, dx
mov cx, 10
div cx
mov cx, dx
pop dx
mov dl, cl
add dl, '0'
mov word [es : bx], dx
pop cx
sub bx, 2
dec cx
jnz .loop
pop es
.end :
popa
ret
; print uint
; ah <- attribute
; dx <- number
consolePrintUint :
pusha
push dx
GET_CURSOR
CONSOLE_RC2IDX dh, dl ; bx = index
pop dx
push dx
mov dx, bx
mov cx, 5
call consoleMakeSpace
mov bx, dx
pop dx
call consoleWriteUintIndex
add bx, 5
CONSOLE_IDX2RC bx
SET_CURSOR
popa
ret
; write string with n length
; ah <- attribute
; bx <- index
; cx <- length
; si <- string
consoleWriteStringIndex :
pusha
cmp bx, (CONSOLE_WIDTH * CONSOLE_HEIGHT - 1)
ja .end ; exceed video dump
push es
mov dx, CONSOLE_DUMP_SEG
mov es, dx
shl bx, 1
.write_loop :
cmp cx, 0
je .write_loop_end
mov byte al, [si]
mov word [es : bx], ax
add bx, 2
inc si
dec cx
jmp .write_loop
.write_loop_end :
pop es
.end :
popa
ret
; print string with n length
; ah <- attribute
; cx <- length
; si <- string
consolePrintString :
pusha
push cx
GET_CURSOR
CONSOLE_RC2IDX dh, dl
pop cx
mov dx, bx
call consoleMakeSpace ; dx = new starting index
mov bx, dx
call consoleWriteStringIndex
add bx, cx
CONSOLE_IDX2RC bx
SET_CURSOR
popa
ret
; give some space for printing text by scolling
; cx <- length of text will be printed, it will calculate rows to be scrolled for the text
; dx <- starting index of screen for text to be printed
; dx -> new starting index after scroll
consoleMakeSpace :
push cx
push bx
add cx, dx
xor bl, bl ; bl = lines to be scrolled
.count_loop :
cmp cx, (CONSOLE_WIDTH * CONSOLE_HEIGHT)
jb .count_loop_end
inc bl
sub dx, CONSOLE_WIDTH
sub cx, CONSOLE_WIDTH
jmp .count_loop
.count_loop_end :
call consoleScrollUp
pop bx
pop cx
ret
; read line from console
; si <- address of list 16 for storing output
; bx <- painter function that colorize the the input. It won 't be called if it is 0.
consoleReadLine :
pusha
LIST16_CLEAR
push bx
GET_CURSOR
CONSOLE_RC2IDX dh, dl
mov dx, bx ; dx = starting index
pop bx
.loop :
CONSOLE_READ_CHAR
; get cursor 's index on console
push bx
push dx
GET_CURSOR
CONSOLE_RC2IDX dh, dl
mov cx, bx ; cx = current index
pop dx
pop bx
cmp cx, dx
jb .reject_handle ; invalid cursor index
; ah = scan code {update per loop}
; al = ascii character {update per loop}
; cx = current cursor index (during a keystroke detected) {update per loop}
; si = address of list 16 buffer
; dx = starting cursor index
; bx = painter function
; classify
cmp ax, KEY_ENTER
je .handle_enter
cmp ax, KEY_LEFT
je .handle_left
cmp ax, KEY_RIGHT
je .handle_right
cmp ax, KEY_BS
je .handle_bs
jmp .handle_normal
.handle_enter :
jmp .loop_end
; cx <- current cursor index
; dx <- starting cursor index
.handle_left :
cmp cx, dx
je .reject_handle ; cursor at the begining
CURSOR_BACKWARD
jmp .loop
; cx <- current cursor index
; dx <- starting cursor index
; ~cx
; ~ax
.handle_right :
mov ax, cx ; ax = current cursor index
sub ax, dx ; ax = cursor pos relative to begining
LIST16_GET_INFO ; cl = max ; ch = length
cmp al, ch
jae .reject_handle
CURSOR_FORWARD
jmp .loop
.handle_bs :
cmp cx, dx
je .reject_handle ; cursor index at begining
call consoleClearInputLine
pusha
sub cx, dx
dec cx ; cx = index of character to be erased, right before cursor
mov dh, cl
clc
call list16Erase
popa
jc .reject_handle
cmp bx, 0
je .no_painter_handle_bs
call bx
.no_painter_handle_bs :
call consoleUpdateInputLine
CURSOR_BACKWARD
jmp .loop
; ax <- scancode
; cx <- current cursor index
; dx <- starting cursor index
.handle_normal :
cmp al, 0
je .reject_handle ; invalid ascii character
pusha
sub cx, dx ; cx = index of character to be inserted
mov dh, cl
mov ah, CONSOLE_READ_LINE_DEFAULT_COLOR
clc
call list16Insert
popa
jc .reject_handle
cmp bx, 0
je .no_painter_handle_normal
call bx
.no_painter_handle_normal :
call consoleUpdateInputLine
CURSOR_FORWARD
jmp .loop
.reject_handle :
jmp .loop
.loop_end :
popa
ret
; update region in console with list 16 user input buffer
; si <- address of list 16 buffer
; dx <- starting index
; dx -> updated starting index (if scroll)
consoleUpdateInputLine :
push cx
push bx
LIST16_GET_COUNT ; cx = count
call consoleMakeSpace
mov bx, dx
call consoleWriteList16Index
pop bx
pop cx
ret
; clear region in console that is written with list 16 user input buffer
; si <- address of list 16 buffer
; dx <- starting index
consoleClearInputLine :
pusha
LIST16_GET_COUNT ; cx = count
mov bx, dx
; limit cx, not beyond the video dump
add cx, bx
cmp cx, (CONSOLE_WIDTH * CONSOLE_HEIGHT)
jb .within_video_dump
mov cx, (CONSOLE_WIDTH * CONSOLE_HEIGHT)
.within_video_dump :
sub cx, bx
push es
mov dx, CONSOLE_DUMP_SEG
mov es, dx
shl bx, 1
xor ax, ax
mov ah, GREY
call wordset
pop es
popa
ret
%endif ; _CONSLE_SUB_ASM_