;*******************************************************
;****       THIS IS THE NORTH STAR DISK OPERATING   ****
;****  SYSTEM AS DIS-ASSEMBLED BY BARRY WATZMAN,    ****
;****  CCP, CDP.  NO WARRANTIES ARE MADE AS TO      ****
;****  THE CORRECTNESS OF THIS DIS-ASSEMBLY,        ****
;****  THOUGH THE AUTHOR IS NOT AWARE OF ANY ERROR  ****
;****  IN IT.  THIS WORK WAS DERIVED FROM VERSION   ****
;****  2 RELEASE 3, WHICH INCLUDES LINE EDITING,    ****
;****  AND INCLUDES THE FIX FOR THE 134 BLOCK       ****
;****  LOCKUP BUG DISCOVERED BY THE AUTHOR          ****
;****  (AT 24CFH).  NORTH STAR COMPUTERS INC. IS    ****
;****  AWARE OF THIS PUBLICATION AND HAS AUTHORIZED ****
;****  IT'S RELEASE ON A LIMITED WORD OF MOUTH ONLY ****
;****  (NO ADVERTISING) BASIS IN AN AGREEMEMT       ****
;****  BETWEEN DR. CHARLES GRANT AND THE AUTHOR IN  ****
;****  NOV., 1977.  THE NORTH STAR DOS PROGRAM IS   ****
;****  COPYRIGHT 1977 BY NORTH STAR COMPUTERS, INC. ****
;****  THIS LISTING IS COPYRIGHT 1977 BY BARRY A.   ****
;****  WATZMAN, CDP.  ADDITIONAL COPIES MAY BE      ****
;****  OBTAINED FOR $25.00 FROM THE AUTHOR AT 2330  ****
;****  MILLENNIUM LN., RESTON, VA. 22091.  THE      ****
;****  AUTHOR WOULD APPRECIATE BEING NOTIFIED OF    ****
;****  CORRECTIONS OR ADDITIONS TO THE UNCOMMENTED  ****
;****  PORTIONS OF THE LISTING.                     ****
;*******************************************************
;PAGE
;********************************************************
;****  THE NORTH STAR DISK OPERATING SYSTEM AS       ****
;****  DIS-ASSEMBLED BY BARRY A. WATZMAN, CDP        ****
;********************************************************
;****  THIS IS THE BOOT-STRAP ROUTINE IN PROM        ****
;********************************************************
BOARD	EQU	0E800H		;CONTROLLER BOARD ADDR
BRD	EQU	0E8H		;BOARD PAGE
DOS	EQU	2000H		;DOS ADDRESS
SYNCF	EQU	04H		;SYNC CHAR FOUND-RDY TO READ
SCTPS	EQU	0FH		;SECTOR POSITION MASK
TRAK0	EQU	01H		;TRACK ZERO MASK
MOTST	EQU	10H		;MOTOR ON TEST MASK
SETFF	EQU	BOARD+309H	;SET TRACK STEP FF
RESFF	EQU	BOARD+308H	;RESET TRACK STEP FF
ASTMS	EQU	BOARD+390H	;LOAD A STAT & START MOTR
ASTAT	EQU	BOARD+310H	;LOAD A STAT ONLY
BSTAT	EQU	BOARD+330H	;LOAD B STAT ONLY
RSFLG	EQU	BOARD+314H	;RESET SECTOR FLAG
STPIN	EQU	BOARD+31DH	;LOAD STEP DIR 'IN'
STPOU	EQU	BOARD+31CH	;LOAD STEP DIR 'OUT'
RDATA	EQU	BOARD+350H	;MASK TO READ DATA FROM DISK
;********************************************************
;**** THIS SECTION PERFORMS NECESSARY INITIALIZATION ****
;**** SO THAT THE NORMAL BLOCK READ ROUTINE AT E91EH ****
;**** MAY BE CALLED.  NOTE THAT THE MAX NO OF TRACK  ****
;**** MOVEMENTS TO GET THE HEAD TO TRACK 0 IS 58 -   ****
;**** THE AUTHOR APPARENTLY ADDED ONE FOR SAFETY BUT ****
;**** FORGOT THAT THE 58 WAS DECIMAL, NOT HEX.       ****
;********************************************************
	ORG	BOARD+100H
	LXI	SP,DOS+114H
	MVI	B,10		;READ 10 TIMES THEN GIVE UP
LE905	PUSH	B
	MVI	A,59H		;58D=MAX NO OF MOVES TO TRAK 0
	STA	DOS		;ASSUME HEAD AT WORST CASE LOC
	STA	DRSEL		;NONE OF THREE DRIVES SELECTED
	LXI	B,0001H		;B BECOMES DESIRED TRK;C=DRIVE
	MOV	A,C		;READ ONLY 1 SECTOR
	MVI	D,4		;D=BLK TO BE READ WITHIN TRACK
	MOV	E,C		;COMMAND;1 = READ
	LXI	H,DOS		;ADDRESS OF DOS TO BE LOADED
	CALL	LE91E		;MAIN PROCESSING LOOP
	JMP	CKBS		;IF OK EXIT ELSE RETRY OR DIE
;********************************************************
;**** THIS IS THE NORMAL READ ROUTINE.  THE ACC      ****
;**** HAS THE NUMBER OF SECTORS TO BE READ.  REG B   ****
;**** CONTAINS THE DESIRED TRACK, REGISTER C HAS     ****
;**** THE DESIRED DRIVE AND REGISTER D CONTAINS THE  ****
;**** DESIRED SECTOR (0-9) WITHIN THE TRACK.  THE    ****
;**** DATA WILL BE LOADED BEGINNING AT H,L. TRAK2    ****
;**** AND TRAK3 ARE INITIALIZED FROM THE DISK TO 59H ****
;**** WHEN THE 1ST BLOCK IS READ IN; THE TEST FOR    ****
;**** OLD TRK=59H IS REQD IN MULTIPLE DRIVE SYSTEMS  ****
;**** WHERE THE 2ND & 3RD DRIVES MAY BE UNINITIALIZED****
;**** FOR SOME TIME AFTER THE SYSTEM 1ST COMES UP.   ****
;********************************************************
LE91E	PUSH	PSW
	PUSH	H
	PUSH	D
	PUSH	B
	MVI	B,BRD+3		;CMNDS START AT 0EBH (C = 01H)
	CALL	MOTON		;MOTOR ON, SEL DRIVE, LOAD HEAD
	LXI	H,DOS-(BOARD+300H)-1
	DAD	B		;H = DOS + SELECTED DRIVE (1-3)
	MOV	A,M		;GET CURRENT TRACK ADDRESS
	XRI	59H		;STARTUP INIT. ALL 3 TO 59H
	PUSH	H
	CZ	LE964		;WILL POSITION HEAD TO TRK 0
	POP	H
	POP	PSW		;PUSHED AS B - DESIRED TRACK
	CALL	LE964		;POSITN HEAD TO TRK IN A
	POP	B		;PUSHED AS D - DESIRED SECTOR
;********************************************************
;**** THIS ROUTINE WAITS UNTIL WE HAVE THE DESIRED   ****
;**** SECTOR AND THEN JUMPS TO EITHER 200AH OR 2007H ****
;**** OR FALLS THRU TO READ DATA DEPENDING ON REG C  ****
;**** WHICH IS THE COMMAND (0=WRITE, 1=READ, 2=VER)  ****
;********************************************************
LE938	CALL	LE9CE		;WAIT FOR SECTOR FLAG
	LDA	BSTAT		;GET SECTOR POSITION
	ANI	SCTPS		;MASK IT
	CMP	B		;IS IT THE ONE WE WANT?
	JNZ	LE938		;NO--WAIT FOR NEXT SECTOR
	POP	H		;PUSHED AS H-DATA LOAD ADDRESS
	DCR	C		;TO SET COMMAND FOR PROPER JUMP
	JM	BOARD+0AH	;RETURN FOR WRITE ROUTINE
	JNZ	BOARD+7H	;RETURN FOR VERIFY ROUTINE
;********************************************************
;**** THIS ROUTINE WAITS UNTIL IT IS TIME TO READ    ****
;**** AND THEN JUMPS TO THE ACTUAL READ ROUTINE.  IF ****
;**** A SYNC CHARACTER HAS NOT BEEN DETECTED WITHIN  ****
;**** A SPECIFIED TIME FOLLOWING A SECTOR HOLE, THEN ****
;**** THEN ACC IS SET NON-ZERO AND A JUMP TO AN ERROR****
;**** ROUTINE IS MADE.                               ****
;********************************************************
LE94C	MVI	B,8CH		;MAX DELAY SECTOR TO SYNC CHAR
	LXI	D,RDATA		;SET UP D TO READ ACTUAL DATA
	MVI	C,0
LE953	LDA	ASTAT		;LOAD A STAT INTO ACC
	ANI	SYNCF		;SYNC CHAR FOUND-RDY TO READ
	JNZ	READ		;TO DO ACTUAL READ
	DCR	B		;WAIT SOME MORE
	JNZ	LE953		;WE HAVEN'T REACHED LIMIT YET
	MVI	A,01H		;WE'RE IN TROUBLE
	JMP	LE9AB		;JUMP TO ERROR ROUTINE
