$ALLPUBLIC
;	Demo Program for Z80
;	Written by Ken Anderson
;	July 1985
;
;	This program is intended to demonstrate features of
;	the Z80 CPU that are easily visualized on Avocet's
;	AVSIM Z80 Simulator.
;
;	The functions of this program include:
;
;	1. MAIN routine reads the bit pattern from PIO A Pins 0 - 3
;	   and cycles it on the LEDs attached to PIO A Pins 4 - 7
;	   (like a light chaser) where HI bits represent
;	   LIGHT ON (or vice-versa, of course).
;	   The light chaser rotates alternately to the right,
;	   then to the left at a rate corresponding to
;	   the binary value of the bit pattern.
;
;	2. CTC 0 interrupt routine changes the rotation direction
;	   on each timeout.
;
;	3. PIO B is supporting a second task:
;	   On Input interrupt, read ASCII character from 
;	   port, and buffer it.
;	   Special character <CR> clears the buffer contents - for
;	   visual effect in the simulator!
;

;	Variable Map

BFSIZE	EQU	31		; Maximum Buffer size 
RETURN	EQU	0DH		; Carriage Return

;	Register Usage:

;	D	; store switch settings
;	E	; 2 copies of 4 - bit pattern for rotating
;	L	; bit 0 is direction flag
;	C	; pointer to PIO address
;	IX	; PIO B Int routine Buffer pointer - next free position
;	B	; PIO B Int routine Buffer counter

;	I/O Map

	SEG	IOSPACE,START=0

CTC0:	DS	1	; CTC at 0 - 3 in I/O Space

	DEFSEG	PIOSEG,START=4,CLASS=IOSPACE
	SEG	PIOSEG

PIOAD:	DS	1	; PIO at 4 - 7 in I/O Space
PIOBD:	DS	1
PIOAC:	DS	2

	DEFSEG	ZEROCODE,START=0
	SEG	ZEROCODE
	
ZERO:	JP	MAIN

	DEFSEG	STSEG,START=20H
	SEG	STSEG
	DS	20H
STACK:				; Stack at top

	DEFSEG	BUFBASESEG
	SEG	BUFBASESEG,START=40H

BUFBASE:DS	BFSIZE		; PIO B Int routine Buffer space

	DEFSEG	MAINCODE,START=100H
	SEG	MAINCODE

MAIN:	LD	SP,40H		; Stack down from BUFBASE
	; Init PIO
	LD	C,PIOAC
	LD	DE,0CF0FH	; Port A Mode 3 0-3 In, 4-7 Out
	OUT	(C),D
	OUT	(C),E
	LD	A,7		; Int OFF
	OUT	(C),A
	INC	C		; to PIOB Control
	LD	A,4FH		; Mode 1
	OUT	(C),A
	LD	DE,0283H
	OUT	(C),D		; Int Vector
	OUT	(C),E		; Ints Enabled
	; Init CTC
	LD	C,CTC0
	LD 	A,4		; Int Vector
	OUT	(C),A
	LD 	A,10010101B	; CCW0: INT/TIMER/16/AUTO/TC follows
	OUT	(C),A
	IM	2		; Mode 2
	LD	A,10		; Time Constant for direction change
	OUT	(C),A
	LD	A,10H		; IV Table at 1000H: User/PIO B/CTCs
	LD	I,A
	; Init LEDS
	LD	C,PIOAD
	XOR	A
	OUT	(C),A		; Clear LEDS
	LD	L,A		; Pattern rotation to right
	; Init Int task pointer
	LD	IX,BUFBASE
	EXX
	LD	B,0
	EXX
	EI			; Int service ON
	CALL	GETSW		; get switch settings
NEWPTRN:LD	D,A		; save switches
	SLA	A		; rotate x 4
	SLA	A		
	SLA	A		
	SLA	A		
	OR	A,D		; 2 copies of pattern
	LD	E,A		; save in E
	LD 	A,10010101B	; CCW0: INT/TIMER/16/AUTO/TC follows
	OUT	(CTC0),A	; Adjust
	LD	A,E		; Time Constant for direction change
	OUT	(CTC0),A

ROTATE:	BIT	0,L		; get direction
	JR	NZ,ROTLEFT	; HI -> to left
	RRC	E
	JR	SETLEDS
ROTLEFT:RLC	E
SETLEDS:OUT	(C),E		; Update LEDS
	CALL	GETSW		; Test switches
	CP	D		; change?
	JR	Z,ROTATE	; No, keep cycling
	JR	NEWPTRN		; Yes, reload

GETSW:	IN	A,(C)		; Subroutine to show stack working
	AND	0FH		; Strip to inputs ONLY
	RET

CTC:	INC	L		; Toggle BIT 0: Direction
	EI
	RETI

PIO:	EX	AF,AF'		; Swap
	EXX
	IN	A,(PIOBD)	; Get data
	LD	C,A
	CP	RETURN		; <CR>?
	JR	NZ,BUFCHAR	; No, buffer character
CLEAR:	LD	(IX),0		; Yes, clear buffer to zeroes
	DEC	IX		; from back to front
	DJNZ	CLEAR		; until at front
	JR	EXIT

BUFCHAR:LD	A,B	
	CP	BFSIZE		; Check if space left in buffer
	JR	NC,EXIT		; No room left
	LD	(IX),C		; Yes, save char
	INC	IX
	INC	B
EXIT:	EX	AF,AF'
	EXX
	EI
	RETI 


;	Vectors are stored at 1000H

	DEFSEG	VECTORS,CLASS=CODE,START=1000H
	SEG	VECTORS

	DW	MAIN		; RESET if USER Int
	DW	PIO		; PIO B Input Int
	DW	CTC		; CTC 0 Timer Int

	END

