;
;INDIVIDUAL I/O ROUTINES FOR CP/M-2 ON NORTHSTAR DD
;**************************************************
;	by Keith Petersen, W8SDZ
; 	 (revised July 4, 1981 by Bob Clyne)
;
;07/04/81  Added additional I/O drivers and changed to table selection
;	   of drivers. (Bob Clyne)
;
;04/22/81  Changed some of the JUMP instructions to Z80 JUMP RELATIVEs
;	   using Z80.LIB.  (Bob Clyne)
;
;04/21/81  Changed the list device status routine to use the code suggested
;	   by Robert Halsall in the February 1981 issue of LIFELINES.
;	   (Bob Clyne)
;
;03/15/81  Added check for illegal drive - currently set for a two drive
;	   system. Changed clear screen character for Intertube. Added code
;	   to list status routine to return with carry set if the printer is
;	   busy.  (Bob Clyne)
;
;This is a special user area which allows output
;from the system to both the console and the
;TTY port when STAT'ed with the command:
;	STAT CON:=UC1:
;
;The command to output to just the TTY is:
;	STAT CON:=TTY:
;
;NOTE: Contents of IOBYTE (address 0003h)
;	0 = TTY output only
;	1 = CRT output only
;	3 = both TTY and CRT output
;
;The initialization in this version causes a cold
;boot to set CON:=CRT:.
;
;COLPT and COUL1 both output to the Horizon parallel port but the code is
;different. (RAC)
;
;Change MSIZE to the nominal system size desired
;
MSIZE	EQU	58	;<----58K SYSTEM SIZE----
;
BIOS	EQU	5300H+(MSIZE-24)*1024
USER	EQU	BIOS+700H	;WHERE THE USER AREA STARTS
OFFSET	EQU	2700H-USER	;TO OVERLAY SYSGEN IMAGE
IOBYTE	EQU	3		;USE INTEL CONVENTION
;
;Define port assignments
;
CRTS	EQU	03H	;CRT STATUS PORT
CRTD	EQU	02H	;CRT DATA PORT
CRTBE	EQU	01H	;TBE MASK FOR CRT PORT
KBDS	EQU	03H	;CONSOLE KEYBOARD STATUS PORT
KBDD	EQU	02H	;CONSOLE KEYBOARD DATA PORT
KBDDA	EQU	02H	;RDA MASK FOR KBD PORT
LSTS	EQU	05H	;LIST STATUS PORT
LSTD	EQU	04H	;LIST DATA PORT
LSTDA	EQU	02H	;RDA MASK FOR LIST PORT
LSTBE	EQU	01H	;TBE MASK FOR LIST PORT
MBSTATP	EQU	06H	;MOTHERBOARD STATUS PORT - USED FOR PARALLEL PORT IO
PARPT	EQU	00H	;PARALLEL PORT
PARINMSK EQU	02H	;PARALLEL PORT INPUT CHAR AVAILABLE MASK
PIFLGR	 EQU	30H	;PARALLEL PORT INPUT CHAR AVAIL. FLAG RESET
PAROTMSK EQU	01H	;PARALLEL PORT OUTPUT BUFFER EMPTY MASK
POFLGR	 EQU	20H	;PARALLEL PORT OUTPUT BUFFER EMPTY FLAG RESET
POSTROB	 EQU	80H	;PARALLEL PORT OUTPUT STROBE
;
CLR	EQU	0CH	;Intertec Intertube CLEAR SCREEN CHARACTER
;
MACLIB Z80
;
DRVS	EQU	02H	;NUMBER OF DRIVES IN SYSTEM
;
	ORG	USER	;WHERE THE USER AREA STARTS
;
;The jump table following MUST be present in the correct sequence
;
CINIT:	JMP	CINITR	;COLD INIT I/O PORTS
	JMP	CONST	;CONSOLE STATUS
	JMP	CONIN	;CONSOLE INPUT
	JMP	CONOUT	;CONSOLE OUTPUT
	JMP	LIST	;LIST OUTPUT
	JMP	PUNCH	;PUNCH=CONSOLE OUTPUT
	JMP	READER	;READER=CONSOLE INPUT
LSTAT:	JMP	LISTST	;LIST STATUS
	DB	0,0,0	;RESERVED
	DW	HORLEN	;LENGTH OF THIS PROGRAM