;********************************************************
;**** THIS IS THE TRACK SELECT ROUTINE.  ENTER WITH  ****
;**** DESIRED TRACK IN A AND H,L POINT TO CURRENT    ****
;**** TRACK.  IT LOADS H,L WITH A DIRECTION SETTING  ****
;**** ADDRESS AND PUTS NO OF STEPS REQD IN REG C.    ****
;********************************************************
LE964	MOV	D,A		;SAVE DESIRED TRACK
	SUB	M		;SUBTRACT PRESENT TRACK
	MOV	M,D		;STORE NEW TRACK ADDRESS
	RZ			;DONE IF OLD ADDR=NEW ADDR
	LXI	H,STPIN		;LOAD H STEP DIR 'IN'
	MOV	C,A		;DIFFERENCE IS NO OF STEPS REQD
	JP	LE97B		;GO STEP IT
	CMA			;DIFF WAS NEG--NEED TO STEP OUT
	INR	A		;INVRT THE NEG NO OF STEPS REQD
	MOV	C,A		;NO OF STEPS 'OUT' REQD IN C
	LDA	ASTAT		;ALREADY ALL THE WAY OUT?
	ANI	TRAK0		;TRACK 0 FLAG
	RNZ			;YES--CAN'T GO OUT ANY FURTHER
	LXI	H,STPOU		;LOAD H STEP DIR 'OUT'
;********************************************************
;**** THIS ROUTINE ACTUALLY DOES THE HEAD STEPPING.  ****
;********************************************************
LE97B	MOV	A,M		;SET DIR FF AS PER H REG
LE97C	LDA	SETFF		;SET TRACK STEP FF
	XTHL			;SHORT TIME DELAY
	XTHL			;MORE DELAY (MIN 10 USEC TOTAL)
	LDA	RESFF		;RESET TRACK STEP FF
	MVI	D,02H		;WAIT 2 SECTOR TIMES (40 MSEC)
	CALL	DELAY
	LDA	ASTAT		;FIND OUT WHERE WE'RE AT
	ANI	TRAK0		;TRACK ZERO?
	JZ	LE993		;JUMP IF NOT TRACK 0
	MVI	C,01H		;WERE ALL WAY OUT-SET C TO STOP
LE993	DCR	C		;NEED MORE STEPS?
	JNZ	LE97C		;YES--CONTINUE STEPPING
	RET			;NO--WERE DONE,	RETURN.
;********************************************************
;**** THIS IS THE ERROR ROUTINE FOR THE BOOTSRAP ONLY****
;********************************************************
CKBS	POP	B		;B IS CONDITION CODE
	JZ	BOARD+4H	;OK--JMP TO LOADED 1ST BLOCK
	DCR	B		;IF HARD ERROR, TRY 10 TIMES
	JNZ	LE905		;TRY AGAIN
DIE	JMP	DIE		;HARD ERROR IN BS, NO RECOVERY
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
;********************************************************
;**** THIS SETS UP B FOR HANDLING BY THE ERR ROUTINE ****
;**** POPS STACK & 0'S REG A SO CKBS WILL DET ERROR  ****
;********************************************************
LE9AB	POP	B
	ORA	A
	RET
;********************************************************
;**** THIS IS THE ACTUAL DATA READ ROUTINE.          ****
;********************************************************
READ	MOV	B,C		;MOVE 0 TO B
READ1	LDAX	D		;THIS IS THE ACTUAL DATA READ
	MOV	M,A		;STORE DATA IN MEMORY
	XRA	B		;I THINK THIS ADDS TO CKSUM
	RLC			;THIS TOO
	MOV	B,A		;MOVE PARTIAL CKSUM TO B
	INX	 H		;SET H FOR NEXT BYTE
	DCR	C		;GOING TO READ 256 BYTES & CKSUM
	JNZ	READ1		;READ MORE DATA
	LDAX	D		;READ THE CHECKSUM FROM DISK
	XRA	B		;COMPARE IT WITH CALCULATED CKSUM
	JZ	LE9C4		;IF THEY ARE SAME GO ON
	MOV	A,B		;?--CAN'T FIGURE THIS ONE OUT
	MVI	A,02H		;SET A NON-ZERO TO DETECT ERROR
	JMP	LE9AB		;JUMP TO THE ERROR HANDLER
LE9C4	POP	PSW		;GET NO OF SECTORS TO BE READ
	DCR	A		;DECREMENT IT
	RZ			;RETURN IF DONE
	PUSH	PSW		;SAVE IT
	CALL	LE9CE		;WAIT FOR SECTOR HOLE
	JMP	LE94C		;WAIT FOR SYNC & READ NXT SECTR
;********************************************************
;**** DELAY ROUTINE; DELAY IS NO OF SECTOR TIMES IN  ****
;**** THE D REGISTER.                                ****
;********************************************************
LE9CE	MVI	D,01H		;HERE TO RET WHEN SCTR FOUND
DELAY	LDA	RSFLG		;RESET SECTOR FLAG
TSTSF	LDA	ASTMS		;LOAD A STATUS REG TO ACC
	ANI	80H		;MASK SECTOR FLAG
	JZ	TSTSF		;TEST SECTOR FLAG
	DCR	D
	RZ			;IF ZERO WE'RE DONE
	JMP	DELAY		;GIVE IT MORE TIME
;********************************************************
;**** THIS ROUTINE STARTS THE MOTOR, WAITS 5 REV (50 ****
;**** SECTOR TIMES) FOR IT TO COME UP, LOADS HEAD &  ****
;**** DRIVE SELECT REG (USING CONTENTS OF C REGISTER)****
;**** STORES SELECTED DRIVE AT 2003H & DELAYS 13     ****
;**** SECTOR TIMES FOR HEAD TO SETTLE FROM LOAD.     ****
;**** IF MOTOR WAS ALREADY ON, CHECKS DRIVE CURRENTLY****
;**** SELECTED (2003H) VS DRIVE REQUESTED IN REG C   ****
;**** IF THEY ARE SAME, SKIPS HEAD LOAD SETTLE DELAY.****
;****      ON ENTRY, C=DESIRED DRIVE, B=0EBH.        ****
;********************************************************
MOTON	LDA	ASTMS		;LOAD A STAT & START MOTOR
	ANI	MOTST		;MASK MOTOR ON TEST BIT
	JNZ	CKDRV		;JUMP IF MOTOR ON
	MVI	D,32H		;5 REV TO SPEED UP
	CALL	DELAY
	JMP	LHSD		;LOAD HEAD & SELECT DRIVE
CKDRV	LDA	DRSEL		;GET DRIVE CUR SELECTED IN ACC
	CMP	C		;C HAS DRIVE WE WANT--SAME?
	RZ			;YES--HEAD IS LOADED, SKIP DELAY
LHSD	LDAX	B		;LOAD HEAD & DR SEL REG USING C
	MOV	A,C		;MOVE SELECTED DRIVE TO ACC
	STA	DRSEL		;STORE IT
	MVI	D,0DH		;SETTLE TIME FROM HEAD LOAD
	JMP	DELAY
DEFST	ORG	DOS
TRAK1	DS	1		;STORE HEAD LOC (TRACK) DRIVE #1
TRAK2	DS	1		;STORE HEAD LOC (TRACK) DRIVE #2
TRAK3	DS	1		;STORE HEAD LOC (TRACK) DRIVE #3
DRSEL	DB	1		;DRIVE CURRENTLY SELECTED
LEVL2	JMP	DOS+5AH		;ENTRY TO 2ND LEVEL BOOT
VERFY	JMP	DOS+75FH	;RE-ENTRY TO VERIFY ROUTINE
WRITE	JMP	DOS+78EH	;RE-ENTRY TO WRITE ROUTINE
	;PAGE
;*********************************************************
;**** THE NORTH STAR DOS AS DIS-ASSEMBLED BY BARRY A. ****
;**** WATZMAN, CCP, CDP.  COPYRIGHT 1977 BY NORTH     ****
;**** STAR COMPUTERS AND BARRY A. WATZMAN.            ****
;*********************************************************
;**** THE MAIN DOS STARTS HERE.                       ****
;*********************************************************
BOARD	EQU	0E800H		;LOCATION OF NORTH STAR BOARD
BRD	EQU	0E8H		;HIGH ORDER BYTE OF BOARD
DOS	EQU	2000H		;ADDR OF DOS
LE91E	EQU	BOARD+11EH	;READ ROUTINE IN PROM BOOTSTRAP
LE9CE	EQU	BOARD+1CEH	;RETURN ON NEXT SCTR FOUND FLAG
LEB90	EQU	BOARD+390H	;LOAD A STAT REG & START MOTOR
LE9D0	EQU	BOARD+1D0H	;SECTOR BASED DELAY ROUTINE
LEB10	EQU	BOARD+310H	;LOAD A STATUS REG
LE9AB	EQU	BOARD+1ABH	;ERROR HNDLER IN PROM BOOTSTRAP
LEB04	EQU	BOARD+304H	;START A WRITE SECTOR SEQUENCE
NCOM	EQU	15		;NO OF ENTRIES IN COMD TABLE
	ORG	DOS
TRAK1	DB	0		;CUR TRK LOCATION OF HEAD DR #1
TRAK2	DB	59H		;SAME DR #2
TRAK3	DB	59H		;SAME DR #3
DRSEL	DB	1		;DRIVE CURRENTLY SELECTED
BOOT2	JMP	STACK		;ENTRY TO 2ND LEVEL BOOTSTRAP
	JMP	L275F		;VERIFY ROUTINE
