;----------------------------------------------------------------------------
;ca1disis.asm
;1-dimensional Cellular Automaton
;For the Intellec MDS888 (8080) running ISIS/OSIRIS
;By Roger Arrick
;3/4/2018
;Edit 18
;----------------------------------------------------------------------------
;To build and run: submit :f1:ca1disis.mak
;
;ca1disis.mak
;  asm80 :f1:ca1disis.asm
;  link :f1:ca1disis.obj, system.lib to :f1:ca1disis.lnk
;  locate :f1:ca1disis.lnk
;  :f1:ca1disis

;----------------------------------------------------------------------------
;Operation:
;There are two 1-dim arrays - ROW 1 for display, ROW 2 for work.
;Starts with a single * in the middle of ROW 1.
;A rule is applied to ROW 1 and stored in the work array ROW 2.
;ROW 2 is transferred to ROW 1 then sent to the console.
;ROW 2 is cleared for the next loop.
;Pressing SPACE pauses the program, any other key quits.
;----------------------------------------------------------------------------

NAME	ca1disis
EXTRN	ISIS			;Must link with system.lib for EXIT.

STKTOP	EQU	08FFFH
COLS	EQU	132		;# of columns.
CR	EQU	0DH
LF	EQU	0AH
STOP	EQU	0		;String terminator for type routine.
ESC	EQU	18H
BS	EQU	08H
SPACE	EQU	20H
CTRLC	EQU	03H

;Monitor calls for console IO.
CI	EQU	0F803H		;Console input.
CO	EQU	0F809H		;Console output

;ISIS System Call Identifiers.
OPEN	EQU	0
CLOSE	EQU	1
DELETE	EQU	2
READ	EQU	3
WRITE	EQU	4
SEEK	EQU	5
LOAD	EQU	6
RENAME	EQU	7
CONSOL	EQU	8
EXIT	EQU	9
ATTRIB	EQU	10
RESCAN	EQU	11
ERROR	EQU	12
WHOCON	EQU	13
SPATH	EQU	14

	CSEG

main: 
;	lxi	sp, STKTOP	;Stack pointer.
	
	;Sign-on message.
	call	type
	DB	CR,LF,'One-Dimensional Cellular Automaton by Roger Arrick 2018',STOP

	;Get blob char from user.
	mvi	a,'*'
	sta	BLOB
;	call	blobg
	
	;Get rule from user.
	call	ruleg

	;Start message.
	call	type
	DB	CR,LF,'Running.  Q=Quit, Space=Pause',CR,LF,STOP
	
	;Load initial conditions into Row 1.
	call	r1clr
	lda	BLOB
	sta	ROW1+(COLS/2)		;Middle

	;Main Loop.
main1:
	;Display Row 1.
	call	rout
	
	;Clear Row 2.
	call	r2clr

	;Calculate rule into Row 2.
	call	rulee

	;Move Row 2 into Row 1.
	call	rmov

	;If user enters a character, stop or pause, otherwise loop.
	in	0F7H		;Get console 8251 status.  MDS888 CRT port.
	ani	02H		;Received a char?  Zero=no.
	in	0F6H		;Get char.  Do this either way to clear buffer.
	jz	main1
	cpi	SPACE		;Space bar pauses.
	jnz	mainx		;Any other char stops.
	call	CI		;Wait for char to resume.
	jmp	main1		;Loop.
	
mainx:	;All done, restart.
	call	type
	DB	CR,LF,'Done.',STOP
	jmp	main


;----------------------------------------------------------------------------
;Calculate rule into Row 2.

;Pseudo code.
;Setup vars. b=column counter, hl=row1, de=row2, c=pattern
;if b counter zero then done
;get row 1 left into bit 2
;get row 1 center into bit 1
;get row 1 right into bit 0
;These 3 bits are the pattern stored in c
;if pattern = 000 then
;  if rule bit 0 = 1 then set blob in row 2 
;if pattern = 001 then
;  if rule bit 1 = 1 then set blob in row 2 
;if pattern = 010 then
;  if rule bit 2 = 1 then set blob in row 2 
;if pattern = 011 then
;  if rule bit 3 = 1 then set blob in row 2 
;if pattern = 100 then
;  if rule bit 4 = 1 then set blob in row 2 
;if pattern = 101 then
;  if rule bit 5 = 1 then set blob in row 2 
;if pattern = 110 then
;  if rule bit 6 = 1 then set blob in row 2 
;if pattern = 111 then
;  if rule bit 7 = 1 then set blob in row 2 
;adjust counters/pointers.  
;loop

