297 lines
6.5 KiB
NASM
Executable File
297 lines
6.5 KiB
NASM
Executable File
; 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
|