L200A	JMP	L278E		;WRITE ROUTINE
COUT	JMP	COUT		;REPL W JMP TO CHAR OUT ROUTINE
CIN	JMP	CIN		;REPL W JMP TO KYBD INP ROUTINE
TINIT	JMP	TINIT		;REPL W JMP TO INIT ROUT IF ANY
CONTC	JMP	CONTC		;REPL W JMP TO CNTL C ROUTINE
HDERR	JMP	DSKER		;HARD DISK ERROR ROUTINE
DLOOK	JMP	L2399		;DIRECTORY LOOKUP ROUTINE
DWRIT	JMP	L240E		;DIRECTORY WRITE ROUTINE
DCOM	JMP	DCOMD		;TO ISSUE DISK COMMAND
LIST	JMP	LICMD+3		;DIRECTORY LIST ROUTINE
BEGIN	JMP	START		;ENTRY FOR LOADED DOS
RWCHK	DB	0		;READ AFTR WRIT CK IF 1
	DS	46		;RESERVED FOR STACK
;**********************************************************
;****  2ND LEVEL BOOT LOADS DISK ADDRS. 5-13 AT 2100H. ****
;**********************************************************
STACK	LXI	SP,STACK
	MVI	A,5		;5 BLKS
	LXI	B,1		;TRACK 0 DRIVE 1
	LXI	D,0501H		;SECTOR 5, READ
	LXI	H,DOS+100H	;PUT THEM AT 2100H (STD VER)
	CALL	LE91E		;DO IT
	JNZ	STACK		;ON ERROR(?)
	MVI	A,4		;4 BLKS
	LXI	B,0101H		;TRACK 1, DRIVE 1
	LXI	D,1		;SECTOR 0, READ
	LXI	H,DOS+600H	;PUT THEM AT 2600H (STD VER)
	CALL	LE91E		;DO IT
	JNZ	STACK		;ON ERROR(?)
	CALL	TINIT		;START MAIN DOS
;**********************************************************
;**** MAIN DOS STARTS HERE.                            ****
;**********************************************************
START	LXI	SP,STACK	;SET STACK
	LXI	H,DOS+0B7H	;?--DOES NOT SEEM NECESSARY
	SHLD	HDERR+1
	MVI	B,'*'		;GET THE PROMPT
	CALL	PRINT		;PRINT IT
	CALL	GETLN		;GET A COMMAND LINE FROM INPUT
	LXI	H,LNBUF		;POINT H,L TO COMMAND
	CALL	LDDEM		;LOAD IT TO D,E
	LXI	H,CMDTB		;POINT H,L TO COMMAND TABLE
	MVI	B,NCOM		;B HAS NO OF COMMANDS IN TABLE
TYNXT	CALL	COMPR		;LOOK FOR MATCH
	INX	H		;TO ADDR FOR COMD JUST TESTED
	INX	H
	JZ	DOIT		;COMMANDS MATCHED--SET IT UP
	INX	H		;NO MATCH-POINT TO NXT COMMAND
	INX	H
	DCR	B		;DCR NO OF COMDS LEFT TO TEST
	JNZ	TYNXT		;NOT DONE-TEST NEXT COMMAND
WHAT	MVI	B,'?'		;OPPS-NONE OF COMDS MATCHED
	CALL	PRINT
CRLFR	CALL	CRLF
	JMP	START
;**********************************************************
;**** HARD DISK ERROR ROUTINE.  C=DRIVE NO.; B=TRACK;  ****
;**********************************************************
DSKER	PUSH	D
	PUSH	B
	MOV	A,C		;GET DRIVE
	ADI	30H		;CONVERT TO ASCII
	MOV	B,A
	CALL	PRINT
	CALL	PSPAC		;PRINT DRIVE FOLLOWED BY SPACE
	POP	B
	MOV	L,B		;SET TRACK (0-34) IN H,L
	MVI	H,0
	CALL	TDDPT		;TWO DIGIT DECIMAL PRT ROUTINE
	POP	D
	LXI	H,DOS+7BFH
	LDA	L27BE
	SUB	M
	ADD	D
	ADI	30H		;CONVERT TO ASCII
	MOV	B,A
	CALL	PRINT
	MVI	B,'H'
	CALL	PRINT
	MVI	B,'D'
	CALL	PRINT
	JMP	WHAT
;**********************************************************
;****  ROUTINE TO JMP TO COMMAND ADDR & COMMAND TABLE. ****
;**********************************************************
DOIT	CALL	LDDEM		;GET CMND ADDR IN D,E
	XCHG			;TO H,L
	LXI	D,START
	PUSH	D		;SET UP SO RET RESTARTS DOS
	PCHL			;DO IT
CMDTB	DB	'CR'
	DW	CRCMD
	DB	'DE'
	DW	DECMD
	DB	'GO'
	DW	GOCMD
	DB	'JP'
	DW	JPCMD
	DB	'RD'
	DW	RDCMD
	DB	'WR'
	DW	WRCMD
	DB	'DT'
	DW	DTCMD
	DB	'IN'
	DW	INCMD
	DB	'LI'
	DW	LICMD
	DB	'TY'
	DW	TYCMD
	DB	'LF'
	DW	LFCMD
	DB	'SF'
	DW	SFCMD
	DB	'CF'
	DW	CFCMD
	DB	'CD'
	DW	CDCMD
	DB	'CO'
	DW	COCMD
;**********************************************************
;****  DELETE COMMAND.  ERASES FILE NAME IN DIRECTORY. ****
;**********************************************************
DECMD	CALL	L23B1		;GET NAME, DRIVE, DO LOOKUP
	CALL	L2750		; ?
	CALL	L2404		;PUT SPACES IN FILE-NAME BUFFER
	JMP	L240E		;WRITE DIRECTORY BLK BACK TO DISK
;**********************************************************
;**** LIST COMMAND (LIST DISK DIRECTORY).              ****
;**********************************************************
LICMD	CALL	GTDRV		;GET UNIT IF SPECIFIED
	STA	L28EE		;DRIVE IN ACC FOR EXTERNAL LISTS
	MVI	A,1		;1=LIST COMMAND
	JMP	L250D		;DO IT
;**********************************************************
;****  JPCMD.  JUMP (EXEC) COMMAND.                    ****
;**********************************************************
JPCMD	CALL	HXBIN		;CONVERT ADDRESS TO BIN IN H,L
	CALL	L2750		;MAKE SURE IT IS END OF INPUT LINE
	PCHL			;GO TO IT
;**********************************************************
;****  GO COMMAND.  LOADS FILE & JUMPS TO GO ADDRESS.  ****
;**********************************************************
GOCMD	CALL	L23B1		;GET NAME, DRIVE & DO DIR LOOKUP
	MOV	C,A		;DRIVE TO REG C
	CALL	L2750		; ?
	CALL	LDDEM		;GET DISK ADDRESS
	PUSH	D		;PUSH	IT
	CALL	LDDEM		;GET DISK LENGTH
	MOV	A,M		;GET TYPE
	INX	H		;POINT TO GO ADDRESS
	CPI	1		;TYPE = 1 ?
	JNZ	WHAT		;NO--REPORT ERROR
	MOV	A,E		;YES--LENGTH TO A (NOTE 256 MAX)
	CALL	LDDEM		;GET GO ADDRESS
	POP	H		;DISK ADDRESS TO H,L
	PUSH	D		;PUSH GO ADDR SO FINAL RET JMPS
	MVI	B,1		;1=READ
	JMP	DCOMD		;DO THE READ
;**********************************************************
;****  TYPE COMMAND.  ADDS TYPE & GO ADDR TO DIR ENTRY ****
;**********************************************************
TYCMD	CALL	L23B1		;GET NAME, DRIVE & DO DIR LOOKUP
	LXI	D,4		;SET UP TO POINT TO TYPE BYTE
	DAD	D
	PUSH	H		;SAVE POINTER
	CALL	DCBIN		;CONVERT DECIMAL TYPE TO BINARY
	JC	WHAT		;IF TYPE KEYED IN NOT LEGAL
	MOV	A,L		;BINARY TYPE TO ACC
	POP	H		;GET BACK POINTER
	MOV	M,A		;CHANGE TYPE
	CPI	1		;TYPE = 1 (EG, NEED GO ADDR) ?
	JNZ	L2189		;NO--WRITE DIRECTORY BLK BACK
	PUSH	H		;SAVE POINTER
	CALL	HXBIN		;CONVERT ASCII HEX GA TO BINARY
	XCHG			;MOVE IT TO D,E
	POP	H		;GET BACK POINTER
	INX	H		;POINT TO GO ADDRESS
	CALL	LDMDE		;PUT NEW GA (D,E) THERE
L2189	CALL	L2750		;END OF COMMAND ?
	JMP	L240E		;YES--WRITE UPDATD DIR BACK TO DSK
;**********************************************************
;****  CF (COPY FILE) COMMAND.                         ****
;**********************************************************
CFCMD	CALL	L23B1
	LDA	L28EE
	STA	LNBUF
	CALL	LDDEM
	PUSH	D
	CALL	LDDEM
	PUSH	D
	CALL	LDDEM
	PUSH	D
	CALL	LDDEM
	PUSH	D
	CALL	L23B1
	CALL	L2750
	LXI	B,7
	DAD	B
	POP	B
	MOV	M,B
	DCX	H
	MOV	M,C
	POP	B
	DCX	H
	MOV	M,B
	DCX	H
	MOV	M,C
	DCX	H
	DCX	H
	POP	D
	PUSH	D
	DCX	D
	CALL	COMPR
	JNC	WHAT
	DCX	H
	MOV	D,M
	DCX	H
	MOV	E,M
	PUSH	D
	CALL	L240E
	POP	H
	POP	B
	POP	D
	JMP	L234F
