[net.sources.games] Fast life program for Atari ST

jsgray@watrose.UUCP (03/01/87)

Here is a fast (400,000 cell-generations/s) life program for monochrome
Atari-ST computers (which should port easily to other 68000 machines).

It animates all 240,000 pixels on the screen.  Feel free to add a
better user-interface!

But how does it go so fast?  It sums the neighbours of 32 cells in one
pass, by synthesizing addition instructions out of logical operators.

The rest of this file is a shar containing
	life.c		- mainline
	gen.s		- quickly compute next generation
	life.uue	- uuencoded life.prg (Atari ST only)

Have fun!

Jan Gray    jsgray@watrose    University of Waterloo    (519) 885-1211 x3870

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by watrose!jsgray on Sun Mar  1 11:29:07 EST 1987
# Contents:  life.c gen.s life.uue
 
echo x - life.c
sed 's/^@//' > "life.c" <<'@//E*O*F life.c//'
/*
 * Fast monochrome life for Atari ST.
 *
 * Written by
 *   Jan Gray
 *   300 Regina St. N Apt. 2-905
 *   Waterloo, Ontario
 *   N2J 4H2
 *   Canada
 *   (jsgray@watrose.UUCP)
 *
 * Copyright (C) 1987 Jan Gray.
 * This program may be freely redistributed if this notice is retained.
 */

#include "define.h"
#include "osbind.h"

#define	MAXX		640
#define	MAXY		400
#define	BPL		32

#define	ROW_LONGS	(MAXX / BPL)
#define SCREEN_LONGS	(ROW_LONGS * MAXY)

long	*Screen;
long	NextScreen[SCREEN_LONGS];

main()
{
	Screen = (long *)Physbase();

	while (!Cconis()) {			/* until key press... */
		clearBorders();
		gen();
		copyScreen();
	}
}


copyScreen()
{
	register long	*p;
	register long	*q;

	for (p = NextScreen, q = Screen; p < &NextScreen[SCREEN_LONGS]; ) {
		*q++ = *p++;
		*q++ = *p++;
		*q++ = *p++;
		*q++ = *p++;
	}
}

clearBorders()
{
	register long	*p;

	for (p = Screen; p < &Screen[ROW_LONGS]; p++)
		*p = 0L;

	for (p = &Screen[(MAXY - 1) * ROW_LONGS]; p < &Screen[MAXY * ROW_LONGS]; p++)
		*p = 0L;

	for (p = Screen; p < &Screen[SCREEN_LONGS]; p += ROW_LONGS)
		*p &= ~0x80000000L;

	for (p = &Screen[ROW_LONGS-1]; p < &Screen[SCREEN_LONGS]; p += ROW_LONGS)
		*p &= ~1L;
}
@//E*O*F life.c//
chmod u=rw,g=rw,o=r life.c
 
echo x - gen.s
sed 's/^@//' > "gen.s" <<'@//E*O*F gen.s//'
*
* Fast monochrome life for Atari ST.
*
* Written by
*   Jan Gray
*   300 Regina St. N Apt. 2-905
*   Waterloo, Ontario
*   N2J 4H2
*   Canada
*   (jsgray@watrose.UUCP)
*
* Copyright (C) 1987 Jan Gray.
* This program may be freely redistributed if this notice is retained.
*

*
* gen -- compute the next generation of cells
*
* This code is a transliteration of the the pdp-11 code presented in
* "Life Algorithms" by Mark Niemiec, Byte, 4:1, January 1979.
*
* gen currently does about 400,000 cell-generations/second.  It can go faster.
*
* Forgive the hardwired-in constants, and the terse comments.  It's a hack.
* Think of the fun you'll have figuring out how it works.
*
@.globl _gen
@.text
_gen:
	movem.l	d0-d7/a0-a2,-(sp)

	move.l	_Screen,a0
	move.l	a0,a2
	add.l	#80,a0
	add.l	#31920,a2
	move.l	#_NextScreen+80,a1

* 1 2 3
* 7 * 8
* 4 5 6

* (d1,d0) = neighbours 1+2
again:
	move.l	-80(a0),d0
	move.l	d0,d1
	move.l	d0,d2
	move.b	-81(a0),d7
	roxr.b	#1,d7
	roxr.l	#1,d0
	eor.l	d1,d0
	or.l	d0,d1
	eor.l	d0,d1

* (d1,d0) = neighbours 1+2+3

	move.b	-76(a0),d7
	roxl.b	#1,d7
	roxl.l	#1,d2
	eor.l	d2,d0
	or.l	d0,d2
	eor.l	d0,d2
	or.l	d2,d1

* (d3,d2) = neighbours 4+5

	move.l	80(a0),d2
	move.l	d2,d3
	move.l	d2,d4
	move.b	79(a0),d7
	roxr.b	#1,d7
	roxr.l	#1,d2
	eor.l	d3,d2
	or.l	d2,d3
	eor.l	d2,d3

