Categories
z80

Conway’s Life on z80

I have not coded Conway’s life in many years – 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.

#include <time.h>
#include <stdlib.h>
#include <stdio.h>

unsigned char *grid;
const int rows=48, cols=160, maxt=3;
int same;

void* calc_grid(int *t) {
int i, j, q;
    for (i=rows+rows-*t*rows/maxt-1; i>=rows+rows-(*t+1)*rows/maxt; i--) {
        for (j=cols+cols-1; j>=cols; j--) {

            if ( (grid[(i-rows)*cols+j-cols] & 64) ) { /* for each cell that is alive, add 1 to all the neighbours in every (8) adjacent cell */
                grid[((i-1) % rows)*cols + (j-1) % cols] += 1;
                grid[((i-1) % rows)*cols + (j  ) % cols] += 1;
                grid[((i-1) % rows)*cols + (j+1) % cols] += 1;
                grid[((i  ) % rows)*cols + (j-1) % cols] += 1;
                grid[((i  ) % rows)*cols + (j+1) % cols] += 1;
                grid[((i+1) % rows)*cols + (j-1) % cols] += 1;
                grid[((i+1) % rows)*cols + (j  ) % cols] += 1;
                grid[((i+1) % rows)*cols + (j+1) % cols] += 1;
            }
        }
    }

}
void* shift_grid(int *t) {
        int i, j;
        for (i=*t*rows/maxt; i<(*t+1)*rows/maxt; i++) {
            for (j=0; j<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*/
                if ((grid[i*cols+j] & 79) == 3 || (grid[i*cols+j] & 79) == 66 || (grid[i*cols+j] & 79) == 67)   grid[i*cols+j] |= 128;
                grid[i*cols+j] = (grid[i*cols+j] >> 1) & 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  */
                if ( same == 1 && ((grid[i*cols+j] & 64)>>2) != (grid[i*cols+j] & 16) )  /* compare the 7th bit to the 5th bit- if those are not the same, then the pattern is changing */
                    same=0;
            }
        }
}

int main() {

    time_t qt;
    srand((unsigned) time(&qt));

    pthread_t thr[maxt];

    int c, x, y, i, j, gen, t, rc;

    grid = malloc(rows*cols*sizeof(char));

for ( c=0; c<1000; c++) {
//    printf("Try: %d\n", c);
    for (i=0; i<rows; i++)
        for (j=0; j<cols; j++)
            grid[i*cols+j] = 64 * (rand() % 2);  /*  initialize the array with random numbers in the 7th bit */

    for (gen=0; gen<20000; gen++) {
        for (t=0; t<maxt; t++) {
                calc_grid(&t);
        }

        same=1;
        for (t=0; t<maxt; t++) {
                shift_grid(&t);
        }
        //if (same==1) break;
        printf("Gen: %d\n", gen );
    for (i=0; i<rows; i++) {
        for (j=0; j<cols; j++)
         putc( (grid[i*cols+j] & 64 ) ? '*': ' ', stdout);
        putc('\n', stdout);
        }
        getc(stdin);
    }
    }
/*  print out survivor */
        printf("Gen: %d\n", gen );
    for (i=0; i<rows; i++) {
        for (j=0; j<cols; j++)
         putc( (grid[i*cols+j] & 64 ) ? '*': ' ', stdout);
        putc('\n', stdout);
        }

    free(grid);
}

I’ve made it very similar on the z80 in terms of the algorithm that is implemented. The grid it uses is smaller.

        org     0100h

        ; 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
        ; board is 78x24 with an extra space all around so 80x26  - 2080 elements
        ld a,0ffh    ; do at most 255 generations
top:    push af
        ld hl,c_home
        call my_write_string
        call print_board
        call calc_n
        call calc_g
        pop af
        dec a
        jr nz,top
        ld hl,c_home
        call my_write_string
        call print_board

        ret
calc_g:         ; calculate the next generation
        ld de, board
calc_g_loop:
        ld b, 080h
        ld a,(de)
        ld c,a
        and b
        jr z,no_128
        ld (de),a
        jr end_calc_g

no_128: ; continue with calcs
        ld a,c
        ld b,79
        and b
        ld b,3
        cp b
        jr z, set_128
        ld b,66
        cp b
        jr z, set_128
        ld b,67
        cp b
        jr z, set_128
        ld a,c
        jr shift_mask
set_128:
        ld a,c
        ld b,128
        or b
shift_mask:
        ld b,224
        and b
        srl a
        ld (de), a
end_calc_g:
        inc de
        ld hl,b_done
        sbc hl,de
        ret z
        jr calc_g_loop

calc_n:
        ld ix, board
        ld de, board
        ld c,040h
        ld b,080h
calc_n_loop:
        ld a,(ix+0)
        and b
        jr nz,calc_x    ; found a 128 - skip calc
        ld a,(ix+0)
        and c
        jr z,calc_x     ; only increment if its currently alive
        inc (ix-1)
        inc (ix+1)
        inc (ix-79)
        inc (ix-80)
        inc (ix-81)
        inc (ix+79)
        inc (ix+80)
        inc (ix+81)
calc_x: inc ix
        inc de
        ld hl,b_done
        sbc hl,de
        ret z
        jr calc_n_loop

        ; print_board:  routine to print out board - uses a, bc, de, hl
print_board:
        ld de, board
print_nl:
        ld c, 00h
print_loop:
        ld a,(de)
        ld b,040h
        and b
        jr z,space_char
        ld b,'@'
        jr end_char
space_char:
        ld b,' '
end_char:
        call my_write_char
        inc de
        inc c
        ld a,80
        sub c
        jr nz,print_loop
        ld hl,crlf
        call my_write_string
        ld hl,b_done
        sbc hl,de
        ret z
        jr print_nl
        ; puts a single char (byte value) on serial output
        ; call with char to send in B register; also uses A register
my_write_char:
        in a,(3)
        and 001h
        jp z, my_write_char
        ld a,b
        out (2),a
        ret
my_write_string:
        in a,(3)
        and 001h
        jr z,my_write_string
        ld a,(hl)
        and a
        ret z
        out (2),a
        inc hl
        jr my_write_string

crlf:   defm    0dh,0ah,0h
c_home: defm    01bh,"[H",0h
b_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
        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
board:  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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
        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
b_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
        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
        end
From the R-pentomino, the most common methuselah.

Leave a Reply

Your email address will not be published. Required fields are marked *