;**********************************************************
;****  LF & SF (LOAD FILE / SAVE FILE) COMMANDS.       ****
;**********************************************************
LFCMD	MVI	B,1		;1 = READ COMMAND
	JMP	L21DB
SFCMD	MVI	B,0		;0 = WRITE COMMAND
L21DB	PUSH	B		;SAVE COMMAND
	CALL	L23B1		;GET FILENAME, UNIT, DO LOOKUP
	POP	B		;GET BACK COMMAND
	LDA	L28EE		;GET DRIVE
	MOV	C,A		;TO REG C
	PUSH	B		;SAVE COMMAND
	CALL	LDDEM		;GET DISK ADDRESS
	PUSH	D		;SAVE IT
	CALL	LDDEM		;GET DISK LENGTH
	MOV	A,E		;MOVE IT TO ACC.
	PUSH	PSW		;SAVE DISK LENGTH
	CALL	HXBIN		;CONVERT LOAD ADDR TO BIN IN HL
	XCHG			;MOVE IT TO D,E
	CALL	L2750		;MAKE SURE IT'S END OF COMMAND
	POP	PSW		;GET BACK DISK LENGTH
	POP	H		;GET BACK DISK ADDRESS
	POP	B		;GET BACK COMMAND & UNIT
L21F8	CALL	DCOMD		;DO IT
	JC	WHAT		;ON ERROR
	RET			;DONE
;**********************************************************
;****  RD & WR (READ & WRITE SINGLE BLOCK) COMMANDS.   ****
;**********************************************************
RDCMD	MVI	B,1		;1 = READ COMMAND
	JMP	L2206
WRCMD	MVI	B,0		;0 = WRITE COMMAND
L2206	CALL	DCBIN		;GET DISK ADDR TO R/W IN H,L
	JC	WHAT		;ON ERROR
	PUSH	H		;SAVE DISK ADDRESS
	MVI	C,1		;SET DEFAULT UNIT
	CPI	' '		;SEE IF SPACE FOLLOWS DISK ADDR
	JZ	L221C		;YES--GET RAM ADDRESS
	CPI	','		;NO--DOES COMMA FOLLOW DISK ADDR?
	JNZ	WHAT		;ONLY ' ' & ',' MAY FOLLOW D.A.
	CALL	GTDRV		;COMMA FOLLOWS D.A.--GET DRIVE
L221C	CALL	HXBIN		;CNVRT HEX ADDR TO BIN IN HL
	PUSH	H		;SAVE IT
	CALL	DCBIN		;CONVERT NO. OF BLOCKS TO BINARY
	MOV	A,L		;MOVE IT TO ACC (256 MAX)
	POP	D		;GET BACK RAM ADDRESS
	POP	H		;GET BACK DISK ADDRESS
	JMP	L21F8		;DO IT
;**********************************************************
BLKBF	DS	8		;BLANK FILE-NAME
;**********************************************************
;****  CR (CREATE FILE) COMMAND.                       ****
;**********************************************************
CRCMD	CALL	L23BB		;GET DRIVE #, FILE NAME
	CALL	L250C		;LOOK UP FILE NAME
	JNC	WHAT		;IF IT ALREADY EXISTS
	PUSH	H		;ADDRESS OF 1ST FREE BLOCK
	LXI	D,BLKBF		;PTR TO BLANKED OUT FILE NAME AREA
	CALL	L250C		;FIND 1ST BLANK DIR ENTRY
	JC	WHAT		;IF NONE EXISTS
	XTHL			;1ST FREE TO HL, DIR PTR TO STACK
	PUSH	H		;PUSH	1ST FREE BLOCK
	CALL	DCBIN		;GET LENGTH
	JC	WHAT		;LENGTH MISSING OR INVALID
	XTHL			;LEN TO STACK TOP, HL=1ST FREE BLK
	CALL	DCBIN		;REPL HL WITH ADDR IN CMD IF ANY
	CALL	L2750		;END OF COMD REQD
	XCHG			;START ADDR TO D,E
	LXI	H,-351		;SET UP TO TEST LENGTH, START ADDR
	POP	B		;GET LENGTH
	DAD	B		;ADD TO -MAX	LENGTH
	JC	WHAT		;IF TOO LONG
	DAD	D		;ADD STARTING ADDR
	JC	WHAT		;IF NOT ENOUGH ROOM LEFT ON DISK
	POP	H		;GET POINTR TO 9TH BYTE IN RAM DIR
	PUSH	H		;PUT IT BACK
	CALL	LDMDE		;PUT START ADDR IN RAM DIR ENTRY
	MOV	M,C		;MOVING LENGTH TO RAM DIR ENTRY
	INX	H		;CONTINUED
	MOV	M,B		;CONTINUED
	INX	H		;CONTINUED
	MVI	M,0		;DEFAULT TYPE
	POP	H		;POINT BACK TO END OF NAME
	LXI	D,DOS+8EDH	;DE POINT TO END OF NAME BUFFER
	MVI	B,8		;NO OF CHAR IN FILE NAME
L2271	DCX	H		;MOVING NAME TO RAM DIR ENTRY
	LDAX	D		;CONTINUED
	MOV	M,A		;CONTINUED
	DCX	D		;CONTINUED
	DCR	B		;CONTINUED
	JNZ	L2271		;IF NOT DONE
	JMP	L240E		;WRITE DIRECTORY BACK TO DISK
;**********************************************************
;****  CO (COMPRESS DISKETTE) COMMAND.                 ****
;**********************************************************
COCMD	CALL	GTDRV
	STA	LNBUF
	CALL	L2750
	LXI	H,4
L2288	PUSH	H
	MVI	A,2
	CALL	L250D
	JC	L229B
	INX	H
	INX	H
	CALL	LDDEM
	POP	H
	DAD	D
	JMP	L2288
L229B	POP	D
	LDA	L28F1
	ORA	A
	RNZ	
	LHLD	L28F4
	PUSH	H
	PUSH	D
	MVI	A,2
	CALL	L250D
	POP	D
	PUSH	D
	CALL	LDMDE
	CALL	LDDEM
	PUSH	D
	CALL	L240E
	POP	B
	POP	H
	POP	D
	PUSH	H
	DAD	B
	XTHL
	CALL	L234F
	POP	H
	JMP	L2288
;**********************************************************
;****  IN (INITIALIZE BLANK DISKETTE) COMMAND.         ****
;****  THE "INCREMENT" IS FOR THE DT COMD & IS 0 HERE. ****
;**********************************************************
INCMD	CALL	GTDRV		;GET THE DRIVE
	CALL	L2750		;MAKE SURE IT'S END OF COMMAND
	LXI	H,2000H		;20=INITLZATION CHAR; 00=INCREMENT
	SHLD	LNBUF		;SAVE THEM
L22D0	MVI	B,0		;0=WRITE COMMAND
L22D2	LDA	L28EE		;GET THE DRIVE
	MOV	C,A		;MOVE IT TO REG C
	MVI	A,35		;NO OF TRACKS ON DISK
	LXI	H,0		;STARTING DISK ADDRESS
L22DB	PUSH	PSW		;SAVE NO TRACKS LEFT TO DO
	PUSH	B		;SAVE COMMAND & UNIT
	PUSH	H		;SAVE STARTING DISK ADDRESS
	LHLD	LNBUF		;GET INIT CHAR & INCREMENT
	MOV	A,H		;INITIALIZATION CHAR TO ACC.
	LXI	D,DOS+1400H	;TOP OF RAM SCRATCH AREA
	LXI	B,0A00H		;LENGTH OF RAM SCRACTH AREA
L22E8	DCX	D		;DCR POINTER
	STAX	D		;MOVE INIT CHAR TO DE POINTER
	DCR	C		;DCR NO OF CHAR LEFT IN BLOCK
	JNZ	L22E8		;CONTINUE IF NOT DONE WITH BLOCK
	ADD	L		;DONE W BLOCK; INR INIT CHAR.
	MOV	H,A		;SAVE NEW INIT CHAR
	DCR	B		;DCR NO OF BLOCKS LEFT TO DO
	JNZ	L22E8		;DO NEXT BLOCK UNLESS DONE
	SHLD	LNBUF		;SAVE INIT CHAR & INCREMENT
	POP	H		;GET DISK ADDRESS
	POP	B		;GET UNIT & COMMAND
	PUSH	B		;PUT THEM BACK
	PUSH	H		;SAVE DISK ADDRESS
	MVI	A,10		;10 BLOCKS/TRACK & IN CORE
	CALL	DCOMD		;WRITE THEM OUT
	JC	WHAT		;ON ERROR
	CALL	CONTC		;CHECK FOR ABORT
	JZ	WHAT		;FOUND--ABORT IT
	POP	H		;GET DISK ADDRESS
	LXI	B,000AH		;WE JUST DID 10 BLOCKS
	DAD	B		;INR DISK ADDRESS
	POP	B		;RESTORE COMMAND & UNIT
	POP	PSW		;RESTORE NO OF LEFT TO DO
	DCR	A		;DCR NO OF TRACKS LEFT TO DO
	JNZ	L22DB		;DO NEXT TRACK IF NOT DONE
	RET			;DONE