rulee:	;Setup variables.
	lxi	h,ROW1		;HL = Row 1 cell counter.
	lxi	d,ROW2		;DE = Row 2 cell counter.
	mvi	b,COLS		;B = Columns counter. 

ruleel:	;Check for done.
	mov	a,b		
	cpi	0		;If B=0 then return.
	rz

	;Create bit pattern in C according to row 1 cells.
	mvi	c,0		;C = bit2=left, bit1=center, bit0=right

	;Get row 1 left into bit 2 of c.
	;If left is less than zero then skip.
	mov	a,b		;if counter = cols then at 0.
	cpi	COLS
	jz	ruleex
	dcx	h		;Get left of current cell.
	mov	a,m
	inx	h
	jmp	ruleez
	;At far left edge, get far right edge (wrap around).
ruleex:	lda	ROW1+COLS-1	;Get far right edge (wraparound).
	jmp	ruleez
	;At far left edge, fudge space.
	mvi	a,SPACE
	;Now set the bit.
ruleez:	cpi	SPACE
	jz	rulee2		;If space then empty, don't set bit.
	mvi	a,00000100b	;Set the bit.
	ora	c
	mov	c,a		;Save in c.
	
rulee2:	;Get row 1 center into bit 1 of c.
	mov	a,m
	cpi	SPACE
	jz	rulee3		;If space then empty, don't set bit.
	mvi	a,00000010b	;Set the bit.
	ora	c
	mov	c,a		;Save in c.

rulee3:	;Get row 1 right into bit 0 of c.
	;If right is beyond cols then skip.
	mov	a,b		;if counter = 1 then at end.
	cpi	1
	jz	ruleey
	inx	h		;Get right of current cell.
	mov	a,m
	dcx	h
	jmp	ruleew
	;At far right edge, get far left edge (wrap around).
ruleey:	lda	ROW1		;Get far left edge (wraparound).
	jmp	ruleew
	;At far right edge, fudge space.
	mvi	a,SPACE
	;Now set the bit
ruleew:	cpi	SPACE
	jz	rulee4		;If space then empty, don't set bit.
	mvi	a,00000001b	;Set the bit.
	ora	c
	mov	c,a		;Pattern bits in c.

	;Now, set row 2 cells according to row 1 pattern and rule bits.

rulee4:	;If cell pattern 000 then 
	mov	a,c		;C=pattern bits.
	cpi	00000000b
	jnz	rulee5
	;then if rule bit = 1 then
	lda	RULEL		;Get the rule.
	ani	00000001b
	jz	rulee5
	;Set row 2 cell
	lda	BLOB
	stax	d

rulee5:	;If cell pattern 001 then 
	mov	a,c		;C=pattern bits.
	cpi	00000001b
	jnz	rulee6
	;then if rule bit = 1 then
	lda	RULEL		;Get the rule.
	ani	00000010b
	jz	rulee6
	;Set row 2 cell
	lda	BLOB
	stax	d
	
rulee6:	;If cell pattern 010 then 
	mov	a,c		;C=pattern bits.
	cpi	00000010b
	jnz	rulee7
	;then if rule bit = 1 then
	lda	RULEL		;Get the rule.
	ani	00000100b
	jz	rulee7
	;Set row 2 cell
	lda	BLOB
	stax	d

rulee7:	;If cell pattern 011 then 
	mov	a,c		;C=pattern bits.
	cpi	00000011b
	jnz	rulee8
	;then if rule bit = 1 then
	lda	RULEL		;Get the rule.
	ani	00001000b
	jz	rulee8
	;Set row 2 cell
	lda	BLOB
	stax	d

