;
	TITLE	'DISK MOSS 2.2 MONITOR'
	MACLIB	Z80
	PAGE	56
;
; DISK MOSS MONITOR (VERSION 2.2)
;
; 14 JUNE 1980
; ALL RIGHTS RESERVED BY ROBERT B. MASON
;
MOSS:	ORG	0F000H
ROM:	EQU	0F000H	;ROM START ADDRESS
WSVEC:	EQU	0	;VECTOR FOR WARM RESTART
NBKPTS:	EQU	2	;NUMBER OF BREAKPOINTS
CTRLS:	EQU	13H	;ASCII DC3
CR:	EQU	0DH	;ASCII CARRIAGE RETURN
LF:	EQU	0AH	;ASCII LINE FEED
FMFD:	EQU	0CH	;ASCII FORM FEED
BELL:	EQU	7	;ASCII CNTRL CHAR TO RING THE BELL
IOBYTE:	EQU	3	;ADDRESS OF I/O CONTROL BYTE
SDATA:	EQU	20H	;SERIAL DATA PORT BASE ADDRESS
SINTEN:	EQU	SDATA+1	;SERIAL INTERRUPT ENABLE REGISTER
SIDENT:	EQU	SDATA+2	;SERIAL INTERRUPT IDENTIFICATION REGISTER
SLCTRL:	EQU	SDATA+3	;SERIAL LINE CONTROL REGISTER
SMDMCT:	EQU	SDATA+4	;SERIAL MODEM CONTROL REGISTER
SLSTAT:	EQU	SDATA+5	;SERIAL LINE STATUS REGISTER
SMDMST:	EQU	SDATA+6	;SERIAL MODEM STATUS REGISTER
;
;
SPSV:	EQU	6	;STACK POINTER SAVE LOCATION
;
;
; REGISTER STORAGE DISPLACEMENTS FROM
; NORMAL SYSTEM STACK LOCATION.
;
ALOC:	EQU	15H
BLOC:	EQU	13H
CLOC:	EQU	12H
DLOC:	EQU	11H
ELOC:	EQU	10H
FLOC:	EQU	14H
HLOC:	EQU	31H
LLOC:	EQU	30H
PLOC:	EQU	34H
SLOC:	EQU	17H
TLOC:	EQU	35H
TLOCX:	EQU	25H
LLOCX:	EQU	20H
;
APLOC:	EQU	9
BPLOC:	EQU	11
CPLOC:	EQU	10
DPLOC:	EQU	13
EPLOC:	EQU	12
FPLOC:	EQU	8
HPLOC:	EQU	15
LPLOC:	EQU	14
XLOC:	EQU	7
YLOC:	EQU	5
RLOC:	EQU	2
ILOC:	EQU	3
;
; DISK CONTROLLER UNIQUE EQUATES
;
DSTAT	EQU	30H	;DISK STATUS PORT
DCMMD	EQU	DSTAT	;DISK COMMAND PORT
DTRCK	EQU	DSTAT+1	;DISK TRACK PORT
DSCTR	EQU	DSTAT+2	;DISK SECTOR PORT
DDATA	EQU	DSTAT+3	;DISK DATA PORT
DFLAG	EQU	DSTAT+4	;DISK FLAG PORT
DCNTL	EQU	DSTAT+4	;DISK CONTROL PORT
;
;
DISKNO:	EQU	40H	;ACTIVE DISK NUMBER
TRACK:	EQU	DISKNO+1
SECTOR:	EQU	TRACK+1
SIDE:	EQU	SECTOR+1  ;SIDE SELECT HOLD AREA
SPT:	EQU	SIDE+1	;SECTORS PER TRACK HOLD
TWOSID:	EQU	SPT+1	;SINGLE/DOUBLE SIDED SWITCH HOLD
STPRAT:	EQU	46H	;STEP RATE SAVE AREA
STATUS:	EQU	47H
CMND:	EQU	STATUS+1
LUNIT:	EQU	49H	;LAST USED DRIVE
CUNIT:	EQU	LUNIT+1	;CURRENT DRIVE
RWFLG:	EQU	4BH
HSTBUF:	EQU	4CH	;HOST BUFFER ADDRESS
IDSV:	EQU	4EH	;DISK ID SAVE AREA
TBUF:	EQU	80H
;
;
; JUMP TARGETS FOR BASIC INPUT/OUTPUT
;
CBOOT:	JMP	INIT	;COLD START
CONIN:	JMP	CI	;CONSOLE INPUT
READER:	JMP	RI	;READER INPUT
CONOUT:	JMP	CO	;CONSOLE OUTPUT
PUNCH:	JMP	PO	;PUNCH OUTPUT
LIST:	JMP	LO	;LIST OUTPUT
CONST:	JMP	CSTS	;CONSOLE STATUS
	JMP	IOCHK	;PUT IOBYTE INTO (A)
	JMP	IOSET	;(C) HAS A NEW IOBYTE
	JMP	MEMCK	;MEMORY LIMIT CHECK
	JMP	RTS	;IODEF- DEFINE USER I/O ENTRY POINTS
	JMP	RTS	;SPCL- I/O CONTROL
	JMP	REST	;BREAKPOINT ENTRY POINT
;
; TBL CONTAINS THE ADDRESSES OF THE ACTION ROUTINES
;   THE EXECUTIVE USES IT TO LOOK UP THE DESIRED ADDRESS.
;
TBL:	DW	ASGN
	DW	BOOT
	DW	QPRT
	DW	DISP
	DW	QPRT
	DW	FILL
	DW	GOTO
	DW	HEXN
	DW	INPT
	DW	QPRT
	DW	QPRT
	DW	QPRT
	DW	MOVE
	DW	QPRT
	DW	OUPT
	DW	PARM
	DW	QPARM
	DW	READ
	DW	SUBS
	DW	MTEST
	DW	QPRT
	DW	COMP
	DW	WRITE
	DW	XMNE
	DW	I8250
	DW	BYE
;
; THE COLD INITIALIZATION CODE
;
INIT:	DI		;DISABLE INTERRUPTS
	LXI	SP,3FH	;USE STACK TO INITIALIZE RESTARTS
	LXI	H,JMP*256	;  WITH RESTART ERROR VECTORS
	LXI	D,RSTER
	MVI	B,16	;16 TIMES (64 BYTES)
INIT1:	PUSH	D
	PUSH	H
	DJNZ	INIT1
	LXI	SP,FAKE-2	;SET UP TEMPORARY STACK
	MVI	A,0	; SKIP THE NEXT INST
	ORG	$-1	;SAVE A BYTE HERE
;
; MEMSIZ CALCULATES THE TOP OF CONTIGUOUS RAM.  IT SEARCHES
;	FROM THE BOTTOM UP UNTIL A NON-RAM LOCATION IS
;	FOUND.  IT THEN TAKES OFF FOR MONITOR WORK SPACE
;	NEEDS AND RETURNS THE VALUE IN (H,L).
;
MEMSIZ:	PUSH	B	;MONITOR START LOCATION
	LXI	B,ROM
	LXI	H,-1	;START OF MEMORY ADDRESS SPACE
MEMSZ1:	INR	H
	MOV	A,M
	CMA
	MOV	M,A
	CMP	M
	CMA
	MOV	M,A
	JRNZ	MEMSZ2
	MOV	A,H	;SEE IF ON MONITOR BORDER
	CMP	B
	JRNZ	MEMSZ1
MEMSZ2:	DCR	H	;TAKE OFF WORKSPACE
	LXI	B,EXIT-ENDX-3*NBKPTS+1
	DAD	B
	POP	B	;(B,C) IS UNPREDICTABLE DURING INIT
	RET
;
; ROUTINE MEMCHK FINDS THE CURRENT TOP OF CONTIGUOUS MEMORY
;	(LESS THE MONITOR WORKSPACE) AND RETURNS THE VALUE.
;
MEMCK:	PUSH	H	;SAVE (H,L)
	CALL	MEMSIZ	;GET THE RAM SIZE
	MOV	A,L
	SUI	60	;TAKE OFF WORK SPACE
	JRNC	MEMCK0
	DCR	H
MEMCK0:	MOV	B,H
	POP	H
	RET
;
FAKE:	DW	FAKE+2
	SPHL
	LXI	D,EXIT
	XCHG
	LXI	B,ENDX-EXIT
	LDIR
	LXI	B,3*NBKPTS
	PUSH	D
	POP	H
	DCX	H
	LDIR
	LXI	H,-24
	DAD	SP
	PUSH	H
	INX	H	;ADJUST USER STACK LOCATION
	INX	H
	SHLD	SPSV	;SAVE THE STACK INITIAL VALUE
	MVI	D,10	;INITIALIZE REGISTER STORAGE AREA
INIT2:	PUSH	B
	DCR	D	;LOOP CONTROL
	JRNZ	INIT2
; INSERT I/O INIT CODE HERE
	CALL	DINIT	;SEE IF AUTO BOOT WANTED
	CALL	I8250	;INITIALIZE THE 8250
	CALL	RTS
	LXI	H,LOGMSG ;LOG ONTO THE SYSTEM
	CALL	PRTWD
	JR	WINIT	;GO TO MONITOR EXECUTIVE
;
;  ROUTINE EXF READS ONE PARAMETER.  IT EXPECTS THE FIRST
;	CHARACTER OF THE PARAMETER TO BE IN THE A REGISTER
;	ON ENTRY.
;
EXF:	MVI	B,1	;SET UP FOR ONE PARAMETER
	LXI	H,0
	JR	EX1	;FIRST CHARACTER IN A ALREADY
