;----------------------------------------------------------------
; USERHRZ.ASM		MAR  2, 1981
;
;  Updated 11-13-15 by M Douglas for use with
;    CP/M 2.2 for single density North Star controller
;
;  This USER AREA is for a Horizon computer
;  as used with CP/M 2.2 for single density North Star
;
;  It may be used as a prototype for modification.
;
;  USER area location (180h bytes long)
;	0500h from start of BIOS
;	1B00h from start of CP/M
;	2500h in memory after loading or running MOVCPM
;	1C00h offset in the disk image file
;			
;  IOBYTE location: 1Dh from start of USER area
;
;  To install this patch:
;    1) Set MSIZE immediately below and assemble this file.
;    2) Run MOVCPM and save the image to a file (e.g., CPM.COM)
;       as prompted.
;    3) Use DDT to install the patch in the CP/M image:
;       A>DDT CPM.COM
;       -IUSERHRZ.HEX
;       -R7200		(replace 7200 with value of "OFFSET" below)
;       -G0		(G zero, not "oh", or type ctrl-c)
;       A>SYSGEN	(hit return at source prompt to use
;		 	 image in memory, then follow remaining
;			 prompts).
;
;  IOBYTE behavior in this code
;
;    CON device (bits 1,0):
;	00 - TTY left serial port*
;	01 - CRT right serial port
;	10 - BAT batch mode
;	11 - UC1 parallel port
;
;    RDR device (bits 3,2):
;	00 - TTY left serial port*
;	01 - PTR right serial port
;	10 - UR1 parallel port
;	11 - UR2 parallel port
;
;    PUN device (bits 5,4):
;	00 - TTY left serial port*
;	01 - PTP right serial port
;	10 - UP1 parallel port
;	11 - UP2 parallel port
; 
;    LST device bits (7,6):
;	00 - TTY left serial port*
;	01 - CRT right serial port
;	10 - LPT parallel port
;	11 - UL1 parallel port
;
;     *default setting, see HORIOB below
;----------------------------------------------------------------
;Change MSIZE to the memory size desired.

MSIZE	EQU	48		;Distribution system

; BIOS and USER area equates

BIOSLEN	equ	1200h		;length of the BIOS
USROFF	equ	0500h		;offset of USER area in BIOS
USRAREA	equ	MSIZE*1024 - BIOSLEN + USROFF
IOBYT	equ	3		;IOBYTE in CP/M

OFFSET	equ	2500h-USRAREA	;offset to overlay SYSGEN image

	ORG	USRAREA		;Origin of this program

;THE JUMP TABLE FOLLOWING MUST BE PRESENT AND
;THE SEQUENCE OF JUMPS MAY NOT BE CHANGED

	JMP	HCINIT		;Initialize I/O ports
	JMP	HWINIT		;Warm boot init
	JMP	HCONST		;Console status
	JMP	HCONIN		;Console input
	JMP	HCONOUT		;Console output
	JMP	HLIST		;Printer output
	JMP	HPUNCH		;Punch output
	JMP	HREADER		;Reader input
	JMP	HLISTST		;Printer status
	DW	HORLEN		;Length of USER AREA
HORIOB:	DB	0		;Initial IOBYT value
	DB	0,0,0		;Reserved


;YOU MAY MAKE ANY CHANGES DESIRED FROM THIS POINT ON.
;KEEP THE TOTAL USER AREA UNDER 384 BYTES.

	;LOGICAL I/O ROUTINES

;Each logical I/O routine loads the IOBYT at address 3,
;rotates the proper two bit field into bits 0 and 1,
;and calls the DSPCH routine which selects one
;of the four physical drivers from the table following
;depending on the value of bits 0 and 1.
;The HLIST routine has been fully commented to aid you.

HCONST:
	;Select console status routine.
	LDA	IOBYT
	CALL	DSPCH	
	DW	CINST0		;Left serial
	DW	CINST1		;Right serial
	DW	HLISTST		;Batch mode
	DW	CINST2		;Parallel port
HCONIN:
	;Select console input routine.
	LDA	IOBYT
	CALL	DSPCH	
	DW	CIN0		;Left serial
	DW	CIN1		;Right serial
	DW	HREADER		;Batch mode
	DW	CIN2		;Parallel port
HCONOUT:
	;Select console output routine.
	LDA	IOBYT
	CALL	DSPCH	
	DW	COUT0		;Left serial
	DW	COUT1		;Right serial
	DW	HLIST		;Batch mode
	DW	COUT2		;Parallel port
HLIST:
	;Select a list driver.
	LDA	IOBYT		;Load IOBYT from address 4.
	RLC			;Rotate LIST selection bits
	RLC			;into bit position 0 and 1.
	CALL	DSPCH		;Call dispatcher.

	;The dispatcher selects a routine from the table
	;following depending on the value of bits 0-1.
	;The selected routine will return to the caller.
	DW	COUT0		;00B = Left serial
	DW	COUT1		;01B = Right serial
	DW	COUT2		;10B = Parallel port
	DW	COUT2		;11B = Parellel port