rulee8:	;If cell pattern 100 then 
	mov	a,c		;C=pattern bits.
	cpi	00000100b
	jnz	rulee9
	;then if rule bit = 1 then
	lda	RULEL		;Get the rule.
	ani	00010000b
	jz	rulee9
	;Set row 2 cell
	lda	BLOB
	stax	d
	
rulee9:	;If cell pattern 101 then 
	mov	a,c		;C=pattern bits.
	cpi	00000101b
	jnz	ruleea
	;then if rule bit = 1 then
	lda	RULEL		;Get the rule.
	ani	00100000b
	jz	ruleea
	;Set row 2 cell
	lda	BLOB
	stax	d
	
ruleea:	;If cell pattern 110 then 
	mov	a,c		;C=pattern bits.
	cpi	00000110b
	jnz	ruleeb
	;then if rule bit = 1 then
	lda	RULEL		;Get the rule.
	ani	01000000b
	jz	ruleeb
	;Set row 2 cell
	lda	BLOB
	stax	d

ruleeb:	;If cell pattern 111 then 
	mov	a,c		;C=pattern bits.
	cpi	00000111b
	jnz	ruleec
	;then if rule bit = 1 then
	lda	RULEL		;Get the rule.
	ani	10000000b
	jz	ruleec
	;Set row 2 cell
	lda	BLOB
	stax	d

ruleec:	;Update pointers and counters for next loop.
	inx	h		;Next row 1 cell location.
	inx	d		;Next row 2 cell location.
	dcr	b		;Down count.
	
	jmp	ruleel		;Loop until done with all cells in row

;----------------------------------------------------------------------------
;Rule # Test.  Return carry = 1 if HL matches RULEH and RULEL.
;Destroys A.
;
rulet:	lda	RULEH		;Compare high byte.
	cmp	h
	jnz	ruletn		;No match
	lda	RULEL		;Compare low byte.
	cmp	l
	jnz	ruletn		;No match
	stc			;Match - Set carry.
	ret
ruletn:	stc			;No match - clear carry.
	cmc			
	ret
	
;----------------------------------------------------------------------------
;Get rule code from console as a 4-char hex word 0-65535 into RULEL, RULEH.
;Backspace restarts program.
;Destroys A.
;
ruleg:	call	type		;Ask
	db	CR,LF,'Enter Rule (0000-ffff, Q=quit, BS=restart): ',STOP
	call	hexinw		;Get 4-char hex word from console into HL.
	mov	a,h		;High byte into RuleH.
	sta	RULEH
	mov	a,l		;High byte into RuleL.
	sta	RULEL
	call	crlf		;New line.
	ret
	
;----------------------------------------------------------------------------
;Get blob char from user.
;Destroys A.
;
blobg:	call	type		;Ask
	db	CR,LF,'Enter blob char in hex (2A=*): ',STOP
	call	hexin		;Get 2-char hex word from console into A.
	sta	BLOB
	ret

;----------------------------------------------------------------------------
;Display row 1.
;Destroys A.
;
rout:	push	h		;Save regs.
	push	b
	lxi	h,ROW1		;HL = Row.
	mvi	b,COLS		;B = Columns counter.
	call	crlf		;New line.
routl:	mov	a,b		;Check for done.
	cpi	0
	jz	routx
	mov	c,m		;Get char.
	call	CO		;Display it.
	inx	h		;Point to next column.
	dcr	b		;Decrement column counter.
	jmp	routl		;Loop until done.
routx:	pop	b		;Restore regs.
	pop	h
	ret
	
;----------------------------------------------------------------------------
;Clear row 1.
;Destroys A.
;
r1clr:	push	h		;Save regs.
	push	b
	lxi	h,ROW1
	mvi	b,COLS		;B = Columns counter.
r1clrl:	mov	a,b		;Check for done.
	cpi	0
	jz	r1clrx
	mvi	m,SPACE		;Clear char.  
	inx	h		;Point to next column.
	dcr	b		;Decrement column counter.
	jmp	r1clrl		;Loop until done.
r1clrx:	pop	b		;Restore regs.
	pop	h
	ret

