' =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ' File...... Wall_of_Life.SXB ' Purpose... Digital Life Program ' Author.... Sean Hillmeyer ' Based on the work of Jon Williams ' Copyright (c) 2008 Sean Hillmeyer ' Some Rights Reserved ' -- see http://creativecommons.org/licenses/by/2.5/ ' E-mail.... hillmeyer@gmail.com ' Started... 1 APR 2008 ' ' Program Description: ' ' Conway's Game of Life simulation. ' -- see: http://en.wikipedia.org/wiki/Conway's_Game_of_Life ' Runs on a 8x26 martix of LEDs. ' ' =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ' ' ------------------------------------------------------------------------- ' Device Settings ' ------------------------------------------------------------------------- DEVICE SX28, OSCXT2, TURBO, STACKX, OPTIONX FREQ 20_000_000 ID "LIFE" ' ------------------------------------------------------------------------- ' IO Pins ' ------------------------------------------------------------------------- Anodes PIN RA OUTPUT 'Anodes are controled by BCD on port RA Dout PIN RB.0 OUTPUT 'Cathodes are controled by a serial shift to MAX69XX LED drivers Cout PIN RB.1 OUTPUT Latch PIN RB.2 OUTPUT OE PIN RB.3 OUTPUT ' ------------------------------------------------------------------------- ' Constants ' ------------------------------------------------------------------------- Yes CON 1 No CON 0 Alive CON 1 Dead CON 0 ' ------------------------------------------------------------------------- ' Variables ' ------------------------------------------------------------------------- ' The following four bytes contain the display buffer for the matrix. ' Pixel 0,0 (upper left) is the highest bit in ColHH,Byte(0) ' 0 | ColHH, ColHL, ColLH, ColLL | 0 ' 1 | ColHH, ColHL, ColLH, ColLL | 1 ' 2 | ColHH, ColHL, ColLH, ColLL | 2 ' 3 | ColHH, ColHL, ColLH, ColLL | 3 ' 4 | ColHH, ColHL, ColLH, ColLL | 4 ' 5 | ColHH, ColHL, ColLH, ColLL | 5 ' 6 | ColHH, ColHL, ColLH, ColLL | 6 ' 7 | ColHH, ColHL, ColLH, ColLL | 7 ColHH VAR Byte(8) ColHL VAR Byte(8) ColLH VAR Byte(8) ColLL VAR Byte(8) newGenHH VAR Byte(8) newGenHL VAR Byte(8) newGenLH VAR Byte(8) newGenLL VAR Byte(8) genCount VAR Byte row VAR Byte ' current display row (ISR) ms VAR Word ' for delay timing (ISR) seed VAR Byte ' running random value (ISR) idxCol VAR Byte idxRow VAR Byte neighbors VAR Byte chkRow VAR Byte chkCol VAR Byte colTmp VAR Byte cell VAR Byte tmpB1 VAR Byte ' work variables tmpB2 VAR Byte tmpB3 VAR Byte ' ------------------------------------------------------------------------- INTERRUPT 1000 ' run every 2 milliseconds ' ------------------------------------------------------------------------- GOTO INT_HANDLER ' ========================================================================= PROGRAM Start ' ========================================================================= ' ------------------------------------------------------------------------- ' Subroutine Declarations ' ------------------------------------------------------------------------- DELAY SUB 1, 2 ' delay in 1 ms units COUNT_NEIGHBORS SUB 0 ' counts cell neighbors GET_BIT FUNC 1, 2 ' get bit value SET_BIT FUNC 1, 2 ' sets a bit in a byte CLR_BIT FUNC 1, 2 ' clears a bit in a byte PUT_BIT FUNC 1, 3 ' writes bitVal into byte GET_CELL FUNC 1, 0 ' get cell status ' ------------------------------------------------------------------------- ' Program Code ' ------------------------------------------------------------------------- Start: Display_Test: ' fill the display and clear for test FOR idxRow = 0 TO 7 ColHH(idxRow) = $FF ColHL(idxRow) = $FF ColLH(idxRow) = $FF ColLL(idxRow) = $FF NEXT DELAY 5000 FOR idxRow = 0 to 7 ColHH(idxRow) = 0 ColHL(idxRow) = 0 ColLH(idxRow) = 0 ColLL(idxRow) = 0 NEXT Randomize_Cells: ' fill the display buffer with a random initial state FOR idxRow = 0 TO 7 ColHH(idxRow) = seed ColHL(idxRow) = seed ColLH(idxRow) = seed ColLL(idxRow) = seed DELAY 5 ' let rand gen run NEXT DELAY 10 Main: Game_of_Life: FOR idxCol = 0 TO 31 FOR idxRow = 0 TO 7 COUNT_NEIGHBORS IF neighbors <= 1 THEN ' alone... dies IF idxCol <= 7 THEN newGenLL(idxRow) = CLR_BIT newGenLL(idxRow), idxCol ELSEIF idxCol <= 15 THEN colTmp = idxCol - 8 newGenLH(idxRow) = CLR_BIT newGenLH(idxRow), colTmp ELSEIF idxCol <= 23 THEN colTmp = idxCol - 16 newGenHL(idxRow) = CLR_BIT newGenHL(idxRow), colTmp ELSEIF idxCol <= 31 THEN colTmp = idxCol - 24 newGenHH(idxRow) = CLR_BIT newGenHH(idxRow), colTmp ENDIF ENDIF IF neighbors = 2 THEN ' no change IF idxCol <= 7 THEN cell = GET_BIT ColLL(idxRow), idxCol newGenLL(idxRow) = PUT_BIT newGenLL(idxRow), idxCol, cell ELSEIF idxCol <= 15 THEN colTmp = idxCol - 8 cell = GET_BIT ColLH(idxRow), colTmp newGenLH(idxRow) = PUT_BIT newGenLH(idxRow), colTmp, cell ELSEIF idxCol <= 23 THEN colTmp = idxCol - 16 cell = GET_BIT ColHL(idxRow), colTmp newGenHL(idxRow) = PUT_BIT newGenHL(idxRow), colTmp, cell ELSEIF idxCol <= 31 THEN colTmp = idxCol - 24 cell = GET_BIT ColHH(idxRow), colTmp newGenHH(idxRow) = PUT_BIT newGenHH(idxRow), colTmp, cell ENDIF ENDIF IF neighbors = 3 THEN ' lives! IF idxCol <= 7 THEN newGenLL(idxRow) = SET_BIT newGenLL(idxRow), idxCol ELSEIF idxCol <= 15 THEN colTmp = idxCol - 8 newGenLH(idxRow) = SET_BIT newGenLH(idxRow), colTmp ELSEIF idxCol <= 23 THEN colTmp = idxCol - 16 newGenHL(idxRow) = SET_BIT newGenHL(idxRow), colTmp ELSEIF idxCol <= 31 THEN colTmp = idxCol - 24 newGenHH(idxRow) = SET_BIT newGenHH(idxRow), colTmp ENDIF ENDIF IF neighbors >= 4 THEN ' crowded... dies IF idxCol <= 7 THEN newGenLL(idxRow) = CLR_BIT newGenLL(idxRow), idxCol ELSEIF idxCol <= 15 THEN colTmp = idxCol - 8 newGenLH(idxRow) = CLR_BIT newGenLH(idxRow), colTmp ELSEIF idxCol <= 23 THEN colTmp = idxCol - 16 newGenHL(idxRow) = CLR_BIT newGenHL(idxRow), colTmp ELSEIF idxCol <= 31 THEN colTmp = idxCol - 24 newGenHH(idxRow) = CLR_BIT newGenHH(idxRow), colTmp ENDIF ENDIF NEXT NEXT FOR idxRow = 0 TO 7 ' update display ColLL(idxRow) = newGenLL(idxRow) ColLH(idxRow) = newGenLH(idxRow) ColHL(idxRow) = newGenHL(idxRow) ColHH(idxRow) = newGenHH(idxRow) NEXT INC genCount DELAY 1000 ' inter-generation timing IF genCount = 150 THEN genCount = 0 Goto Randomize_Cells ENDIF GOTO Game_of_Life ' ------------------------------------------------------------------------- ' Interrupt handler ' ------------------------------------------------------------------------- INT_HANDLER: ' Disable the outputs and shift out the current row HIGH OE Anodes = row SHIFTOUT Dout, Cout, 0, ColLL(row)\8 SHIFTOUT Dout, Cout, 0, ColLH(row)\8 SHIFTOUT Dout, Cout, 0, ColHL(row)\8 SHIFTOUT Dout, Cout, 0, ColHH(row)\8 PULSOUT Latch, 1 ' Switch to the displayed row and re-enable the outputs LOW OE INC row ' point to next column in the sequence IF row = 8 THEN row = 0 ' yes, reset ENDIF Update_Timer: IF ms > 0 THEN ' delay timer running? DEC ms ' yes, decrement ENDIF LFSR: ' randomize "seed" IF seed = 0 THEN seed = 24 ENDIF ASM MOV W, #$1D CLRB C RL seed SNB C XOR seed, W ENDASM ISR_Exit: RETURNINT ' ------------------------------------------------------------------------- ' Subroutine Code ' ------------------------------------------------------------------------- ' Use: DELAY msec DELAY: IF __PARAMCNT = 1 THEN ms = __PARAM1 ' get byte parameter ELSE ms = __WPARAM12 ' get word parameter ENDIF DO ' wait for timer to expire LOOP UNTIL ms = 0 RETURN ' ------------------------------------------------------------------------- ' Use: COUNT_NEIGHBORS ' -- counts live neighbors of cell in dispBuf ' -- location of cell in idxCol/idxRow COUNT_NEIGHBORS: neighbors = 0 ' reset neighbors count chkCol = idxCol - 1 ' SW chkRow = idxRow - 1 cell = GET_CELL neighbors = neighbors + cell chkCol = idxCol - 1 ' W chkRow = idxRow + 0 cell = GET_CELL neighbors = neighbors + cell chkCol = idxCol - 1 ' NW chkRow = idxRow + 1 cell = GET_CELL neighbors = neighbors + cell chkCol = idxCol + 0 ' N chkRow = idxRow + 1 cell = GET_CELL neighbors = neighbors + cell chkCol = idxCol + 1 ' NE chkRow = idxRow + 1 cell = GET_CELL neighbors = neighbors + cell chkCol = idxCol + 1 ' E chkRow = idxRow + 0 cell = GET_CELL neighbors = neighbors + cell chkCol = idxCol + 1 ' SE chkRow = idxRow - 1 cell = GET_CELL neighbors = neighbors + cell chkCol = idxCol + 0 ' S chkRow = idxRow - 1 cell = GET_CELL neighbors = neighbors + cell RETURN ' ------------------------------------------------------------------------- ' Use: result = GET_CELL ' -- returns value of cell (0 or 1) from dispBuf array ' -- uses bound checking for "chkCol" and "chkRow" GET_CELL: tmpB1 = 0 IF chkCol >= 0 THEN IF chkCol <= 32 THEN IF chkRow >= 0 THEN IF chkRow <= 8 THEN IF chkCol <= 7 THEN tmpB1 = GET_BIT ColLL(chkRow), chkCol ELSEIF chkCol <= 15 THEN colTmp = chkCol - 8 tmpB1 = GET_BIT ColLH(chkRow), colTmp ELSEIF chkCol <= 23 THEN colTmp = chkCol - 16 tmpB1 = GET_BIT ColHL(chkRow), colTmp ELSEIF chkCol <= 31 THEN colTmp = chkCol - 24 tmpB1 = GET_BIT ColHH(chkRow), colTmp ENDIF ENDIF ENDIF ENDIF ENDIF RETURN tmpB1 ' ------------------------------------------------------------------------- ' Use: result = GET_BIT value, position ' -- returns 1 or 0 GET_BIT: tmpB1 = __PARAM1 ' save value tmpB2 = __PARAM2 ' save position tmpB2 = 1 << tmpB2 ' create mask tmpB1 = tmpB1 & tmpB2 ' isolate bit IF tmpB1 > 0 THEN tmpB1 = 1 ENDIF RETURN tmpB1 ' ------------------------------------------------------------------------- ' Use: result = SET_BIT value, position ' -- returns copy of value with position bit set SET_BIT: tmpB1 = __PARAM1 ' save value tmpB2 = __PARAM2 ' save position tmpB2 = 1 << tmpB2 ' create mask tmpB1 = tmpB1 | tmpB2 ' set the bit RETURN tmpB1 ' ------------------------------------------------------------------------- ' Use: result = CLR_BIT value, position ' -- returns value with position bit cleared CLR_BIT: tmpB1 = __PARAM1 ' save value tmpB2 = __PARAM2 ' save position tmpB2 = 1 << tmpB2 ' create mask tmpB2 = tmpB2 ^ %11111111 ' invert the mask tmpB1 = tmpB1 & tmpB2 ' clear the bit RETURN tmpB1 ' ------------------------------------------------------------------------- ' Use: result = PUT_BIT value, position, bitVal ' -- writes bitVal to value.position PUT_BIT: tmpB1 = __PARAM1 ' save value tmpB2 = __PARAM2 ' save position tmpB3 = __PARAM3.0 ' save bit value tmpB2 = 1 << tmpB2 ' create mask IF tmpB3 = 1 THEN tmpB1 = tmpB1 | tmpB2 ' set the bit ELSE tmpB2 = tmpB2 ^ %11111111 ' invert the mask tmpB1 = tmpB1 & tmpB2 ' clear the bit ENDIF RETURN tmpB1