;**********************************************************
;****  DT (DISKETTE TEST) COMMAND.                     ****
;**********************************************************
DTCMD	CALL	GTDRV
	CALL	L2750
	LXI	H,1
	SHLD	LNBUF
L2321	CALL	L22D0
	LXI	H,LNBUF+1
	MOV	A,M
	SUI	5EH
	MOV	M,A
	MVI	B,2
	CALL	L22D2
	JMP	L2321
;**********************************************************
;****  CD (COPY DISKETTE) COMMAND.                     ****
;**********************************************************
CDCMD	CALL	GTDRV
	STA	LNBUF
	CALL	FTCHR
	CPI	' '
	JNZ	WHAT
	CALL	GTDRV
	CALL	L2750
	LXI	B,015EH
	LXI	H,0
	MOV	D,H
	MOV	E,L
L234F	SHLD	LNBUF+1
	XCHG
	SHLD	LNBUF+3
	LXI	H,0FFF6H
	DAD	B
	JNC	L2373
	PUSH	H
	MVI	A,0AH
	CALL	L2376
	LXI	B,000AH
	LHLD	LNBUF+3
	DAD	B
	XCHG
	LHLD	LNBUF+1
	DAD	B
	POP	B
	JMP	L234F
L2373	MOV	A,C
	ORA	A
	RZ	
L2376	PUSH	PSW
	LHLD	LNBUF
	MOV	C,L
	LHLD	LNBUF+3
	LXI	D,DOS+0A00H
	PUSH	D
	MVI	B,1
	CALL	DCOMD
	LHLD	LNBUF+1
	POP	D
	LDA	L28EE
	MOV	C,A
	MVI	B,0
	POP	PSW
	CALL	DCOMD
	JC	WHAT
	RET
;**********************************************************
;****  THIS ROUTINE DOES DIRECTORY LOOKUPS.  ON ENTRY  ****
;****  H,L POINT TO NAME TO BE LOOKED UP, A HAS DRIVE. ****
;**********************************************************
L2399	SHLD	CLPTR		;STORE POINTER TO NAME TO LOOK UP
	STA	L28EE		;STORE REQUESTED DRIVE
	MOV	A,M		;GET 1ST CHAR OF NAME TO LOOK UP
	CPI	' '		;LOOKING FOR AN EMPTY ENTRY ?
	JNZ	L23AB		;NO--LOAD BUFFER,DO LOOKUP
	CALL	L2401		;YES--BLANK BUFFER
	JMP	L23AE		;DO LOOKUP
L23AB	CALL	L23C0		;LOAD BUFFER FROM INPUT LINE
L23AE	JMP	L250C		;DO DE/CR TYPE LOOKUP
;**********************************************************
;****  BLANK OUT FILE-NAME BUFFER, GET FILE NAME,      ****
;****  DRIVE, DO DIRECTORY LOOKUP.                     ****
;**********************************************************
L23B1	CALL	L23BB		;GET DRIVE, FILE NAME
	CALL	L250C		;DO LOOKUP
	JC	WHAT		;IF ERROR DETECTED
	RET
L23BB	MVI	A,1		;DRIVE #1 = DEFAULT
	STA	L28EE		;STORE IT AS SELECTED DRIVE
L23C0	CALL	L2401		;BLANK OUT BUFFER & POINT TO START
	PUSH	H		;SAVE PTR TO FILE NAME BUFFER
L23C4	CALL	FTCHR		;GET CHAR FROM INPUT LINE
	JZ	L24BF		;STC & RETURN IF 1ST CHAR = CR
	CPI	' '		;1ST CHAR = SPACE ?
	JZ	L23C4		;YES--GET NEXT CHAR
	CPI	','		;1ST CHAR = ',' ?
	JZ	L24BF		;STC & RET; , NOT ALLOWED HERE
	MVI	B,8		;GOT LIVE CHAR--SET NAME LENGTH
L23D6	JZ	L23FF		;CHAR WAS C/R; DONE WITH NAME
	CPI	' '		;WAS CHAR SPACE ?
	JZ	L23FF		;YES--DONE WITH NAME
	CPI	','		;WAS CHAR ',' ?
	JZ	L23EF		;YES--GET SPECIFIED DRIVE
	DCR	B		;NORM CHAR; DCR COUNT OF CHR LEFT
	JM	L24BF		;JMP IF DONE WITH 8 CHAR NAME
	MOV	M,A		;STORE CHAR IN BUFFER
	INX	H		;INR NAME BUFFER POINTER
	CALL	FTCHR		;GET THE NEXT CHAR
	JMP	L23D6		;PROCESS IT
L23EF	CALL	GTDRV		;GET THE SPECIFIED DRIVE
	CALL	FTCHR		;GET THE NEXT CHAR
	CPI	' '		;SPACE ?
	JZ	L23FF		;YES--DONE
	CPI	0DH		;NO--C/R ?
	JNZ	L24BF		;NO--INVALID CHAR TYPED; STC & RET
L23FF	POP	D		;RESTORE PTR TO FILENAME BUF TO D
	RET
;**********************************************************
;****  THIS ROUTINE BLANKS OUT A FILE NAME BUFFER AT   ****
;****  28E6H TO 28EDH USED TO HOLD FILE NAMES.         ****
;**********************************************************
L2401	LXI	H,DOS+8EEH	;LOAD 1 PAST END OF BUFFER
L2404	MVI	B,8		;SET BUFFER LENGTH
L2406	DCX	H		;DCR BUFFER POINTER
	MVI	M,' '		;PUT SPACE IN BUFFER
	DCR	B		;DCR COUNT OF CHAR LEFT
	JNZ	L2406		;IF NOT DONE
	RET
;**********************************************************
;****  THIS ROUTINE WRITES AN UPDATED DIRECTORY BLOCK  ****
;****  BACK TO THE DISK.                               ****
;**********************************************************
L240E	LDA	L28EE		;GET DRIVE
	MOV	C,A		;TO REG C
	LDA	L28F0		;LOW ORDER DISK ADDRESS
	MOV	L,A		;TO REG L
	MVI	H,0		;HIGH ORDER DISK ADDR
	MVI	B,0		;0=WRITE COMMAND
	LXI	D,AREA		;CORE ADDR OF BLK TO BE WRITTEN
	MVI	A,1		;JUST 1 BLOCK
	CALL	DCOMD		;DO IT
	JC	WHAT		;IF ERROR
	RET
;**********************************************************
L2426	MOV	A,E
	ORA	A
	JNZ	L245A
	LDA	RWCHK
	ORA	A
	JZ	L245A
	POP	H
	POP	PSW
	LDA	L27BE
	MVI	E,2
L2439	STA	L27BE
	MVI	A,0AH
L243E	PUSH	PSW
	PUSH	H
	PUSH	D
	PUSH	B
	LDA	L27BE
	CALL	LE91E
	MOV	A,B
	STA	L27BF
	POP	B
	POP	D
	JZ	L2426
	POP	H
	POP	PSW
	DCR	A
	JNZ	L243E
	JMP	HDERR
L245A	POP	D
	POP	D
	JMP	LE9CE
;NSDOS2 3000 9073 2770 11/06/77
;**********************************************************
;****  DISK COMMAND ROUTINE.  ACC = NO. BLOCKS;        ****
;****  B = COMMAND (0=WRITE, 1=READ, 2=VRFY), C = UNIT ****
;****  DE = STARTING RAM ADDR., HL = DISK ADDR.        ****
;****  RETURN WITH CARRY SET IF ARGS ARE ILLEGAL.      ****
;**********************************************************
DCOMD	PUSH	D		;SAVE REGISTERS
	PUSH	B
	PUSH	PSW
	PUSH	H
	ORA	A		;NO BLOCKS = 0 ?
	JZ	L24BC		;YES - ERROR
	LXI	D,-350D		;NO - CHECK VALU OF DISK ADDR.
	DAD	D		;ADD REQ. STARTING DISK ADDR
	JC	L24BC		;IF START ADDR > 349
	MOV	E,A		;NO BLOCKS TO E
	MVI	D,0
	DCX	D
	DAD	D		;ADD NO BLOCKS TO START ADDR
	JC	L24BC		;IF RESULT > 349
	MOV	A,C		;UNIT NO.
	CPI	1		;MUST BE 1,2 OR 3 -- NOT 0
	JC	L24BC		;IF ERROR
	CPI	4		;MUST NOT BE > 3
	JNC	L24BC		;IF ERROR
	MOV	A,B		;COMMAND
	CPI	1		;READ ?
	JZ	L24C2		;YES - GO TO READ ROUTINE
	CPI	2		;VERIFY ?
	JZ	L24C2		;YES-GO TO VERYIFY/READ ROUTINE
	CPI	0		;WRITE ?
	JNZ	L24BC		;NO - ERROR IF NOT 0,1 OR 2
	LDA	LEB90		;LOAD A STAT & START MOTOR
	ANI	10H		;MOTOR ON ?
	JNZ	L24A1		;YES - JUMP
	MVI	D,50		;NO-SET UP 50 SECTOR HOLE DELAY
	CALL	LE9D0		;WAIT
	JMP	L24A8
L24A1	LDA	DRSEL		;FIND OUT WHICH DRIVE SEL.
	CMP	C		;THE ONE WE WANT ?
	JZ	L24B4		;YES