;----------------------------------------------------------------------------
;Clear row 2.
;Destroys A.
;
r2clr:	push	h		;Save regs.
	push	b
	lxi	h,ROW2
	mvi	b,COLS		;B = Columns counter.
r2clrl:	mov	a,b		;Check for done.
	cpi	0
	jz	r2clrx
	mvi	m,SPACE		;Clear char.  
	inx	h		;Point to next column.
	dcr	b		;Decrement column counter.
	jmp	r2clrl		;Loop until done.
r2clrx:	pop	b		;Restore regs.
	pop	h
	ret

	;----------------------------------------------------------------------------
;Move ROW 2 to ROW 1.
;Destroys A.
;
rmov:	push	h		;Save regs.
	push	d
	push	b
	lxi	h,ROW1		;HL = Row 1.
	lxi	d,ROW2		;DE = Row 1.
	mvi	b,COLS		;B = Columns counter.
rmov1:	mov	a,b		;Check for done.
	cpi	0
	jz	rmovx
	ldax	d		;get row 2.
	mov	m,a		;put in row 1.
	inx	h		;Point to next column.
	inx	d
	dcr	b		;Decrement column counter.
	jmp	rmov1		;Loop until done.
rmovx:	pop	b		;Restore regs.
	pop	d
	pop	h
	ret
	
;----------------------------------------------------------------------------
;Type string following call to CO.
;
type:	xthl			;Get pointer to string.
	push	b		;Don't destroy BC.
	mov	a,m		;Get the char.
	inx	h		;Point to next char.
	cpi	STOP		;Stop?
	jz	type1
	mov	c,a		;Send char.
	call	CO
	jmp	type+2		;Next char.
type1:	pop	b
	xthl			;Get return address back to caller.
	ret
		
;----------------------------------------------------------------------------
;Read 4-char hex byte from console.  
;No validation.
;Return in HL.
;
hexinw:	call	hexin		;Get hex byte
	mov	h,a		;High byte.
	call	hexin		;Get hex byte
	mov	l,a		;Low byte.
	ret
	
;----------------------------------------------------------------------------
;Read 2-char hex byte from console.  
;No validation.
;Return in A.
;
hexin:	push	b		;Don't destroy regs.
	call	hexine		;Get 1st char and echo.
	call	hexinc		;Convert char into value.
	mov	b,a		;Save temp.
	call	hexine		;Get 2nd char and echo.
	call	hexinc		;Convert char into value.
	mov	c,a		;Save temp.
	mov	a,b		;Put 1st value in high nibble.
	rlc
	rlc
	rlc
	rlc
	ani	0f0h
	ora	c		;Put 2nd value in low nibble.
	pop	b		;Don't destroy regs.
	ret			;All done.
;Get char and echo, into A.
hexine:	call	CI
	cpi	BS		;BS restarts program.
	jz	main
	cpi	'q'		;q=quit.
	jz	done
	cpi	'Q'		;Q=quit.
	jz	done
	mov	c,a
	call	CO
	cpi	BS		;BS restarts program.
	jz	main
	mov	a,c
	ret
;Convert ASCII char in A to a 4 bit value. 0-F = 0-15.
hexinc:	sui	'0'
	cpi	10
	rm
	sui	7
	ani	0fh
	ret

;----------------------------------------------------------------------------
;CRLF.
;
crlf:	push	b
	mvi	c,CR
	call	CO
	mvi	c,LF
	call	CO
	pop	b
	ret	
	
;----------------------------------------------------------------------------
;Return to OS.
;
done:	call	crlf
	MVI	C,EXIT
	LXI	D,EBLK
	CALL	ISIS
	
;----------------------------------------------------------------------------
;Storage
;	
EBLK:	dw	ESTAT		;For ISIS calls.
ESTAT:	ds	2

BLOB:	ds	1		;Blob character.
RULEH:	ds	1		;Rule high byte.
RULEL:	ds	1		;Rule low byte.
ROW1:	ds	COLS		;Row of elements displayed.
ROW2:	ds	COLS		;Row of elements being worked on.

	END	main

