-
Notifications
You must be signed in to change notification settings - Fork 0
/
bootloader.asm
230 lines (218 loc) · 5.28 KB
/
bootloader.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
BITS 16
ORG 0x7C0
setup_mode: ; Sets up 300x200 8 bd mode, and a custom palette!
mov ax, 0x0013 ; Set video mode to 320x200 8 bpp
int 0x10 ; Video address starts at 0xA0000, ends at 0xAF8C0
.grays: ; bx = color number
mov dh, bl ; dh = red (6 bits)
mov ch, bl ; ch = green (6 bits)
mov cl, bl ; cl = blue (6 bits)
call set_palette_value
inc bl
cmp bl, 64 ; Make sure it loops for every value
jl .grays
.hues:
; Calculate appropriate 6 bit RGB triplet for hues in bl, and move as 6 bit RGB values to dh, ch, cl
push bx
sub bx, 64
mov al, bl ; Move bx into ax register for division
mov bh, 0x20 ; Set to get 32 colors per 6 hue segments
div bh ; Result is in AL, Modulus is in AH
shl ah, 1 ; Multiply Modulus for 6 bit (not 5 bit) colors
mov dl, 0x3F
sub dl, ah ; Reverse slope Modulus is now in dl
xor bh, bh
mov ch, ah
xor cl, cl
mov dh, 0x3F ; Prepare RGB for if Section one is selected
cmp bx, 0x20
jl .done
mov ch, 0x3F
mov dh, dl ; Prepare RGB for if Section two is selected
cmp bx, 0x40
jl .done
xor dh, dh
mov cl, ah ; Prepare RGB for if Section three is selected
cmp bx, 0x60
jl .done
mov ch, dl
mov cl, 0x3F ; Prepare RGB for if Section four is selected
cmp bx, 0x80
jl .done
mov dh, ah
xor ch, ch ; Prepare RGB for if Section five is selected
cmp bx, 0xA0
jl .done
mov dh, 0x3F
mov cl, dl ; Set RGB for section six
.done: ; End of 6 segment split, write end result to
pop bx
call set_palette_value
inc bl ; Complete loop through hue range
jnz .hues
.game_start:
xor bx, bx
.clear_buffer_loop: ; Clear screen buffer
xor di, di
mov ax, bx
shr ax, 1
mov si, 0x28
xor dx, dx
div si ;ax holds row, dx holds column
cmp al, 0
je .wall
cmp al, 24
je .wall
cmp dl, 0
je .wall
cmp dl, 39
je .wall
jmp .empty_space
.wall:
mov di, 63
.empty_space:
mov [ebx + 0x9F830], word di
inc bx
inc bx
cmp bx, 0x7D0
jl .clear_buffer_loop
mov [0xFA01], word 0x3E8 ; Snake starts in the middle of the screen
mov [0xFA03], word 65 ; Snake starts with a length of two
call place_food
.game_loop:
mov ax, word [0xFA01] ; Draw snake
mov bx, word [0xFA03]
mov [eax + 0x9F830], bx
.draw_block_buffer:
xor ax, ax ; Use eax to hold the position of the screen buffer
.dbb_screen_loop:
push ax
mov si, 320
xor dx, dx
div si ; ax holds rows, dx holds columns
shr ax, 3
shr dx, 3
mov di, dx
mov si, 40
mul si
add ax, di
shl ax, 1
mov dx, [eax + 0x9F830]
cmp dx, 64
jl .dbb_static_color
mov ax, dx
mov bx, 192
xor dx, dx
div bx
add dx, 64
.dbb_static_color:
pop ax
mov [eax + 0xA0000], dl
inc ax
cmp ah, 0xFA
jne .dbb_screen_loop
.decay_snake:
cmp word [eax + 0x9F830], 0x40
jl .static_item_decay
dec word [eax + 0x9F830]
cmp word [eax + 0x9F830], 0x40
jge .static_item_decay
mov [eax + 0x9F830], word 0
.static_item_decay:
inc ax
inc ax
cmp ax, 0x7D0
jne .decay_snake
mov cl, 2 ; Sleep for 1/8 second, neglect setting dx, due to constant value.
mov ah, 0x86
int 0x15
.check_keys: ; Checks for any key presses, updates snakes heading
mov ah, 0x01 ; Any key pressed?
int 0x16
jz .nokey ; No, go to main loop
xor ah, ah
int 0x16 ; Get key
cmp ah, 0x48
jne .nu_key
cmp [0xFA00], byte 1 ; Snake must also not be going down
je .nd_key
mov [0xFA00], byte 3
.nu_key:
cmp ah, 0x50
jne .nd_key
cmp [0xFA00], byte 3 ; Snake must also not be going up
je .nr_key
mov [0xFA00], byte 1
.nd_key:
cmp ah, 0x4D
jne .nr_key
cmp [0xFA00], byte 2 ; Snake must also not be going left
je .nokey
mov [0xFA00], byte 0
.nr_key:
cmp ah, 0x4B
jne .nokey
cmp [0xFA00], byte 0 ; Snake must also not be going right
je .nokey
mov [0xFA00], byte 2
.nokey:
mov ax, word [0xFA01] ; Get snake position
cmp [0xFA00], byte 1 ; Get direction of snake, evaluate next position
jge .not_right
inc ax
inc ax
jmp .continue
.not_right:
jg .not_down
add ax, 0x50 ; The snake is facing down
jmp .continue
.not_down:
cmp [0xFA00], byte 2
jne .not_left
dec ax
dec ax
jmp .continue
.not_left:
sub ax, 0x50 ; The snake is facing up
.continue:
mov [0xFA01], word ax
cmp [eax + 0x9F830], word 48 ; Block must be food
jne .no_food
inc word [0xFA03] ; Increase length of snake
call place_food
jmp .game_loop ; Skip death evaluation, because the block is food.
.no_food: ; The block which the snake advances to is not food
mov ax, word [0xFA01] ; Evaluate any Death
cmp [eax + 0x9F830], word 0 ; Block must be empty
jz .game_loop
.death:
mov cl, 10 ; Sleep for ~1 seconds, to emphasize death.
mov ah, 0x86
int 0x15
jmp .game_start
place_food:
xor ah, ah ; interrupts to get system time
int 0x1A ; CX:DX now hold number of clock ticks since midnight
rol dx, 3 ; increase importance of LSB, resulting in better PRNG
.loop:
inc ax
inc ax
cmp ax, 2000 ; Roll over, to prevent placing food outside of game
jl .ax_not_overflown
xor ax, ax
.ax_not_overflown:
cmp [eax + 0x9F830], word 0 ; Only decrement dx and check for placement if empty cell
jnz .loop
dec dx
cmp dx, 0
jnz .loop ; Only decrement dx if empty cell, and if zero,
mov [eax + 0x9F830], word 48 ; Place food.
ret ; This is where the game will halt, if you happen to win.
set_palette_value:
mov ax, 0x1007
int 0x10
mov ax, 0x1010
int 0x10
ret
times 510-($-$$) db 0 ;Pad remainder of boot sector with 0s
dw 0xAA55 ;The standard PC boot signature