;
;  ROUTINE EXPR READS PARAMETERS FROM THE CONSOLE
;	AND DEVELOPS A 16 BIT HEXADECIMAL FOR EACH ONE.
;	THE NUMBER OF PARAMETERS WANTED IS IN THE B REG
;	ON ENTRY.  A CARRIAGE RETURN WILL TERMINATE THE
;	ENTRY SEQUENCE; A BLANK OR A COMMA WILL END THE
;	CURRENT PARAMETER ENTRY.  EACH PARAMETER ONLY
;	TAKES THE LAST 4 DIGITS TYPED IN; ANY EXCESS IS
;	DISCARDED.  A NON-HEX DIGIT WILL TERMINATE THE
;	ENTRY SEQUENCE AND CAUSE A WARM BOOT OF THE MON.
;
AS3:	DJNZ	AS2	;PART OF THE ASSIGN CODE
EX3:	JRNZ	QPRT	;NON-ZERO IS ERROR
EXPR1:	DCR	B	;MORE PARAMETERS?
	RZ		;NO, RETURN
EXPR:	LXI	H,0	;INITIALIZE PARAMETER
EX0:	CALL	ECHO	;GET NEXT NUMBER
EX1:	MOV	C,A	;SAVE CHAR FOR LATER USE
	CALL	NIBBLE
	JRC	EX2	;NOT A NUMBER, JUMP
	DAD	H	;MULTIPLY BY 16
	DAD	H
	DAD	H
	DAD	H
	ORA	L	;ADD ON NEW DIGIT
	MOV	L,A
	JR	EX0	;GO GET NEXT DIGIT
EX2:	XTHL		;PUT UNDER RETURN ADDRESS ON STACK
	PUSH	H	;RESTORE RETURN ADDRESS
	MOV	A,C	;REGET THE LAST CHARACTER
	CALL	P2C	;TEST FOR DELIMITER
	JRNC	EX3	;JUMP IF NOT CARRIAGE RETURN
	DJNZ	QPRT	;CARRET WITH MORE PARAM MEANS ERROR
	RET
;
; MAIN ACTION ROUTINES
;
;
; LOGICAL ASSIGNMENT OF PERIPHERALS
;
;THIS ROUTINE CONTROLS THE ASSIGNMENT OF PHYSICAL 
;	PERIPHERALS TO THE FOUR LOGICAL DEVICE TYPES. IT
;	ALTERS IOBYTE (MEMORY LOCATION 0003) TO MATCH THE
;	CURRENT ASSIGNMENT.  THE FOUR LOGICAL DEVICES ARE
;	CONSOLE, READER, LIST, AND PUNCH.  IN ALL CASES,
;	THE TTY DEVICE IS SET UP AS THE DEFAULT DEVICE.
;
ASGN:	CALL	ECHO	;GET THE LOGICAL DEVICE DESIRED
	LXI	H,ALT	;START OF CONVERSION TABLE
	LXI	D,APT-ALT	;DISTANCE BETWEEN LOGICAL CHOICES
	MVI	B,4	;NUMBER OF LOGICAL CHOICES
AS0:	CMP	M	;IS THIS ONE IT?
	JRZ	AS1	;YES, JUMP
	DAD	D	;NO, GO TO NEXT LOGICAL ENTRY
	DJNZ	AS0
QPRT:	LXI	H,QMSG	;GET ADDRESS OF QUESTION MARK MSG
	CALL	PRTWA	;PRINT IT
;
; THE WARM START CODE
;
WINIT:	LHLD	SPSV	;RESET THE STACK
	SPHL
WINITA:	LXI	H,WINIT	;RESET RETURN AND WARM START VECTOR
	PUSH	H
	SHLD	WSVEC+1
	MVI	A,0C3H
	STA	WSVEC
	CALL	CRLF	;START A NEW LINE
	CALL	DECHO	;GET THE COMMAND
	SUI	'A'	;GET RID OF ASCII ZONE
	JRC	QPRT	;BAD COMMAND
	CPI	'Z'-'A'+1	;CHECK UPPER LIMIT
	JRNC	QPRT	;BAD COMMAND
	ADD	A	;DOUBLE IT FOR TABLE OFFSET
	MOV	E,A	;SET UP FOR DOUBLE ADD
	MVI	D,0
	MVI	B,2	;SET UP FOR TWO PARAMETERS
	LXI	H,TBL	;GET ACTION ROUTINE ADDRESS
	DAD	D
	MOV	A,M	;LOAD H,L INDIRECT
	INX	H
	MOV	H,M
	MOV	L,A
	PCHL		;GO TO ACTION ROUTINE
;
; FILL ACTION ROUTINE
;
;	THIS ROUTINE FILLS A BLOCK OF MEMORY WITH A USER-
;	DETERMINED CONSTANT.  IT EXPECTS THREE PARAMETERS
;	TO BE ENTERED IN THE FOLLOWING ORDER:
;
;	START ADDRESS
;	FINISH ADDRESS
;	FILL VALUE
;
FILL:	CALL	EXPR3	;GET THREE PARAMETERS
FI0:	MOV	M,C	;PUT DOWN THE FILL VALUE
	CALL	HILO	;INCREMENT AND CHECK THE POINTER
	JRNC	FI0	;NOT DONE YET, JUMP
	POP	D	;RESTORE STACK POINTER IN CASE
	JR	WINIT	; STACK WAS OVERWRITTEN
;
AS1:	MOV	D,B	;SAVE THE COUNTER RESIDUE
	MVI	B,4	;LOOP CONTROL
	CALL	DECHO	;GET THE NEW ASSIGNMENT
AS2:	INX	H	;INCREMENT POINTER
	CMP	M	;SEE IF THIS IS IT
	JRNZ	AS3
	MOV	L,B	;SAVE THE RESIDUE TO FORM ASGT
	DCR	L	;ADJUST VALUE
	MOV	B,D	;REGET THE LOGICAL RESIDUE
	MVI	H,3	;SET UP THE IOBYTE MASK
	DCR	B	;ADJUST THIS ONE ALSO
	JRZ	AS5	;NO SHIFT NEEDED
AS4:	DAD	H	;SHIFT THE MASKS INTO POSITION
	DAD	H
	DJNZ	AS4	;NOT DONE YET, JUMP
AS5:	LDA	IOBYTE
	ORA	H	;MASK THE DESIRED ASSIGNMENT IN
	XRA	H	;LOGICAL ASGT BITS NOW OFF
	ORA	L	;PUT IN NEW VALUE
	MOV	C,A
IOSET:	MOV	A,C
	STA	IOBYTE	;SAVE NEW ASSIGNMENTS
	RET
IOCHK:	LDA	IOBYTE
	RET
;
ALT:	DB	'L'	;LOGICAL LIST DEVICE TABLE
	DB	'2'	;USER DEVICE #2
	DB	'1'	;USER DEVICE #1
	DB	'L'	;LIST TO HIGH SPEED PRINTER
	DB	'T'	;LIST TO TTY
APT:	DB	'P'	;LOGIPAL PUNCH DEVICE TABLE
	DB	'2'	;USER DEVICE #2
	DB	'1'	;USER DEVICE #1
	DB	'P'	;PUNCH TO HIGH SPEED PUNCH
	DB	'T'	;PUNCH TO TTY
ART:	DB	'R'	;LOGIPAL READER DEVICE TABLE
	DB	'2'	;USER DEVICE #2
	DB	'1'	;USER DEVICE #1
	DB	'P'	;READER TO HIGH SPEED READER
	DB	'T'	;READER TO TTY
ACT:	DB	'C'	;LOGIPAL CONSOLE DEVICE TABLE
	DB	'1'	;USER DEVICE #1
	DB	'B'	;CONSOLE TO BATCH (PRINTER OR PTR)
	DB	'C'	;CONSOLE TO CRT
	DB	'T'	;CONSOLE TO TTY
;
; THE BYE ROUTINE IS USED TO PREVENT UNAUTHORIZED USAGE
;	OF THE SYSTEM.  THE SYSTEM LOCKS UP AND WILL NOT
;	RESPOND TO ANYTHING OTHER THAN TWO ASCII BELL
;	CHARACTERS.  WHEN IT SEES THEM CONSECUTIVELY,
;	CONTROL IS RETURNED TO THE MONITOR WITHOUT ALTERING
;	ANYTHING.
;
BYE:	MVI	B,2	;SET UP FOR TWO CHARACTERS
BYE1:	CALL	CONI	;GO READ THE CONSOLE
	CPI	BELL	;SEE IF AN ASCII BELL
	JRNZ	BYE	;NO, START OVER AGAIN
	CALL	ECH1	;ECHO THE BELL
	DJNZ	BYE1	;NOT YET, GET NEXT ONE
	RET		;RETURN TO MONITOR
;
;  COMPARE ROUTINE
;
;THIS ROUTINE COMPARES TWO BLOCKS OF MEMORY AGAINST EACH
;	OTHER.  IF ADIFFERENCE IN THE RELATIVE ADDRESSES
;	IS DETECTED, THE ADDRESS OF THE FIRST BLOCK IS
;	DISPLAYED, ALONG WITH ITS CONTENTS AND THE CONTENTS
;	OF THE OTHER BLOCK'S SAME RELATIVE ADDRESS.
;
COMP:	CALL	EXPR3	;GO GET THREE PARAMETERS
CMPA:	LDAX	B	;GET SOURCE 2 DATA
	PUSH	B	;SAVE SOURCE 2 POINTER
	MOV	B,M	;READ SOURCE 1 DATA
	CMP	B	;COMPARE DATA
	JRZ	CMPB	;JUMP IF OK
	PUSH	PSW	;SAVE SOURCE 2 DATA
	CALL	LADRB	;WRITE THE ADDRESS
	MOV	A,B	;GET SOURCE 1 DATA
	CALL	DASH1	;FORMAT
	POP	PSW	;REGET SOURCE 2 DATA
	CALL	HEX1	;OUTPUT IT
CMPB:	POP	B
	CALL	HILOXB	;INCREMENT SOURCE 1 POINTER AND SEE IF DONE
	JR	CMPA	;JUMP IF NOT DONE YET
