-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathlife.asm
179 lines (159 loc) · 6.11 KB
/
life.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; ooooo ooooooo o ;
; o o oo o o oooooo o o oooooo o o oooooo oooooo ;
; o o o oo oo o o o o o o o o ;
; o oooo o o o oo o ooooo o o ooooo o o ooooo ooooo ;
; o o oooooo o o o o o o o o o o ;
; o o o o o o o o o o o o o o ;
; ooooo o o o o oooooo ooooooo o ooooooo o o oooooo ;
; ;
; NASM assembler, Linux x86-64 ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro print 2
mov eax, sys_write
mov edi, 1 ; stdout
mov rsi, %1
mov edx, %2
syscall
%endmacro
global _start
section .data
row_cells: equ 32 ; set to any (reasonable) value you wish
column_cells: equ 128 ; set to any (reasonable) value you wish
array_length: equ row_cells * column_cells + row_cells ; cells are mapped to bytes in the array and a new line char ends each row
cells1: times array_length db new_line
cells2: times array_length db new_line
live: equ 111 ; ascii code for live cells, can be any odd number
dead: equ 32 ; ascii code for dead cells, can be any even number
new_line: equ 10 ; ascii code for new line
timespec:
tv_sec dq 0
tv_nsec dq 200000000
clear: db 27, "[2J", 27, "[H"
clear_length: equ $-clear
sys_write: equ 1
sys_nanosleep: equ 35
sys_time: equ 201
section .text
_start:
print clear, clear_length
call first_generation
mov r9, cells1
mov r8, cells2
.generate_cells:
xchg r8, r9 ; exchange roles of current and next generation cell containers
print r8, array_length ; print current generation
mov eax, sys_nanosleep
mov rdi, timespec
xor esi, esi ; ignore remaining time in case of call interruption
syscall ; sleep for tv_sec seconds + tv_nsec nanoseconds
print clear, clear_length
jmp next_generation
; r8: current generation, r9: next generation
next_generation:
xor ebx, ebx ; array index counter
.process_cell:
cmp byte [r8 + rbx], new_line
je .next_cell ; do not count live neighbours if new_line
xor eax, eax ; live neighbours
.lower_index_neighbours:
mov rdx, rbx ; copy of array index counter, will point to neighbour positions
dec rdx ; move to middle left neighbour
js .higher_index_neighbours ; < 0, jump to neighbours with higher indexes
mov cl, [r8 + rdx]
and cl, 1 ; 1 if live, 0 if dead or new_line
add al, cl
sub rdx, column_cells - 1 ; move to top right neighbour
js .higher_index_neighbours ; < 0, jump to neighbours with higher indexes
mov cl, [r8 + rdx]
and cl, 1 ; 1 if live, 0 if dead or new_line
add al, cl
dec rdx ; move to top middle neighbour
js .higher_index_neighbours ; < 0, jump to neighbours with higher indexes
mov cl, [r8 + rdx]
and cl, 1 ; 1 if live, 0 if dead or new_line
add al, cl
dec rdx ; move to top left neighbour
js .higher_index_neighbours ; < 0, jump to neighbours with higher indexes
mov cl, [r8 + rdx]
and cl, 1 ; 1 if live, 0 if dead or new_line
add al, cl
.higher_index_neighbours:
mov rdx, rbx ; reset neighbour index
inc rdx ; move to middle right neighbour
cmp rdx, array_length - 1
jge .assign_cell ; out of bounds, no more neighbours to consider
mov cl, [r8 + rdx]
and cl, 1 ; 1 if live, 0 if dead or new_line
add al, cl
add rdx, column_cells - 1 ; move to bottom left neighbour
cmp rdx, array_length - 1
jge .assign_cell ; out of bounds, no more neighbours to consider
mov cl, [r8 + rdx]
and cl, 1 ; 1 if live, 0 if dead or new_line
add al, cl
inc rdx ; move to bottom middle neighbour
cmp rdx, array_length - 1
jge .assign_cell ; out of bounds, no more neighbours to consider
mov cl, [r8 + rdx]
and cl, 1 ; 1 if live, 0 if dead or new_line
add al, cl
inc rdx ; move to bottom right neighbour
cmp rdx, array_length - 1
jge .assign_cell ; out of bounds, no more neighbours to consider
mov cl, [r8 + rdx]
and cl, 1 ; 1 if live, 0 if dead or new_line
add al, cl
.assign_cell:
cmp al, 2
je .keep_current ; 2 live neigbours, next generation cell same as current
mov byte [r9 + rbx], dead
cmp al, 3
jne .next_cell ; neither 2 or 3, dead cell
mov byte [r9 + rbx], live ; 3 live neighbours, live cell
jmp .next_cell
.keep_current:
mov cl, [r8 + rbx]
mov [r9 + rbx], cl
.next_cell:
inc rbx
cmp rbx, array_length ; check whether end of array
jne .process_cell
jmp _start.generate_cells
; array cells1 is initialised with pseudorandom cells using a middle-square Weyl sequence RNG
first_generation:
mov eax, sys_time
xor edi, edi ; time stored in rax, rdi later used as array index counter
syscall
mov r8w, ax ; r8w stores seed, must be odd
and ax, 1 ; 1 if odd and 0 if even
dec ax ; map to 0 if odd and - 1 if even
sub r8w, ax ; make seed odd
xor cx, cx ; rcx stores random number
xor r9w, r9w ; r9w stores Weyl sequence
mov rbx, column_cells ; rbx stores index of next new_line
.init_cell:
mov ax, cx
mul cx ; square random number
add r9w, r8w ; calculate next iteration of Weyl sequence
add ax, r9w ; add Weyl sequence
mov al, ah ; get lower byte of random number from higher byte of ax
mov ah, dl ; get higher byte of random number from lower byte of dx
mov cx, ax ; save random number for next iteration
and rax, 1 ; test whether even or odd
jz .add_dead ; 0 dead, 1 live
add rax, live - dead - 1
.add_dead:
add rax, dead ; rax is either 0 or live - dead
mov [cells1 + rdi], al ; store ascii code in array
inc rdi ; increment array index
cmp rdi, rbx ; check whether index of new_line
jne .init_next
inc rdi ; increment array index again to preserve new_line
add rbx, column_cells + 1 ; update index of next expected new_line
.init_next:
cmp rdi, array_length ; check whether end of array
jne .init_cell
ret