L24A8	MVI	B,BRD+3		;SET UP HD. LOAD & DRIVE
	LDAX	B		;LOAD HEAD & SELECT
	MOV	A,C		;GET SELECTED DRIVE
	STA	DRSEL		;STASH SELECTED DRIVE
	MVI	D,13		;SET UP DELAY FOR SETTLE TIME
	CALL	LE9D0		;WAIT
L24B4	LDA	LEB10		;LOAD A STAT REG
	ANI	2		;WRITE PROTECT ?
	JZ	L24C2		;JUMP IF NOT
L24BC	POP	H		;ELSE ERROR RETURN
	POP	PSW
	POP	B
L24BF	POP	D
	STC
	RET
L24C2	POP	H		;GET DISK ADDR BACK
	POP	PSW		;GET NO BLOCKS BACK
	LXI	D,-10
	MVI	B,0FFH		;0FFH = -1
L24C9	INR	B		;KEEP A COUNT OF "ADDITIONS"
	DAD	D		;SUBTRACT 10 FROM DISK ADDR
	JC	L24C9		;DO IT AGAIN IF ANS > 0
L24CE	ADD	L		;GET STARTING SECTOR (?)
;**********************************************************
;****  NOTE THAT THE FOLLOWING INST WAS ORIGINALLY A   ****
;****  JM (FA) RATHER THAN A JNC (D2).  THIS PREVENTED ****
;****  THE DOS FROM WORKING WITH FILES > 134 BLOCKS.   ****
;**********************************************************
	JNC	L24FE
	JZ	L24FE
	MOV	H,A
	MOV	A,L
	ADI	10
	MOV	D,A
	SUI	0BH
	CMA
	STA	L27BF
	MOV	L,B
	SHLD	L28E0
	POP	H
	SHLD	L28E2
	MOV	C,L
	MOV	E,H
	POP	H
	CALL	L2439
	PUSH	H
	LHLD	L28E2
	PUSH	H
	LHLD	L28E0
	MOV	A,H
	MOV	B,L
	INR	B
	MVI	L,0F6H
	JMP	L24CE
L24FE	SUB	L
	PUSH	PSW
	MOV	A,L
	ADI	10
	MOV	D,A
	POP	PSW
	POP	H
	MOV	E,H
	MOV	C,L
	POP	H
	JMP	L2439
;**********************************************************
;****  THE ROUTINES FROM 250C TO 2625 ARE USED TO READ ****
;****  THE DIRECTORY AND USE IT FOR THE DIRECTORY LIST,****
;****  COMPRESS AND CREATE COMMANDS. LOOK UP NAMES,    ****
;****  GET 1ST FREE BLOCK, 1ST FILE NEEDING COMPR, ETC.****
;**********************************************************
L250C	XRA	A		;ENTRY PT. FOR CR,DE COMMAND
L250D	STA	L28EF		;SAVE COMD; 0=CR,DE, 1=LI, 2=CO
	STA	L28F1		;"NEED COMRESSION" FLAG
	SHLD	L28F2		;1ST "UNCOMPRESSED" FILE BLOCK
	LXI	H,351		;NO OF DISK BLOCKS + 1
	SHLD	L28F4		;D.A. OF LOWEST UNCOMPRESSED FILE
	LXI	H,4		;LOWEST AVAIL BLK FOR NEW FILE
	SHLD	L28E4		;1ST FREE BLOCK
	LXI	B,0400H		;NO DIR BLKS, NO CHECKED
L2525	XCHG
	PUSH	H		;H POINTS TO NAME TO BE LOOKED UP
	PUSH	B		;NO DIR BLKS, NO CHECKED SO FAR
	CALL	L253B		;TO GET DIR BLK & PROCESS IT
	POP	B		;RESTORE REGESTER
	POP	D		;RESTORE REG-PUSHED AS H AFTR XCHG
	LDA	L28EE		;GET REQUESTED DRIVE BACK IN A
	RZ			;SET BY PROCESSING ROUTINE IF DONE
	INR	C		;INR DISK ADDR TO BE CHECKED NEXT
	DCR	B		;DCR COUNT OF REMAINING DIR BLOCKS
	JNZ	L2525		;DO NEXT DIRECTORY BLOCK
	STC			;ALL BLKS CHECKED & NO MATCH FOUND
	LHLD	L28E4		;GET 1ST FREE BLOCK IN H,L
	RET			;TO CALLER
L253B	PUSH	H		;SAVE REG-DIR BLKS CKD, CUR BLOCK
	MVI	H,0		;HIGH ORDER DISK ADDRESS
	MOV	L,C		;LOW ORDER--DIR BLK TO BE CHECKED
	LXI	D,AREA		;READ WILL STORE DATA BEG AT AREA
	MOV	A,C		;DIRECTORY BLOCK TO BE READ
	STA	L28F0		;SAVE IT
	LDA	L28EE		;GET THE REQUESTED DRIVE
	MOV	C,A		;MOVE IT TO REG C
	MVI	B,1		;WE'RE GOING TO READ
	MVI	A,1		;1 BLOCK
	CALL	DCOMD		;DO READ
	LXI	H,AREA		;POINT TO DOS RAM AREA
	MVI	B,16		;NO OF DIRECTRY ENTRIES PER BLOCK
	POP	D		;PUSHED AS H; PTR TO NAME TO CHECK
L2557	PUSH	D		;PUT IT BACK
	PUSH	H		;SAVE PTR TO DIR ENTRY IN DOS RAM
	MVI	C,8		;FILE NAME IS 8 CHAR
	LDA	L28EF		;GET THE COMMAND
	ORA	A		;SET THE FLAG
	JNZ	L25A2		;IF IT'S NOT CREATE FILE, JMP
;**********************************************************
;****  THIS ROUTINE COMPARES A NAME POINTED TO BY D,E  ****
;****  AGAINST NAMES IN DOS RAM TO SEE IF NAME ALREADY ****
;****  EXISTS.  H,L POINT TO DIRECTORY ENTRY IN RAM.   ****
;****  ALSO FINDS 1ST FREE ADDR FOR ADDING NEW FILES.  ****
;**********************************************************
L2562	LDAX	D		;POINT TO NAME TO BE MATCHED
	CMP	M		;SAME AS 1ST CHAR OF DIR ENTRY ?
	JNZ	L2571		;NO-MATCH FAIL OR EMPTY DIR ENTRY
	INX	D		;MATCH--INR POINTER TO NAME
	INX	H		;INR POINTER INTO DIRECT. ENTRY
	DCR	C		;DCR COUNT OF CHAR LEFT TO CHECK
	JNZ	L2562		;CHECK NEXT CHAR UNLESS DONE
L256D	POP	B		;RESTORE REGISTERS
	POP	B		;RESTORE REGISTERS
	XRA	A		;CLEAR ACCUM. & FLAGS
	RET			;RET TO CALLER IND. MATCH FOUND
L2571	POP	H		;GET POINTER INTO RAM DIR ENTRY
	PUSH	H		;PUT IT BACK
	MOV	A,M		;GET 1ST CHAR OF FILE NAME
	CPI	' '		;BLANK (E.G. ENTRY EMPTY) ?
	JZ	L2595		;YES--CHECK NEXT DIRECTORY ENTRY
	PUSH	B		;NO--TRUE MISMATCH; SAVE B REG
	LXI	D,8		;LOAD D WITH NAME LENGTH
	DAD	D		;POINT TO FILE STARTING DSK ADDR
	CALL	LDDEM		;GET IT TO D,E
	MOV	C,M		;MOVING FILE DISK LENGTH TO B,C
	INX	H		;2ND BYTE
	MOV	B,M		;FILE DISK LENGTH IN B,C
	XCHG			;MOVE FILE START DISK ADDR TO H,L
	DAD	B		;ADD DSK LNGTH TO DISK START ADDR
	XCHG			;MOVE RESULT TO D,E
	LXI	H,DOS+8E4H	;GET CURRENT 1ST FREE BLOCK
	CALL	COMPR		;COMPARE IT TO END OF THIS FILE
	POP	B		;RESTORE REGISTER
	JC	L2595		;IF CUR 1ST FREE>END OF THIS FILE
	XCHG			;PUT END OF THIS FILE + 1 IN H,L
	SHLD	L28E4		;UPDATE 1ST FREE BLOCK
;**********************************************************
;****  RESTORES HL TO POINT TO BEG OF CUR DIR ENTRY,   ****
;****  INR'S IT BY ENTRY LENGTH & JUMPS TO CHK NEXT    ****
;****  ENTRY UNLESS NO ENTRIES LEFT THIS BLOCK; IN     ****
;****  WHICH CASE CLEAR FLAGS, SET ACC=1 & RETURN.     ****
;**********************************************************
L2595	POP	H		;GET PNTR TO BEG OF CUR DIR ENTRY
	LXI	D,16		;LENGTH OF DIRECTORY ENTRY
	DAD	D		;ADD IT TO START OF CUR ENTRY
	POP	D		;POINTER TO NAME TO MATCH
	DCR	B		;MORE ENTRIES TO CHK THIS BLOCK?
	JNZ	L2557		;YES--SET UP TO CHECK THEM
	XRA	A		;NO-ZERO ACC & CLEAR FLAGS
	INR	A		;PUT 1 IN ACC
	RET			;RET-TO GET NEXT BLK OR DONE