;
; DISPLAY ACTION ROUTINE
;
;	THIS ROUTINE DISPLAYS A BLOCK OF MEMORY ON THE
;	CURRENT CONSOLE DEVICE (CONSOLE DUMP).  THE USER
;	MUST SPECIFY THE START AND FINISH ADDRESSES.
;	THE DISPLAY IS ORGANIZED TO DISPLAY UP TO 16 BYTES
;	PER DISPLAY LINE, WITH ALL COLUMNS ALIGNED SO
;	EACH COLUMN HAS THE SAME LAST HEX DIGIT IN ITS ADDRESS.
;
DISP:	CALL	EXLF	;GO GET BLOCK LIMITS
DIS1:	CALL	LADRB	;DISPLAY THE START ADDRESS
	MOV	A,L	;SEE IF ON 16 BYTE BOUNDARY
	CALL	TRPLSP	;SKIP OVER TO RIGHT COLUMN
	PUSH	H	;SAVE (H,L)
DIS2:	MOV	A,M	;GET THE CONTENTS
	CALL	HEX1	;OUTPUT IT
	CALL	HILO	;INCREMENT, CHECK POINTER
	JRC	DIS7	;DONE IF CARRY SET
	CALL	BLK	;MAKE COLUMNS
	MOV	A,L	;READY FOR NEW LINE?
	ANI	0FH
	JRNZ	DIS2
DIS3:	POP	H	;REGET LINE START ADDRESS
	MOV	A,L	;SKIP OVER TO RIGHT SPACE
	ANI	0FH
	CALL	TRPL2
DIS4:	MOV	A,M	;GET MEMORY VALUE
	ANI	7FH	;STRIP OFF PARITY BIT
	MOV	C,A	;SET UP FOR OUTPUT
	CPI	' '	;SEE IF PRINTABLE IN ASCII
	JRC	DIS5	;JUMP IF SO
	CPI	7EH
	JRC	DIS6
DIS5:	MVI	C,'.'	;ELSE, PRINT A DOT
DIS6:	CALL	CONOUT
	CALL	HILOX	;INCREMENT (H,L) AND SEE IF DONE
	MOV	A,L	;NOT DONE, READY FOR NEW LINE?
	ANI	0FH
	JRNZ	DIS4	;JUMP IF NOT
	JR	DIS1	;DO THE NEXT LINE
DIS7:	SUB	E	;SKIP OVER TO START ASCII PRINTOUT
	CALL	TRPLSP
	JR	DIS3	;GO PRINT THE ASCII
;
TRPLSP:	ANI	0FH	;ISOLATE THE LOW FOUR BITS
	MOV	B,A	;PREPARE TO SPACE OVER TO RIGHT COLUMN
	ADD	A	;TRIPLE THE COUNT
	ADD	B
TRPL2:	MOV	B,A	;PUT BACK INTO B
	INR	B	;ADJUST COUNTER
TRPL1:	CALL	BLK	;DO THE SPACING
	DJNZ	TRPL1	;NO, DO ANOTHER COLUMN
	RET
;
; GO TO ACTION ROUTINE
;
;
; GOTO COMMAND TRANSFERS CONTROL TO A SPECIFIED ADDRESS.
;   IT ALLOWS THE SELECTIVE SETTING OF UP TO TWO BREAKPOINTS
;   AS WELL AS ALLOWING ANY CONSOLE INPUT TO BREAKPOINT
;   THE RUN, AS LONG AS INTERRUPT 1 IS ACTIVE.
;
GOTO:	CALL	PCHK	;SEE IF OLD ADDRESS WANTED
	JRC	GO3	;  YES, JUMP
	JRZ	GO0	;  YES, BUT SET SOME BREAKPOINTS
	CALL	EXF	;GET NEW GOTO ADDRESS
	POP	D 
	LXI	H,PLOC	;PUT ADDRESS IN PC LOCATION 
	DAD	SP
	MOV	M,D	;LOW BYTE
	DCX	H 
	MOV	M,E	;HIGH BYTE
	MOV	A,C 
	CPI	CR	;SEE IF A CR WAS LAST ENTERED
	JRZ	GO3 
GO0:	MVI	B,NBKPTS 
	LXI	H,TLOC	;POINT TO TRAP STORAGE
	DAD	SP 
GO1:	PUSH	B	;SAVE NUMBER OF BREAKPOINTS
	PUSH	H	;SAVE STORAGE POINTER
	MVI	B,2	;SET UP TO GET A TRAP ADDRESS
	CALL	EXPR1	;GET A TRAP ADDRESS
	POP	D	;GET THE TRAP ADDRESS INTO (D,E)
	POP	H	;REGET THE STORAGE ADDRESS
	MOV	A,D	;INSURE THE TRAP ADDRESS ISN'T ZERO
	ORA	E 
	JRZ	GO2	;JUMP IF SO
	MOV	M,E	;SAVE THE BREAKPOINT ADDRESS
	INX	H 
	MOV	M,D 
	INX	H 
	LDAX	D	;SAVE THE INSTRUCTION FROM THE BP ADDRESS
	MOV	M,A 
	INX	H 
	MVI	A,RST OR 8	;INSERT THE BREAKPOINT
	STAX	D 
GO2:	MOV	A,C	;REGET THE DELIMITER TO SEE
	CPI	CR	;  IF WE ARE DONE SETTING BREAKPOINTS
	POP	B	;  UNLOAD THE STACK FIRST
	JRZ	GO3	;YES, JUMP
	DJNZ	GO1	;JUMP IF NOT AT BP LIMIT
GO3:	CALL	CRLF 
	POP	H	;GET RID OF STACK JUNK
	LXI	H,RS9
	PUSH	H
	LXI	H,REST 
	SHLD	9	;SET BREAKPOINT JUMP VECTOR ADDRESS
	LXI	H,24	;FIND REGISTER SET ROUTINE ADDRESS
	DAD	SP
	POP	D	;ADJUST THE STACK
	PCHL		;GO TO THE DESIRED PLACE
;
; GENERAL PURPOSE INPUT/OUTPUT ROUTINES
;
;THESE ROUTINES ALLOW BYTE-BY-BYTE INPUT OR OUTPUT FROM
;	THE CURRENT CONSOLE DEVICE.  THEY ARE INVOKED BY
;	THE MONITOR "I" OR "O" COMMAND, THEN ANSWERING THE
;	QUESTIONS WHICH APPEAR ON THE CONSOLE.
;
INPT:	CALL	EXPR1	;GET INPUT PORT NUMBER
	POP	B	;GET PORT # INTO C REGISTER
	INP	E	;READ VALUE INTO E REGISTER
	JR	BITS2	;GO DO A BINARY PRINT OF THE VALUE
;
OUPT:	CALL	EXPR	;GET THE ADDRESS AND DATA FOR OUPTUT
	POP	D	;DATA VALUE INTO E
	POP	B	;PORT INTO C
	OUTP	E	;DO THE OUTPUT
	RET
;
;  MOVE ROUTINE
;
;	THIS ROUTINE EXPECTS THREE PARAMETERS, ENTERED IN THE FOLLOWING ORDER:
;	SOURCE FIRST BYTE ADDRESS
;	SOURCE LAST BYTE ADDRESS
;	DESTINATION FIRST BYTE ADDRESS
;
MOVE:	CALL	EXPR3	;GET THREE PARAMETERS
MOV1:	MOV	A,M	;GET NEXT BYTE
	STAX	B	;MOVE IT
	CALL	HILOXB	;GO INCREMENT, CHECK SOURCE POINTER
	JR	MOV1	;NOT THERE YET, GO DO IT AGAIN
;
;
; SUBSTITUTE ACTION ROUTINE
;
;THIS ROUTINE ALLOWS THE USER TO INSPECT ANY MEMORY LOCATION
;	AND ALTER THE CONTENTS, IF DESIRED AND IF THE ADDRESS
;	IS IN RAM.  THE CONTENTS MAY BE LEFT UNALTERED
;	BY ENTERING A SPACE, COMMA, OR A CARRIAGE RETURN.  IF
;	A CARRIAGE RETURN IS ENTERED, THE ROUTINE IS TERMINATED.
;	IF A SPACE OR COMMA IS ENTERED, THE ROUTINE
;	PROCEEDS TO THE NEXT LOCATION AND PRESENTS THE USER
;	WITH AN OPPORTUNITY TO ALTER IT.
;
SUBS:	CALL	EXPR1	;GO GET ONE PARAMETER
	POP	H	;GET THE START ADDRESS
SUB1:	MOV	A,M	;GET THE CONTENTS OF THE ADDRESS
	CALL	DASH1	;DISPLAY IT ON CONSOLE AND A DASH
	CALL	PCHK	;GET, CHECK CHARACTER
	RC		;DONE IF CARRIAGE RETURN
	JRZ	SUB2	;NO CHANGE IF BLANK OR ,
	CPI	LF	;SEE IF PREVIOUS BYTE WANTED
	JRZ	SUB3	;YES, DO IT
	PUSH	H	;SAVE MEMORY POINTER
	CALL	EXF	;GO GET REST OF NEW VALUE
	POP	D	;NEW VALUE TO E REGISTER
	POP	H	;RESTORE MEMORY POINTER
	MOV	M,E	;PUT DOWN NEW VALUE
	MOV	A,C	;GET THE DELIMITER
	CPI	CR	;SEE IF DONE (CARRIAGE RETURN)
	RZ		;YES, RETURN TO MONITOR
SUB2:	INX	H	;NO, INCREMENT MEMORY POINTER
	INX	H	;ALLOW A FALL-THROUGH ON THE NEXT INSTRUCTION
