/
gol_optimized.asm
executable file
·296 lines (251 loc) · 6.53 KB
/
gol_optimized.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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
; Conway's Game of Life for Apple II
; Copyright (C) 2016 Christophe Meneboeuf <christophe@xtof.info>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.include "apple2.inc"
.include "zeropage.inc"
.import _memcpy
.import popa
.import popax
.import pusha
.import pushax
.import _gfx_pixel
.import _get_color
.export _init_asm
.export _count_neighbours
.export _update
.define NB_LINES 40
.define NB_COLUMNS 40
.define JUMP_BEGINNING_NEXT_LINE NB_LINES - 2
.define ALIVE 1
.define DEAD 0
.define BLACK 0
.define CELLS_SIZE 1600
.BSS
Cells: .word $0
Cells_Future: .word $0
cell_neighbourhoud: .word $0
cell_line: .word $0
cell_future: .word $0
.CODE
;16 bit addition of the content of an adress with a 16bit value
.macro add_16 addr_dst, addr_src, value_low, value_hi
CLC
LDA addr_src
ADC value_low
STA addr_dst
LDA addr_src+1
ADC value_hi
STA addr_dst+1
.endmacro
;16 bit copy from a memory location to another
.macro copy_16 addr_dst, addr_src
LDA addr_src
STA addr_dst
LDA addr_src+1
STA addr_dst+1
.endmacro
; ******************
; Initialize the variables used in ASM functions
;void __fastcall__ init_asm( uint8_t* p_cell, uint8_t* p_cells_future )
;param: p_cell is in AX
; p_cells_future in sreg
_init_asm:
STA Cells_Future
STX Cells_Future+1
LDY #1
LDA (sp),Y
STA Cells+1
DEY
LDA (sp),Y
STA Cells
JSR popa
JSR popa
RTS
; ******************
;void __fastcall__ update( void )
; ! A, X, Y & ALL PTRx ARE OVERWRITTEN !
_update:
;aliases
cell_curr := ptr1
cell_neighbourhoud_line := ptr2
cell_future_line := ptr3
nb_neighbours := tmp1
LDA ptr1
LDX ptr1+1
JSR pushax
LDA ptr2
LDX ptr2+1
JSR pushax
LDA ptr3
LDX ptr3+1
JSR pushax
;preambule
; cell_neighbourhoud = Cells
copy_16 cell_neighbourhoud, Cells
; cell_line = cell_neighbourhoud + NB_LINES + 1u
add_16 cell_line, cell_neighbourhoud, #NB_LINES+1, #0
; cell_future = Cells_Future + NB_LINES + 1u
add_16 cell_future, Cells_Future, #NB_LINES+1, #0
; loop : for( y = 1u; y < NB_LINES - 1u; ++y )
LDY #1
loop_y:
;those macros don't touch Y
copy_16 cell_curr, cell_line
copy_16 cell_neighbourhoud_line, cell_neighbourhoud
copy_16 cell_future_line, cell_future
STY tmp3
CPY #NB_LINES-1
BEQ end_y
; loop : for( x = 1u; x < NB_COLUMNS - 1u; ++x )
LDX #1
loop_x:
CPX #NB_COLUMNS-1
BEQ end_x
; uint8_t nb_neighbours = count_neighbours( cell_neighbourhoud_line )
STX tmp2
LDA cell_neighbourhoud_line
LDX cell_neighbourhoud_line+1
JSR _count_neighbours ; nb_neighbours in A
STA nb_neighbours
JMP tst_alive
next_x:
add_16 cell_curr, cell_curr, #NB_LINES, #0
add_16 cell_neighbourhoud_line, cell_neighbourhoud_line, #NB_LINES, #0
add_16 cell_future_line, cell_future_line, #NB_LINES, #0
; next X
LDX tmp2
INX
JMP loop_x
end_x:
add_16 cell_line, cell_line, #1, #0
add_16 cell_neighbourhoud, cell_neighbourhoud, #1, #0
add_16 cell_future, cell_future, #1, #0
; next Y
LDY tmp3
INY
JMP loop_y
end_y:
JMP end_update ; This jump allows conditional branching
; tst_dead section in the following (optimization)
; *** TIP */
; those should be placed inside loop_x (search for JMP tst_alive)
; they are placed here not to overflow the 8 bit range of conditional branching
tst_dead:
LDY #0
LDA (cell_curr),Y
CMP #DEAD
BNE next_x
LDA nb_neighbours
CMP #3
BNE next_x
; a cell is born
LDA #ALIVE
STA (cell_future_line),Y
JSR _get_color ;random color in A
JSR pusha
LDA tmp2
JSR pusha
LDA tmp3
JSR _gfx_pixel
JMP next_x
tst_alive:
LDY #0
LDA (cell_curr),Y
CMP #ALIVE
BNE tst_dead
LDA nb_neighbours
CLC
ADC #$FE
BCC kill_cell ; if nb_neighbours < 2
LDA nb_neighbours
CLC
ADC #$FC ; no need to CLC again as prev tst failed
BCC tst_dead ; if nb_neighbours <= 3
kill_cell:
LDA #DEAD
STA (cell_future_line),Y
JSR pusha ; #DEAD == #BLACK COLOR
LDA tmp2
JSR pusha
LDA tmp3
JSR _gfx_pixel
JMP next_x
end_update:
; Cells_Future -> Cells
LDA Cells
LDX Cells+1
JSR pushax
LDA Cells_Future
LDX Cells_Future+1
JSR pushax
LDA #<CELLS_SIZE
LDX #>CELLS_SIZE
JSR _memcpy
JSR popax
STA ptr3
STX ptr3+1
JSR popax
STA ptr2
STX ptr2+1
JSR popax
STA ptr1
STX ptr1+1
RTS
;*************** END OF UPDATE **************
; ******************
;uint8_t __fastcall__ count_neighbours( uint8_t* cell )
;param: cell is in AX
; ! A, X, Y & PTR4 ARE OVERWRITTEN !
_count_neighbours:
;ASSUMPTIONS:
; -> A and Y (offset to starting ptr) won't overflow!
;alias
cell := ptr4
;init
STA cell
STX cell+1
LDA #0
LDY #0
CLC
;acc 1st row
ADC (cell),Y
INY
ADC (cell),Y
INY
ADC (cell),Y
;next row
STA tmp4
TYA
ADC #JUMP_BEGINNING_NEXT_LINE
TAY
LDA tmp4
ADC (cell),Y
INY
INY
ADC (cell),Y
;next row
STA tmp4
TYA
ADC #JUMP_BEGINNING_NEXT_LINE
TAY
LDA tmp4
ADC (cell),Y
INY
ADC (cell),Y
INY
ADC (cell),Y
;return
LDX #0
RTS