CONST:	LXI	H,CSTBLE	;BEGINNING OF JUMP TABLE
	JR	CONIN1		;SELECT CORRECT JUMP

CSREADR:LXI	H,CSRTBLE	;BEGINNING OF READER STATUS TABLE
	JR	READERA

CONIN:	LXI	H,CITBLE	;BEGINNING OF CHARACTER INPUT TABLE

;ENTRY AT CONIN1 WILL DECODE THE TWO LEAST SIGNIFICANT BITS OF IOBYTE.
;THIS IS USED BY CONIN, CONOUT, AND CONST.

CONIN1:	LDA	IOBYTE
	RAL

;Entry at SELDEV will form an offset into the table pointed to by HL and
;then pick up the address and jump there.

SELDEV:	ANI	06H		;STRIP OFF UNWANTED BITS
	MVI	D,0		;FORM OFFSET
	MOV	E,A
	DAD	D		;ADD OFFSET
	MOV	A,M		;PICK UP HIGH BYTE
	INX	H
	MOV	H,M		;PICK UP LOW BYTE
	MOV	L,A		;FORM ADDRESS
	PCHL

CONOUT:	LDA	0004H		;GET DRIVE/USER NUMBER
	ANI	0FH		;ONLY LOOK AT DRIVE NUMBER
	CPI	DRVS		;IS IT GREATER THAN HIGHEST DRIVE ON LINE
	JRC	CONOUT1		;NO...THEN JUMP
	XRA	A		;SET DRIVE AND USER NUMBERS TO 0
	STA	0004H		;SAVE DRIVE 0 / USER 0
CONOUT1:LXI	H,COTBLE	;BEGINNING OF CHARACTER OUT TABLE
	JR	CONIN1		;DO THE DECODE

READER:	LXI	H,RTBLE		;BEGINNING OF READER INPUT TABLE

;Entry at READERA will decode bits 2 & 3 of IOBYTE, used by CSREADER

READERA:LDA	IOBYTE

;Entry at READER1 will shift the bits into position, used by LIST and PUNCH.

READER1:RAR
	JR	SELDEV

;PUNCH:	Selects the correct punch device. The selection comes from bits
;4 & 5 of IOBYTE.

PUNCH:	LXI	H,PTBLE		;BEGINNING OF PUNCH TABLE
	LDA	IOBYTE

;Entry at PNCH1 rotates bits a little more in prep for SELDEV, used by LIST.

PNCH1:	RAR
	RAR
	JR	READER1

;LIST:	Select a list device based on bits 6 & 7 of IOBYTE.

LIST:	LXI	H,LTBLE		;BEGINNING OF LIST DEVICE TABLE
LIST1:	LDA	IOBYTE
	RAR
	RAR
	JR	PNCH1

;LISTST: Get the status of the currently assigned list device.

LISTST:	LXI	H,LSTBLE	;BEGINNING OF THE LIST DEVICE STATUS
	JR	LIST1

;Console input table.

