home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume30 / life / part01 < prev    next >
Encoding:
Text File  |  1992-06-20  |  11.2 KB  |  340 lines

  1. Newsgroups: comp.sources.misc
  2. From: hatch@math.berkeley.edu (Don Hatch)
  3. Subject:  v30i078:  life - fast pixel-level life for b&w Sun screen, Part01/01
  4. Message-ID: <1992Jun21.041824.3808@sparky.imd.sterling.com>
  5. X-Md4-Signature: 9ce19ce6fec727dbfebadc6a2fcf9e8e
  6. Date: Sun, 21 Jun 1992 04:18:24 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: hatch@math.berkeley.edu (Don Hatch)
  10. Posting-number: Volume 30, Issue 78
  11. Archive-name: life/part01
  12. Environment: SUNOS
  13.  
  14. Conway's game of life on a torus, for a black&white Sun screen (/dev/bwtwo0).
  15. Uses a very clever method of calculating 32 positions at once.
  16. I don't know who invented it, but Lew Hitchner gave it as an assignment
  17. in his Computer Architecture course at UCSC.
  18. I optimized it as much as I could, so even I don't understand it any more.
  19.  
  20. On a sparc (compiled with -O) it gives about 6.8 frames per second
  21. full screen, and proportionately faster on smaller regions.
  22.  
  23. :================================ CUT HERE ====================================
  24. : This is a shell archive.  Remove anything before this line, then unpack
  25. : it by saving it into a file and typing "sh file".  To overwrite
  26. : existing files, type "sh file -c".  If this archive is complete, you
  27. : will see the following message at the end:
  28. :               "End of shell archive."
  29. : Contents:
  30. :     life.c
  31. : Archive created Mon Jun 15 03:39:05 PDT 1992  by  hatch@beirut.berkeley.edu
  32.  
  33. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  34. if test -f life.c -a "${1}" != "-c" ; then 
  35.   echo shar: Will not clobber existing file \"life.c\"
  36. else
  37. echo x - life.c
  38. sed 's/^X//' > life.c <<'+END+OF+life.c'
  39. X/*
  40. X * life.c
  41. X *
  42. X * Conway's game of life on a torus, for a black&white Sun screen (/dev/bwtwo0).
  43. X * Uses a very clever method of calculating 32 positions at once.
  44. X * I don't know who invented it, but Lew Hitchner gave it as an assignment
  45. X * in his Computer Architecture course at UCSC.
  46. X * I optimized it as much as I could, so even I don't understand it any more.
  47. X *
  48. X * On a sparc (compiled with -O) it gives about 6.8 frames per second
  49. X * full screen, and proportionately faster on smaller regions.
  50. X *
  51. X * Usage: life [-i] [<x> <y> <w> <h>]
  52. X *    x is rounded down to a multiple of 32,
  53. X *    w is rounded up to a multiple of 32.
  54. X *    Default is the full screen.
  55. X *
  56. X * The -i option makes it incorporate externally generated screen changes
  57. X * (such as cursor movement and clock refreshes) into the calculations,
  58. X * but it runs about half as fast.
  59. X * 
  60. X * Environment options:
  61. X *      LIFETIMES --    If set and nonnegative, program exits after
  62. X *                      this many generations
  63. X *      LIFE_USEC --    If set and positive, the program pauses between
  64. X *                      generations if necessary so that each generation
  65. X *                      takes at least this many microseconds
  66. X *      LIFE_FB --      Name of frame buffer device (default is /dev/bwtwo0)
  67. X *      LIFE_OFF --     Offset into frame buffer device (default is 0)
  68. X *
  69. X * Compiling notes:
  70. X *      Default is white life on black background, assuming the frame buffer
  71. X *      uses 1 for black and 0 for white.
  72. X *      If you want it to be black on white, xor your frame buffer
  73. X *      does it the opposite way,
  74. X *      compile with: (cut and paste the following line)
  75. X                cc -O -DBLACK_ON_WHITE life.c -o life
  76. X *      otherwise just say
  77. X                cc -O life.c -o life
  78. X *
  79. X * Author: Don Hatch (hatch@math.berkeley.edu)
  80. X * Last modified: Mon Jun  8 17:01:13 PDT 1992
  81. X *
  82. X * This program may be distributed freely.
  83. X * If you like it, please send me money or give me a job.
  84. X * Comments and suggestions are welcome regardless.
  85. X */
  86. X
  87. X#include <stdio.h>
  88. X#include <stdlib.h>
  89. X#include <signal.h>
  90. X#include <sys/time.h>
  91. X#include <sys/mman.h>
  92. X#include <fcntl.h>
  93. X#include <pixrect/pixrect_hs.h>
  94. X
  95. X#define SIZEX BW2SIZEX
  96. X#define SIZEY BW2SIZEY
  97. X
  98. X#define LIFE_FB "/dev/bwtwo0"
  99. X
  100. X
  101. X#define ADD21(B1,B0, x) \
  102. X       (carry = (x), \
  103. X        B0 ^= carry, \
  104. X        carry &=~ B0, \
  105. X        B1 ^= carry)
  106. X#define ADD31(B2,B1,B0, x) \
  107. X       (ADD21(B1,B0, x), \
  108. X        carry &=~ B1, \
  109. X        B2 ^= carry)
  110. X#define ADD32(B2,B1,B0, X1,X0) \
  111. X       (ADD21(B2,B1, X1), \
  112. X        ADD31(B2,B1,B0, X0))
  113. X
  114. X#ifdef BLACK_ON_WHITE
  115. X#define RESULT(B2,B1,B0,self) (((B2)^(B1)) & ((B2)^(B0)) & ((B0)|(self)))
  116. X#else
  117. X#define RESULT(B2,B1,B0,self) (~(B2) | (~(B1)^(B0)) | (~(B1) & (self)))
  118. X#endif
  119. X
  120. X#define SET21(T1,T0, F0)        SET22(T1,T0, 0, F0)
  121. X#define SET22(T1,T0, F1,F0)     ((T1)=(F1), (T0)=(F0))
  122. X#define SET32(T2,T1,T0, F1,F0)  ((T2)=0, (T1)=(F1), (T0)=(F0))
  123. X#define SUMleftmidright(B1,B0, l,m,r) \
  124. X       (SET21(B1,B0, tmp=(m)), \
  125. X        ADD21(B1,B0, (tmp>>1)|((l)<<31)), \
  126. X        ADD21(B1,B0, (tmp<<1)|((r)>>31)))
  127. X
  128. X#define SWAP(a,b) {u_int (*_temp_)[SIZEX/32] = (a); (a) = (b); (b) = _temp_;}
  129. X            
  130. X            
  131. X
  132. X
  133. X/* VARARGS */
  134. Xlife(src, dst, h, w, i, j)
  135. Xu_int src[][SIZEX/32];
  136. Xregister u_int dst[][SIZEX/32];
  137. Xregister int h, w;
  138. Xregister int i, j;              /* really local variables */
  139. X{
  140. X    register u_int SUM2,SUM1,SUM0,carry, tmp;
  141. X    register u_int *rightcol, *leftcol, *midcol;
  142. X
  143. X    /*
  144. X     * These probably won't get registers, but that's okay
  145. X     */
  146. X    register u_int BOT1,BOT0;
  147. X    register u_int MID1,MID0;
  148. X    register u_int TOP1,TOP0;
  149. X    register u_int VERYTOP1,VERYTOP0;
  150. X
  151. X    for (j = 0; j < w; ++j) {
  152. X        leftcol =  &src[h-1][(j-1+w)%w];
  153. X        midcol =   &src[h-1][j];
  154. X        rightcol = &src[h-1][(j+1)%w];
  155. X        SUMleftmidright(SUM1,SUM0, *leftcol, *midcol, *rightcol);
  156. X        SET22(TOP1, TOP0, SUM1, SUM0);
  157. X        leftcol =  &src[0][(j-1+w)%w];
  158. X        midcol =   &src[0][j];
  159. X        rightcol = &src[0][(j+1)%w];
  160. X        SUMleftmidright(SUM1,SUM0, *leftcol, *midcol, *rightcol);
  161. X        SET22(MID1, MID0, VERYTOP1=SUM1, VERYTOP0=SUM0);
  162. X        for (i = 0; i < h-1; ++i) {
  163. X            leftcol += SIZEX/32;
  164. X            midcol += SIZEX/32;
  165. X            rightcol += SIZEX/32;
  166. X            SUMleftmidright(SUM1,SUM0, *leftcol, *midcol, *rightcol);
  167. X            SET22(BOT1, BOT0, SUM1, SUM0);
  168. X            SUM2=0;
  169. X            ADD32(SUM2,SUM1,SUM0, MID1, MID0);
  170. X            ADD32(SUM2,SUM1,SUM0, TOP1, TOP0);
  171. X            dst[i][j] = RESULT(SUM2,SUM1,SUM0, src[i][j]);
  172. X            SET22(TOP1,TOP0, MID1,MID0);
  173. X            SET22(MID1,MID0, BOT1,BOT0);
  174. X        }
  175. X        SET32(SUM2,SUM1,SUM0, VERYTOP1,VERYTOP0);
  176. X        ADD32(SUM2,SUM1,SUM0, MID1, MID0);
  177. X        ADD32(SUM2,SUM1,SUM0, TOP1, TOP0);
  178. X        dst[i][j] = RESULT(SUM2,SUM1,SUM0, src[i][j]);
  179. X    }
  180. X}
  181. X
  182. X/* VARARGS */
  183. Xcopy(src, dst, h, w)
  184. Xregister u_int src[][SIZEX/32];
  185. Xregister u_int dst[][SIZEX/32];
  186. Xregister int h, w;
  187. X{
  188. X    register int i, j;
  189. X    for (i = 0; i < h; ++i) {
  190. X        for (j = 0; j < w; ++j) {
  191. X            dst[0][j] = src[0][j];
  192. X        }
  193. X        src++;
  194. X        dst++;
  195. X    }
  196. X}
  197. X
  198. Xvoid ring()
  199. X{
  200. X}
  201. X
  202. Xmain(argc, argv)
  203. Xchar **argv;
  204. X{
  205. X    int argi;
  206. X    u_int (*screen)[SIZEX/32], (*next)[SIZEX/32], (*prev)[SIZEX/32];
  207. X    int x=0, y=0, w=SIZEX, h=SIZEY;
  208. X    int interactive = 0;
  209. X    int usec = 0;
  210. X    int times=-1;
  211. X    int fd;
  212. X    char *fbname = LIFE_FB;
  213. X    if (getenv("LIFE_FB"))
  214. X        fbname = getenv("LIFE_FB");
  215. X
  216. X    for (argi = 1; argi < argc; ++argi) {
  217. X        if (!strcmp(argv[argi], "-i"))
  218. X            interactive = 1;
  219. X        else if (argi+3 < argc) {
  220. X            x = atoi(argv[argi++]);
  221. X            y = atoi(argv[argi++]);
  222. X            w = atoi(argv[argi++]);
  223. X            h = atoi(argv[argi]);
  224. X        } else {
  225. X            (void) fprintf(stderr, "Usage: %s [-i] [<x> <y> <w> <h>]\n",
  226. X                                           argv[0]);
  227. X            exit(1);
  228. X        }
  229. X    }
  230. X
  231. X    /*
  232. X     * From the user's perspective, x is rounded down to a multiple of 32
  233. X     * and w is rounded up to a multiple of 32.
  234. X     */
  235. X    x = x / 32;
  236. X    w = howmany(w, 32);
  237. X
  238. X    if (w > SIZEX/32-x)
  239. X        w = SIZEX/32-x;
  240. X    if (h > SIZEY-y)
  241. X        h = SIZEY-y;
  242. X
  243. X
  244. X    if (getenv("LIFETIMES"))
  245. X        times = atoi(getenv("LIFETIMES"));
  246. X    if (getenv("LIFE_USEC"))
  247. X        usec = atoi(getenv("LIFE_USEC"));
  248. X        
  249. X    /*
  250. X     * Get the frame buffer as a chunk of memory.
  251. X     * This could also be done by:
  252. X     *          screen = (int (*)[SIZEX/32])(mpr_d(pr)->md_image);
  253. X     * where pr is a pixrect referring to the screen.
  254. X     * But then you'd have to link with -lpixrect, producing
  255. X     * a needlessly big executable...
  256. X     */
  257. X    if ((fd = open(fbname, O_RDWR)) == -1)
  258. X        perror(fbname), exit(1);
  259. X    screen = (u_int (*)[SIZEX/32])mmap((caddr_t)NULL,
  260. X                    SIZEY*sizeof(*screen),
  261. X                    PROT_READ|PROT_WRITE, MAP_SHARED, fd,
  262. X                    (off_t) (getenv("LIFE_OFF") ? atoi(getenv("LIFE_OFF")) :0));
  263. X    if ((int)screen == -1)
  264. X        perror("mmap"), exit(1);
  265. X    (void) close(fd);
  266. X
  267. X
  268. X    next = (u_int (*)[SIZEX/32])malloc(SIZEY * SIZEX/32 * sizeof(int));
  269. X    if (!next)
  270. X        perror("malloc"), exit(1);
  271. X    if (!interactive) {
  272. X        prev = (u_int (*)[SIZEX/32])malloc(SIZEY * SIZEX/32 * sizeof(int));
  273. X        if (!prev)
  274. X            perror("malloc"), exit(1);
  275. X    } else
  276. X        prev = 0;
  277. X
  278. X    (void) signal(SIGALRM, ring);
  279. X
  280. X    if (prev)
  281. X        copy(&screen[y][x], &prev[y][x], h, w);
  282. X
  283. X    while (times--) {
  284. X        if (usec) {
  285. X            struct itimerval it, oit;
  286. X            timerclear(&it.it_interval);
  287. X            timerclear(&it.it_value);
  288. X            it.it_value.tv_sec = usec / 1000000;
  289. X            it.it_value.tv_usec = usec % 1000000;
  290. X            (void) sigblock(sigmask(SIGALRM));
  291. X            if (setitimer(ITIMER_REAL, &it, &oit) < 0)
  292. X                perror("setitimer"), exit(1);;
  293. X        }
  294. X        if (interactive) {
  295. X            /*
  296. X             * "Interactive" mode.
  297. X             * Calculate new generation into back buffer from screen,
  298. X             * then copy back buffer to screen.
  299. X             * This is slow, since accessing the frame buffer is
  300. X             * slower than accessing "normal" memory.
  301. X             * .306 seconds/screen on a sparc
  302. X             */
  303. X            life(&screen[y][x], &next[y][x], h, w);
  304. X            copy(&next[y][x], &screen[y][x], h, w);
  305. X        } else {
  306. X            /*
  307. X             * This is the fastest mode, and is the default.
  308. X             * it calculates the new generations using only
  309. X             * the "prev" and "next" arrays, which
  310. X             * seems to be faster than accessing the frame buffer
  311. X             * memory directly.  The disadvantage is that there
  312. X             * can be no input except what is on the screen
  313. X             * at startup.
  314. X             * (Sometimes it is fun to let it run on top of a clock
  315. X             * or to violate the prime directive with the mouse.)
  316. X             * Also this mode uses an extra screen-sized chunk of memory.
  317. X             * .148 seconds/screen on a sparc
  318. X             */
  319. X            life(&prev[y][x], &next[y][x], h, w);
  320. X            copy(&next[y][x], &screen[y][x], h, w);
  321. X            SWAP(prev, next);
  322. X        }
  323. X        if (usec)
  324. X            (void) sigpause(0);
  325. X    }
  326. X    return 0;
  327. X}
  328. +END+OF+life.c
  329. echo '-rw-------  1 hatch        9288 Jun 15 03:38 life.c    (as sent)'
  330. chmod u=rw,g=,o= life.c
  331. ls -ldo life.c
  332. if test 9288 -ne `wc -c <life.c` ; then 
  333.   echo shar: \"life.c\" unpacked with wrong size!
  334. fi
  335. fi
  336. echo shar: End of shell archive.
  337. exit 0
  338.  
  339. exit 0 # Just in case...
  340.