; Conway's Game of Life ; 2020 Ciaran Anscomb ; ; In tribute to John Conway, who died this year from COVID-19. ; No built-in editor, just sets up some hopefully-interesting initial ; conditions and sets it going. ; - Cells stored in off-screen buffer ; - Current/next state stored in separate nibbles, alternating per frame ; - Partial calculations stored for later use ; - Lots of self-modifying code ; - Ability to define a viewport (whole numbers of screen bytes only) ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; Set to 1 for a higher resolution screen (but much slower updates). Note ; that the framebuffers are held at the same address even in low-res for ; code simplicity (I know, right?). HIRES set 0 if HIRES piamode equ $e0 ; G3C (128x96) fb_w equ 32 fb_h equ 96 vp_w equ 32 vp_h equ 96 vp_x equ (fb_w-vp_w)/2 vp_y equ (fb_h-vp_h)/2 else piamode equ $80 ; G1C (64x64) fb_w equ 16 fb_h equ 64 vp_w equ 16 vp_h equ 64 vp_x equ (fb_w-vp_w)/2 vp_y equ (fb_h-vp_h)/2 endif fb0 equ $0c00 fb1 equ $1800 fb_end equ $2400 grid_w equ vp_w*4 grid_h equ vp_h eol_skip equ fb_w-vp_w vp0 equ fb0+vp_y*fb_w+vp_x vp1 equ fb1+vp_y*fb_w+vp_x reg_pia0_pdrb equ $ff02 reg_pia1_pdrb equ $ff22 reg_sam_v0c equ $ffc0 reg_sam_v0s equ $ffc1 reg_sam_v1c equ $ffc2 reg_sam_v1s equ $ffc3 reg_sam_v2c equ $ffc4 reg_sam_v2s equ $ffc5 reg_sam_f0c equ $ffc6 reg_sam_f0s equ $ffc7 reg_sam_f1c equ $ffc8 reg_sam_f1s equ $ffc9 reg_sam_f2c equ $ffca reg_sam_f2s equ $ffcb reg_sam_f3c equ $ffcc reg_sam_f3s equ $ffcd ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - org $0112 out_ptr rmb 2 cells_ptr rmb 2 outbyte rmb 1 ycount rmb 1 xcount rmb 1 ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - org $2400 orcc #$50 ; DP, VDG video mode ldd #($01<<8)|piamode tfr a,dp setdp $01 stb reg_pia1_pdrb ; SAM video mode if HIRES sta reg_sam_v0c sta reg_sam_v1c sta reg_sam_v2s else sta reg_sam_v0s sta reg_sam_v1c sta reg_sam_v2c endif ; SAM VRAM base - these bits don't change sta reg_sam_f0c sta reg_sam_f2s ; Clear screen ldx #$0c00 ldd #$aaaa ! std ,x++ cmpx #$2400 blo < ; Clear cell grid ldx #cells ! clr ,x+ cmpx #cells_end blo < ; Initial conditions if HIRES ; Acorn is better in hi-res ldd #(48<<8)|74 ; y,x ldu #acorn ; object jsr plonk else ; Couple of gosper guns facing each other ldd #(13<<8)|12 ; y,x ldu #gun ; object jsr plonk ldd #(41<<8)|12 ; y,x ldu #gun2 ; object jsr plonk endif ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - main_loop lda reg_pia0_pdrb ; clear any existing IRQ sync ; wait for next sta reg_sam_f1s ; SAM VRAM base sta reg_sam_f3c ; = $0c00 ldd #$0203 ; self-mod values ldu #$0f10 ; self-mod values ldx #vp1 bsr dolife lda reg_pia0_pdrb ; clear any existing IRQ sync ; wait for next sta reg_sam_f1c ; SAM VRAM base sta reg_sam_f3s ; = $1800 ldd #$2030 ; self-mod values ldu #$f001 ; self-mod values ldx #vp0 bsr dolife bra main_loop ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - dolife ; Self-modifying code: alternate which half of cell ; nibbles are used for calculations, and which half is ; used for the result. ; Compares against 2 for currently-live cells sta mod_c0_a2 sta mod_c1_a2 sta mod_c2_a2 sta mod_c3_a2 sta mod_r3_a2 ; Compares against 3 for currently-live cells stb mod_c0_a3 stb mod_c1_a3 stb mod_c2_a3 stb mod_c3_a3 stb mod_r3_a3 ; Compares against 3 for currently-dead cells stb mod_c0_d3 stb mod_c1_d3 stb mod_c2_d3 stb mod_c3_d3 stb mod_r3_d3 tfr u,d ; Masking off calculation nibble sta mod_c0_m0 sta mod_c0_m1 sta mod_c1_m0 sta mod_c1_m1 sta mod_c2_m0 sta mod_c2_m1 sta mod_c3_m0 sta mod_c3_m1 sta mod_r3_m0 sta mod_r3_m1 ; Setting result nibble stb mod_c0_s0 stb mod_c0_s1 stb mod_c1_s0 stb mod_c2_s0 stb mod_c3_s0 stb mod_c3_s1 stb mod_r3_s0 stb mod_r3_s1 ; Setup lda #vp_h sta ycount stx out_ptr ldx #cells ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; leftmost cell 0 line_start_c0 lda #vp_w sta xcount leau -grid_w,x cmpx #cells+grid_w bhs > ldu #cells_end-grid_w ! leay grid_w,x cmpx #cells_end-grid_w blo > ldy #cells ! ldb ,u addb ,x addb ,y stb c1_pre ldb grid_w-1,u addb grid_w-1,x addb grid_w-1,y stb c0_pre ; cell 0 c0 ldb 1,u addb 1,x addb 1,y stb c2_pre c0_pre equ *+1 addb #$00 addb ,u+ addb ,y+ mod_c0_m0 equ *+1 andb #$0f lda ,x mod_c0_m1 equ *+1 anda #$0f beq > ; cell currently alive mod_c0_a2 equ *+1 cmpb #2 blo 10F ; cell dies mod_c0_a3 equ *+1 cmpb #3 bhi 10F ; cell dies ; cell remains alive (red) mod_c0_s0 equ *+1 ora #$10 ldb #$c0 bra 20F ; cell currently dead mod_c0_d3 equ *+1 ! cmpb #3 bne 10F ; cell remains dead ; cell becomes alive (blue) mod_c0_s1 equ *+1 ora #$10 ldb #$80 bra 20F 10 clrb 20 sta ,x+ stb outbyte ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; cell 1 ldb 1,u addb 1,x addb 1,y stb c3_pre c1_pre equ *+1 addb #$00 addb ,u+ addb ,y+ mod_c1_m0 equ *+1 andb #$0f lda ,x mod_c1_m1 equ *+1 anda #$0f beq > ; cell currently alive mod_c1_a2 equ *+1 cmpb #2 blo 10F ; cell dies mod_c1_a3 equ *+1 cmpb #3 bhi 10F ; cell dies ; cell remains alive (red) ldb #$30 bra 20F ; cell currently dead mod_c1_d3 equ *+1 ! cmpb #3 bne 10F ; cell remains dead ; cell becomes alive (blue) ldb #$20 20 orb outbyte stb outbyte mod_c1_s0 equ *+1 ora #$10 10 sta ,x+ ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; cell 2 ldb 1,u addb 1,x addb 1,y stb c0_pre c2_pre equ *+1 addb #$00 addb ,u+ addb ,y+ mod_c2_m0 equ *+1 andb #$0f lda ,x mod_c2_m1 equ *+1 anda #$0f beq > ; cell currently alive mod_c2_a2 equ *+1 cmpb #2 blo 10F ; cell dies mod_c2_a3 equ *+1 cmpb #3 bhi 10F ; cell dies ; live cell remains alive (red) ldb #$0c bra 20F ; cell currently dead mod_c2_d3 equ *+1 ! cmpb #3 bne 10F ; cell remains dead ; dead cell becomes alive (blue) ldb #$08 20 orb outbyte stb outbyte mod_c2_s0 equ *+1 ora #$10 10 sta ,x+ ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - dec xcount beq line_end_c3 ; cell 3 ldb 1,u addb 1,x addb 1,y stb c1_pre c3_pre equ *+1 addb #$00 addb ,u+ addb ,y+ mod_c3_m0 equ *+1 andb #$0f lda ,x mod_c3_m1 equ *+1 anda #$0f beq > ; cell currently alive mod_c3_a2 equ *+1 cmpb #2 blo 10F ; cell dies mod_c3_a3 equ *+1 cmpb #3 bhi 10F ; cell dies ; cell remains alive (red) mod_c3_s0 equ *+1 ora #$10 ldb outbyte orb #$03 bra 20F ; cell currently dead mod_c3_d3 equ *+1 ! cmpb #3 bne 10F ; cell remains dead ; cell becomes alive (blue) mod_c3_s1 equ *+1 ora #$10 ldb outbyte orb #$02 bra 20F 10 ldb outbyte 20 sta ,x+ stx cells_ptr ldx out_ptr stb ,x+ stx out_ptr ldx cells_ptr jmp c0 ; rightmost cell 3 line_end_c3 ldb -(grid_w-1),u addb -(grid_w-1),x addb -(grid_w-1),y addb c3_pre addb ,u+ addb ,y+ mod_r3_m0 equ *+1 andb #$0f lda ,x mod_r3_m1 equ *+1 anda #$0f beq > ; cell currently alive mod_r3_a2 equ *+1 cmpb #2 blo 10F ; cell dies mod_r3_a3 equ *+1 cmpb #3 bhi 10F ; cell dies ; cell remains alive (red) mod_r3_s0 equ *+1 ora #$10 ldb outbyte orb #$03 bra 20F ; cell currently dead mod_r3_d3 equ *+1 ! cmpb #3 bne 10F ; cell remains dead ; cell becomes alive (blue) mod_r3_s1 equ *+1 ora #$10 ldb outbyte orb #$02 bra 20F 10 ldb outbyte 20 sta ,x+ ldu out_ptr stb ,u+ if eol_skip > 0 leau eol_skip,u endif stu out_ptr dec ycount lbne line_start_c0 rts ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; On entry, A,B = (Y,X) within grid, U points to structure def below plonk pshs b ldb #grid_w mul ldx #cells leax d,x puls b abx pulu a,b std ycount 10 stx cells_ptr ldb xcount stb out_ptr 20 ldb #8 stb outbyte lda ,u+ 30 clrb lsla rolb stb ,x+ dec outbyte bne 30B dec out_ptr bne 20B ldx cells_ptr leax grid_w,x dec ycount bne 10B rts ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; Some baked-in structures to set up initial conditions. acorn ; Good in hi-res, a "methusela" fcb 3,1 fcb $20 fcb $08 fcb $67 gun ; Gosper gun fcb 9,5 fcb $00,$00,$00,$20,$00 fcb $00,$00,$00,$a0,$00 fcb $00,$03,$03,$00,$0c fcb $00,$04,$43,$00,$0c fcb $30,$08,$23,$00,$00 fcb $30,$08,$b0,$a0,$00 fcb $00,$08,$20,$20,$00 fcb $00,$04,$40,$00,$00 fcb $00,$03,$00,$00,$00 gun2 ; Same Gosper gun but flipped in X and Y axis fcb 9,5 fcb $00,$00,$00,$c0,$00 fcb $00,$00,$02,$20,$00 fcb $00,$04,$04,$10,$00 fcb $00,$05,$0d,$10,$0c fcb $00,$00,$c4,$10,$0c fcb $30,$00,$c2,$20,$00 fcb $30,$00,$c0,$c0,$00 fcb $00,$05,$00,$00,$00 fcb $00,$04,$00,$00,$00 ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - cells rmb grid_w*grid_h cells_end