]> wirehaze git hosting - lifeboot.git/blob - lifeboot.asm

wirehaze git hosting

e44a671b9c8e4644491e1422377419354509cad0
[lifeboot.git] / lifeboot.asm
1 bits 16
2 org 7c00h
3
4 ; =============================================================================
5
6 ; settings --------------------------------------------------------------------
7
8 %define DEAD ' ' ; char to represent a dead cell
9 %define ALIVE '#' ; char to represent an alive cell
10 %define PRINT_COLOR 07h ; grey on black
11 %define WAIT_DELAY 02h ; 0.131072 seconds
12
13 ; constants -------------------------------------------------------------------
14
15 %define COLS 80
16 %define ROWS 25
17 %define VGAPGSZ (COLS * ROWS * 2 + 96) ; why 96 ??????
18
19 ; memory layout ---------------------------------------------------------------
20
21 %define ORG 7c00h
22 %define VGA 0b8000h
23 %define DAT ORG + 512
24
25 ; static variables ------------------------------------------------------------
26
27 %define xss DAT ; xs() state (word)
28 %define currvgapg DAT + 2 ; current vga page near pointer (word)
29
30 ; =============================================================================
31
32 ; entry point -----------------------------------------------------------------
33
34 ; initialize segment registers
35 mov ax, VGA >> 4
36 mov es, ax
37
38 xor ax, ax
39 mov ds, ax
40 mov ss, ax
41
42 ; set stack pointers
43 mov bp, ORG
44 mov sp, bp
45
46 ; clear direction flag
47 cld
48
49 ; disable cursor
50 mov ch, 3fh ; cursor start and options
51 mov ah, 01h ; set text-mode cursor shape
52 int 10h ; video services
53
54 ; initialize xss
55
56 set_xss_seed:
57
58 mov ah, 00h ; get
59 int 1ah ; system time
60
61 cmp dx, 0
62 je set_xss_seed ; if seed is 0, xs wont work properly
63
64 mov [xss], dx ; cx:dx = number of clock ticks since midnight
65
66 ; initialize currvgapg
67 mov word [currvgapg], 0
68
69 ; start simulation from random state ------------------------------------------
70
71 start:
72
73 call init_grid
74
75 ; apply game of life's rules to determine the next state ----------------------
76
77 next_state:
78
79 call vsync_wait
80 call write_next_vga_page
81 call wait_keypress
82 call flip_vga_page
83
84 jmp next_state
85
86 ; =============================================================================
87
88 ; functions -------------------------------------------------------------------
89
90 ; delay() - suspend program execution temporarily -----------------------------
91
92 ; clobbers ah, cx, dx
93
94 delay:
95
96 mov cx, WAIT_DELAY ; cx:dx = interval in microseconds
97 mov dx, 0
98
99 mov ah, 86h
100 int 15h ; wait
101
102 ret
103
104 ; wait_keypress() - wait for any keypress -------------------------------------
105
106 ; clobbers: ax
107
108 wait_keypress:
109
110 mov ah, 00h ; read key press
111 int 16h ; keyboard services
112
113 ret
114
115 ; vsync_wait() - wait for display to enter the next VBlank cycle --------------
116
117 ; clobbers ax, dx
118
119 vsync_wait:
120
121 mov dx, 3dah ; input status #1 register
122
123 .wait_on:
124 in al, dx
125 test al, 08h ; vertical retrace bit
126 jnz .wait_on
127
128 .wait_off:
129 in al, dx
130 test al, 08h
131 jz .wait_off
132
133 ret
134
135 ; xs() - xorshift pseudorandom number generator -------------------------------
136
137 ; output:
138 ; [xss] = updated state
139
140 ; clobbers bx, dx
141
142 xs:
143
144 mov bx, [xss]
145 mov dx, bx
146
147 shl dx, 1 ; dx = xss << 1
148 xor bx, dx ; bx = xss ^ (xss << 1)
149 mov dx, bx
150
151 shr dx, 3 ; dx = xss' >> 3
152 xor bx, dx ; bx = xss' ^ (xss' >> 3)
153 mov dx, bx
154
155 shl dx, 10 ; dx = xss'' << 10
156 xor bx, dx ; bx = xss'' ^ (xss'' << 10)
157 mov [xss], bx
158
159 ret
160
161 ; init_grid() - initialize grid cells randomly --------------------------------
162
163 ; clobbers ax, bx, cx, dx, di
164
165 init_grid:
166
167 mov ah, PRINT_COLOR ; ah = color attribute
168 mov di, [currvgapg] ; es:di -> grid start
169 mov cx, COLS * ROWS ; for each cell
170
171 .write_cell: ; do {
172 call xs ; [xss] = rand
173 mov al, DEAD ; al = DEAD (likely)
174
175 test word [xss], 0b11
176
177 jnz .nz ; if ([xss] % 4 == 0)
178 mov al, ALIVE ; al = ALIVE
179
180 .nz:
181 stosw ; [es:di] = ax ; di += 2
182
183 loop .write_cell ; } while (--cx)
184
185 ret
186
187 ; flip_vga_page() - flip active display page ----------------------------------
188
189 ; clobbers ax, dx
190
191 flip_vga_page:
192
193 call vsync_wait
194
195 xor word [currvgapg], VGAPGSZ ; flip currvgapg
196 setnz al ; al = !(currvgapg == 0)
197
198 mov ah, 05h ; select active display page
199 int 10h ; video services
200
201 ret
202
203 ; alive_neighbours() ----------------------------------------------------------
204
205 ; input:
206 ; es:si -> current grid
207 ; cx -> cell index
208
209 ; output:
210 ; ax = # alive neighbours
211
212 ; clobbers ax, bx, dx
213
214 alive_neighbours:
215 enter 5, 0
216
217 ; [bp - 1]: row
218 ; [bp - 2]: col
219 ; [bp - 3]: neighbours
220 ; [bp - 4]: i
221 ; [bp - 5]: j
222
223 mov ax, cx ; ax = idx
224 mov bl, COLS ; bl = COLS
225 div bl ; al = idx / COLS ; ah = idx % COLS
226
227 mov [bp - 1], al ; row = idx / COLS
228 mov [bp - 2], ah ; row = idx % COLS
229 mov byte [bp - 3], 0 ; neighbours = 0
230
231 mov byte [bp - 4], -1 ; i = -1
232 .i: ; do {
233
234 mov byte [bp - 5], -1 ; j = -1
235 .j: ; do {
236
237 mov al, [bp - 4]
238 or al, [bp - 5]
239 jz .continue ; if (!i && !j) continue
240
241 mov al, [bp - 1]
242 add al, [bp - 4] ; al = row + i
243
244 cmp al, 0
245 jl .continue ; if (row + i < 0) continue
246
247 cmp al, ROWS
248 jge .continue ; if (row + i >= ROWS) continue
249
250 mov ah, [bp - 2]
251 add ah, [bp - 5] ; ah = col + j
252
253 cmp ah, 0
254 jl .continue ; if (col + j < 0) continue
255
256 cmp ah, COLS
257 jge .continue ; if (col + j >= COLS) continue
258
259 movzx bx, ah ; bx = col + j
260
261 mov ah, COLS
262 mul ah ; ax = (row + i) * COLS
263
264 add bx, ax ; bx = cell index
265 shl bx, 1 ; bx = grid offset
266
267 mov dx, [es:si + bx] ; dl = cell state
268
269 cmp dl, ALIVE ; if (!ALIVE) continue
270 jne .continue
271
272 inc byte [bp - 3] ; neighbours++
273
274 .continue:
275 inc byte [bp - 5]
276 cmp byte [bp - 5], 1
277 jle .j ; } while (++j <= 1)
278
279 inc byte [bp - 4]
280 cmp byte [bp - 4], 1
281 jle .i ; } while (++i <= 1)
282
283 movzx ax, byte [bp - 3] ; ax = # alive neighbours
284
285 leave
286 ret
287
288 ; write_next_cell_state() -----------------------------------------------------
289
290 ; input:
291 ; es:si -> current grid
292 ; es:di -> next grid
293 ; cx -> cell index
294
295 ; output:
296 ; [es:di + cx * 2] = updated cell state
297
298 ; clobbers ax, bx, dx
299
300 write_next_cell_state:
301
302 call alive_neighbours ; ax = # alive neighbours
303
304 mov bx, cx
305 shl bx, 1
306
307 mov dx, [es:si + bx] ; dl = cell current state
308
309 cmp dl, ALIVE ; if (ALIVE) {
310 jne .else
311
312 cmp ax, 2 ; if (n < 2)
313 jl .dead ; return DEAD
314
315 cmp ax, 3 ; if (n > 3)
316 jg .dead ; return DEAD
317
318 jmp .alive ; return ALIVE
319
320 .else: ; }
321
322 cmp ax, 3 ; if (n != 3)
323 jne .dead ; return DEAD
324
325 .alive: ; return ALIVE
326 mov dl, ALIVE
327 jmp .write
328
329 .dead:
330 mov dl, DEAD
331
332 .write:
333 mov [es:di + bx], dx
334
335 ret
336
337 ; write_next_vga_page() -------------------------------------------------------
338
339 ; clobbers di, si, ax, bx, cx, dx
340
341 write_next_vga_page:
342
343 mov si, [currvgapg] ; es:si -> current page
344
345 mov di, VGAPGSZ
346 xor di, si ; es:di -> next page
347
348 xor cx, cx ; i = 0
349
350 .update_loop:
351 call write_next_cell_state
352
353 inc cx
354 cmp cx, COLS * ROWS
355 jl .update_loop ; for i in [0 .. COLS * ROWS - 1]
356
357 ret
358
359 ; halt() - stop program execution ---------------------------------------------
360
361 halt:
362
363 cli ; disable interrupts
364 hlt
365 jmp halt
366
367 ; =============================================================================
368
369 times 510 - ($ - $$) db 0 ; fill remaining bytes with zeroes
370 dw 0aa55h ; mbr magic byte