
;	org 0100H
	org 9000H

	jmp main

go:	equ	ge
chin:	equ	0C20H	;POLY-88 WH0 (keyboard wormhole)
;chin:	equ	read	;subroutine to read VDM (port EC)

vorg:	equ	0F800H
vsiz:	equ	00400H
rsiz	equ	00040H
msk:	equ	00CC9H
wye:	equ	00CCAH
eks:	equ	00CCBH
wy:	equ	00CCCH
ex:	equ	00CCDH

;	move cursor up one pixel

ypl:	lxi h,msk
	mov a,m
	ani 024H
	jnz yp1
	mov a,m
	rlc
	mov m,a
	ret
yp1:	rrc
	rrc
	mov m,a
	lda wye
	sui 010H
	sta wye
	ret

;	move cursor down one pixel

ymi:	lxi h,msk
	mov a,m
	ani 009H
	jnz ym1
	mov a,m
	rrc
	mov m,a
	ret
ym1:	rlc
	rlc
	mov m,a
	lda wye
	adi 010H
	sta wye
	ret

;	move cursor right one pixel

xpl:	lxi h,msk
	mov a,m
	ani 007H
	jnz xp1
	mov a,m
	rrc
	rrc
	rrc
	mov m,a
	ret
xp1:	rlc
	rlc
	rlc
	mov m,a
	lda eks
	adi 004H
	sta eks
	ret

;	move cursor left one pixel

xmi:	lxi h,msk
	mov a,m
	ani 038H
	jnz xm1
	mov a,m
	rlc
	rlc
	rlc
	mov m,a
	ret
xm1:	rrc
	rrc
	rrc
	mov m,a
	lda eks
	sui 004H
	sta eks
	ret

;	load A with the bit mask, HL with a byte address
;	given the cursor positioning data at (msk,wye,eks)

dot:	lhld wye
	mov a,h
	mvi h,03EH
	dad h
	dad h
	rrc
	rrc
	ora l
	mov l,a
	lda msk
	ret

;	home the cursor

home:	lxi h,8080H
	shld wye
	mvi a,008H
	sta msk
	ret

;	extinguish the cursor

cuex:	call dot
	ora m
	mov m,a
	ret

;	light the cursor

culi:	call dot
	cma
	ana m
	mov m,a
	ret

;	reverse the cursor

crev:	call dot
	xra m
	mov m,a
	ret

;	sense the cursor

cuse:	call dot
	ana m
	ani 03FH
	ret

;	clear the whole screen to black

blak:	lxi d,vsiz
	lxi h,vorg
bl1:	mvi m,0FFH
	inx h
	dcr e
	jnz bl1
	dcr d
	jnz bl1
	ret

;	clear the whole screen to white

whit:	lxi d,vsiz
	lxi h,vorg
wh1:	mvi m,080H
	inx h
	dcr e
	jnz wh1
	dcr d
	jnz wh1
	ret

;	reverse the whole screen

reve:	lxi d,vsiz
	lxi h,vorg
rev1:	mov a,m
	xri 03FH
	mov m,a
	inx h
	dcr e
	jnz rev1
	dcr d
	jnz rev1
	ret

;	transform cartesian coordinates in the form of x,y
;	to a mask and byte address

cart:	mvi b,016H
	mvi c,004H
	lda wy
	cma
	adi 031H
car1:	cmp b
	jc car2
	sub b
car2:	cmc
	adc a
	dcr c
	jnz car1
	mov c,a
	ani 00FH
	rlc
	rlc
	rlc
	rlc
	sta wye
	mov a,c
	ani 0F0H
	jnz car3
	mvi a,006H
car3:	mov c,a
	ani 026H
	jz car4
	xri 026H
	mov c,a
car4:	lda ex
	dcr a
	mov b,a
	rlc
	ani 0FCH
	sta eks
	mov a,b
	ani 001H
	mov a,c
	jnz car5
	rrc
	rrc
	rrc
car5:	sta msk
	ret

;	draw a line with increments dx,dy = (C,B).  increment
;	may be + or - using complementary arithmetic, but less
;	than 64 in absolute value to avoid overflow problems.

line:	lxi h,ypl
	mov a,b
	ora a
	jp lin1
	cma
	inr a
	mov b,a
	lxi h,ymi
