]>
wirehaze git hosting - lifeboot.git/blob - lifeboot.asm
8f11b8700d7a9e04ffcb69e53f40962a118375bb
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
12 %
define WAIT_DELAY_CX
01h ; cx:dx = delay in microseconds
13 %
define WAIT_DELAY_DX
00h
15 ; constants -------------------------------------------------------------------
21 ; memory layout ---------------------------------------------------------------
27 ; static variables ------------------------------------------------------------
29 %
define xss DAT
; xs() state (word)
30 %
define currvgapg DAT
+ 2 ; current vga page near pointer (word)
32 ; =============================================================================
34 ; entry point -----------------------------------------------------------------
36 ; initialize segment registers
48 ; clear direction flag
52 mov ch, 3fh
; cursor start and options
53 mov ah, 01h ; set text-mode cursor shape
54 int 10h
; video services
64 je set_xss_seed
; if seed is 0, xs wont work properly
66 mov [xss
], dx ; cx:dx = number of clock ticks since midnight
68 ; initialize currvgapg
69 mov word [currvgapg
], 0
71 ; start simulation from random state ------------------------------------------
77 ; apply game of life's rules to determine the next state ----------------------
82 call write_next_vga_page
88 ; =============================================================================
90 ; functions -------------------------------------------------------------------
92 ; delay() - suspend program execution temporarily -----------------------------
106 ; vsync_wait() - wait for display to enter the next VBlank cycle --------------
112 mov dx, 3dah
; input status #1 register
116 test al, 08h ; vertical retrace bit
126 ; xs() - xorshift pseudorandom number generator -------------------------------
129 ; [xss] = updated state
138 shl dx, 1 ; dx = xss << 1
139 xor bx, dx ; bx = xss ^ (xss << 1)
142 shr dx, 3 ; dx = xss' >> 3
143 xor bx, dx ; bx = xss' ^ (xss' >> 3)
146 shl dx, 10 ; dx = xss'' << 10
147 xor bx, dx ; bx = xss'' ^ (xss'' << 10)
152 ; init_grid() - initialize grid cells randomly --------------------------------
154 ; clobbers ax, bx, cx, dx, di
158 mov ah, PRINT_COLOR
; ah = color attribute
159 mov di, [currvgapg
] ; es:di -> grid start
160 mov cx, COLS
* ROWS
; for each cell
163 call xs
; [xss] = rand
164 mov al, DEAD
; al = DEAD (likely)
166 test word [xss
], 0b11
168 jnz .nz
; if ([xss] % 4 == 0)
169 mov al, ALIVE
; al = ALIVE
172 stosw ; [es:di] = ax ; di += 2
174 loop .write_cell
; } while (--cx)
178 ; flip_vga_page() - flip active display page ----------------------------------
186 xor word [currvgapg
], VGAPGSZ
; flip currvgapg
187 setnz al ; al = !(currvgapg == 0)
189 mov ah, 05h ; select active display page
190 int 10h
; video services
194 ; alive_neighbours() ----------------------------------------------------------
197 ; es:si -> current grid
201 ; ax = # alive neighbours
203 ; clobbers ax, bx, dx
210 ; [bp - 3]: neighbours
214 mov ax, cx ; ax = idx
215 mov bl, COLS
; bl = COLS
216 div bl ; al = idx / COLS ; ah = idx % COLS
218 mov [bp - 1], al ; row = idx / COLS
219 mov [bp - 2], ah ; row = idx % COLS
220 mov byte [bp - 3], 0 ; neighbours = 0
222 mov byte [bp - 4], -1 ; i = -1
225 mov byte [bp - 5], -1 ; j = -1
230 jz .continue
; if (!i && !j) continue
233 add al, [bp - 4] ; al = row + i
236 jl .continue
; if (row + i < 0) continue
239 jge .continue
; if (row + i >= ROWS) continue
242 add ah, [bp - 5] ; ah = col + j
245 jl .continue
; if (col + j < 0) continue
248 jge .continue
; if (col + j >= COLS) continue
250 movzx bx, ah ; bx = col + j
253 mul ah ; ax = (row + i) * COLS
255 add bx, ax ; bx = cell index
256 shl bx, 1 ; bx = grid offset
258 mov dx, [es:si + bx] ; dl = cell state
260 cmp dl, ALIVE
; if (!ALIVE) continue
263 inc byte [bp - 3] ; neighbours++
268 jle .j
; } while (++j <= 1)
272 jle .i
; } while (++i <= 1)
274 movzx ax, byte [bp - 3] ; ax = # alive neighbours
279 ; write_next_cell_state() -----------------------------------------------------
282 ; es:si -> current grid
287 ; [es:di + cx * 2] = updated cell state
289 ; clobbers ax, bx, dx
291 write_next_cell_state:
293 call alive_neighbours
; ax = # alive neighbours
298 mov dx, [es:si + bx] ; dl = cell current state
300 cmp dl, ALIVE
; if (ALIVE) {
303 cmp ax, 2 ; if (n < 2)
304 jl .dead
; return DEAD
306 cmp ax, 3 ; if (n > 3)
307 jg .dead
; return DEAD
309 jmp .alive
; return ALIVE
313 cmp ax, 3 ; if (n != 3)
314 jne .dead
; return DEAD
316 .alive: ; return ALIVE
328 ; write_next_vga_page() -------------------------------------------------------
330 ; clobbers di, si, ax, bx, cx, dx
334 mov si, [currvgapg
] ; es:si -> current page
337 xor di, si ; es:di -> next page
342 call write_next_cell_state
346 jl .update_loop
; for i in [0 .. COLS * ROWS - 1]
350 ; halt() - stop program execution ---------------------------------------------
354 cli ; disable interrupts
358 ; =============================================================================
360 times 510 - ($ - $$) db 0 ; fill remaining bytes with zeroes
361 dw 0aa55h ; mbr magic byte