*        Color Computer Life Program for 16k Color Computer
*        Runs in Hi-res mode, simulates LIFE
*        for now, just operates on screen area as found!
*        9/26/82 Ira D. Baxter
*
         with  wi=80,de=66

World    equ   16*1024-6144-512        Place where Life lives
*                                      (last page holds "dummy" dead row)
WorldWidth equ 256                     Width of world in bits
WorldDepth equ 192                     Depth of world in bits

         org   0
RowCount rmb   1                       holds number of rows left to generate
ByteCount rmb  1                       holds number of bytes left to gen

PreviousRowByte rmb 1                  holds byte from previous row
ThisRowByte    rmb 1                   holds byte from this row
NextRowByte    rmb 1                   holds byte from next row
         if    NextRowByte#ThisRowByte+1
         ?can't use STD to fill ThisRowByte and NextRowByte simultaneously?
         fin

         org   $1800                   this may not be the best place
Life ; began here, 4 billion keystrokes ago...
*
*        Stamp out Life!
*
         ldx   #World
         ldy   #WorldWidth/8*WorldDepth = number of places it can be found
StampOutLifeLoop
         clr   ,x+
         leay  -1,y                    decrement count
         bne   StampOutLifeLoop
*
*        Set up the hardware
*
         sei                           make sure we won't be bugged...
         lds   #$ff                    a tolerable place for the stack
         clra                          set dp register
         tfr   a,dp                    so we can use page zero as work store