CITBLE:	DW	CITTY		;Input from TTY (Horizon device 1 - right
				;serial port, #4).
	DW	CICRT		;Input from CRT (Horizon device 0 - left
				;serial port, #2).
	DW	READER		;Input from READER (depends on READER selection
	DW	CIUC1		;Input from User Console 1 (currently set to
				;accept input from both CRT and TTY.

;Console output table.

COTBLE:	DW	COTTY		;Output to TTY, as above.
	DW	COCRT		;Output to CRT, as above.
	DW	LIST		;Output to list device (depends on bits 6 & 7
				;of IOBYTE).
	DW	COUC1		;Same as input in table above.

;List device table.

LTBLE:	DW	COTTY		;Output to TTY.
	DW	COCRT		;Output to CRT.
	DW	COLPT		;Output to line printer (currently assigned to
				;the Horizon device 2, parallel output port,
				; port #2).
	DW	COUL1		;Output to user line printer (currently
				;assigned to the alternate code for the
				;Horizon device 2  parallel output port #0).

;Punch device table.

PTBLE:	DW	COTTY		;Output to TTY.
	DW	COPTP		;Output to paper tape punch (currently assigned
				;to TTY).
	DW	COUP1		;Output to user punch 1 (currently assigned to
				;user line printer 1).
	DW	COUP2		;Output to user punch 2 (currently assigned to
				;line printer).

;Reader device input table.

RTBLE:	DW	CITTY		;Input from TTY.
	DW	CIPTR		;Input from paper tape reader (currently
				;assigned to CRT).
	DW	CIUR1		;Input from user reader 1 (currently assigned
				;to Horizon device 2 - parallel input port #0).
	DW	CIUR2		;Input from user reader 2 (currently assigned
				;the same as CIUR1).

;Console status table (input status ie. is character available?).

CSTBLE:	DW	CISTTY		;Status of TTY.
	DW	CISCRT		;Status of CRT.
	DW	CSREADR		;Status of reader (depends on reader device
				;assignment).
	DW	CISUC1		;Status of user console 1 (currently just
				;returns status of TTY).

;Status of reader device (input status ie. is character available?).

CSRTBLE:DW	CISTTY		;Status of TTY.
	DW	CISPTR		;Status of paper tape reader (currently
				;assigned to CRT).
	DW	CISUR1		;Status of user reader 1 (curently assigned to
				;Horizon device 2 - parallel input port #0).
	DW	CISUR2		;Status of user reader 2 (currently assigned
				;the same as CSUR1).

;Status of the list device.

LSTBLE:	DW	COSTTY		;Status of TTY.
	DW	COSCRT		;Status of CRT (currently always returns ready)
	DW	COSLPT		;Status of line printer (currently assigned to
				;Horizon device 2, parallel output port,
				;port #0).
	DW	COSUL1		;Status of the user line printer (currently
				;assigned to the alternate code for the
				;Horizon parallel output port).

;CITTY:	Character in from TTY device - Horison device 1, the right serial port,
;	port #4.

CITTY:	IN	LSTS
	ANI	LSTDA
	JRZ	CITTY
	IN	LSTD
	ANI	7FH
	JRZ	CITTY
	RET

;CICRT:	Character in from the CRT device - Horizon device 0, the left serial
;	port, port #2.

CIPTR:
CICRT:	IN	KBDS
	ANI	KBDDA
	JRZ	CICRT
	IN	KBDD
	ANI	7FH
	JRZ	CICRT
	RET

;CIUR1:	Character in from Horizon device 2, the parallel input port, port #0.

CIUR2:
CIUR1:	IN	MBSTATP		;GET MOTHERBOARD STATUS
	ANI	PARINMSK	;MASK FOR CHARACTER INPUT FLAG.
	JRZ	CIUR1		;LOOP IF NOTHING THERE.
	IN	PARPT		;GET THE CHARACTER
	PUSH	PSW		;SAVE IT
	MVI	A,PIFLGR	;RESET CODE FOR PARALLEL INPUT FLAG
	OUT	MBSTATP		;RESET THE FLAG
	POP	PSW		;RESTORE THE CHARACTER
	RET

;CIUC1:	Character in from either TTY or CRT.

CIUC1:	IN	LSTS
	ANI	LSTDA
	JRZ	CIUC1A
	IN	LSTD
	ANI	7FH
	JRZ	CIUC1		;IGNORE NULLS
	RET
CIUC1A:	IN	KBDS
	ANI	KBDDA
	JRZ	CIUC1
	IN	KBDD
	ANI	7FH
	JRZ	CIUC1
	RET

;COTTY:	Character out to TTY - Horizon device 1, right serial port, port #4.

COPTP:
COTTY:	IN	LSTS
	ANI	LSTBE
	JRZ	COTTY
	MOV	A,C
	ANI	7FH
	OUT	LSTD
	RET

;COCRT:	Character out to CRT - Horizon device 0, left serial port, port #2.

COCRT:	IN	CRTS
	ANI	CRTBE
	JRZ	COCRT
	MOV	A,C
	ANI	7FH
	RZ
	CPI	7FH
	RZ
	OUT	CRTD
	RET

;COLPT:	Character out to lineprinter, Horizon device 2, parallel output port,
;	port #0. This code is essentially the same as that furnished by
;	Lifeboat in USER.ASM.

COUP2:
COLPT:	IN	MBSTATP
	ANI	PAROTMSK
	JRZ	COLPT
	MVI	A,POFLGR
	OUT	MBSTATP
	MOV	A,C
TIN1:	ORI	80H		;SET STROBE FALSE
	OUT	PARPT		;SEND CHARACTER
	XRI	80H		;TOGGLE STROBE
	OUT	PARPT
	XRI	80H		;TOGGLE STROBE AGAIN
	OUT	PARPT
	ANI	7FH		;MASK TO ASCII
	RET


;COUL1:	Character out to user lineprinter 1, user punch 1, Horizon device 2,
;	 parallel output port, port #0. This is alternate code similar to
;	that furnished by North Star in SOFT-DOC Revision 2.1.

COUP1:
COUL1:	IN	MBSTATP
	ANI	PAROTMSK
	JRZ	COUL1
	MOV	A,C		;GET CHARACTER INTO ACCUMULATOR
	OUT	PARPT		;SEND IT
	MVI	A,POFLGR	;PARALLEL OUTPUT FLAG RESET
	OUT	MBSTATP		;SEND IT TO MOTHERBOARD STAUS PORT
	MOV	A,C		;GET CHARACTER BACK IN THE ACCUMULATOR.
	RET

;COUC1:	Character out to user console 1, currently outputs to both TTY & CRT.

COUC1:	CALL	COTTY
	JR	COCRT

;CISTTY:	Input status for TTY ie is a character available?

CISTTY:	IN	LSTS
CSCOM:	RRC
CSCOM1:	RRC
	SBB	A
	RET

;CISCRT:	Input status for CRT ie is a character available?

CISPTR:
CISCRT:	IN	KBDS
	JR	CSCOM

;CISUC1:	Input status for user console 1, checks for a character ready
;		on either the CRT or TTY.

CISUC1:	CALL	CISTTY		;CHECK FOR CHARACTER WAITING ON TTY
	RNZ			;CHARACTER THERE, RETURN
	JR	CISCRT		;GO CHECK FOR CHARACTER AT CRT

;CISUR1:	Input status for user reader 1, Horizon device 2, parallel
;		output port, port #0.

CISUR2:
CISUR1:	IN	MBSTATP
	JR	CSCOM

;COSCRT:	Output status of CRT device, always returns ready.

COSCRT:
READY:	MVI	A,0FFH
	RET

;COSTTY: Status of TTY device for output. Returns 0 in ACC and Z and C flags
;	 set if not ready and 0FFH in ACC and Z and C flags reset if ready.

COSUC1:
COSTTY:	IN	LSTS
COSCOM:	RRC			;Rotate the status bit to the carry bit
	SBB	A		;Subtract the ACC from itself the subtract the
				;carry bit.
	CMC			;WORDSTAR expects carry set if NOT ready
	RET


;CSUL1:	Status of user line printer, Horizon device 2, parallel output port,
;	port #0.

COSLPT:
COSUL1:	IN	MBSTATP
	JR	COSCOM

;Cold initialization
;
CINITR:	MVI	A,01H	;SETS CON:=CRT:
	STA	IOBYTE
	XRA	A	;INIT MOTHER BOARD
	OUT	6
	OUT	6
	OUT	6
	OUT	6
	MVI	A,0C1H	;INIT MEMORY BOARDS
	OUT	0C0H
;Set up serial ports
;0CEH sets 2 stop bits, 16X clock, 8 bits, no parity
;4EH sets 1 stop bit, 6X clock, 8 bits, no parity
;	MVI	A,0CEH	;FOR 2 STOP BITS (COMMENTED OUT)
	MVI	A,4EH	;FOR 1 STOP BIT
	OUT	3	;TO FIRST SERIAL PORT
	OUT	5	;TO SECOND SERIAL PORT
	MVI	A,37H	;CMMD: RTS ER RXF DTR TXEN
	OUT	3	;FIRST PORT
	OUT	5	;SECOND PORT
	IN	2	;CLEAR INPUT BUFFERS
	IN	4	;ON BOTH SERIAL PORTS
	MVI	A,CLR	;SCREEN CLEAR
	OUT	2	;TO FIRST PORT
;Set up parallel port
	MVI	A,30H
	OUT	6	;RESET PARALLEL PORT PI FLAG
	MVI	A,60H	;CODE TO SET PO FLAG
	OUT	6
	RET
;
HORLEN:	EQU	$-USER	;LENGTH
;
	END