* (d3,d2) = neighbours 4+5+6

	move.b	84(a0),d7
	roxl.b	#1,d7
	roxl.l	#1,d4
	eor.l	d4,d2
	or.l	d2,d4
	eor.l	d2,d4
	or.l	d4,d3

* (d2,d1,d0) = neighbours 1+2+3+4+5+6

	eor.l	d2,d0
	or.l	d0,d2
	eor.l	d0,d2
	eor.l	d2,d1
	or.l	d1,d2
	eor.l	d1,d2
	eor.l	d3,d1
	or.l	d1,d3
	eor.l	d1,d3
	or.l	d3,d2

* (d4,d3) = neighbours 7+8

	move.l	(a0),d3
	move.l	d3,d4
	move.b	-1(a0),d7
	roxr.b	#1,d7
	roxr.l	#1,d3
	move.b 	4(a0),d7
	roxl.b	#1,d7
	roxl.l	#1,d4
	eor.l	d4,d3
	or.l	d3,d4
	eor.l	d3,d4

* (d2,d1,d0) = neighbours 1+2+3+4+5+6+7+8

	eor.l	d3,d0
	or.l	d0,d3
	eor.l	d0,d3
	eor.l	d3,d1
	or.l	d1,d3
	eor.l	d1,d3
	eor.l	d4,d1
	or.l	d1,d4
	eor.l	d1,d4
	or.l	d3,d2
	or.l	d4,d2

* next generation

	or.l	(a0)+,d0
	not.l	d2
	and.l	d2,d0
	and.l	d1,d0
	move.l	d0,(a1)+

	cmp.l	a2,a0
	blt	again
	movem.l	(sp)+,d0-d7/a0-a2
	rts
@//E*O*F gen.s//
chmod u=rw,g=rw,o=r gen.s
 
echo x - life.uue
sed 's/^@//' > "life.uue" <<'@//E*O*F life.uue//'
begin 664 life.prg
M8!H   )"   !7   C*P                  "I/+GP  !,^*FT !" M  S0
MK0 4T*T '-"\   ! "\ +PT_ #\\ $I.0=_\    #$ZY    2B\\     $Y!
M(B\ !# \ ,A.0DYU3E;__#Z\  ).N0   A(CP   D$9A3F *3KD   %.811A
M0CZ\  M.N0   C)*0&?H3EY.=4Y6  !(YP$,*GP  !-&*'D  )!&8 @HW2C=
M*-THW;O\  "01F7P2I],WS  3EY.=4Y6  !(YP$$*GD  )!&8 1"E5B-(#D 
M )!&T+P   !0N\!E["IY  "01MO\  !\L& $0I58C2 Y  "01M"\  !] +O 
M9>PJ>0  D$9@#B \?____\&5V_P   !0(#D  )!&T+P  'T N\!EXBIY  "0
M1MO\    3& , I7____^V_P   !0(#D  )!&T+P  'T N\!EY$J?3-\@ $Y>
M3G5(Y__@('D  )!&)$C1_    %#5_   ?+ B?   $Y8@*/^P(@ D !XH_Z_B
M%^*0LX""@+&!'BC_M.,7XY*U@(2 L8*"@B0H % F B@"'B@ 3^(7XI*W@H:"
MM8,>* !4XQ?CE+F"B(*UA(:$M8"$@+&"M8&$@;."MX&&@;.#A(,F$"@#'BC_
M_^(7XI,>*  $XQ?CE+F#B(.WA+> AH"Q@[>!AH&S@[F!B(&SA(2#A(2 F$:"
MP(+ @2+ L<IM /]B3-\'_TYU(]\  !-"3DXO.0  $T).=2/?   30DY-+SD 
M !-"3G4CWP  $T).02\Y   30DYU  $  @$! @$!  $! @$! 0$!        
M      $   $  P4 !04   $! @$ $ <! @$              0$! @$! @$!
M @$! 0$" 0$!                 @$! 0$!!@$!! $! 0,! @$!! (!" $!
M         0$!"0$! 0$! 0$   4!                                
M                            ! , " , !@$ " $ " $ ! $! P$!  4 
M 0$!  4   $!  $!                                  ("        
M                            !0$ !0$  0$  0$  @4 !@$  @$  0$ 
M!@4       $!  $  @$  @$! 0$!                      $" P$" 0$!
F 0$!  $!  $"    !"XB!@H.%@80&@P0$A 6$!H>%*P(" @("  "
 
end
@//E*O*F life.uue//
chmod u=rw,g=rw,o=r life.uue
 
echo Inspecting for damage in transit...
temp=/tmp/shar$$; dtemp=/tmp/.shar$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
      69     192    1192 life.c
     138     336    2108 gen.s
      25     185    1381 life.uue
     232     713    4681 total
!!!
wc  life.c gen.s life.uue | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if [ -s $dtemp ]
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
exit 0