SUB3:	DCX	H	;ADJUST (H,L) AS APPROPRIATE
	MOV	A,L	;GET LO ADDRESS BYTE
	ANI	7	;SEE IF ON A BOUNDARY
	CZ	LADRB	;CALL IF ON THE BOUNDARY
	JR	SUB1	;GO DO THE NEXT LOCATION
;
; MTEST ROUTINE TESTS A SPECIFIED BLOCK OF MEMORY TO
;   SEE IF ANY HARD DATA BIT FAILURES EXIST.  IT IS
;   NOT AN EXHAUSTIVE TEST, BUT JUST A QUICK INDICATION
;   OF THE MEMORY'S OPERATIVENESS.
;
MTEST:	CALL	EXLF
MTEST1:	MOV	A,M	;READ A BYTE
	PUSH	PSW	;SAVE IT
	CMA		;COMPLEMENT IT
	MOV	M,A	;WRITE IT
	XRA	M	;RESULT SHOULD BE ZERO
	CNZ	BITS	;LOG ERROR IF NOT
MTEST2:	POP	PSW	;RESTORE ORIGINAL BYTE
	MOV	M,A
	CALL	HILOX	;POINT TO NEXT AND SEE IF DONE
	JR	MTEST1	;NO, CONTINUE
;
BITS:	PUSH	D	;SAVE (D,E)
	MOV	E,A	;SAVE ERROR PATTERN IN E
	CALL	LADRB	;FIRST PRINT THE ADDRESS
BITS2:	MVI	B,8	;LOOP CONTROL FOR 8 BITS
BITS1:	MOV	A,E	;GET NEXT BIT
	RLC		;  INTO CARRY
	MOV	E,A	;SAVE REST
	MVI	A,'0'/2	;BUILD ASCII 1 OR 0
	RAL		;  CARRY DETERMINES WHICH
	MOV	C,A	;NOW, OUPTUT IT
	CALL	CONOUT
	DJNZ	BITS1	;DO IT AGAIN
	POP	D
	RET
;
; EXAMINE REGISTERS COMMAND INSPECTS THE VALUES OF THE
;   THE REGISTERS STORED BY THE LAST ENCOUNTERED BREAKPOINT.
;   THE VALUES MAY BE MODIFIED IF DESIRED.
;
XAA:	INX	H 	;SKIP OVER TO NEXT ENTRY
	INX	H 
XA:	INR	M	;SEE IF AT END OF TABLE
	RZ		;COULDN'T FIND MATCH, QUIT
	JP	XAB	;SORT OUT BIT 7 OF TABLE
	ORI	80H	;SET IT ON TEST VALUE
	JR	XAC
XAB:	ANI	7FH	;RESET BIT 7
XAC:	DCR	M	;TO BE PULLED OUT IN ROM
	CMP	M 	;SEE IF THIS IS IT
	JRNZ	XAA	;NO, GO TRY AGAIN
	CALL	BLK 	;YES, PREPARE TO SHOW CURRENT VALUE
	CALL	PRTVAL	;GO PRINT THE VALUE
	CALL	DASH 	;PROMPT A NEW VALUE
	CALL	PCHK 	;GET THE INPUT
	RC		;DONE IF CARRIAGE RETURN
	JRZ	XF 	;JUMP IF NO CHANGE DESIRED
	PUSH	H 	;TO BE CHANGED, SAVE POINTER
	CALL	EXF 	;GET THE NEW VALUE
	POP	H 	;  INTO (H,L)
	MOV	A,L 	;GET THE NEW LOW BYTE
	INX	D	;ADJUST POINTER
	STAX	D 	;PUT IT DOWN
	XTHL		;RECOVER THE TABLE POINTER
	MOV	A,M	;GET THE ATTRIBUTES
	XTHL		;SET THE STACK STRAIGHT
	RLC		;SEE IF 8 BIT REGISTER
	JRNC	XE	;JUMP IF SO
	INX	D	;REGISTER PAIR, DO OTHER 8 BITS 
	MOV	A,H 
	STAX	D 
XE:	POP	H	;RESTORE THE TABLE POINTER 
XF:	MOV	A,C	;SEE IF IT WAS A CR 
	CPI	CR 
	RZ		;DONE IF SO