;**********************************************************
;****  THIS ROUTINE PRINTS A ONE LINE LISTING OF THE   ****
;****  DIRECTORY ENTRY IN DOS RAM POINTED TO BY H,L.   ****
;****  REG B,C IS PRESERVED & STACK TOP CONTAINS RAM   ****
;****  POINTER AT ENTRY ON RETURN.                     ****
;**********************************************************
L25A2	CPI	2		;IS IT 2 (COMPRESS) ?
	MOV	A,M		;GET CHAR FROM DIRECTY COPY IN RAM
	JZ	L25F8		;IF COMPRESS JMP
	CPI	' '		;IS DIRECTORY ENTRY EMPTY?
	JZ	L2595		;YES--TRY NEXT DIRECTORY ENTRY
	PUSH	B		;NO-SAVE ENTRIES LEFT & ENTRY LEN
L25AE	MOV	B,M		;GET CHAR OF FILE NAME
	CALL	PRINT		;PRINT IT
	INX	H		;POINT TO NEXT CHAR
	DCR	C		;DCR NO OF CHAR LEFT TO PRINT
	JNZ	L25AE		;IF MORE CHAR LEFT, DO NEXT ONE
	CALL	PSPAC		;SPACE AFTER NAME
	CALL	LDDEM		;GET DISK ADDR IN D,E
	PUSH	H		;SAVE POINTER
	XCHG			;DISK ADDR TO H,L
	CALL	THDDP		;CALL 3 DIGT DEC PRINT-DSK ADDR
	CALL	PSPAC		;SPACE BETWEEN DSK ADDR & LENGTH
	POP	H		;GET POINTER BACK
	CALL	LDDEM		;GET LENGTH IN D,E
	PUSH	H		;SAVE POINTER
	XCHG			;LENGTH TO H,L
	CALL	THDDP		;PRINT LENGTH
	CALL	PSPAC		;SPACE AFTER LENGTH
	POP	H		;GET BACK POINTER
	PUSH	H		;SAVE POINTER
	MOV	L,M		;GET TYPE BYTE
	MVI	H,0		;SINCE TYPE<256
	CALL	THDDP		;PRINT TYPE
	POP	H		;GET POINTER
	MOV	A,M		;GET TYPE AGAIN
	CPI	1		;TYPE 1 FILE ?
	JNZ	L25EB		;NO--DON'T PRINT GO ADDR
	CALL	PSPAC		;YES--SPACE AFTER TYPE
	INX	H		;POINT TO GO ADDR
	CALL	LDDEM		;GET GO ADDR IN D,E
	XCHG			;MOVE IT TO H,L
	CALL	HEXPT		;PRINT 4 DIGIT HEX ADDR
L25EB	CALL	CRLF		;CRLF AFTER ENTRY
	CALL	CONTC		;CHECK FOR ABORT
	JZ	WHAT		;ABORT THE DIRECTORY LIST
	POP	B		;GET BACK ENTRIES/BLK & ENTRY LEN
	JMP	L2595		;TO SET UP FOR NEXT ENTRY
;**********************************************************
;****  THIS ROUTINE FINDS NEXT FILE TO BE "MOVED UP".  ****
;****  28F2 HAS 1ST "FREE" DISK ADDR (4 TO START WITH) ****
;****  COMPARE EACH FILE'S START ADDR TO IT; IF START  ****
;****  ADR IS LOWER, FILE IS ALREADY COMPR.  IF EQUAL, ****
;****  FILE IS COMPR, BUT NEED TO RETURN TO FIND NEW   ****
;****  "1ST FREE" ADDR; IF GREATER, COMPARE FILE'S     ****
;****  START ADDR WITH PREVIOUSLY SAVED LOWEST START   ****
;****  ADDRESS OF FILE NEEDING COMPR & SAVE LOWER OF   ****
;****  TWO, SETTING FLAG AT 28F1 SO MAIN ROUTINE KNOWS ****
;****  THAT A COMPRESSION RUN IS NEEDED AFTER ENTIRE   ****
;****  DIRECTORY IS PROCESSED.  CHK EVERY FILE ON DISK.****
;**********************************************************
L25F8	CPI	' '		;IS ENTRY BLANK ?
	JZ	L2595		;YES--GO TO NEXT ENTRY
	LXI	D,8		;PUT NAME LENGTH IN D,E
	DAD	D		;POINT TO START DISK ADDR
	XCHG			;MOVE POINTER TO START D.A. TO DE
	LHLD	L28F2		;GET END ADDR OF LAST COMPR FILE
	XCHG			;MOVE IT TO D,E POINTER TO H,L
	CALL	COMPR		;CUR FILE BEG AT END OF LAST FILE?
	JZ	L256D		;YES-RETN & UPDATE 1ST AVAIL BLOCK
	JNC	L2595		;NO-CUR FILE IS COMPR-GO TO NEXT
	XCHG			;CUR FILE NEEDS COMPR-PTR TO D,E
	LHLD	L28F4		;GET CUR LOWEST FILE NEEDING COMPR
	XCHG			;SET UP FOR TEST
	CALL	COMPR		;COMPARE START ADDR OF TWO FILES
	JC	L2595		;ALREADY HAVE FILE W/LOWER ADDR
	CALL	LDDEM		;THIS ONE LOWER--START ADDR TO D,E
	XCHG			;TO H,L
	SHLD	L28F4		;MAKE IT THE NEW "LOWEST" DISK ADR
	XRA	A		;CLEAR ACC & FLAGS
	STA	L28F1		;0 TELLS CALLER WE NEED A COMPRSN
	JMP	L2595		;CHECK OUT NEXT FILE IN DIR BLOCK
;**********************************************************
;****  THIS IS THE KEYBOARD LINE INPUT ROUTINE.        ****
;**********************************************************
GETLN	LXI	H,LNBUF+2	;ADDR OF 1ST CHAR AFTER COMMAND
	SHLD	CLPTR		;STORE IT
	DCX	H		;BACK UP TO BEG OF BUFFER
	DCX	H
	LXI	D,2001H		;E=CHAR COUNT+1; D=MAX NO OF CHAR
L2633	XRA	A
	CALL	CIN		;GET CHAR
	MOV	B,A
	CALL	PRINT		;ECHO IT
	CPI	'@'		;LINE DELETE CHAR ?
	JZ	CRLFR		;YES--CRLF & RESTART
	CPI	5FH		;NO-CHAR DELETE CHAR ?
	JNZ	L264E		;NO-PROCESS NORMAL CHAR
	INR	D		;YES-INR NO OF ADDL CHAR ALLOWED
	DCR	E		;DCR CHAR COUNT
	JZ	CRLFR		;CRLF & RESET IF CHAR COUNT = 0
	DCX	H		;DCR INPUT LINE BUFFER POINTER
	JMP	L2633		;GET NEXT CHAR
L264E	MOV	M,A		;PUT CHAR IN BUFFER
	CPI	0DH		;CARR RETURN ?
	MVI	B,0AH		;SET UP LINE FEED
	JZ	PRINT		;PRINT IF CR (CR WAS ECHOED)
	INX	H		;NOT CR--INR BUFFER POINTER
	INR	E		;INR CHAR COUNT
	DCR	D		;DCR REMAINING BUFFER AVAIL
	JNZ	L2633		;NEXT CHAR IF BUFFER NOT FULL
	JMP	WHAT		;DUMMY--BUFFER ONLY HOLDS 32 CHAR
;**********************************************************
;****  HEX TO BINARY CONVERSION.  BINARY LEFT IN H,L.  ****
;**********************************************************
HXBIN	CALL	FTCHR		;GET 1ST HEX DIGIT
	CPI	' '		;SPACE ?
	JZ	HXBIN		;YES, TRY AGAIN
	LXI	H,0
CNVRT	CALL	VLDTE		;CHAR BETWEEN 0-F ?
	JC	WHAT		;NO--PRINT ERR MSG.
	DAD	H		;YES--SHIFT H LEFT 1 BIT
	DAD	H		;AGAIN
	DAD	H		;AGAIN
	DAD	H		;AGAIN
	ADD	L		;PUT NEW CHAR + L IN A
	MOV	L,A		;PUT RESULT BACK IN L
	CALL	FTCHR		;GET NEXT HEX DIGIT
	RZ			;DONE IF CAR RET.
	CPI	' '		;COULD BE SPACE
	JNZ	CNVRT		;ITS NOT--PROCESS IT.
	RET			;IT IS--DONE.
VLDTE	CPI	'0'		;LESS THAN 0 ?
	RC			;YES--RETURN CARRY SET
	CPI	'9'+1		;GREATER THAN 9 ?
	JNC	CKHEX		;YES--CK FOR HEX DIGIT.
	SUI	'0'		;NO--CONVERT TO BINARY.
	RET
CKHEX	CPI	'A'		;LESS THAN A ?
	RC			;YES--RETURN CARRY SET
	CPI	'F'+1		;GREATER THAN F ?
	CMC
	RC			;YES--RETURN CARRY SET.
	SUI	37H		;SUBTRACT ASCII HEX BIAS.
	RET
;**********************************************************
;****  DECIMAL TO BINARY CONVERSION.  BINARY IN H,L.   ****
;**********************************************************
DCBIN	CALL	FTCHR		;GET 1ST DEC DIGIT
	STC
	RZ			;AT LEAST 1 DIGIT REQD.
	CPI	' '		;BUT SPACES ALLOWED
	JZ	DCBIN
	LXI	H,0
