
;	-------------------------------------------------------
;	Adaptation of VTI for UAP's POLY-88
;		[Version October 15,1978]
;
;		VTI88  -  Copyright (C) 1978
;		Universidad Autonoma de Puebla
;
;	written by Harold V. McIntosh, summer 1978, with
;	reference to: Harvey A. Cohen, "The Oznaki LIFE",
;	Dr. Dobbs Journal of Computer Calisthenics and
;	Orthodontia, volume 3, issue 4 (April 1978) pp. 10-11;
;	and with acknowledgements to the hospitality of the
;	Quantum Theory Project, University of Florida,
;	Gainesville, Florida.
;
;	Note that this board has been modified: bit 7=1 now
;	signifies graphic mode, contrary to the normal board.
;	------------------------------------------------------

	org	09000H
                
                
read:	equ	0C20H	;POLY-88 WH0 keyboard input routine
kbfl:	equ	0C0CH	;keyboard input ready flag

;	-------------------------------------------------------
;	Constants defining screen size and location.  Note that
;	while the programmer has some discretion in assigning
;	these constants, there is highly implicit usage of the
;	assumption that the screen memory begins at a 1K Hex
;	boundary, and that the row length is a power of 2.
;	Thus the video board origin may be changed through its
;	address switches, and new parameters defined without
;	difficulty; nevertheless adaptation to an 80-column 
;	board would require restructuring the subroutines.
;	-------------------------------------------------------

vorg:	equ	0F800H	;origin of video screen memory area
vsiz:	equ	00400H	;size of video screen memory area
rsiz	equ	00040H	;length of a single display line
rmsk:	equ	rsiz-1	;mask for single row addresses
morg:	equ	04000H	;area for defining macros

;	-------------------------------------------------------
;	Data storage locations required by the subroutines.
;	-------------------------------------------------------

ma:	equ	00CC9H	;bit mask to locate pixel within byte
wy:	equ	00CCAH	;row count * 16  -  16 rows total
ex:	equ	00CCBH	;column count * 4  -  64 columns total
wye:	equ	00CCCH	;8-bit cartesian y-coordinate
eks:	equ	00CCDH	;8-bit cartesian x-coordinate

;	-----------------------------------------------------
;	Entry vector designed to systematize communication with
;	calling programs written in BASIC or other external
;	languages.  These entry points should remain the same
;	even though the subroutines are revised, corrected, or
;	otherwise modified.

	jmp	ypl	;move cursor up one pixel
	jmp	ymi	;move cursor down one pixel
	jmp	xpl	;move cursor right one pixel
	jmp	xmi	;move cursor left one pixel
	jmp	home	;place cursor at screen center
	jmp	cuex	;extinguish the cursor
	jmp	culi	;illuminate the cursor
	jmp	cure	;reverse the cursor
	jmp	cuse	;sense the cursor (zero test afterward)
	jmp	blak	;make the whole screen black
	jmp	whit	;make the whole screen white
	jmp	reve	;reverse the whole screen
	jmp	cart	;form (ma, wy, ex) from (wye, eks)
	jmp	line	;line segment with increments (dx,dy)
	jmp	ekspl	;rotate whole screen right
	jmp	eksmi	;rotate whole screen left
	jmp	wyepl	;rotate whole screen up
	jmp	wyemi	;rotate whole screen down
	jmp	hh	;advance one cycle of LIFE
	jmp	ee	;move cursor east one LIFE cell
	jmp	ww	;move cursor west one LIFE cell
	jmp	nn	;move cursor north one LIFE cell
	jmp	ss	;move cursor south one LIFE cell
	jmp	kk	;deactivate cell under cursor
	jmp	ll	;activate cell under cursor
	jmp	eas	;rotate screen and cursor one cell east
	jmp	wes	;rotate screen and cursor one cell west
	jmp	nor	;rotate screen and cursor one cell north
	jmp	sou	;rotate screen and cursor one cell south
	jmp	coop	;fetch count and terminating character
	jmp	pair	;fetch a pair of coordinates

;	-------------------------------------------------------

