]>
wirehaze git hosting - lifeboot.git/blob - lifeboot.asm
d4ba435081f7892280834e2b6e67274773c483c9
4 ; =============================================================================
6 ; settings --------------------------------------------------------------------
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 ITER_LIM
500 ; reset the simulation after this # iterations
13 ; constants -------------------------------------------------------------------
17 %
define VGAPGSZ 1000h
; (bytes)
19 ; memory layout ---------------------------------------------------------------
25 ; static variables ------------------------------------------------------------
27 %
define xss DAT
; xs() state (word)
28 %
define currvgapg DAT
+ 2 ; current vga page near pointer (word)
29 %
define iter DAT
+ 4 ; current iteration # (word)
31 ; =============================================================================
33 ; entry point -----------------------------------------------------------------
37 ; initialize segment registers
39 mov es, ax ; es:0 -> video memory
49 ; clear direction flag
53 mov ch, 3fh
; cursor start and options
54 mov ah, 01h ; set text-mode cursor shape
55 int 10h
; bios video services
59 mov ah, 00h ; get system time
60 int 1
ah ; bios time services
61 ; cx:dx = # clock ticks since midnight
63 jz .set_xss
; wait for something meaningful
67 ; initialize currvgapg
68 mov word [currvgapg
], 0
70 ; start simulation from random state ------------------------------------------
86 cmp word [iter
], ITER_LIM
91 ; =============================================================================
93 ; functions -------------------------------------------------------------------
95 ; vsync_wait() - wait for display to enter the next retrace cycle -------------
101 mov dx, 3dah
; input status #1 register
105 test al, 08h ; vertical retrace bit
106 jnz .wait_retrace_end
111 jz .wait_retrace_start
115 ; xs() - xorshift pseudorandom number generator -------------------------------
118 ; [xss] = updated state
128 shl dx, 1 ; dx = xss << 1
129 xor bx, dx ; bx = xss ^ (xss << 1)
132 shr dx, 3 ; dx = xss' >> 3
133 xor bx, dx ; bx = xss' ^ (xss' >> 3)
136 shl dx, 10 ; dx = xss'' << 10
137 xor bx, dx ; bx = xss'' ^ (xss'' << 10)
142 ; init_grid() - initialize grid cells randomly --------------------------------
144 ; clobbers ax, bx, cx, dx, di
148 mov ah, PRINT_COLOR
; ah = color attribute
149 mov di, [currvgapg
] ; es:di -> grid start
150 mov cx, COLS
* ROWS
; for each cell
153 call xs
; bx = random value
154 mov al, DEAD
; al = DEAD (likely)
158 jnz .nz
; if (bx % 4 == 0)
159 mov al, ALIVE
; al = ALIVE
162 stosw ; [es:di] = ax, di += 2
164 loop .write_cell
; } while (--cx)
168 ; flip_vgapg() - flip active display page -------------------------------------
171 ; [currvgapg] ^= VGAPGSZ
177 xor word [currvgapg
], VGAPGSZ
179 setnz al ; al = !(currvgapg == 0)
180 mov ah, 05h ; select active display page
181 int 10h
; bios video services
185 ; alive_neighbours() - get number of alive adjacent cells ---------------------
188 ; es:si -> current grid
192 ; ax = # alive neighbours
194 ; clobbers ax, bx, dx
201 ; [bp - 3]: neighbours
205 mov ax, cx ; ax = idx
206 mov bl, COLS
; bl = COLS
207 div bl ; al = idx / COLS, ah = idx % COLS
209 mov [bp - 1], al ; row = idx / COLS
210 mov [bp - 2], ah ; row = idx % COLS
211 mov byte [bp - 3], 0 ; neighbours = 0
213 mov byte [bp - 4], -1 ; i = -1
216 mov byte [bp - 5], -1 ; j = -1
220 or al, [bp - 5] ; if (!i && !j)
221 jz .continue
; continue
224 add al, [bp - 4] ; al = row + i
226 cmp al, 0 ; if (row + i < 0)
227 jl .continue
; continue
229 cmp al, ROWS
; if (row + i >= ROWS)
230 jge .continue
; continue
233 add ah, [bp - 5] ; ah = col + j
235 cmp ah, 0 ; if (col + j < 0)
236 jl .continue
; continue
238 cmp ah, COLS
; if (col + j >= COLS)
239 jge .continue
; continue
241 movzx bx, ah ; bx = col + j
244 mul ah ; ax = (row + i) * COLS
246 add bx, ax ; bx = cell index
247 shl bx, 1 ; bx = grid offset
249 mov dx, [es:si + bx] ; dl = cell state
251 cmp dl, ALIVE
; if (!ALIVE)
252 jne .continue
; continue
254 inc byte [bp - 3] ; neighbours++
259 jle .j
; } while (++j <= 1)
263 jle .i
; } while (++i <= 1)
265 movzx ax, byte [bp - 3] ; ax = # alive neighbours
270 ; update_cell() - write next cell state ---------------------------------------
273 ; es:si -> current grid
278 ; [es:di + cx * 2] = updated cell state
280 ; clobbers ax, bx, dx
284 call alive_neighbours
; ax = # alive neighbours
289 mov dx, [es:si + bx] ; dl = cell current state
291 cmp dl, ALIVE
; if (ALIVE) {
294 cmp ax, 2 ; if (n < 2)
295 jl .dead
; return DEAD
297 cmp ax, 3 ; if (n > 3)
298 jg .dead
; return DEAD
300 jmp .alive
; return ALIVE
304 cmp ax, 3 ; if (n != 3)
305 jne .dead
; return DEAD
307 .alive: ; return ALIVE
319 ; update_grid() - write next grid (inactive vga page) -------------------------
321 ; clobbers di, si, ax, bx, cx, dx
325 mov si, [currvgapg
] ; es:si -> current page
328 xor di, si ; es:di -> next page
330 mov cx, COLS
* ROWS
- 1 ; for each cell (index)
337 jns .update_loop
; } while (--cx > 0)
341 ; halt() - stop program execution ---------------------------------------------
345 cli ; disable interrupts
349 ; =============================================================================
351 times 510 - ($ - $$) db 0 ; fill remaining bytes with zeroes
352 dw 0aa55h ; mbr magic byte