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

wirehaze git hosting

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