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
|
%ifndef _BUILTIN_VIDEO_MODE_ASM
%define _BUILTIN_VIDEO_MODE_ASM
builtin_video_mode:
push bp
mov bp, sp
mov cx, [bp + 4] ; Load argc
mov bx, [bp + 6] ; Load argv
cmp cx, 1 ; Not enough args?
jl .no_args ; ... die
jmp .main
.no_args:
push .error_arg
call printf
add sp, 2 * 1
jmp .return
; main program
.main:
mov bx, [bx] ; Load first element in argv array
mov si, bx ; First element is source index
push bx ; Get length of element
call strlen
add sp, 2
mov cx, ax ; Store length
mov bx, 0
mov ax, 0
mov dx, 0
.chars:
lodsb ; Load character from ES:SI
cmp ax, '9' ; If value is greater than '9' it's likely hex, so
; adjust AX to compensate
jg .ishex
sub ax, '0' ; Otherwise, the value is base-10
jmp .nosub
.tolower:
sub ax, 20h
.ishex:
cmp ax, 'a'
jge .tolower ; If we recieved a lowercase letter, convert it
; to uppercase, then continue
cmp ax, 'F' ; Is this a valid hexadecimal value? (0 ~ F)
jg .invalid_input
sub ax, 'A' ; Convert character to BCD
add ax, 10
.nosub:
shl dx, 4 ; Shift current BCD value 4-bits left
or dx, ax ; Tack on the latest value
dec cx ; Decrement counter
jne .chars ; continue until no characters remain
cmp dx, 13h ; Is the final value a valid video mode?
jg .invalid_mode
mov al, dl ; BIOS video services only operate on a byte value
; ... oh well.
mov ah, 00h
int 10h ; Set video mode
.return:
mov sp, bp
pop bp
ret
.invalid_input:
push ax
push .error_hex
call printf
add sp, 2 * 2
jmp .return
.invalid_mode:
push dx
push .error_mode
call printf
add sp, 2 * 2
jmp .return
.error_arg: db 'error: no graphics mode requested. (0..13)\n', 0
.error_hex: db 'error: "%c" is an invalid hexadecimal value (0..F)\n', 0
.error_mode: db 'error: %2x is an invalid video mode (0..13)\n', 0
%endif
|