;	move cursor up one pixel

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

;	move cursor down one pixel

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

;	move cursor right one pixel

xpl:	lxi h,ma
	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 ex
	adi 004H
	sta ex
	ret

;	move cursor left one pixel

xmi:	lxi h,ma
	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 ex
	sui 004H
	sta ex
	ret

;	load A with the bit mask, HL with a byte address
;	given the cursor positioning data at (ma,wy,ex)

dot:	lhld wy
	mov a,h
	mvi h,vorg/0400H
	dad h
	dad h
	rrc
	rrc
	ora l
	mov l,a
	lda ma
	ret

;	home the cursor

home:	lxi h,8080H
	shld wy
	mvi a,008H
	sta ma
	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

cure:	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
whi:	mvi m,080H
	inx h
	dcr e
	jnz whi
	dcr d
	jnz whi
	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,018H
	mvi c,004H
	lda wye
	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 wy
	mov a,c
	ani 0F0H
	jnz car3
	mvi a,020H
	jmp car4
car3:	xri 030H
	rrc
car4:	mov c,a
	lda eks
	dcr a
	mov b,a
	rlc
	ani 0FCH
	sta ex
	mov a,b
	ani 001H
	mov a,c
	jz car5
	rrc
	rrc
	rrc
car5:	sta ma
	ret

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

line:	lxi h,ypl
	mov a,c
	ora a
	jp lin1
	cma
	inr a
	mov c,a
	lxi h,ymi
lin1:	lxi d,xpl
	mov a,b
	ora a
	jp lin2
	cma
	inr a
	mov b,a
	lxi d,xmi
lin2:	cmp c
	jnc lin3
	xchg
	mov b,c
	mov c,a
lin3:	mov a,b
	sta eks
	mov a,c
	add a
	mov c,a
	sub b
	push psw
	sub b
	mov b,a
lin4:	pop psw
	push h
	lxi h,culi
	xthl
	cpi 001H
	jm lin5
	push h
	add b
	jmp lin6
lin5:	add c
lin6:	push d
	push psw
	lda eks
	dcr a
	sta eks
	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 byte 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

;	rotate 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 rmsk
	jnz eksp2
	mov a,h
	cpi (vorg+vsiz)/0100H
	jnz eksp1
	ret

;	rotate 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 rmsk
	dcx h
	jnz eksm2
	mov a,h
	cpi (vorg/0100H)-1
	jnz eksm1
	ret

;	rotate the whole screen up one pixel.

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 (vorg/0100H)-1
	jnz wyep2
	pop h
	mov a,l
	ani rmsk
	dcx h
	jnz wyep1
	ret

;	rotate 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 (vorg+vsiz)/0100H
	jnz wyem2
	pop h
	inx h
	mov a,l
	ani rmsk
	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 rmsk
	jnz delt
	push d
	lxi d,2*rsiz-1
	dad d
	pop d
	mov a,h
	cpi (vorg+vsiz)/0100H
	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 (vorg+vsiz)/0100H
	jnz cyc1
	ret

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

hh:	call epsi
	call wyepl
	call epsi
	call wyepl
	call epsi
	call wyemi
	call wyemi
	jmp cycl

;	extinguish cursor, move two pixels east, light cursor

ee:	call cure
	call xpl
	call xpl
	jmp  cure

;	extinguish cursor, two pixels west, light cursor

ww:	call cure
	call xmi
	call xmi
	jmp  cure

;	extinguish cursor, one pixel north, light cursor

nn:	call cure
	call ypl
	jmp  cure

;	extinguish cursor, one pixel south, light cursor

ss:	call cure
	call ymi
	jmp  cure

;	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

;	build up one-byte decimal number from digit string
;	null string =1, minus creates negative modulo 256
;	to correct an error type four zeroes and start over

decm:	mvi b,01H
	call read
	cpi '-'
	jnz dec1
	lxi h,dec3
	push h
	call read
dec1:	cpi '0'
	rc
	cpi '9'+1
	rnc
	mvi b,00H