NXTDG	CPI	'9'+1		;GREATER THAN 9 ?
	JNC	WHAT		;YES--ERROR
	SUI	'0'		;SUBTRACT 0
	JC	WHAT		;ERROR IF ANS NEG.
	MOV	D,H
	MOV	E,L		;ORIG NO TO D,E
	DAD	H		;  2*H=2H
	DAD	H		;  2*2H=4H
	DAD	D		;  4H+H=5H
	DAD	H		;  2*5H=10H
	MOV	E,A
	MVI	D,0		;PUT NEW DIGIT IN D,E
	DAD	D		;ADD IT TO H,L
	CALL	FTCHR		;GET NEXT CHAR
	RZ			;CR, ' ' AND ',' TERMINATE STRING
	CPI	' '
	RZ
	CPI	','
	RZ
	JMP	NXTDG
;**********************************************************
;****  THESE ARE NUMBER CONVERSION & PRINT ROUTINES    ****
;**********************************************************
HEXPT	LXI	D,-4096		;SET UP FOR MSD OF 4 DIGIT HEX
	MVI	C,'0'		;SUPRESS LEADING 0'S
	CALL	PTDGT		;CALL PRINT DIGIT
	LXI	D,-256		;SET UP FOR 2ND MSB OF 4 HEX
	CALL	PTDGT
	LXI	D,-16		;SET UP FOR 3RD MSB OF 4 HEX
	JMP	NXTOL
THDDP	LXI	D,-100		;THREE DIGIT DECIMAL PRINT
	MVI	C,'0'		;SUPRESS LEADING 0'S
	CALL	PTDGT
TDDPT	LXI	D,-10		;SET UP FOR DECIMAL 10'S DIGIT
NXTOL	CALL	PTDGT		;GET NEXT TO LSB, DEC OR HEX
	LXI	D,-1		;SET UP FOR UNITS DIGIT
	MVI	C,0FFH		;TO KEEP FROM PRINTING SPACE
PTDGT	MVI	B,'0'-1		;INITIALIZE ASCII DIGIT
GT0	SHLD	LNBUF		;STORE POSITIVE REMAINDER
	INR	B		;INR COUNT OF SUBTRACTIONS
	DAD	D		;SUBTRACT AGAIN (D < 0)
	JC	GT0		;SUBTRACT AGAIN IF STILL > 0
	LHLD	LNBUF		;GET LAST POSITIVE REMAINDER
	MOV	A,B		;CK FOR SUPRESSION OF LEADING 0'S
	CMP	C		;SUPPRESS (YES IF C=30H) ?
	JZ	PSPAC		;YES--PRINT SPACE INSTEAD OF 0
	MVI	C,0FFH		;DON'T SUPRESS ANY MORE 0'S
	CPI	'9'+1		;GREATER THAN 9 (EG, HEX A-F)?
	JC	PRINT		;NO--PRINT AS IS
	ADI	7		;YES--CONVERT TO ASCII HEX
	MOV	B,A
	JMP	PRINT		;PRINT IT
;**********************************************************
;**** FIVE UTILITY ROUTINES; PRINT SPACE, PRINT CHAR,  ****
;**** CAR RET/LINE FEED & LOAD M FROM DE AND DE FROM M ****
;**********************************************************
PSPAC	MVI	B,' '
PRINT	XRA	A
	JMP	COUT
CRLF	MVI	B,0DH
	CALL	PRINT
	MVI	B,0AH
	JMP	PRINT
LDMDE	MOV	M,E
	INX	H
	MOV	M,D
	INX	H
	RET
LDDEM	MOV	E,M
	INX	H
	MOV	D,M
	INX	H
	RET
;**********************************************************
;**** GET THE DESIRED DRIVE FROM COMAND LINE & CONVERT ****
;**** IT TO BINARY.  STORE DESIRED DRIVE AT 28EEH.     ****
;**********************************************************
GTDRV	MVI	C,1		;1 IS DEFAULT IF NO DATA FOUND
	CALL	FTCHR		;FETCH A CHARACTER
	JZ	CRFND		;IF CARRIAGE RET FOUND
	CPI	' '
	JZ	GTDRV		;IF SPACE KEEP LOOKING
	SUI	'0'		;CONVERT ASCII TO BINARY
	JZ	WHAT		;ZERO INVALID
	MOV	C,A
	ANI	0FCH
	JNZ	WHAT		;ANS > 3 INVALID
CRFND	MOV	A,C
	STA	L28EE
	RET			;WITH ANSWER IN C,A AND AT 28EEH
;**********************************************************
;****  ROUTINE TO SUPPLY ONE CHAR FROM INPUT BUFFER    ****
;**********************************************************
FTCHR	PUSH	H
	LHLD	CLPTR
	MOV	A,M
	CPI	0DH
	JZ	L274E
	INX	H
	SHLD	CLPTR
L274E	POP	H
	RET
L2750	CALL	FTCHR		;ENTR HERE IF EOF REQD
	JNZ	WHAT
	RET
;**********************************************************
;****  COMPARE D,E WITH STRING POINTED TO BY H,L       ****
;**********************************************************
COMPR	INX	H
	MOV	A,D
	CMP	M
	DCX	H
	RNZ
	MOV	A,E
	CMP	M
	RET
;**********************************************************
;****  ROUTINES TO COMPARE DISK TO RAM MEMORY.  VERY   ****
;****  SIMILAR TO ROUTINES IN PROM BS AT E94C & E9AE.  ****
;**********************************************************
L275F	MVI	B,8CH		;MAX DELAY SECTR TO SYNC CHAR
	LXI	D,BOARD+350H	;SET UP MEM MAP DATA READ ADDR
	MVI	C,0
SWAIT	LDA	LEB10		;LOAD A STAT REG INTO ACC
	ANI	4		;MASK SYNC CHAR FOUND
	JNZ	RDVER		;TO DO ACTUAL READ/VERIFY
	DCR	B		;NOT FOUND-DCR COUNT
	JNZ	SWAIT		;JUMP SYNC WAIT
	MVI	A,1		;TOO MUCH TIME PASSED
	JMP	LE9AB		;ERROR ROUTINE IN PROM
RDVER	MOV	B,C		;C & B HAVE 0
NXBYT	LDAX	D		;THIS IS ACTUAL READ STMNT
	CMP	M		;COMPARE WITH RAM
	MVI	A,3
	JNZ	LE9AB		;JUMP TO ERR IN PROM IF NOT SAME
	INX	H		;OK--INR RAM ADDR
	DCR	C		;DCR BYTES TO GO (DOING 256)
	JNZ	NXBYT		;IF NOT DONE, CONTINUE
	POP	PSW		;NO OF 256 BYTE BLOCKS TO CHECK
	DCR	A
	RZ			;IF ZERO, DONE.
	PUSH	PSW		;NOT DONE, PUT IT BACK
	CALL	LE9CE		;WAIT FOR NEXT SECTOR HOLE
	JMP	L275F		;AND DO NEXT BLOCK
;**********************************************************
;****  DISK WRITE ROUTINE.                             ****
;**********************************************************
L278E	LDA	LEB04		;START WRITE SECTOR SEQ
L2791	LDA	LEB10		;LOAD A STATUS REG
	ANI	8		;MASK WRITE STATUS BIT
	JZ	L2791		;WAIT IF NOT FOUND
	MVI	D,BRD+2		;THE "WRITE" ADDR-DATA OFFSET
	LXI	B,000FH		;B = 0, C = 15
	MOV	E,B		;DATA TO WRITE IS ZERO
L279F	LDAX	D		;WRITE A ZERO
	DCR	C		;WRITE 15 OF THEM
	JNZ	L279F		;IF NOT DONE
	MVI	E,0FBH		;SET UP THE SYNC CHAR
	LDAX	D		;WRITE IT
L27A7	MOV	A,M		;GET THE DATA TO WRITE
	MOV	E,A		;SET IT UP
	XRA	B		;WORKING ON CRC
	RLC			;STILL WORKING ON CRC
	MOV	B,A		;SAVE PARTIAL CRC
	LDAX	D		;WRITE THE DATA
	INX	H		;POINT TO NEXT DATA BYTE
	DCR	C		;DCR COUNT OF BYTES LEFT
	JNZ	L27A7		;TO DO NEXT BYTE
	MOV	E,B		;SET TO WRITE CRC BYTE
	LDAX	D		;DO IT
	POP	PSW		;GET NO SECTORS LEFT TO DO
	DCR	A		;DECREMENT BY ONE
	RZ			;RETURN IF ZERO
	PUSH	PSW		;SAVE NO SECTORS
	CALL	LE9CE		;WAIT FOR SECTOR HOLE
	JMP	L200A		;TO DO NEXT SECTOR
L27BE	NOP
L27BF	NOP
LNBUF	DS	32		;THESE ARE ACTUALLY NOP'S
AREA	DS	24		;THESE ARE ACTUALLY DB 20H'S
	DS	232		;THESE ARE ACTUALLY NOP'S
L28E0	NOP
	NOP
L28E2	NOP
	NOP
L28E4	DS	2		;THESE ARE ACTUALLY NOP'S
L28E6	DS	8		;A NAME BUFFER (ACT NOP'S)
L28EE	NOP
L28EF	NOP
L28F0	NOP
L28F1	NOP
L28F2	NOP
	NOP
L28F4	NOP
	NOP
CLPTR	DS	2		;COMND LINE POINTER (ACT NOP)
	DS	8		;ACTUALLY NOP'S
L2900	DS	256		;USER I/O AREA--ACTUALLY NOP'S