HPUNCH:
	;Select as PUNCH driver.
	LDA	IOBYT
	RRC
	RRC
	RRC
	RRC
	CALL	DSPCH	
	DW	COUT0	
	DW	COUT1	
	DW	COUT2	
	DW	COUT2	
HREADER:
	;Select a READER driver.
	LDA	IOBYT
	RRC
	RRC
	CALL	DSPCH	
	DW	CIN0	
	DW	CIN1	
	DW	CIN2	
	DW	CIN2	
HLISTST:
	;List status not implemented.
	XRA	A
	RET
DSPCH:
	;Select routine from table of caller.
	ANI	3		;Mask IOBYT and
	RLC			;mult times 2.
	MOV	E,A		;Put index into
	MVI	D,0		;DE register.
	POP	H		;get addr of table
	DAD	D		;and add index.
	MOV	E,M		;Get addr of routine
	INX	H		;into
	MOV	D,M		;DE first,
	XCHG			;then put into HL
	PCHL			;and transfer control.

	;PHYSICAL STATUS ROUTINES

CINST0:
	;Left serial port status.
	IN	3
	ANI	2
	RZ			;No key
	MVI	A,0FFH
	RET			;Char ready
CINST1:
	;Right serial port status.
	IN	5
	ANI	2
	RZ			;No key
	MVI	A,0FFH
	RET			;Char ready
CINST2:
	;Parallel port status.
	IN	6
	ANI	2
	RZ
	MVI	A,0FFH
	RET

	;PHYSICAL INPUT ROUTINES

CIN0:
	;Left serial port input.
	IN	3
	ANI	2
	JZ	CIN0	
	IN	2
	ANI	7FH
	RET
CIN1:
	;Right serial port input.
	IN	5
	ANI	2
	JZ	CIN1	
	IN	4
	ANI	7FH
	RET
CIN2:
	;Parallel port input.
	IN	6		;Motherboard status
	ANI	2
	JZ	CIN2	
	IN	0		;Read keyboard
	PUSH	PSW		;Save char
	MVI	A,30H
	OUT	6		;Reset PI flag
	POP	PSW
	ANI	7FH
	RET

	;PHYSICAL OUTPUT ROUTINES

COUT0:
	;Left serial port output.
	IN	3
	ANI	1
	JZ	COUT0	
	MOV	A,C
	OUT	2
	RET
COUT1:
	;Right serial port output.
	IN	5
	ANI	1
	JZ	COUT1	
	MOV	A,C
	OUT	4
	RET
COUT2:
	;Parallel port output.
	IN	6		;Motherboard status
	ANI	1
	JZ	COUT2	
	MVI	A,20H		;Reset PO flag
	OUT	6		;Output char
	MOV	A,C  		;Load accumulator
TIN1:
	ORI	80H		;Set strobe false
	OUT	0		;and send character
	XRI	80H		;Toggle strobe
	OUT	0		;Output
	XRI	80H		;and toggle again
	OUT	0
	ANI	7FH		;Mask to ASCII
	RET

	;HORIZON HARDWARE INITIALIZATION

HWINIT:
	;Warm boot initialization.
	DB	0,0,0		;May be patched
	RET

HCINIT:
	;Cold boot initialization.
	LDA	HORIOB		;Get initial IOBYT
	STA	IOBYT		;and store
	CALL	HUINIT		;User init routine

	;Init motherboard and set up serial ports.
	XRA	A
	OUT	6
	OUT	6
	OUT	6
	OUT	6
	;Init left serial port (Standard console).
	MVI	A,0CEH		;Set 2 stop bits
	OUT	3		;to first serial port
	MVI	A,37H		;CMMD: RTS ER RXF DTR TXEN
	OUT	3		;to first port
	;Init right serial port.
	MVI	A,0CEH		;Set 2 stop bits
	OUT	5		;to second serial port
	MVI	A,37H		;Same command
	OUT	5		;to second port
	;0CEH sets 2 stop, 8 data bits, 16X clock, no parity.
	;04EH sets 1 stop, 8 data bits, 16X clock, no parity.

	;Parity initialization.
	MVI	A,40H		;Disarm parity logic
	OUT	0C0H
	LXI	H,0
	MVI	A,0E0H

	;Loop to set parity for first 56K of RAM.
TINCP:	MOV	B,M		;Read byte
	MOV	M,B		;Put back with parity set
	INR	L		;Next memory location
	JNZ	TINCP	
	INR	H		;Next 256 byte page
	CMP	H		;up to 0E0H
	JNZ	TINCP	
	;Enable parity logic on memory board.
	MVI	A,41H
	OUT	0C0H

	;Clear input buffers on serial ports.
	IN	2
	IN	4
	;Init parallel port.
	MVI	A,30H
	OUT	6		;Reset parallel port PI flag
	MVI	A,60H		;Code to set PO flag
	OUT	6
	MVI	A,0DH		;Output a carriage return
	JMP	TIN1		;to parallel port

	;SPECIAL INITIALIZATION FOR USER

HUINIT:
	RET

HORLEN	EQU	$-USRAREA	;LENGTH
	END