lin1:	lxi d,xpl
	mov a,c
	ora a
	jp lin2
	cma
	inr a
	mov c,a
	lxi d,xmi
lin2:	cmp b
	jnc lin3
	xchg
	mov c,b
	mov b,a
lin3:	mov a,c
	sta wy
	mov a,b
	add a
	mov b,a
	sub c
	push psw
	sub c
	mov c,a
lin4:	pop psw
	push h
	lxi h,culi
	xthl
	cpi 001H
	jm lin5
	push h
	add c
	jmp lin6
lin5:	add b
lin6:	push d
	push psw
	lda ex
	dcr a
	sta ex
	jnz lin4
	pop psw
	ret

;	the movements in one byte necessary to shift the
;	whole screen right one pixel.

expl:	mov a,m
	ani 03FH
	mov b,a
	ani 038H
	rrc
	rrc
	rrc
	ora c
	mov c,a
	mov a,b
	rlc
	rlc
	rlc
	ani 038H
	mov b,c
	mov c,a
	ret

;	the movements within one pixel necessary for shifting
;	the whole screen left one pixel.

exmi:	mov a,m
	ani 03FH
	mov b,a
	rlc
	rlc
	rlc
	ani 038H
	ora c
	mov c,a
	mov a,b
	ani 038H
	rrc
	rrc
	rrc
	mov b,c
	mov c,a
	ret

;	the movements necessary within one byte to shift the
;	whole screen down one pixel.

wymi:	mov a,m
	ani 03FH
	mov b,a
	ani 036H
	rrc
	ora c
	mov c,a
	mov a,b
	rlc
	rlc
	ani 024H
	mov b,c
	mov c,a
	ret

;	the movements necessary within one byte to shift the
;	whole screen up one pixel.

wypl:	mov a,m
	ani 03FH
	mov b,a
	rlc
	ani 036H
	ora c
	mov c,a
	mov a,b
	ani 024H
	rrc
	rrc
	mov b,c
	mov c,a
	ret

;	move the whole screen right one pixel

ekspl:	lxi h,vorg
	lxi d,rsiz-1
eksp1:	push h
	dad d
	call expl
	pop h
eksp2:	call expl
	mov a,b
	ori 080H
	mov m,a
	inx h
	mov a,l
	ani 03FH
	jnz eksp2
	mov a,h
	cpi 0FCH
	jnz eksp1
	ret

;	move the whole screen left one pixel

eksmi:	lxi h,vorg+vsiz-1
	lxi d,-rsiz+1
eksm1:	push h
	dad d
	call exmi
	pop h
eksm2:	call exmi
	mov a,b
	ori 080H
	mov m,a
	mov a,l
	ani 03FH
	dcx h
	jnz eksm2
	mov a,h
	cpi 0F7H
	jnz eksm1
	ret

;	Move the whole screen up one pixel.
;	this is the control loop which calls the shift of
;	a column in such a way as to make it cyclic.

wyepl:	lxi h,vorg+vsiz-1
wyep1:	lxi d,-vsiz+rsiz
	push h
	dad d
	call wypl
	pop h
	push h
	lxi d,-rsiz
wyep2:	call wypl
	mov a,b
	ori 080H
	mov m,a
	dad d
	mov a,h
	cpi 0F7H
	jnz wyep2
	pop h
	mov a,l
	ani 03FH
	dcx h
	jnz wyep1
	ret

;	Move the whole screen down one pixel

wyemi:	lxi h,vorg
wyem1:	lxi d,vsiz-rsiz
	push h
	dad d
	call wymi
	pop h
	push h
	lxi d,rsiz
wyem2:	call wymi
	mov a,b
	ori 080H
	mov m,a
	dad d
	mov a,h
	cpi 0FCH
	jnz wyem2
	pop h
	inx h
	mov a,l
	ani 03FH
	jnz wyem1
	ret

;	Add to the neighbor count of adjoining cells according
;	to the bits in this byte.  We do the middle pixel,
;	adding to the count of three successive neighbors in
;	registers B,C,D.

alfa:	mov a,m
	rrc
	jc alf1
	inr b
	inr c
	inr d
alf1:	rrc
	jc alf2
	inr b
	inr d
alf2:	rrc
	rc
	inr b
	inr c
	inr d
	ret

