{"id":15,"date":"2022-07-25T13:20:50","date_gmt":"2022-07-25T18:20:50","guid":{"rendered":"https:\/\/fortycreek.org\/?p=15"},"modified":"2022-07-25T13:20:50","modified_gmt":"2022-07-25T18:20:50","slug":"conways-life-on-z80","status":"publish","type":"post","link":"https:\/\/fortycreek.org\/index.php\/2022\/07\/25\/conways-life-on-z80\/","title":{"rendered":"Conway&#8217;s Life on z80"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<p>I have not coded Conway&#8217;s life in many years &#8211; I thought it would be fun to try on the Z80.  First I implemented it in C on the Raspberry Pi.  It uses an array to both keep track of prior generations (to determine if the pattern is still evolving) and the same array to figure out the neighbour count.  <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;time.h>\n#include &lt;stdlib.h>\n#include &lt;stdio.h>\n\nunsigned char *grid;\nconst int rows=48, cols=160, maxt=3;\nint same;\n\nvoid* calc_grid(int *t) {\nint i, j, q;\n    for (i=rows+rows-*t*rows\/maxt-1; i>=rows+rows-(*t+1)*rows\/maxt; i--) {\n        for (j=cols+cols-1; j>=cols; j--) {\n\n            if ( (grid&#91;(i-rows)*cols+j-cols] &amp; 64) ) { \/* for each cell that is alive, add 1 to all the neighbours in every (8) adjacent cell *\/\n                grid&#91;((i-1) % rows)*cols + (j-1) % cols] += 1;\n                grid&#91;((i-1) % rows)*cols + (j  ) % cols] += 1;\n                grid&#91;((i-1) % rows)*cols + (j+1) % cols] += 1;\n                grid&#91;((i  ) % rows)*cols + (j-1) % cols] += 1;\n                grid&#91;((i  ) % rows)*cols + (j+1) % cols] += 1;\n                grid&#91;((i+1) % rows)*cols + (j-1) % cols] += 1;\n                grid&#91;((i+1) % rows)*cols + (j  ) % cols] += 1;\n                grid&#91;((i+1) % rows)*cols + (j+1) % cols] += 1;\n            }\n        }\n    }\n\n}\nvoid* shift_grid(int *t) {\n        int i, j;\n        for (i=*t*rows\/maxt; i&lt;(*t+1)*rows\/maxt; i++) {\n            for (j=0; j&lt;cols; j++) {  \/* for every cell take the 7th bit and the lower 4 bits (total) - empty cell =3  - live cell = 64+2 or 64+3 - then mark the 8th bit as live for next gen*\/\n                if ((grid&#91;i*cols+j] &amp; 79) == 3 || (grid&#91;i*cols+j] &amp; 79) == 66 || (grid&#91;i*cols+j] &amp; 79) == 67)   grid&#91;i*cols+j] |= 128;\n                grid&#91;i*cols+j] = (grid&#91;i*cols+j] >> 1) &amp; 240;   \/* shift to the right one bit, and keep the top 4 bits 128+64+32+16 to see what was going on in prior gens  *\/\n                if ( same == 1 &amp;&amp; ((grid&#91;i*cols+j] &amp; 64)>>2) != (grid&#91;i*cols+j] &amp; 16) )  \/* compare the 7th bit to the 5th bit- if those are not the same, then the pattern is changing *\/\n                    same=0;\n            }\n        }\n}\n\nint main() {\n\n    time_t qt;\n    srand((unsigned) time(&amp;qt));\n\n    pthread_t thr&#91;maxt];\n\n    int c, x, y, i, j, gen, t, rc;\n\n    grid = malloc(rows*cols*sizeof(char));\n\nfor ( c=0; c&lt;1000; c++) {\n\/\/    printf(\"Try: %d\\n\", c);\n    for (i=0; i&lt;rows; i++)\n        for (j=0; j&lt;cols; j++)\n            grid&#91;i*cols+j] = 64 * (rand() % 2);  \/*  initialize the array with random numbers in the 7th bit *\/\n\n    for (gen=0; gen&lt;20000; gen++) {\n        for (t=0; t&lt;maxt; t++) {\n                calc_grid(&amp;t);\n        }\n\n        same=1;\n        for (t=0; t&lt;maxt; t++) {\n                shift_grid(&amp;t);\n        }\n        \/\/if (same==1) break;\n        printf(\"Gen: %d\\n\", gen );\n    for (i=0; i&lt;rows; i++) {\n        for (j=0; j&lt;cols; j++)\n         putc( (grid&#91;i*cols+j] &amp; 64 ) ? '*': ' ', stdout);\n        putc('\\n', stdout);\n        }\n        getc(stdin);\n    }\n    }\n\/*  print out survivor *\/\n        printf(\"Gen: %d\\n\", gen );\n    for (i=0; i&lt;rows; i++) {\n        for (j=0; j&lt;cols; j++)\n         putc( (grid&#91;i*cols+j] &amp; 64 ) ? '*': ' ', stdout);\n        putc('\\n', stdout);\n        }\n\n    free(grid);\n}\n<\/code><\/pre>\n\n\n\n<p>I&#8217;ve made it very similar on the z80 in terms of the algorithm that is implemented.  The grid it uses is smaller.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>        org     0100h\n\n        ; to do a given cell, we need to do IX-1, IX+1, IX-81, IX-80, IX-79, IX+79, IX+80, IX+81\n        ; board is 78x24 with an extra space all around so 80x26  - 2080 elements\n        ld a,0ffh    ; do at most 255 generations\ntop:    push af\n        ld hl,c_home\n        call my_write_string\n        call print_board\n        call calc_n\n        call calc_g\n        pop af\n        dec a\n        jr nz,top\n        ld hl,c_home\n        call my_write_string\n        call print_board\n\n        ret\ncalc_g:         ; calculate the next generation\n        ld de, board\ncalc_g_loop:\n        ld b, 080h\n        ld a,(de)\n        ld c,a\n        and b\n        jr z,no_128\n        ld (de),a\n        jr end_calc_g\n\nno_128: ; continue with calcs\n        ld a,c\n        ld b,79\n        and b\n        ld b,3\n        cp b\n        jr z, set_128\n        ld b,66\n        cp b\n        jr z, set_128\n        ld b,67\n        cp b\n        jr z, set_128\n        ld a,c\n        jr shift_mask\nset_128:\n        ld a,c\n        ld b,128\n        or b\nshift_mask:\n        ld b,224\n        and b\n        srl a\n        ld (de), a\nend_calc_g:\n        inc de\n        ld hl,b_done\n        sbc hl,de\n        ret z\n        jr calc_g_loop\n\ncalc_n:\n        ld ix, board\n        ld de, board\n        ld c,040h\n        ld b,080h\ncalc_n_loop:\n        ld a,(ix+0)\n        and b\n        jr nz,calc_x    ; found a 128 - skip calc\n        ld a,(ix+0)\n        and c\n        jr z,calc_x     ; only increment if its currently alive\n        inc (ix-1)\n        inc (ix+1)\n        inc (ix-79)\n        inc (ix-80)\n        inc (ix-81)\n        inc (ix+79)\n        inc (ix+80)\n        inc (ix+81)\ncalc_x: inc ix\n        inc de\n        ld hl,b_done\n        sbc hl,de\n        ret z\n        jr calc_n_loop\n\n        ; print_board:  routine to print out board - uses a, bc, de, hl\nprint_board:\n        ld de, board\nprint_nl:\n        ld c, 00h\nprint_loop:\n        ld a,(de)\n        ld b,040h\n        and b\n        jr z,space_char\n        ld b,'@'\n        jr end_char\nspace_char:\n        ld b,' '\nend_char:\n        call my_write_char\n        inc de\n        inc c\n        ld a,80\n        sub c\n        jr nz,print_loop\n        ld hl,crlf\n        call my_write_string\n        ld hl,b_done\n        sbc hl,de\n        ret z\n        jr print_nl\n        ; puts a single char (byte value) on serial output\n        ; call with char to send in B register; also uses A register\nmy_write_char:\n        in a,(3)\n        and 001h\n        jp z, my_write_char\n        ld a,b\n        out (2),a\n        ret\nmy_write_string:\n        in a,(3)\n        and 001h\n        jr z,my_write_string\n        ld a,(hl)\n        and a\n        ret z\n        out (2),a\n        inc hl\n        jr my_write_string\n\ncrlf:   defm    0dh,0ah,0h\nc_home: defm    01bh,\"&#91;H\",0h\nb_junk: defm    128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128\n        defm    128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128\nboard:  defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,64,64,00,00,00,00,00,00,64,64,00,00,00,00,00,00,00,00,00,00,00,00,64,64,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00,00,00,64,64,64,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,64,00,00,00,00,64,64,00,00,00,00,00,00,00,00,00,00,00,00,64,64,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,64,64,00,00,00,00,00,00,00,00,64,00,00,00,00,00,64,00,00,00,64,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,64,64,00,00,00,00,00,00,00,00,64,00,00,00,64,00,64,64,00,00,00,00,64,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,64,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00,00,00,64,64,64,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,64,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00,00,00,64,64,64,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00,00,00,64,64,64,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128\n        defm    128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00\n        defm    00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128\nb_done: defm    128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128\n        defm    128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128\n        end\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"642\" height=\"456\" src=\"https:\/\/fortycreek.org\/wp-content\/uploads\/2022\/07\/life.png\" alt=\"\" class=\"wp-image-17\" srcset=\"https:\/\/fortycreek.org\/wp-content\/uploads\/2022\/07\/life.png 642w, https:\/\/fortycreek.org\/wp-content\/uploads\/2022\/07\/life-300x213.png 300w\" sizes=\"auto, (max-width: 642px) 100vw, 642px\" \/><figcaption>From the R-pentomino, the most common methuselah.<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I have not coded Conway&#8217;s life in many years &#8211; I thought it would be fun to try on the Z80. First I implemented it in C on the Raspberry Pi. It uses an array to both keep track of prior generations (to determine if the pattern is still evolving) and the same array to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-15","post","type-post","status-publish","format-standard","hentry","category-z80"],"_links":{"self":[{"href":"https:\/\/fortycreek.org\/index.php\/wp-json\/wp\/v2\/posts\/15","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fortycreek.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fortycreek.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fortycreek.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fortycreek.org\/index.php\/wp-json\/wp\/v2\/comments?post=15"}],"version-history":[{"count":3,"href":"https:\/\/fortycreek.org\/index.php\/wp-json\/wp\/v2\/posts\/15\/revisions"}],"predecessor-version":[{"id":19,"href":"https:\/\/fortycreek.org\/index.php\/wp-json\/wp\/v2\/posts\/15\/revisions\/19"}],"wp:attachment":[{"href":"https:\/\/fortycreek.org\/index.php\/wp-json\/wp\/v2\/media?parent=15"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fortycreek.org\/index.php\/wp-json\/wp\/v2\/categories?post=15"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fortycreek.org\/index.php\/wp-json\/wp\/v2\/tags?post=15"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}