XMNE:	LXI	H,ACTBL	;GET ADDRESS OF REGISTER LOOK-UP TABLE
XMNE1:	CALL	PCHK	;FIND OUT WHAT ACTION IS WANTED
	JRC	XG	;SHOW ALL IF CARRIAGE RETURN 
	JRZ	XMNE1	;IGNORE BLANKS OR COMMAS
	CPI	''''	;SEE IF PRIMES WANTED
	JRNZ	XA	;NO, MUST BE SINGLE REGISTER
	LXI	H,PRMTB	;YES, SET TABLE ADDRESS
	JR	XMNE1	;  AND FIND OUT WHICH ONE
;
XG:	MOV	A,M 
	MOV	C,A 
	INR	A	;SEE IF AT END OF TABLE
	RZ		;DONE IF SO
	CM	CRLF	;START A NEW LINE IF BIT 7 IS SET
	CALL	CONOUT 
	CALL	DASH	;PROMPT FOR A NEW VALUE 
	CALL	PRTVAL	;GO PRINT THE VALUE
	CALL	BLK	;FORMATTER
	INX	H	;POINT TO NEXT ENTRY
	JR	XG	;DO THE NEXT VALUE
;
PRTVAL:	INX	H	;POINT TO NEXT ENTRY
	MOV	A,M	;GET OFFSET AND ATTRIBUTES BYTE
	ANI	3FH	;ISOLATE THE OFFSET
	ADI	2	;ALLOW FOR RETURN ADDRESS
	XCHG		;SWAP POINTERS
	MOV	L,A	;BUILD THE ADDRESS OF THE REG CONTENTS
	MVI	H,0
	DAD	SP
	XCHG		;RE-SWAP THE POINTERS
	MOV	A,M	;NOW FIND OUT ATTRIBUTES
	MVI	B,1	;SET UP FOR SINGLE REG VALUE
	RLC
	JRNC	PV1	;JUMP IF SINGLE REGISTER VALUE WANTED
	INR	B	;SET UP FOR REGISTER PAIR
	RLC
	JRNC	PV1	;JUMP IF REGISTER PAIR IS NEXT
	PUSH	H	;SPECIAL CASE FOR MEMORY REGISTER
	LDAX	D	;BUILD ADDRESS IN (H,L)
	MOV	H,A
	DCX	D
	LDAX	D
	MOV	L,A
	MOV	A,M	;GET THE MEMORY VALUE
	POP	H	;RESTORE (H,L)
	DJNZ	PV2	;ALWAYS JUMP
PV1:	LDAX	D	;GET THE REGISTER CONTENTS
PV2:	CALL	HEX1	;OUTPUT THE VALUE
	DCX	D	;ADJUST THE MEMORY POINTER
	DJNZ	PV1
	RET
;
ACTBL:	DB	80H+'A',ALOC
	DB	'B',BLOC
	DB	'C',CLOC
	DB	'D',DLOC
	DB	'E',ELOC
	DB	'F',FLOC
	DB	'H',HLOC
	DB	'L',LLOC
	DB	80H+'M',HLOC+0C0H
	DB	'P',PLOC+80H
	DB	'S',SLOC+80H
	DB	'I',ILOC
;
; REST OF Z-80 REGISTER OFFSETS
;
PRMTB:	DB	80H+'A',APLOC
	DB	'B',BPLOC
	DB	'C',CPLOC
	DB	'D',DPLOC
	DB	'E',EPLOC
	DB	'F',FPLOC
	DB	'H',HPLOC
	DB	'L',LPLOC
	DB	80H+'M',HPLOC+0C0H
	DB	'X',XLOC+80H
	DB	'Y',YLOC+80H
	DB	'R',RLOC
	DB	0FFH
;
; GENERAL PURPOSE ROUTINES
;
;
; ROUTINE CONV CONVERTS THE LOW ORDER NIBBLE OF THE 
;	ACCUMULATOR TO ITS ASCII EQUIVELANT.  IT
;	PUTS THE RESULT INTO C FOR LATER OUTPUT.
;
CONV:	ANI	0FH	;STRIP OFF BITS 4-7
	ADI	90H	;PUT ON THE ASCII ZONE
	DAA
	ACI	40H
	DAA
	MOV	C,A	;PUT IN OUTPUT PASS REGISTER
	RET
;
; ROUTINE ECHO READS A BYTE FROM A HALF-DUPLEX CONSOLE
;	DEVICE, THEN ECHOES THE CHARACTER BACK TO THE
;	CONSOLE.
;
DECHO:	CALL	DASH	;PRINT A DASH
ECHO:	CALL	CONI	;CONSOLE READ, WRITE ROUTINE
ECH1:	PUSH	B	;  SAVE (B,C)
	MOV	C,A	;  PASS CHARACTER IN C REGISTER
	CALL	CONOUT	;  OUTPUT IT
	MOV	A,C	;  PUT CHARACTER BACK INTO A
	POP	B	;  RESTORE (B,C)
	RET
;
; ROUTINE EXPR3 GETS THREE PARAMETERS, DOES A CR, LF AND 
;     THEN LOADS (B,C), (D,E), AND (H,L) WITH THE PARAMETERS.
;
EXPR3:	INR	B	;2 IS ALREADY IN THE B REGISTER
	CALL	EXPR	;GET THE PARAMETERS
	POP	B	;PUT PARAMETERS INTO REGISTERS
	POP	D
	JMP	CRLFA	;GO DO THE CARRIAGE RETURN SEQUENCE
;
; ROUTINE HILO INCREMENTS (H,L).  IT THEN CHECKS FOR (AND
;	DISALLOWS) A WRAP-AROUND SITUATION.  IF IT OCCURS,
;	THE CARRY BIT WILL BE SET ON RETURN.  IF NO WRAP-
;	AROUND OCCURRED, (H,L) IS COMPARED TO (D,E) AND
;	THE FLAG BITS SET ACCORDINGLY.
;
HILO:	INX	H	;INCREMENT (H,L)
	MOV	A,H	;TEST IF ZERO
	ORA	L	;  IN (H,L)
	STC		;SET CARRY FOR (H,L)=0
	RZ		;RETURN IF (H,L) = 0
	MOV	A,E	;COMPARE (H,L) TO (D,E)
	SUB	L
	MOV	A,D
	SBB	H
	RET		;RETURN WITH FLAGS SET
;
; ROUTINE HILOX INCREMENTS (H,L), COMPARES IT TO (D,E) AND
;   IF EQUAL, RETURNS CONTROL TO THE MONITOR EXECUTIVE.
;   OTHERWISE, CONTROL RETURNS TO THE CALLING ROUTINE.
;
HILOD:	POP	D	;GET RID OF RETURN ADDRESS
	RET		;RETURN TO MONITOR
HILOXB:	INX	B	;INCREMENT (B,C)
HILOX:	CALL	HILO	;INC AND CHECK (H,L)
	JRC	HILOD	;DONE IF CARRY SET
	CALL	CONST	;SEE IF CONSOLE BREAK PENDING
	ORA	A
	RZ		;NONE, RETURN TO CONTINUE
	CALL	CONI	;SEE IF WAIT OR BREAK
	CPI	CTRLS
	JRNZ	HILOD	;JUMP IF BREAK
	JMP	CONI	;WAIT FOR ANY INPUT
;
; ROUTINE NIBBLE CONVERTS THE ASCII CHARACTERS 0-9 AND
;	A-F TO THEIR EQUIVELANT HEXADECIMAL VALUE.  IF
;	THE CHARACTER IS NOT IN RANGE, THE CARRY BIT IS SET TO
;	FLAG THE ERROR.
;
NIBBLE:	SUI	'0'	;ASCII TO HEX CONVERSION
	RC		;  DONE IF OUT OF RANGE
	CPI	'G'-'0'	;CHECK UPPER END
	CMC		;  TOGGLE THE CARRY BIT
	RC		;  DONE IF OUT OF RANGE
	CPI	'9'-'0'+1  ;SEE IF NUMERIC
	CMC		;  TOGGLE THE CARRY BIT
	RNC		;  DONE IF SO
	SUI	'A'-'9'-1  ;SUBTRACT THE ALPHA BIAS
	CPI	10	;  SET CARRY FOR INVALID CHAR
	RET
;
; ROUTINE PCHK READS A CHARACTER FROM THE CONSOLE, THEN
;	CHECKS IT FOR A DELIMITER. IF IT IS NOT
;	A DELIMITER, A NON-ZERO CONDITION IS RETURNED.
;	IF IT IS A DELIMITER, A ZERO CONDITION IS RETURNED.
;	FURTHER, IF THE DELIMITER IS A CARRIAGE RETURN,
;	THE CARRY BIT IS SET.  A BLANK OR A COMMA RESET THE
;	CARRY BIT.
;
PCHK:	CALL	ECHO	;GET, TEST FOR DELIMITER
P2C:	CPI	' '	;  BLANK?
	RZ		;  YES, DONE
	CPI	','	;  NO, COMMA?
	RZ		;  YES, DONE
	CPI	CR	;  NO, CARRIAGE RETURN?
	STC		;  SHOW IT IN CARRY BIT
	RZ		;  DONE IF CR
	CMC		;CLEAR CARRY FOR NO DELIMITER
	RET
;
;
; ROUTINE REST TRAPS ALL OF THE REGISTER CONTENTS WHENEVER A
;	RESTART 1 INSTRUCTION IS EXECUTED.  THE TRAPPED CONTENTS
;	ARE STORED IN THE SYSTEM STACK AREA FOR LATER ACCESS AND
;	USE BY THE GOTO AND THE EXAMINE REGISTERS COMMANDS.
;
; INSERT INTERRUPT DISABLER SOFTWARE AT START OF REST:
REST:	PUSH	H	;SAVE ALL THE REGISTERS
	PUSH	D
	PUSH	B
	PUSH	PSW
	CALL	MEMSIZ	;GET THE MONITOR'S STACK LOCATION
	XCHG
	LXI	H,10	;GO UP 10 BYTES IN THE STACK
	DAD	SP	;  TO SKIP OVER TEMP REGISTER SAVE
	MVI	B,4	;PICK OFF THE REGISTER VALUES
	XCHG
RS1:	DCX	H
	MOV	M,D	;SAVE IN WORK AREA
	DCX	H
	MOV	M,E
	POP	D
	DJNZ	RS1
	POP	B	;GET THE BREAKPOINT LOCATION
	DCX	B
	SPHL		;SET THE MONITOR STACK
	LXI	H,TLOCX	;SET UP TO RESTORE BREAKPOINTS
	DAD	SP
	PUSH	D
	MVI	D,NBKPTS ;LOOP CONTROL FOR N BREAKPOINTS
RS2:	MOV	A,M
	SUB	C	;SEE IF A SOFTWARE TRAP
	INX	H
	MOV	A,M
	SBB	B	;MAYBE, TRY REST OF ADDRESS
	JRZ	RS5	;FOUND ONE, JUMP TO RESET IT
RS3:	INX	H	;NOT FOUND, TRY NEXT ONE
	INX	H
	DCR	D
	JRNZ	RS2
RS4:	INX	B	;NONE FOUND
RS5:	LXI	H,LLOCX
	POP	D
	DAD	SP
	MOV	M,E	;STORE USER (H,L)
	INX	H
	MOV	M,D
	PUSH	B	;SAVE (B,C)
	MVI	C,'*'	;TYPE THE BREAK INDICATION
	CALL	CONOUT
	POP	D	;REGET THE BREAKPOINT LOCATION
	MVI	A,RS9/256
	CMP	D	;SEE IF A RET BREAKPOINT
	JRZ	RS6
	INX	H
	INX	H
	MOV	M,E	;RESTORE USER PROGRAM COUNTER
	INX	H
	MOV	M,D
	XCHG		;PRINT THE BREAKPOINT LOCATION
	CALL	LADR
RS6:	LXI	H,TLOCX
	DAD	SP
	LXI	B,NBKPTS*256
RS7:	MOV	E,M	;RESTORE BREAKPOINTED LOCATIONS
	MOV	M,C	;RESET SYSTEM BP SAVE AREA
	INX	H
	MOV	D,M
	MOV	M,C
	INX	H
	MOV	A,E
	ORA	D
	JRZ	RS8	;DO NOTHING IF ZERO
	MOV	A,M
	STAX	D
RS8:	INX	H	;SAME THING FOR OTHER
	DJNZ	RS7	; BREAKPOINT
	EXAF		;NOW SAVE THE Z-80 UNIQUES
	EXX
E5        	PUSH	H
	PUSH	D
	PUSH	B
	PUSH	PSW
	PUSHIX
	PUSHIY
	LDAI
	MOV	B,A
	LDAR
	MOV	C,A
	PUSH	B
	JMP	WINITA	;RETURN TO MONITOR
RS9:	PUSH	H	;RET BREAKPOINT ENCOUNTERED, ADJUST THE STACK
	RST	1	;DO THE BREAKPOINT
;
EXIT:	POP	B
	MOV	A,C
	STAR
	MOV	A,B
	STAI
	POPIX
	POPIY
	POP	PSW
	POP	B
	POP	D
	POP	H
	EXAF
	EXX
  	POP	D
	POP	B
	POP	PSW
	POP	H
	SPHL
	DB	0	;PLACE FOR EI
	LXI	H,0
	JMP	0
ENDX:	EQU	$
;
; ERROR HANDLERS
;
;	THREE TYPES OF ERRORS ARE DETECTED:  A RESTART
;	ERROR; AN I/O ASSIGNMENT ERROR; AND CERTAIN PROGRAM
;	ERRORS (DETERMINED BY THE PARTICULAR ROUTINE WHERE
;	THE ERROR CONDITION WAS ENCOUNTERED.)  EACH CAUSES
;	A UNIQUE MESSAGE TO BE PRINTED, THEN DOES A WARM
;	INITIALIZATION OF THE MONITOR.  THE I/O ERROR
;	CAUSES THE I/O ASSIGNMENTS TO BE RESET TO DEFAULT ASSIGNMENTS.
;
IOER:	XRA	A	;SET IOBYTE TO DEFAULT VALUE
	STA	IOBYTE
	LXI	H,IOMSG	;GET ADDRESS OF I/O ERROR MSG
	JMP	COMERR	;GO PROCESS IT
;
IOMSG:	DB	'I/O ER','R'+80H
DERMSG:	DB	'DSK ERR: U','-'+80H
	DB	' T','-'+80H
	DB	' S','-'+80H
	DB	' C','-'+80H
	DB	' E','-'+80H
	DB	CR,LF+80H
QMSG:	DB	'???','?'+80H
LOGMSG:	DB	'MOSS VERS 2.2'
	DB	CR,LF+80H
;
;
; INITIALIZATION CODE FOR THE 8250 ASYNCHRONOUS COMMUNICATION
;   ELEMENT.  THIS CODE WILL INITIALIZE THE BAUD RATE OF THE
;   8250, AS WELL AS THE WORD FORMAT.  8 DATA BITS, 1 STOP BIT,
;   AND NO PARITY ARE SELECTED.  EITHER 2 OR 3 CARRIAGE RETURNS
;   MUST BE ENTERED TO ESTABLISH THE CORRECT BAUD RATE.
;
I8250:	MVI	A,0FH	;SET UP THE 8250
	OUT	SMDMCT
	LXI	D,40H	;SET UP TO TIME THE START BIT
	MOV	H,D	;MAKE (H,L)=0
	MOV	L,D
I8250A:	IN	SMDMST	;WAIT FOR START BIT
	ANA	E
	JRZ	I8250A
I8250B:	IN	SMDMST	;NOW, TIME THE START BIT DURATION
	INX	H
	ANA	E
	ANA	E
	JNZ	I8250B
	PUSH	H	;SAVE COUNT IN CASE OF 4 MHZ
	DAD	H	;PREPARE THE 2 MHZ DIVISOR
	MOV	E,H	;SET UP THE FUDGE FACTOR
	DAD	D	;APPLY THE FUDGE FACTOR
	DAD	D
	PUSH	H	;SAVE FOR LATER	USE
	DAD	H	;WAIT FOR 8 BIT TIMES
	DAD	H
I8250C:	IN	SDATA	;WASTE SOME TIME
	DCX	H
	MOV	A,L
	ORA	H
	JNZ	I8250C
	POP	H	;REGET 2 MHZ DIVISOR
I8250D:	MVI	A,83H	;SET DIVISOR REGISTER ACCESS
	OUT	SLCTRL
	MOV	A,H
	OUT	SINTEN
	MOV	A,L	;SET THE DIVISOR
	OUT	SDATA
	MVI	A,3	;SET DATA REGISTER ACCESS
	OUT	SLCTRL
	XRA	A	;DISABLE INTERRUPTS
	OUT	SINTEN
	OUT	SLSTAT	;AND RESET ERROR FLAGS
	CALL	TTYIN	;GET A CHARACTER
	ANI	7FH	;STRIP OFF ANY PARITY BIT
	CPI	0DH	;SEE IF IT IS A CARRIAGE RETURN
	POP	H	;SET THE STACK STRAIGHT
	RZ		;DONE IF CARRIAGE RETURN RECEIVED
	MOV	E,L	;ELSE, MUST BE 4 MHZ SYSTEM
	MOV	D,H	; SO, COUNT=COUNT*5/4
	CALL	DIV2
	CALL	DIV2
	DAD	D
	PUSH	H
	JR	I8250D	;GO SET THE NEW DIVISOR
;
;
DIV2:	ORA	A	;CLEAR THE CARRY BIT
	MOV	A,H	;DO A 16-BIT RIGHT SHIFT
	RAR
	MOV	H,A
	MOV	A,L
	RAR
	MOV	L,A
	RET
;
;
READ:	MVI	A,1	;SET THE READ/WRITE FLAG
	ORG	$-1	;SAVE A BYTE HERE
WRITE:	XRA	A	;RESET THE READ/WRITE FLAG
	STA	RWFLG	;SAVE THE FLAG
	LXI	H,80H
	SHLD	LUNIT	;FORCE A READ ADDRESS COMMAND
	CALL	EXLF	;GET THE START, STOP ADDRESS
	PUSH	D	;SAVE THE LIMIT
RW1:	LDA	RWFLG
	ORA	A	;SEE IF READ OR WRITE
	JRNZ	RW2	;JUMP IF READ
	SHLD	HSTBUF	;SET THE WRITE SOURCE BUF
	CALL	DWRITE	;ELSE, DO THE WRITE
	JR	RW3
RW2:	CALL	DREADH	;DO THE READ
RW3:	POP	D
	JRNZ	DERROR	;JUMP IF ERROR
	LDA	SPT	;GET THE SECTORS PER TRACK
	MOV	B,A	;SAVE IT
	IN	DTRCK	;SEE IF ON TRACK 00
	ORA	A
	JRNZ	RW4	;JUMP IF NOT
	MVI	B,26	;ELSE, SET THE SECTORS PER TRK 00
	LDA	CUNIT
	ANI	10H
	JRNZ	RW4
	MVI	B,18	;MINI DRIVES
RW4:	PUSH	H	;SAVE THE DMA ADDRESS
	LXI	H,SECTOR  ;SET UP MEMORY POINTER
	MOV	A,M	;GET NUMBER OF SECTORS
	CMP	B	;SEE IF TRACK OVERFLOW
	JRC	RW5	;JUMP IF NOT
	LDA	TWOSID	;SEE IF DOUBLE-SIDED
	ORA	A
	JRZ	RW7	;JUMP IF NOT
	LDA	SIDE	;YES, SEE IF NEXT SIDE OR TRACK NEEDED
	CPI	0D0H
	JRNZ	RW7	;NEXT TRACK, JUMP
	MVI	A,90H	;ELSE, SET NEXT SIDE
	JR	RW8
RW7:	MVI	A,0D0H
	DCX	H	;ELSE, UPDATE THE TRACK
	INR	M
	INX	H
RW8:	STA	SIDE
	MVI	M,0	;  AND THE SECTOR POINTER
RW5:	INR	M
	POP	H	;RESTORE THE DMA ADDRESS
	DCX	H
	CALL	HILOX	;SEE IF DONE
	PUSH	D	;CONTINUE IF CONTROL RETURNED
	JR	RW1
;
; ROUTINE DINIT CHECKS THE 2422'S AUTO-BOOT CONTROL BIT
;	DURING INITIALIZATION.  IT THEN TRANSFERS
;	CONTROL TO EITHER THE MONITOR OR THE BOOTSTRAP,
;	AS APPROPRIATE.
;
DINIT:	IN	DCNTL	;SEE IF AUTO-BOOT WANTED
	ANI	40H
	RNZ		;NO, RETURN TO MONITOR INITIALIZATION
;
; ROUTINE BOOT LOADS IN THE FIRST TWO SECTORS OF
;	DRIVE 00 INTO LOCATIONS 80H-17FH, THEN
;	TRANSFERS PROGRAM CONTROL TO LOCATION 80H.
;	IT EXPECTS THE DOS LOADER TO BE ON THESE
;	TWO SECTORS.
;
BOOT:	LXI	H,0	;SET UP THE DISK PARMS
	SHLD	DISKNO
	LXI	H,0D001H  ;SIDE 0, SECTOR 1
	SHLD	SECTOR
	LXI	H,TBUF
	SHLD	LUNIT	;FORCE A DISK DETERMINATION
	CALL	DREADH	;GO GET A SECTOR
	JRNZ	DERROR	;QUIT IF AN ERROR ENCOUNTERED
	MVI	A,2	;GET SECTOR 2, ALSO
	STA	SECTOR
	CALL	DREADH
	JZ	TBUF	;GO TO THE LOADER
;
DERROR:	LXI	H,DERMSG  ;ADDRESS OF DISK ERROR MESSAGE
	CALL	PRTWD	;START THE MESSAGE
	LDA	DISKNO	;DO THE UNIT ASSIGNMENT
	CALL	DERR1
	LDA	TRACK	;AND THE TRACK
	CALL	DERR1
	LDA	SECTOR	;AND THE SECTOR
	CALL	DERR1
	LDA	CMND	;AND THE COMMAND
	CALL	DERR1
	LDA	STATUS	;AND THE STATUS
DERR1:	CALL	HEX1	;OUTPUT IT IN HEX
	JMP	PRTWA	;CONTINUE THE MESSAGE
;
; SET DISK PARAMETERS ROUTINE EXPECTS THREE PARAMETERS
;	TO BE ENTERED FROM THE CONSOLE.  THESE PARAMETERS
;	ARE:  UNIT NUMBER (0-3); SECTORS PER TRACK;
;	AND DOUBLE-SIDED SWITCH (0 OR NON-0).
;	ONLY THE UNIT NUMBER IS CHECKED FOR ERRORS.
;
;	THIS ROUTINE MUST BE CALLED BEFORE USE OF EITHER
;	THE DISK READ OR WRITE ROUTINE.
;
PARM:	CALL	EXPR3	;GET THE THREE PARAMETERS
	MOV	A,L	;ERROR CHECK THE UNIT ASSIGNMENT
	ORA	A
	JM	QPRT
	CPI	4
	JNC	QPRT
	STA	DISKNO	;SET THE UNIT SELECT
	MOV	L,E	;MOVE THE SECTORS PER TRACK OVER
	MOV	H,C	;  AND THE TWO-SIDED SWITCH
	SHLD	SPT	;STORE THEM
	RET
;
; ROUTINE QPARM ALSO SETS CERTAIN DISK PARAMETERS.  IN THIS
;	CASE, THE DESIRED START TRACK, SIDE, AND SECTOR ARE
;	SET.  THESE PARAMETERS NEED ONLY BE SET PRIOR TO THE
;	FIRST DISK ACCESS, OR WHEN A NON-CONTIGUOUS DISK ACCESS
;	IS DESIRED.  IF THE PARAMETERS ARE NOT RESET BETWEEN
;	DISK ACCESSES, THE DATA TRANSFER WILL OCCUR TO/FROM
;	THE NEXT LOGICALLY SEQUENTIAL DISK LOCATIONS.
;
QPARM:	CALL	EXPR3	;GET THE THREE PARAMETERS
	MOV	H,C	;MOVE OVER THE START SECTOR
	SHLD	TRACK	;STORE THE TRACK AND SECTOR
	MOV	A,E	;GET THE SIDE INDICATOR
	ORA	A	;SEE IF SINGLE-SIDED
	MVI	A,0D0H	;SIDE 0 SELECT BITS
	JRZ	QPARM1	;JUMP IF SO
	MVI	A,90H	;ELSE, SET THE SIDE 1 CONTROL BIT
QPARM1:	STA	SIDE	;SAVE IT
	RET
;
; HEXN ROUTINE
;
;THIS ROUTINE ADDS AND SUBTRACTS TWO HEXADECIMAL 16 BIT
;	UNSIGNED NUMBERS AND DISPLAYS THE RESULTS ON THE
;	CONSOLE.
;
HEXN:	CALL	EXLF	;GET THE TWO NUMBERS
	PUSH	H	;SAVE IT FOR THE SUBTRACT
	DAD	D	;ADD THEM
	CALL	LADRB	;OUTPUT THEM
	POP	H	;REGET THE FIRST NUMBER
	ORA	A	;CLEAR THE CARRY BIT
	DSBC	D	;DO THE SUBTRACT
	JR	LADR	;GO OUTPUT THE RESULT
;
; ROUTINE LADR PRINTS THE CONTENTS OF (H,L) ON THE 
;	CURRENT CONSOLE, EITHER AT THE START OF A NEW
;	LINE (EP = LADRA) OR AT THE CURRENT LOCATION (EP
;	= LADR).
;
LADRA:	CALL	CRLF	;START A NEW LINE
LADR:	MOV	A,H	;GET HIGH TWO DIGITS
	CALL	HEX1	;PRINT THEM
	MOV	A,L	;GET LOW TWO DIGITS
HEX1:	PUSH	PSW	;SAVE THE LOW DIGIT
	RRC		;PUT HIGH NIBBLE INTO BITS 0-3
	RRC
	RRC
	RRC
	CALL	HEX2	;GO PRINT SINGLE DIGIT
	POP	PSW	;REGET THE LOW DIGIT
HEX2:	CALL	CONV	;GO INSERT ASCII ZONE
	JR	CO	;DO THE CHARACTER OUTPUT
;
; ROUTINE DASH TYPES A DASH ON THE CURRENT CONSOLE DEVICE.
;
DASH1:	CALL	HEX1	;FIRST, PRINT ACCUM AS TWO HEX DIGITS
DASH:	MVI	C,'-'	;GET AN ASCII DASH
	JR	CO	;GO TYPE IT
;
; IOBYTE HANDLERS
;
	ORG	MOSS+5FBH
LADRB:	CALL	LADRA	;OUTPUT (H,L) AS 4 ASCII DIGITS
;
BLK:	MVI	C,' '	;OUPTUT A BLANK
;
CO:	LDA	IOBYTE
	ANI	3	;ISOLATE CONSOLE ASGT
	JZ	TTYOUT	;TTY DEVICE ACTIVE
	CPI	2
	JM	CRTOUT	;CRT ACTIVE
	JNZ	CUSO1	;USER CONSOLE 1 ACTIVE
;
LO:	LDA	IOBYTE
	ANI	0C0H	;ISOLATE LIST ASGT
	JZ	TTYOUT	;TTY DEVICE ACTIVE
	CPI	80H
	JM	CRTOUT	;CRT ACTIVE
	JZ	LPRT	;LINE PRINTER ACTIVE
	JMP	LUSE1	;USER PRINTER 1 ACTIVE
;
CSTS:	LDA	IOBYTE
	ANI	3	;ISOLATE CONSOLE ASGT
	JZ	TTST	;TTY ACTIVE
	CPI	2
	JM	CRTST	;CRT ACTIVE
	JNZ	CUST1	;USER CONSOLE 1 ACTIVE
;
BATST:	LDA	IOBYTE
	ANI	0CH	;ISOLATE BATCH ASGT
	JZ	TTST	;TTY ACTIVE
	CPI	8
	JM	PTRST	;PAPER TAPE READER ACTIVE
	JZ	RUST1	;USER READER 1 ACTIVE
	JMP	RUST2	;USER READER 2 ACTIVE
;
CI:	LDA	IOBYTE
	ANI	3	;ISOLATE CONSOLE ASGT
	JZ	TTYIN	;TTY DEVICE ACTIVE
	CPI	2
	JM	CRTIN	;CRT ACTIVE
	JNZ	CUSI1	;USER CONSOLE 1 ACTIVE
;
RI:	LDA	IOBYTE
	ANI	0CH	;ISOLATE BATCH ASGT
	JZ	TTYRDR	;TTY ACTIVE
	CPI	8
	JM	PTRIN	;PAPER TAPE READER ACTIVE
	JZ	RUSI1	;USER READER 1 ACTIVE
	JMP	RUSI2	;USER READER 2 ACTIVE
;
LSTAT:	LDA	IOBYTE
	ANI	0C0H	;ISOLATE THE LIST DEVICE ASSIGNMENT
	JZ	TTOST
	CPI	80H
	JM	CRTOST
	JZ	LPRST
	JMP	LUST1
;
PO:	LDA	IOBYTE
	ANI	30H	;ISOLATE PUNCH ASGT
	JZ	TTPNCH	;TTY ACTIVE
	CPI	20H
	JM	HSP	;HIGH SPEED PUNCH ACTIVE
	JZ	PUSO1	;USER PUNCH 1 ACTIVE
	JMP	PUSO2	;USER PUNCH 2 ACTIVE
;
; ROUTINE CONI READS THE CONSOLE AND STRIPS OFF THE ASCII
;	PARITY BIT.
;
CONI:	CALL	CI	;GET THE NEXT CHARACTER
	ANI	7FH	;STRIP OFF THE PARITY BIT
RTS:	RET
;
; ROUTINE PRTWD PRINTS AN ASCII STRING ONTO THE CONSOLE.
;	THE STRING MUST BE TERMINATED BY BIT 7 SET IN THE
;	LAST CHARACTER OF THE STRING.  THE STRING WILL START
;	A NEW LINE (EP = PRTWD) OR CONTINUE ON THE SAME
;	LINE (EP = PRTWA)
;
PRTWD:	CALL	CRLF	;START A NEW LINE
PRTWA:	PUSH	B	;SAVE (B,C)
PRTA:	MOV	C,M	;GET NEXT CHARACTER FROM MEMORY
	CALL	CO	;OUTPUT IT
	INX	H	;INCREMENT MEMORY POINTER
	MOV	A,C
	RLC		;TEST FOR BIT 7 DELIMITER
	JRNC	PRTA	;NO DELIMITER, GO DO NEXT CHARACTER
PRTB:	POP	B	;RESTORE (B,C)
	RET
;
; ROUTINE EXLF READS TWO PARAMETERS, PUTS THEM INTO THE
;	D,E AND H,L REGISTERS, THEN DOES A CARRIAGE RETURN,
;	LINE FEED SEQUENCE.
;
EXLF:	CALL	EXPR	;GO GET TWO PARAMETERS
	POP	D
	POP	H
;
; ROUTINE CRLF GENERATES A CARRIAGE RETURN, LINE FEED
;	SEQUENCE ON THE CURRENT CONSOLE TO START A NEW LINE
;	IT INCLUDES TWO NULL CHARACTERS FOR TTY TYPE
;	DEVICES FOR THE HEAD MOVEMENT TIME.
;
CRLF:	PUSH	H	;SAVE THE CONTENTS OF (H,L)
CRLFA:	LXI	H,CRMSG	;ADDRESS OF CR,LF MESSAGE
	CALL	PRTWA	;  OUTPUT IT
	POP	H	;RESTORE (H,L)
	RET
;
RSTER:	LXI	H,RSTMSG ;GET ADDRESS OF RESTART ERROR MSG
COMERR:	CALL	PRTWD	;PRINT IT ON NEW LINE
	JMP	WSVEC	;GO TO WARM BOOT
;
RSTMSG:	DB	'RST ER','R'+80H
CRMSG:	DB	CR,LF,0,80H
;
; I/O DRIVERS FOR THE 8250 ASYNC COMM ELEMENT
;
TTST:	IN	SLSTAT	;GET 8250 LINE STATUS
	ANI	1	;SEE IF RECEIVE DATA AVAILABLE
	RZ		;RETURN IF NOT
	ADI	0FEH	;FLAG THAT DATA IS AVAILABLE
	RET
;
TTYIN:	IN	SLSTAT	;GET 8250 LINE STATUS
	RAR		;MOVE RX DATA READY BIT INTO CARRY
	JRNC	TTYIN	;LOOP UNTIL DATA IS IN
	IN	SDATA	;READ THE DATA
	RET
;
TTOST:	IN	SLSTAT	;GET 8250 LINE STATUS
	ANI	20H	;ISOLATE TX BUFFER EMPTY BIT
	RZ		;RETURN IF NOT EMPTY
	ADI	0BFH	;FLAG THE EMPTY STATE
	RET
;
TTYOUT:	CALL	TTOST	;GET 8250 LINE STATUS
	JRZ	TTYOUT	;WAIT UNTIL ONE OF THE REGISTERS EMPTIES
	MOV	A,C	;MOVE THE DATA OVER
	OUT	SDATA	;OUTPUT THE DATA
	RET
;
; EQUATES FOR ADDITIONAL CONSOLE DEVICES
;
CRTIN:	EQU	IOER
CRTOUT:	EQU	IOER
CRTST:	EQU	IOER
CRTOST:	EQU	IOER	;UNASSIGNED CRT OUTPUT STATUS
CUSI1:	EQU	IOER	;UNASSIGNED USER CONSOLE (INPUT)
CUSO1:	EQU	IOER	;UNASSIGNED USER CONSOLE (OUPTUT)
CUST1:	EQU	IOER
;
;  EQUATES FOR ADDITIONAL PAPER TAPE PUNCH DEVICES
;
TTPNCH:	EQU	TTYOUT	;UNASSIGNED TELETYPE PUNCH
HSP:	EQU	IOER	;UNASSIGNED HIGH SPEED PUNCH
HSPST:	EQU	IOER	;UNASSIGNED HIGH SPEED PUNCH STATUS
PUSO1:	EQU	IOER	;UNASSIGNED USER PUNCH 1
PUSO2:	EQU	IOER	;UNASSIGNED USER PUNCH 2
;
;  EQUATES FOR ADDITIONAL LIST DEVICES
;
LPRT:	EQU	IOER	;UNASSIGNED LINE PRINTER
LPRST:	EQU	IOER	;UNASSIGNED LINE PRINTER STATUS
LUSE1:	EQU	IOER	;LIST DEVICE 1
LUST1:	EQU	IOER	;UNASSIGNED LIST DEVICE 1 STATUS
;
;  EQUATES FOR ADDITIONAL PAPER TAPE READER DEVICES
;
TTYRDR:	EQU	TTYIN	;UNASSIGNED TELETYPE PAPER TAPE READER
PTRIN:	EQU	IOER	;UNASSIGNED HIGH SPEED PAPER TAPE READER
PTRST:	EQU	IOER	;UNASSIGNED HS PTR STATUS
RUSI1:	EQU	IOER	;UNASSIGNED PAPER TAPE READER 1
RUST1:	EQU	IOER	;UNASSIGNED PAPER TAPE READER 1 (STATUS)
RUSI2:	EQU	IOER	;UNASSIGNED PAPER TAPE READER 2
RUST2:	EQU	IOER	;UNASSIGNED PAPER TAPE READER 2 (STATUS)
;
;
; THE FOLLOWING ROUTINES DO THE PRIMITIVE DISK ACCESSES.
;	IN ALL CASES, ONE SECTOR OF DATA IS TRANSFERRED.
;	IF THE DISK HAS NOT BEEN PREVIOUSLY ACCESSED,
;	THESE ROUTINES WILL AUTOMATICALLY DETERMINE THE
;	DISK TYPE (8" OR 5"), SINGLE OR DOUBLE DENSITY,
;	AND SECTOR SIZE.
;
;	BEFORE THE DESIRED DATA IS TRANSFERRED, THE DESIRED
;	TRACK IS SEEKED OUT, THE DESIRED SECTOR AND SIDE IS
;	SET, THEN THE ACTUAL DATA TRANSFER.
;
;	UP TO TEN TRIES WILL BE ATTEMPTED BEFORE THE DATA
;	TRANSFER IS ABORTED.  ON RETURN TO THE CALLING
;	ROUTINE, THE A REGISTER WILL CONTAIN A ZERO IF THE
;	OPERATION WAS SUCCESSFUL, OR NON-ZERO IF NOT
;	SUCCESSFUL.  THE FLAG REGISTER WILL NOT NECESSARILY
;	CORRESPOND WITH THE A REGISTER CONTENT.
;
;	THESE ROUTINES ARE CP/M COMPATABLE, AND MAY BE USED
;	AS PART OF THE BIOS.
;
;
DREADH:	SHLD	HSTBUF	;SAVE THE DMA ADDRESS
DREAD:	MVI	A,1	;SET READ FLAG
	ORG	$-1	;SAVE A BYTE HERE
DWRITE:	XRA	A	;SET WRITE FLAG
	STA	RWFLG	;SAVE IT FOR LATER USE
	MVI	B,10	;NUMBER OF RETRIES
AGN:	PUSH	B
	CALL	SEEK
	CZ	RDWR
READ3:	POP	B
	RZ
	DJNZ	AGN
	RET
;
RDWR:	MOV	E,A	;SAVE COMMAND
	LDA	RWFLG
	ORA	A
	MOV	A,E	;REGET THE COMMAND
	JRZ	WRDAT	;WRITE IF ZERO
RDAT:	STA	CMND
	OUT	DCMMD	;DISK COMMAND PORT
READ1:	INIR
	DCR	D
	JRNZ	READ1
	CALL	EOJ
	ANI	9CH	;ISOLATE READ ERROR BITS
	RET
;
WRDAT:	ORI	20H	;ADD WRITE COMMAND
	STA	CMND
	OUT	DCMMD	;DISK COMMAND PORT
WRT1:	OUTIR		;DO THE OUTPUT
	DCR	D	;IN CASE > 256 BYTES
	JRNZ	WRT1
	JR	EOJ
;
EOJB:	MVI	B,8	;BASIS OF RESTORE COMMAND
EOJA:	LDA	STPRAT	;GET THE STEP RATE BITS
	ORA	B	;ADD ON THE COMMAND
	STA	CMND
	OUT	DCMMD	;DO THE COMMAND
EOJ:	IN	DFLAG	;DISK FLAG PORT
	RAR
	JRNC	EOJ
EOJ1:	IN	DSTAT	;GET THE DISK STATUS
	STA	STATUS
	ANI	0FCH
	RET
;
SEEK:	CALL	IDRD	;INSURE HEADER HAS BEEN READ
	CNZ	EOJB	;RESTORE THE DRIVE IF ERROR
	RM		;DONE IF NO DRIVE
SEEK1:	LDA	SECTOR	;SET THE SECTOR
	OUT	DSCTR	;DISK SECTOR PORT
	IN	DTRCK	;DISK TRACK PORT
	MOV	C,A	;SAVE IT
	LDA	TRACK	;GET DESIRED TRACK
	CMP	C
	JRZ	RDWRT	;JUMP IF NO SEEK NEEDED
	OUT	DDATA	;SET THE SEEK TRACK
	MVI	B,1CH	;BUILD THE SEEK COMMAND
	CALL	EOJA	;DO THE SEEK
	ANI	98H	;SEEK ERROR MASK
	RNZ		;DONE IF SEEK ERROR
	IN	DTRCK	;CHECK FOR TRACK 00
RDWRT:	ORA	A
	LXI	H,40H	;BUILD SECTOR BYTE COUNT
	JRZ	RDWRT0	;JUMP IF TRACK 00
	LDA	IDSV+3	;GET SECTOR SIZE
RDWRT0:	DAD	H	;DOUBLE (H,L)
	DCR	A	;LOOP CONTROL
	JP	RDWRT0
	PUSH	H
	MVI	C,80H	;AUTO-WAIT BIT
	CALL	SETUP
	IN	DFLAG	;DISK FLAG PORT
	ANI	20H	;SEE IF HEAD IS LOADED
	MVI	A,4
	JRZ	RDWRT1	;JUMP IF NOT
	XRA	A	;ELSE, RESET THE HEAD LOAD FLAG
RDWRT1:	ADI	88H	;BUILD A READ SECTOR COMMAND
	LHLD	HSTBUF	;GET THE DMA ADDRESS
	POP	D	;GET THE BYTE COUNT
	MOV	B,E	;SET UP FOR Z-80 I/O
	DCR	D	;SEE IF 128 BYTE SECTOR
	INR	D
	JRNZ	RDWRT2	;JUMP IF NOT
	INR	D
RDWRT2:	MVI	C,DDATA
	CMP	A	;CLEAR THE FLAGS
	RET
;
IDRD5:	MVI	B,58H	;BUILD A STEP-IN COMMAND
	CALL	EOJA
IDRD:	LHLD	LUNIT
	MOV	A,H	;GET THE CUNIT VALUE
	CMP	L	;SEE IF SAME AS LUNIT
	RZ		;RETURN IF SO
IDRD1:	MVI	C,80H	;SET THE AUTO-WAIT BIT
	CALL	SETUP
	CALL	EOJ1	;INSURE A DRIVE IS THERE
	RM		;ERROR IF NOT
	PUSH	H	;SAVE POINTER
	LXI	H,IDSV	;SET UP TO READ ADDRESS
	LXI	B,600H+DDATA
	MVI	D,1
	MVI	A,0C4H	;READ ADDRESS COMMAND
	CALL	RDAT
	POP	H	;RESTORE POINTER
	JRZ	IDRD2	;JUMP IF GOOD READ
	MVI	A,40H	;SEE IF DDEN IS SET
	CMP	M
	RC		;TAKE THE ERROR IF SO
	ORA	M	;ELSE, TRY DDEN
	MOV	M,A
	JR	IDRD
;
IDRD2:	IN	DSCTR	;GET THE TRACK NUMBER
	OUT	DTRCK	;SET THE TRACK REGISTER
	ORA	A	;INSURE NOT ON TRACK 0
	JRZ	IDRD5	;JUMP IF NOT OKAY
	MOV	A,M	;REGET SELBITS
	STA	LUNIT	;UPDATE LAST USED UNIT
	XRA	A	;RESET ERROR FLAGS
	RET
;
;SET UP DRIVE NUMBER
SETUP:	LXI	H,CUNIT	;SEE IF DRIVE HAS BEEN ACTIVE
	MOV	A,M	;GET THE SELBITS
	ORA	A	;SEE IF SET UP YET
	JRNZ	SU0	;YES, SKIP INIT CODE
;
SETIT:	LDA	DISKNO	;GET THE DESIRED DRIVE
	MOV	B,A	;SAVE IN WORK REGISTER
	INR	B	;PREPARE TO CONVERT TO SELBITS
	XRA	A	;ZERO TO A
	STC		;DRIVE SELECT BIT
SET1:	RAL		;SHIFT BIT INTO POSITION
	DJNZ	SET1	;LOOP TIL BIT IS IN POSITION
	ORI	20H	;ADD ON MOTOR ON BIT
	MOV	M,A	;SAVE IT
	OUT	DCNTL	;SELECT THE DRIVE
	LXI	D,STPRAT  ;SET INITIAL STEP RATE
	MVI	A,3	; TO SLOWEST POSSIBLE
	STAX	D
	CALL	EOJB	;RESTORE THE DRIVE
	RM		;DONE IF DRIVE NOT READY
	IN	4	;READ THE MINI TRK00 BIT
	RAR		;ISOLATE IT
	JRNC	SU0	;JUMP IF MINI DRIVE
	MVI	A,10H	;ELSE, ADD ON MAXI BIT
	ORA	M
	MOV	M,A
	MVI	A,2	;SET MAXI STEP RATE
	STAX	D
SU0:	IN	DTRCK	;ELSE, SEE IF TRACK ZERO
	ORA	A
	MOV	A,M	;REGET THE SELBITS
	JRNZ	SU1
	ANI	0BFH	;INSURE DDEN IS RESET
SU1:	ORA	C	;ADD ON AUTOWAIT BIT
	OUT	DCNTL	;OUTPUT THE SELBITS
	LDA	SIDE	;SET THE SIDE SELECT
	OUT	4
	RET
