''This is a life solver that uses 7 loops of a 32 by 3-bit adder to calculate LIFE ''on a 128x128-bit array. {{something is messed up with the boundary conditions. add code to confirm the initialization of the cardinal direction longs. (multi-long rotates may be broken)}} CON _CLKMODE = XTAL1 + PLL16X _xinfreq = 5_000_000 'reduced display for testing {lcd_p = 64 lcd_l = 32 '} 'un comment for 96x96 pixels lcd_p = 96 'pixels per line lcd_l = 48 '96 'lines in a display } 'un comment for 128x128 pixels {lcd_p = 128 'pixels per line lcd_l = 128 'lines in a display } 'calculated constants extin_freq = 2 '[Hz] lcd_longs = lcd_p*lcd_l/32 'longs to alocate for buffer. Assumes lcd_p is divisable by 32 line_longs = lcd_p/32 '#number of longs in a line. Assumes lcd_p is divisable by 32 msb_mask = |< 31 'just the MSB set OBJ 'Buttons : "Touch Buttons" pst : "Parallax Serial Terminal" 'gfx : "memory_lcd_gfx" var long seed 'long g_frame_wait pub main | temp', frame_wait ''test framework for my life solver seed := cnt '$dead_beef pst.Start(115_200) 'start up the serial cog waitcnt(cnt + clkfreq*3) 'wait for the terminal program to come up pst.str(string("128x128 game of life with torroidal BC implimented as boolean algebra")) pst.char($0d) 'new line 'gfx.start(lcd_p,lcd_l) 'start graphics cog rand_buf 'randomise starting conditions 'grower_life_array pst.str(string("randomization of life array complete")) pst.char($0d) 'new line repeat 'print life array over serial port 'g_frame_wait := frame_wait + cnt 'frame_wait := -cnt serial_life_display_fancy 'waitcnt(cnt + clkfreq) 'update life array life_generation ''g_frame_wait = 48585232 pri grower_life_array 'fill the life array with a glider longfill(@life_array,0,lcd_longs) 'clear the array life_array[0*line_longs] := %0000_0000_0000_0000__0000_0000_0001_1101 life_array[1*line_longs] := %0000_0000_0000_0000__0000_0000_0001_0000 life_array[2*line_longs] := %0000_0000_0000_0000__0000_0000_0000_0011 life_array[3*line_longs] := %0000_0000_0000_0000__0000_0000_0000_1101 life_array[4*line_longs] := %0000_0000_0000_0000__0000_0000_0001_0101 pri rand_buf | temp '' fill the frame buffer with random data repeat temp from 0 to lcd_longs-1 long[@life_array][temp] := seed? & seed? & seed? {pri serial_life_display | temp 'display the contents of life_array over the serial port repeat temp from 0 to lcd_longs-1 if not(temp//line_longs) pst.char($0d) 'new line pst.bin(life_array[temp],32) pst.clearend pst.char($0d)'new line pst.char($0d) 'extra new line } pri serial_life_display_fancy | temp, mark, space, bit, max_index mark := $2A space := $20 max_index := lcd_longs - 1 pst.home 'pst.chars($0d,5) repeat temp from 0 to max_index if not(temp//line_longs) pst.clearend pst.char($0d) bit := life_array[temp] repeat 32 if (bit <-= 1) & 1 pst.char(mark) else pst.char(space) { pst.clearend pst.char($0d) pst.str(string("g_frame_wait = ")) pst.dec(g_frame_wait) } pst.clearend pst.char($0d) pst.clearbelow {pub serial_life_dis(ptr, count) | temp 'display the contents of life_array over the serial port count-- repeat temp from 0 to count '-1'lcd_longs-1 if not(temp//line_longs) pst.char($0b) pst.char($0d) 'new line pst.bin( long[ptr][temp] {life_array[temp]},32) pst.char($0b) pst.char($0d)'new line pst.char($0b) pst.char($0d) 'extra new line } var long life_BC_start[line_longs] 'long to store boundary conditions long life_array[lcd_longs] '32x32 bit celular automata array long life_BC_end[line_longs] 'long to store boundary conditions long nw[line_longs] 'direction longs used in array update calculations long n[line_longs] 'nw n ne long ne[line_longs] 'w ct e long w[line_longs] 'sw s se long e[line_longs] long sw[line_longs] long s[line_longs] long se[line_longs] long ct[line_longs] 'space for center, at the end because it's not added to the parallel counter long s_1 'one component of a 3x32-bit parallel counter long s_2 long s_3 long carry_1 'carry variables for parallel counter long carry_2 pub life_generation | index, temp, row, col, temp2, row_ptr ''calculate the next generation of the life_array ''use a row by row boolean algebra solution with torroidal edges '' ToDo: get rid of multiplication in the array indexing '' ToDo: Make assembly bitmap drawing container object '' ToDo: translate the life solver into assembly. '' ToDo: make a census call in the graphics cog. ala http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel 'initialise row index row := 0 'fill boundary condition variables. 'longmove(@life_BC_end,@life_array,2) 'longmove(@life_BC_start,@life_array + 4*(lcd_longs - line_longs),2) repeat index from 0 to line_longs-1 life_BC_end[index] := life_array[index] life_BC_start[index] := life_array[index+lcd_longs-line_longs] 'serial_life_dis(@life_array,line_longs*5) 'serial_life_dis(@life_bc_start,line_longs) 'serial_life_dis(@life_bc_end,line_longs) 'pst.charin 'initial fill of direction variables (complicated by lack of flag access in spin) 'nw n ne (row-1) 'w ct e (row) 'sw w se (row+1) 'nw := life_bc_start -> 1 repeat index from 0 to line_longs-1 nw[index] := life_bc_start[index] >> 1 if (index-1) < 0 nw[index] |= (life_bc_start[line_longs-1] & 1) -> 1 else nw[index] |= (life_bc_start[index-1] & 1) -> 1 'n := life_bc_start repeat index from 0 to line_longs-1 n[index] := life_bc_start[index] 'ne := life_bc_start <- 1 repeat index from 0 to line_longs-1 ne[index] := life_bc_start[index] << 1 if (index+1) => line_longs ne[index] |= (life_bc_start[0] & msb_mask) <- 1 else ne[index] |= (life_bc_start[index+1] & msb_mask) <- 1 'w := life_array[0] -> 1 repeat index from 0 to line_longs-1 w[index] := life_array[index] >> 1 if (index-1) < 0 w[index] |= (life_array[line_longs-1] & 1) -> 1 else w[index] |= (life_array[index-1] & 1) -> 1 'ct := life_array[0] repeat index from 0 to line_longs-1 ct[index] := life_array[index] 'e := life_array[0] <- 1 repeat index from 0 to line_longs-1 e[index] := life_array[index] << 1 if (index+1) => line_longs e[index] |= (life_array[0] & msb_mask) <- 1 else e[index] |= (life_array[index+1] & msb_mask) <- 1 'sw := life_array[1] -> 1 repeat index from 0 to line_longs-1 sw[index] := life_array[1*line_longs + index] >> 1 if (index-1) < 0 sw[index] |= (life_array[1*line_longs + line_longs-1] & 1) -> 1 else sw[index] |= (life_array[1*line_longs + index-1] & 1) -> 1 's := life_array[1] repeat index from 0 to line_longs-1 s[index] := life_array[1*line_longs + index] 'se := life_array[1] <- 1 repeat index from 0 to line_longs-1 se[index] := life_array[1*line_longs + index] << 1 if (index+1) => line_longs se[index] |= (life_array[1*line_longs + 0] & msb_mask) <- 1 else se[index] |= (life_array[1*line_longs + index+1] & msb_mask) <- 1 'serial_life_dis(@nw, line_longs*9) 'display initial line buffers 'pst.charin 'wait for any key row_ptr := @life_array repeat repeat col from 0 to line_longs-1 'count the number of neighbors for each cell one row at a time with a 3-bit x 32 parallel counter. 'uses direction and counter variables only. s_2 := s_3 := 0 'clear counting variables. 's_1 := nw[col] 'preload first position to count s_1 := long[@nw + col<<2] temp2 := @n + col<<2 repeat index from 0 to 6 temp := long[temp2] 'temp := long[@n][index*line_longs+col] carry_1 := temp & s_1 s_1 ^= temp carry_2 := carry_1 & s_2 s_2 ^= carry_1 s_3 ^= carry_2 temp2 += constant(line_longs*4) 'calculate the population of the next generation of this row and write it back to the life_array 'life_array[row*line_longs + col] := s_2 & !S_3 & (s_1 | ct[col]) temp2 := row_ptr + col<<2 long[temp2] := s_2 & !S_3 & (s_1 | long[@ct + col<<2]) 'shift to next row or exit if done row := row + 1 row_ptr += line_longs << 2 if row => lcd_l 'if row is past the end of the array quit 'jump out of the loop repeat col from 0 to line_longs-1 nw[col] := w[col] n[col] := ct[col] ne[col] := e[col] w[col] := sw[col] ct[col] := s[col] e[col] := se[col] 'sw := life_array[row+1] -> 1 repeat index from 0 to line_longs-1 sw[index] := life_array[(row+1)*line_longs + index] >> 1 if (index-1) < 0 sw[index] |= (life_array[(row+1)*line_longs + line_longs-1] & 1) -> 1 else sw[index] |= (life_array[(row+1)*line_longs + index-1] & 1) -> 1 's := life_array[row+1] repeat index from 0 to line_longs-1 s[index] := life_array[(row+1)*line_longs + index] 'se := life_array[row+1] <- 1 repeat index from 0 to line_longs-1 se[index] := life_array[(row+1)*line_longs + index] << 1 if (index+1) => line_longs se[index] |= (life_array[(row+1)*line_longs + 0] & msb_mask) <- 1 else se[index] |= (life_array[(row+1)*line_longs + index+1] & msb_mask) <- 1