*
*        select G6R mode, move display buffer to top of 16k space
*
         lda   #%110                   "G6R" mode
         ldb   #3                      = # SAM chip bits to set
         ldx   #$FFC0                  SAM chip address
         jsr   SetSAM                  set up SAM chip properly
         lda   $ff22                   (don't disturb 3 lsbs)
         anda  #%111
         ora   #%11111000              finish G6R mode selection
         sta   $ff22                   (see color computer tech ref manual)
         lda   #World/512              = page register select
         ldb   #7                      = # bits to set
         jsr   SetSAM
         page  Initialize for operation
         jsr   GenerateStateToLife     go build lookup table needed

*
*        make border of the World contain Death
*
         ldx   #World                  put death at edges of World
         ldb   #WorldWidth//8          = number of bytes to clear
deadborderloop ; make rows above top and bottom of screen contain death
         clr   WorldWidth/8*WorldDepth,x make 8 dead cells below screen area
         leax  1,x                     advance pointer to next place to die
         decb                          down count number of places to die
         bne   deadborderloop          b/ more places to kill off
         page  DoGeneration
DoGeneration ; Compute next generation and update the World
         ldu   #PreviousRow            zero previous row
         ldb   #WorldWidth//8
DoGenerationL1 ; loop to make PreviousRow completely dead
         clr   ,u+
         decb
         bne   DoGenerationL1
         ldx   #World                  where to start producing new generation
         ldb   #WorldDepth             = number of rows to process
         stb   RowCount                set up loop counter
         ldy   #StateToLifeTable       Converts 9 bit state to $00 or $01
DoGenerationRow ; Compute new generation for Row starting at (X)
         ldu   #PreviousRow            set up for DoGenerationByte
         ldb   #WorldWidth/8-1         = bytes to generate, except rightmost
         stb   ByteCount               set up loop counter
*
*        The following code is special cased to handle...
*        the left edge of the world, where only death can be.
*
         lda   ,x                      save byte to update for this row
         ldb   WorldWidth/8,x          fetch byte from next row...
         std   thisrowbyte             also store "nextrowbyte" for easy access
         bne   DoGenerationRow1        b/ something interesting will happen
         ldb   ,u+                     fetch byte from previous row
         bne   DoGenerationRow1a       sigh... there REALLY is work to do...
*        sta   -1,u                    is zero, already accomplished

DoGenerationSkipByte ; Optimize knowing that region to left is dead
*        Note: must enter with Carry bit reset
*
*        To generate LSB of Life byte, we need MSB of next byte in row.
*
         lda   1,x                     save byte to update for this row
         ldb   WorldWidth/8+1,x        fetch byte from next row...
         std   thisrowbyte             also store "nextrowbyte" for easy access
         bne   DoGenerationSkip1       b/ region to right is interesting...
         ldb   ,u+                     fetch byte from previous row
         bne   DoGenerationSkip1a      b/ region to right is interesting...
         leax  1,x                     byte is all zero, skip it quickly
         dec   ByteCount               all bytes (except last in row) processed?
         bne   DoGenerationSkipByte    b/ no, skip over this byte, too...
         lbra  DoGenerationSkipLast    assert: carry is zero!

DoGenerationSkip1 ; some life units exist
         ldb   ,u+                     fetch byte from previous row
DoGenerationSkip1a
         sta   -1,u                    store this byte for use on next row
         stb   previousrowbyte         and save where we can destroy it
         ldd   #0                      so "rola" can only produce zero or 1
*                                      also, zero (B) to reflect current state
         lbra  GenerateLifeBit0        go generate bit zero conventionally

DoGenerationRow1 ; some life units exist
         ldb   ,u+                     fetch byte from previous row
DoGenerationRow1a
         sta   -1,u                    store this byte for use on next row
         stb   previousrowbyte         and save where we can destroy it

         ldd   #0                      so "rola" below gives only 0 or 1
*        clrb                          set up state to be Death from left edge
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
*        rola                          assert: (A) = 0 after rola
         bra   DoGenerationByte1       don't test, this byte is "interesting"

DoGenerationByte ; (x) points to next 8 bit byte to process
         addb  #0                      any non-zero state bits ? (zero carry)
         bne   DoGenerationByte1       b/ yes, go process the normal way
         lda   previousrowbyte         check to see if region is dead
         ora   thisrowbyte
         ora   nextrowbyte
         beq   DoGenerationSkipByte    b/ yes, optimize execution time!
DoGenerationByte1 ; generate new life the conventional way
         clra                          ensure that "rola" gives only 0 or 1
**** The following code is repeated 8 times, once per bit generated
*** Generate new state for LIFE in bit 7 of byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x                      shift new life state into display memory
*** End repeated code ***

*** Generate new state for LIFE in bit 6 of byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x                      shift new life state into display memory

*** Generate new state for LIFE in bit 5 of byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x                      shift new life state into display memory

*** Generate new state for LIFE in bit 4 of byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x                      shift new life state into display memory

*** Generate new state for LIFE in bit 3 of byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x                      shift new life state into display memory

*** Generate new state for LIFE in bit 2 of byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x                      shift new life state into display memory

*** Generate new state for LIFE in bit 1 of byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x                      shift new life state into display memory
*
*        To generate LSB of Life byte, we need MSB of next byte in row.
*
         lda   ,u                      fetch byte from previous row
         sta   previousrowbyte         and save where we can destroy it
         lda   1,x                     save byte to update for next row
         sta   ,u+                     (and advance save pointer)
         sta   thisrowbyte             save byte where we can destroy it
         lda   WorldWidth/8+1,x        fetch byte from next row...
         sta   nextrowbyte             and save it where we can destroy it
         clra                          so "rola" below produces only 1 or 0

GenerateLifeBit0 ; come here to generate LSB of byte
*** Generate new state for LIFE in bit 0 of byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x+                     shift new life state into display memory

         dec   ByteCount               all bytes (except last) in row processed ?
         bne   DoGenerationByte        b/ no
         page
*        The following code generates new LIFE state...
*        for the rightmost byte on the screen.
*        The code is identical to the above, except for special casing...
*        on the rightmost bit generation.
*
         addb  #0                      any non-zero state bits ? (clear carry)
         bne   DoGenerationLastRowByte b/ yes, go process the normal way
         lda   previousrowbyte         see if region is dead
         ora   thisrowbyte
         ora   nextrowbyte
         beq   DoGenerationSkipLast    b/ yes, optimize execution time!
DoGenerationLastRowByte ; construct last byte in row
         clra                          so that "rola" below gives only 0 or 1
*** Generate new state for LIFE in bit 7 of rightmost screen byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x                      shift new life state into display memory
*** End repeated code ***

*** Generate new state for LIFE in bit 6 of rightmost screen byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x                      shift new life state into display memory

*** Generate new state for LIFE in bit 5 of rightmost screen byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x                      shift new life state into display memory

*** Generate new state for LIFE in bit 4 of rightmost screen byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x                      shift new life state into display memory

*** Generate new state for LIFE in bit 3 of rightmost screen byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x                      shift new life state into display memory

*** Generate new state for LIFE in bit 2 of rightmost screen byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x                      shift new life state into display memory

*** Generate new state for LIFE in bit 1 of rightmost screen byte
         asl   previousrowbyte         construct new state for life cell
         rolb                          (now 7 bits of state constructed)
         asl   thisrowbyte             (insert current state of life cell)
         rolb                          (now 8 bits of state constructed)
         asl   nextrowbyte             insert state of life cell below here
         rolb
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
         rol   ,x                      shift new life state into display memory

*** Generate new state for LIFE in bit 0 of rightmost byte of World
*** This chunk special cased to know that beyond right edge of World is Death
         aslb                          shift in Death from previous row
         aslb                          shift in Death from this row
         aslb                          shift in Death from next row
         rola                          assert: (A) = 0 or 1
         lda   d,y
         lsra                          shift new life state into carry
DoGenerationSkipLast ; enter here with C=0 if rightmost row byte is zero
         rol   ,x+                     shift new life state into display memory

         dec   RowCount                all rows in World processed ?
         lbne  DoGenerationRow         b/ no

         lbra  DoGeneration            one generation complete, start another
         page
GenerateStateToLife ; produce table that converts 9 bit state...
;        into $00 (if new generation is dead)
;        or   $01 (if new generation is alive)
         ldx   #511                    number of table slots to gen, -1
GenerateStateToLifeLoop ; convert state name of this slot to Life or Death
         tfr   x,d                     fetch state to convert
;
;        (D) now contain  "state".
;
;        If and array of life cells exists, in the following form:
;
;        *------*------*------*
;        !      !      !      !        then a "state" is a 9 bit number,
;        !  b8  !  b5  !  b2  !        whose bits correspond to the life units
;        !      !      !      !        as shown in the diagram (i.e., b0
;        *------*------*------*        is the LSB of the state), and whose
;        !      !      !      !        values are "1" if that place is alive
;        !  b7  !  b4  !  b1  !        and zero if dead.
;        !      !      !      !
;        *------*------*------*
;        !      !      !      !
;        !  b6  !  b3  !  b0  !
;        !      !      !      !
;        *------*------*------*
;
         lsrb                          count number of bits in state
         adca  #0                      count bit 0
         lsrb
         adca  #0                      count bit 1
         lsrb
         adca  #0                      count bit 2
         lsrb
         adca  #0                      count bit 3
         lsrb
*        adca  #0                      DON'T count bit 4!
         lsrb
         adca  #0                      count bit 5
         lsrb
         adca  #0                      count bit 6
         lsrb
         adca  #0                      count bit 7
*
*        now decide if life will be present in next generation,
*        according to John Conway's rules...
*
*        if number of neighbors < 2, then die (of lack of company).
*        if number of neighbors = 2, then survive.
*        if number of neighbors = 3, then grow.
*        if number of neighbors > 3, then die (of overcrowding).
*
         cmpa  #2                      die ?
         blo   GenerateStateToLifeStb  b/ yes (assert: (B) = 0 here)
         beq   GenerateStateToLifeSurvive b/ current state survives
         cmpa  #3                      grow ?
         bhi   GenerateStateToLifeStb  b/ no, die of overcrowding
         incb                          set (B) to $01, "new life..."
         bra   GenerateStateToLifeStb

GenerateStateToLifeSurvive ; current state of life in cell survives
         tfr   x,d                     current life cell is b4
         lsrb                          shift b4 into b0
         lsrb
         lsrb
         lsrb
         andb  #1                      mask off other bits
GenerateStateToLifeStb ; (B) contains $00 or $01, store it
         stb   StateToLifeTable,x      store value in proper table slot
         leax  -1,x                    decrement number of table slots left
         bne   GenerateStateToLifeLoop b/ more table slots left to fill
         clr   StateToLifeTable        state code 0 --> die
         rts
         page
SetSAM   rora                          check mode bit state
         bcs   SetSAM1                 b/ bit is set
         sta   ,x                      bit is reset, hit SAM register
         bra   SetSAM2
SetSAM1  sta   1,x                     hit appropriate sam register
SetSAM2  leax  2,x                     advance to next SAM chip pair
         decb                          down count number of bits to set
         bne   SetSAM                  b/ more SAM bits to set
         rts
         page
         fcb   0                       for the loader to louse up
StateToLifeTable rmb 512               Converts 9 bit state to life
PreviousRow rmb WorldWidth//8          Holds copy of row above updated row
*                                      Row above is held from previous gen'tion
         End   Life