dec2:	cpi '0'
	rc
	cpi '9'+1
	rnc
	sui '0'
	mov c,a
	mov a,b
	rlc
	rlc
	add b
	rlc
	add c
	mov b,a
	call read
	jmp dec2
dec3:	push sp
	mov a,b
	cma
	inr a
	mov b,a
	pop sp
	ret

;	get (B,C)= (count, operation)

coop:	call decm
	mov c,a
	ret

;	get (B,C) = (X,Y); for example a pair of coordinates
;	first read b=x, then c=y

pair:	call decm
	push b
	call decm
	pop sp
	mov c,b
	mov b,a
	ret

;	place a dot with coordinates x,y on the screen

pp:	call pair
	lxi h,wye
	mov m,c
	inx h
	mov m,b
	call cart
	jmp culi

;	draw a line with increments (dx,dy)

ii:	call pair
	jmp line

;	=======================================================
;	beginning of second ROM
;	=======================================================

	org	9400H

	jmp main

;	repeat the subroutine in (H,L) for the number of times
;	in B.

rept:	mov a,c
	push h
	push b
	lxi d,repi
	push d
	pchl
repi:	pop b
	pop h
	dcr b
	rz
	jmp rept

;	turn one ASCII digit into a macro location

mloc:	lxi h,0005H
	dad sp
	mov e,m
	mvi d,00H
	mvi m,01H
	lxi b,morg
	xchg
	dad h
	dad h
	dad h
	dad h
	dad h
	dad b
	ret

;	record a macro definition

mdef:	call mloc
mde1:	call coop
	mov m,b
	inx h
	mov m,c
	inx h
	mvi a,01BH
	cmp c
	rz
	push h
	lxi h,vect
	call rept
	pop h
	jmp mde1

;	execute a defined macro

mxec:	call mloc
	push h
mxe1:	pop h
	mov b,m
	inx h
	mov a,m
	inx h
	cpi 01BH
	rz
	cpi ')'
	jz rpar
	cpi '('
	jz lpar
	mov c,a
	push h
	lxi h,vect
	call rept
	jmp mxe1
rpar:	pop psw
	dcr a
	jz  rpa1
	pop h
	push h
	push psw
	push h
	jmp mxe1
rpa1:	xthl
	jmp mxe1
lpar:	push h
	mov a,b
	push psw
	push h
	jmp mxe1

;	directory vector for LIFE demonstration

vect:	cpi 'N'		;rotate screen north
	jz  nor
	cpi 'S'		;rotate screen south
	jz  sou
	cpi 'E'		;rotate screen east
    	jz  eas
	cpi 'W'		;rotate screen west
	jz  wes
	cpi 06EH	;'n' - move cursor north
	jz  nn
	cpi 073H	;'s' - move cursor south
	jz  ss
	cpi 065H	;'e' - move cursor east
	jz  ee
	cpi 077H	;'w' - move cursor west
	jz  ww
	cpi 06BH	;'k' - deactivate cell
	jz  kk
	cpi 06CH	;'l' - activate cell under cursor
	jz  ll
	cpi 'C'		;clear screen to black
	jz  blak
	cpi 'R'		;reverse the screen
	jz  reve
	cpi 068H	;'h' - advance one cycle of LIFE
	jz  hh
	cpi 067H	;'g' - repeat cycles of LIFE
	jz  gg
	cpi '.'		;reverse cursor illumination
	jz  cure
	cpi '!'
	jz mdef
	cpi '?'
	jz mxec
	cpi 069H
	jz  ii
	cpi 070H
	jz  pp
	cpi ';'		;exit to monitor
	jz  0000H
vend:	ret

;	call hh repeatedly unless keyboard input is waiting

gg:	lda kbfl
	ora a
	rz
	call hh
	jmp gg

;	MAIN PROGRAM for LIFE demonstration
;	commands consist of a count and a letter.  An operation
;	is repeated the number of times required, null and zero
;	both being taken as once.  The correspondence between
;	letters and operations is established by a sequence of
;	CPI's and JZ's in the array vect.

main:	call home
loop:	call coop
	lxi h,vect
	call rept
	jmp loop

	end
