]>
wirehaze git hosting - lifeboot.git/blob - lifeboot.asm
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
0x07 ; grey on black
11 %
define WAIT_DELAY
0x02 ; 0.131072 seconds
13 ; constants -------------------------------------------------------------------
17 %
define VGAPGSZ
(COLS
* ROWS
* 2 + 96) ; why 96 ??????
19 ; memory layout ---------------------------------------------------------------
25 ; static variables ------------------------------------------------------------
27 %
define xss DAT
; xs() state (word)
28 %
define currvgapg DAT
+ 2 ; current vga page near pointer (word)
30 ; =============================================================================
32 ; entry point -----------------------------------------------------------------
34 ; initialize segment registers
46 ; clear direction flag
50 mov ch, 0x3f ; cursor start and options
51 mov ah, 0x01 ; set text-mode cursor shape
52 int 0x10 ; video services
59 int 0x1a ; system time
62 je set_xss_seed
; if seed is 0, xs wont work properly
64 mov [xss
], dx ; cx:dx = number of clock ticks since midnight
66 ; initialize currvgapg
67 mov word [currvgapg
], 0
69 ; start simulation from random state ------------------------------------------
75 ; apply game of life's rules to determine the next state ----------------------
79 call write_next_vga_page
85 ; =============================================================================
87 ; functions -------------------------------------------------------------------
89 ; delay() - suspend program execution temporarily -----------------------------
95 mov cx, WAIT_DELAY
; cx:dx = interval in microseconds
103 ; wait_keypress() - wait for any keypress -------------------------------------
109 mov ah, 0x00 ; read key press
110 int 0x16 ; keyboard services
114 ; vsync_wait() - wait for display to enter the next VBlank cycle --------------
120 mov dx, 0x3da ; input status #1 register
124 test al, 0x08 ; vertical retrace bit
134 ; xs() - xorshift pseudorandom number generator -------------------------------
137 ; [xss] = updated state
146 shl dx, 1 ; dx = xss << 1
147 xor bx, dx ; bx = xss ^ (xss << 1)
150 shr dx, 3 ; dx = xss' >> 3
151 xor bx, dx ; bx = xss' ^ (xss' >> 3)
154 shl dx, 10 ; dx = xss'' << 10
155 xor bx, dx ; bx = xss'' ^ (xss'' << 10)
160 ; init_grid() - initialize grid cells randomly --------------------------------
162 ; clobbers ax, bx, cx, dx, di
166 mov ah, PRINT_COLOR
; ah = color attribute
167 mov di, [currvgapg
] ; es:di -> grid start
168 mov cx, COLS
* ROWS
; for each cell
171 call xs
; [xss] = rand
172 mov al, DEAD
; al = DEAD (likely)
174 test word [xss
], 0b11
176 jnz .nz
; if ([xss] % 4 == 0)
177 mov al, ALIVE
; al = ALIVE
180 stosw ; [es:di] = ax ; di += 2
182 loop .write_cell
; } while (--cx)
186 ; flip_vga_page() - flip active display page ----------------------------------
194 xor word [currvgapg
], VGAPGSZ
; flip currvgapg
195 setnz al ; al = !(currvgapg == 0)
197 mov ah, 0x05 ; select active display page
198 int 0x10 ; video services
202 ; alive_neighbours() ----------------------------------------------------------
205 ; es:si -> current grid
209 ; ax = # alive neighbours
211 ; clobbers ax, bx, dx
218 ; [bp - 3]: neighbours
222 mov ax, cx ; ax = idx
223 mov bl, COLS
; bl = COLS
224 div bl ; al = idx / COLS ; ah = idx % COLS
226 mov [bp - 1], al ; row = idx / COLS
227 mov [bp - 2], ah ; row = idx % COLS
228 mov byte [bp - 3], 0 ; neighbours = 0
230 mov byte [bp - 4], -1 ; i = -1
233 mov byte [bp - 5], -1 ; j = -1
238 jz .continue
; if (!i && !j) continue
241 add al, [bp - 4] ; al = row + i
244 jl .continue
; if (row + i < 0) continue
247 jge .continue
; if (row + i >= ROWS) continue
250 add ah, [bp - 5] ; ah = col + j
253 jl .continue
; if (col + j < 0) continue
256 jge .continue
; if (col + j >= COLS) continue
258 movzx bx, ah ; bx = col + j
261 mul ah ; ax = (row + i) * COLS
263 add bx, ax ; bx = cell index
264 shl bx, 1 ; bx = grid offset
266 mov dx, [es:si + bx] ; dl = cell state
268 cmp dl, ALIVE
; if (!ALIVE) continue
271 inc byte [bp - 3] ; neighbours++
276 jle .j
; } while (++j <= 1)
280 jle .i
; } while (++i <= 1)
282 movzx ax, byte [bp - 3] ; ax = # alive neighbours
287 ; write_next_cell_state() -----------------------------------------------------
290 ; es:si -> current grid
295 ; [es:di + cx * 2] = updated cell state
297 ; clobbers ax, bx, dx
299 write_next_cell_state:
301 call alive_neighbours
; ax = # alive neighbours
306 mov dx, [es:si + bx] ; dl = cell current state
308 cmp dl, ALIVE
; if (ALIVE) {
311 cmp ax, 2 ; if (n < 2)
312 jl .dead
; return DEAD
314 cmp ax, 3 ; if (n > 3)
315 jg .dead
; return DEAD
317 jmp .alive
; return ALIVE
321 cmp ax, 3 ; if (n != 3)
322 jne .dead
; return DEAD
324 .alive: ; return ALIVE
336 ; write_next_vga_page() -------------------------------------------------------
338 ; clobbers di, si, ax, bx, cx, dx
342 mov si, [currvgapg
] ; es:si -> current page
345 xor di, si ; es:di -> next page
350 call write_next_cell_state
354 jl .update_loop
; for i in [0 .. COLS * ROWS - 1]
358 ; halt() - stop program execution ---------------------------------------------
362 cli ; disable interrupts
366 ; =============================================================================
368 times 510 - ($ - $$) db 0 ; fill remaining bytes with zeroes
369 dw 0xaa55 ; mbr magic byte