;	shift the neighbor count as we move forward one byte in
;	a row scan

beta:	mov b,c
	mov c,d
	mvi d,00H
	inx h
	mov a,l
	ani 03FH
	rnz
	push d
	lxi d,-rsiz
	dad d
	pop d
	ret

;	PRINCIPAL PROGRAM for carrying out a cycle of LIFE.
;	Only the middle pixel in each byte is calculated
;	so that three passes are necessary after each of three
;	shifts. Two adjacent pixels are used, the right to hold
;	the present living status and the left for information
;	for the next cycle.

epsi:	lxi h,vorg+rsiz-1
gama:	mvi d,00H
	call alfa
	call beta
	call alfa
delt:	push h
	call beta
	call alfa
	xthl
	mov a,b
	cpi 002H
	jz eta
	cpi 003H
	jz zeta
	mov a,m
	ori 010H
	mov m,a
	jmp thet
zeta:	mov a,m
	ani 0EFH
	mov m,a
	jmp thet
eta:	mov a,m
	ani 0EFH
	mov e,a
	ani 002H
	rlc
	rlc
	rlc
	ora e
	mov m,a
thet:	pop h
	mov a,l
	ani 03FH
	jnz delt
	push d
	lxi d,007FH
	dad d
	pop d
	mov a,h
	cpi 0FCH
	jnz gama
	ret

;	updating loop, moving left pixel to right

cycl:	lxi h,vorg
cyc1:	mov a,m
	ani 038H
	mov b,a
	rrc
	rrc
	rrc
	ora b
	ori 080H
	mov m,a
	inx h
	mov a,h
	cpi 0FCH
	jnz cyc1
	ret

;	execute a single cycle of LIFE by updating the middle
;	pixel and making three sweeps after shifting each time

hh:	call epsi
	call wyepl
	call epsi
	call wyepl
	call epsi
	call wyemi
	call wyemi
	call cycl
	ret

;	repeat h unless an ASCII character is waiting
;	(version for VDM using port ED)

gg:	in  0EDH
	ani 040H
	rnz
	call hh
	jmp  gg

;	version for POLY-88 using keyboard flag at 0C0CH

ge:	lda 0C0CH
	ora a
	rz
	call hh
	jmp ge

;	extinguish cursor, move two pixels east, light cursor

ee:	call crev
	call xpl
	call xpl
	jmp  crev

;	extinguish cursor, two pixels west, light cursor

ww:	call crev
	call xmi
	call xmi
	jmp  crev

;	extinguish cursor, one pixel north, light cursor

nn:	call crev
	call ypl
	jmp  crev

;	extinguish cursor, one pixel south, light cursor

ss:	call crev
	call ymi
	jmp  crev

;	extinguish a life cell

kk:	call xpl
	call cuex
	jmp xmi

;	activate a life cell

ll:	call xpl
	call culi
	jmp  xmi

;	move whole screen right one life cell, with cursor

eas:	call ekspl
	call ekspl
	call xpl
	jmp  xpl

;	move the whole screen left one life cell, with cursor

wes:	call eksmi
	call eksmi
	call xmi
	jmp  xmi

;	move the whole screen up one life cell, with cursor

nor:	call wyepl
	jmp  ypl

;	move the whole screen down one life cell, with cursor

sou:	call wyemi
	jmp  ymi

;	directory vector for LIFE demonstration

vect:	cpi 'N'
	jz  nor
	cpi 'S'
	jz  sou
	cpi 'E'
	jz  eas
	cpi 'W'
	jz  wes
	cpi 06EH
	jz  nn
	cpi 073H
	jz  ss
	cpi 065H
	jz  ee
	cpi 077H
	jz  ww
	cpi 06BH
	jz  kk
	cpi 06CH
	jz  ll
	cpi 063H
	jz  blak
	cpi 072H
	jz  reve
	cpi 068H
	jz  hh
	cpi 067H
	jz  go
	cpi '.'
	jz  crev
	cpi ';'
	jz  0000H
	ret

;	keyboard read routine

read:	in  0EDH
	ani 040H
	jz   read
	in  0EFH
	ani 07FH
	ret

;	MAIN PROGRAM for LIFE demonstration

main:	call blak
	call home
	call crev
here:	lxi h,here
	push h
	call chin
	jmp  vect

	end

