	.title	"Digital Research BDOS, Version 2.2"
	.page	49

ENDFIL	.EQU	1		;FILL FULL BDOS LENGTH
;
IOBYTE:	.EQU 3			; I/O DEFINITION BYTE.
TDRIVE:	.EQU 4			; CURRENT DRIVE NAME AND USER NUMBER.
ENTRY:	.EQU 5			; ENTRY POINT FOR THE CP/M BDOS.
TFCB:	.EQU 5CH			; DEFAULT FILE CONTROL BLOCK.
TBUFF:	.EQU 80H			; I/O BUFFER AND COMMAND LINE STORAGE.
TBASE:	.EQU 100H		; TRANSIANT PROGRAM STORAGE AREA.
;
;   SET CONTROL CHARACTER .EQUATES.
;
CNTRLC:	.EQU 3			; CONTROL-C
CNTRLE:	.EQU 05H			; CONTROL-E
BS:	.EQU 08H			; BACKSPACE
TAB:	.EQU 09H			; TAB
LF:	.EQU 0AH			; LINE FEED
FF:	.EQU 0CH			; FORM FEED
CR:	.EQU 0DH			; CARRIAGE RETURN
CNTRLP:	.EQU 10H			; CONTROL-P
CNTRLR:	.EQU 12H			; CONTROL-R
CNTRLS:	.EQU 13H			; CONTROL-S
CNTRLU:	.EQU 15H			; CONTROL-U
CNTRLX:	.EQU 18H			; CONTROL-X
CNTRLZ:	.EQU 1AH			; CONTROL-Z (END-OF-FILE MARK)
DEL:	.EQU 7FH			; RUBOUT

; CPM ORIGIN CALCULATE

NK      .EQU	59		;SYSTEM SIZE
BASE    .EQU	(NK*1024)-5000H
CCPO    .EQU	BASE+3400H	;CCP ORIGIN
BDOSO   .EQU	BASE+3C00H	;BDOS ORIGIN
BIOSO   .EQU	BASE+4A00H	;BIOS ORIGIN

	.ORG	BDOSO
	.DB	0,0,0,0,0,0	;OLD SERIAL NUMBER
;
;**************************************************************
;*
;*                    B D O S   E N T R Y
;*
;**************************************************************
;
FBASE:	JP	FBASE1
;
;   BDOS ERROR TABLE.
;
BADSCTR:.DW ERROR1		; BAD SECTOR ON READ OR WRITE.
BADSLCT:.DW ERROR2		; BAD DISK SELECT.
RODISK:	.DW ERROR3		; DISK IS READ ONLY.
ROFILE:	.DW ERROR4		; FILE IS READ ONLY.
;
;   ENTRY INTO BDOS. (DE) OR (E) ARE THE PARAMETERS PASSED. THE
; FUNCTION NUMBER DESIRED IS IN REGISTER (C).
; E contains drive number if passing this
FBASE1:	EX	DE,HL		; SAVE THE (DE) PARAMETERS.
	LD	(PARAMS),HL
	EX	DE,HL
	LD	A,E		; AND SAVE REGISTER (E) IN PARTICULAR.
	LD	(EPARAM),A
	LD	HL,0
	LD	(STATUS),HL	; CLEAR RETURN STATUS.
	ADD	HL,SP
	LD	(USRSTACK),HL	; SAVE USERS STACK POINTER.
	LD	SP,STKAREA	; AND SET OUR OWN.
	XOR	A		; CLEAR AUTO SELECT STORAGE SPACE.
	LD	(AUTOFLAG),A
	LD	(AUTO),A
	LD	HL,GOBACK	; SET RETURN ADDRESS.
	PUSH	HL
	LD	A,C		; GET FUNCTION NUMBER.
	CP	NFUNCTS		; VALID FUNCTION NUMBER?
	RET	NC
	LD	C,E		; KEEP SINGLE REGISTER FUNCTION HERE.
	LD	HL,FUNCTNS	; NOW LOOK THRU THE FUNCTION TABLE.
	LD	E,A
	LD	D,0		; (DE)=FUNCTION NUMBER.
	ADD	HL,DE
	ADD	HL,DE		; (HL)=(START OF TABLE)+2*(FUNCTION NUMBER).
	LD	E,(HL)
	INC	HL
	LD	D,(HL)		; NOW (DE)=ADDRESS FOR THIS FUNCTION.
	LD	HL,(PARAMS)	; RETRIEVE PARAMETERS.
	EX	DE,HL		; NOW (DE) HAS THE ORIGINAL PARAMETERS.
	JP	(HL)		; EXECUTE DESIRED FUNCTION.
;
;   BDOS FUNCTION JUMP TABLE.
;
NFUNCTS:.EQU 41			; NUMBER OF FUNCTIONS IN FOLLOWIN TABLE.
;
FUNCTNS:.DW WBOOT,GETCON,OUTCON,GETRDR,PUNCH,LIST,DIRCIO,GETIOB
	.DW SETIOB,PRTSTR,R.DBUFF,GETCSTS,GETVER,RSTDSK,SETDSK,OPENFIL
	.DW CLOSEFIL,GETFST,GETNXT,DELFILE,READSEQ,WRTSEQ,FCREATE
	.DW RENFILE,GETLOG,GETCRNT,PUTDMA,GETALOC,WRTPRTD,GETROV,SETATTR
	.DW GETPARM,GETUSER,RDRANDOM,WTRANDOM,FILESIZE,SETRAN,LOGOFF,RTN
	.DW RTN,WTSPECL
;
;   BDOS ERROR MESSAGE SECTION.
;
ERROR1:	LD	HL,BADSEC	; BAD SECTOR MESSAGE.
	CALL	PRTERR		; PRINT IT AND GET A 1 CHAR RESPONCE.
	CP	CNTRLC		; RE-BOOT REQUEST (CONTROL-C)?
	JP	Z,0		; YES.
	RET			; NO, RETURN TO RETRY I/O FUNCTION.

ERROR2:	LD	HL,BADSEL	; BAD DRIVE SELECTED.
	JP	ERROR5
;
ERROR3:	LD	HL,DISKRO	; DISK IS READ ONLY.
	JP	ERROR5
;
ERROR4:	LD	HL,FILERO	; FILE IS READ ONLY.
;
ERROR5:	CALL	PRTERR
	JP	0		; ALWAYS REBOOT ON THESE ERRORS.
;
BDOSERR:.DB "BDOS ERR ON "
BDOSDRV:.DB " : $"
BADSEC:	.DB "BAD SECTOR$"
BADSEL:	.DB "SELECT$"
FILERO:	.DB "FILE "
DISKRO:	.DB "R/O$"
;
;   PRINT BDOS ERROR MESSAGE.
;
PRTERR:	PUSH	HL		; SAVE SECOND MESSAGE POINTER.
	CALL	OUTCRLF		; SEND (CR)(LF).
	LD	A,(ACTIVE)	; GET ACTIVE DRIVE.
	ADD	A,'A'		; MAKE ASCII.
	LD	(BDOSDRV),A	; AND PUT IN MESSAGE.
	LD	BC,BDOSERR	; AND PRINT IT.
	CALL	PRTMESG
	POP	BC		; PRINT SECOND MESSAGE LINE NOW.
	CALL	PRTMESG
;
;   GET AN INPUT CHARACTER. WE WILL CHECK OUR 1 CHARACTER
; BUFFER FIRST. THIS MAY BE SET BY THE CONSOLE STATUS ROUTINE.
;
GETCHAR:LD	HL,CHARBUF	; CHECK CHARACTER BUFFER.
	LD	A,(HL)		; ANYTHING PRESENT ALREADY?
	LD	(HL),0		; ...EITHER CASE CLEAR IT.
	OR	A
	RET	NZ		; YES, USE IT.
	JP	CONIN		; NOPE, GO GET A CHARACTER RESPONCE.
;
;   INPUT AND ECHO A CHARACTER.
;
GETECHO:CALL	GETCHAR		; INPUT A CHARACTER.
	CALL	CHKCHAR		; CARRIAGE CONTROL?
	RET	C		; NO, A REGULAR CONTROL CHAR SO DON'T ECHO.
	PUSH	AF		; OK, SAVE CHARACTER NOW.
	LD	C,A
	CALL	OUTCON		; AND ECHO IT.
	POP	AF		; GET CHARACTER AND RETURN.
	RET
;
;   CHECK CHARACTER IN (A). SET THE ZERO FLAG ON A CARRIAGE
; CONTROL CHARACTER AND THE CARRY FLAG ON ANY OTHER CONTROL
; CHARACTER.
;
CHKCHAR:CP	CR		; CHECK FOR CARRIAGE RETURN, LINE FEED, BACKSPACE,
	RET	Z		; OR A TAB.
	CP	LF
	RET	Z
	CP	TAB
	RET	Z
	CP	BS
	RET	Z
	CP	' '		; OTHER CONTROL CHAR? SET CARRY FLAG.
	RET
;
;   CHECK THE CONSOLE DURING OUTPUT. HALT ON A CONTROL-S, THEN
; REBOOT ON A CONTROL-C. IF ANYTHING ELSE IS READY, CLEAR THE
; ZERO FLAG AND RETURN (THE CALLING ROUTINE MAY WANT TO DO
; SOMETHING).
;
CKCONSOL:
	LD	A,(CHARBUF)	; CHECK BUFFER.
	OR	A		; IF ANYTHING, JUST RETURN WITHOUT CHECKING.
	JP	NZ,CKCON2
	CALL	CONST		; NOTHING IN BUFFER. CHECK CONSOLE.
	AND	01H		; LOOK AT BIT 0.
	RET	Z		; RETURN IF NOTHING.
	CALL	CONIN		; OK, GET IT.
	CP	CNTRLS		; IF NOT CONTROL-S, RETURN WITH ZERO CLEARED.
	JP	NZ,CKCON1
	CALL	CONIN		; HALT PROCESSING UNTIL ANOTHER CHAR
	CP	CNTRLC		; IS TYPED. CONTROL-C?
	JP	Z,0		; YES, REBOOT NOW.
	XOR	A		; NO, JUST PRETEND NOTHING WAS EVER READY.
	RET
CKCON1:	LD	(CHARBUF),A	; SAVE CHARACTER IN BUFFER FOR LATER PROCESSING.
CKCON2:	LD	A,1		; SET (A) TO NON ZERO TO MEAN SOMETHING IS READY.
	RET
;
;   OUTPUT (C) TO THE SCREEN. IF THE PRINTER FLIP-FLOP FLAG
; IS SET, WE WILL SEND CHARACTER TO PRINTER ALSO. THE CONSOLE
; WILL BE CHECKED IN THE PROCESS.
;
OUTCHAR:LD	A,(OUTFLAG)	; CHECK OUTPUT FLAG.
	OR	A		; ANYTHING AND WE WON'T GENERATE OUTPUT.
	JP	NZ,OUTCHR1
	PUSH	BC
	CALL	CKCONSOL	; CHECK CONSOLE (WE DON'T CARE WHATS THERE).
	POP	BC
	PUSH	BC
	CALL	CONOUT		; OUTPUT (C) TO THE SCREEN.
	POP	BC
	PUSH	BC
	LD	A,(PRTFLAG)	; CHECK PRINTER FLIP-FLOP FLAG.
	OR	A
	CALL	NZ,LIST		; PRINT IT ALSO IF NON-ZERO.
	POP	BC
OUTCHR1:LD	A,C		; UPDATE CURSORS POSITION.
	LD	HL,CURPOS
	CP	DEL		; RUBOUTS DON'T DO ANYTHING HERE.
	RET	Z
	INC	(HL)		; BUMP LINE POINTER.
	CP	' '		; AND RETURN IF A NORMAL CHARACTER.
	RET	NC
	DEC	(HL)		; RESTORE AND CHECK FOR THE START OF THE LINE.
	LD	A,(HL)
	OR	A
	RET	Z		; INGNORE CONTROL CHARACTERS AT THE START OF THE LINE.
	LD	A,C
	CP	BS		; IS IT A BACKSPACE?
	JP	NZ,OUTCHR2
	DEC	(HL)		; YES, BACKUP POINTER.
	RET
OUTCHR2:CP	LF		; IS IT A LINE FEED?
	RET	NZ		; IGNORE ANYTHING ELSE.
	LD	(HL),0		; RESET POINTER TO START OF LINE.
	RET
;
;   OUTPUT (A) TO THE SCREEN. IF IT IS A CONTROL CHARACTER
; (OTHER THAN CARRIAGE CONTROL), USE ^X FORMAT.
;
SHOWIT:	LD	A,C
	CALL	CHKCHAR		; CHECK CHARACTER.
	JP	NC,OUTCON	; NOT A CONTROL, USE NORMAL OUTPUT.
	PUSH	AF
	LD	C,'^'		; FOR A CONTROL CHARACTER, PRECEED IT WITH '^'.
	CALL	OUTCHAR
	POP	AF
	OR	'@'		; AND THEN USE THE LETTER .EQUIVELANT.
	LD	C,A
;
;   FUNCTION TO OUTPUT (C) TO THE CONSOLE DEVICE AND EXPAND TABS
; IF NECESSARY.
;
OUTCON:	LD	A,C
	CP	TAB		; IS IT A TAB?
	JP	NZ,OUTCHAR	; USE REGULAR OUTPUT.
OUTCON1:LD	C,' '		; YES IT IS, USE SPACES INSTEAD.
	CALL	OUTCHAR
	LD	A,(CURPOS)	; GO UNTIL THE CURSOR IS AT A MULTIPLE OF 8

	AND	07H		; POSITION.
	JP	NZ,OUTCON1
	RET
;
;   ECHO A BACKSPACE CHARACTER. ERASE THE PREVOIUS CHARACTER
; ON THE SCREEN.
;
BACKUP:	CALL	BACKUP1		; BACKUP THE SCREEN 1 PLACE.
	LD	C,' '		; THEN BLANK THAT CHARACTER.
	CALL	CONOUT
BACKUP1:LD	C,BS		; THEN BACK SPACE ONCE MORE.
	JP	CONOUT
;
;   SIGNAL A DELETED LINE. PRINT A '#' AT THE END AND START
; OVER.
;
NEWLINE:LD	C,'#'
	CALL	OUTCHAR		; PRINT THIS.
	CALL	OUTCRLF		; START NEW LINE.
NEWLN1:	LD	A,(CURPOS)	; MOVE THE CURSOR TO THE STARTING POSITION.
	LD	HL,STARTING
	CP	(HL)
	RET	NC		; THERE YET?
	LD	C,' '
	CALL	OUTCHAR		; NOPE, KEEP GOING.
	JP	NEWLN1
;
;   OUTPUT A (CR) (LF) TO THE CONSOLE DEVICE (SCREEN).
;
OUTCRLF:LD	C,CR
	CALL	OUTCHAR
	LD	C,LF
	JP	OUTCHAR
;
;   PRINT MESSAGE POINTED TO BY (BC). IT WILL END WITH A '$'.
;
PRTMESG:LD	A,(BC)		; CHECK FOR TERMINATING CHARACTER.
	CP	'$'
	RET	Z
	INC	BC
	PUSH	BC		; OTHERWISE, BUMP POINTER AND PRINT IT.
	LD	C,A
	CALL	OUTCON
	POP	BC
	JP	PRTMESG
;
;   FUNCTION TO EXECUTE A BUFFERED READ.
;
R.DBUFF:	LD	A,(CURPOS)	; USE PRESENT LOCATION AS STARTING ONE.
	LD	(STARTING),A
	LD	HL,(PARAMS)	; GET THE MAXIMUM BUFFER SPACE.
	LD	C,(HL)
	INC	HL		; POINT TO FIRST AVAILABLE SPACE.
	PUSH	HL		; AND SAVE.
	LD	B,0		; KEEP A CHARACTER COUNT.
R.DBUF1:	PUSH	BC
	PUSH	HL
R.DBUF2:	CALL	GETCHAR		; GET THE NEXT INPUT CHARACTER.
	AND	7FH		; STRIP BIT 7.
	POP	HL		; RESET REGISTERS.
	POP	BC
	CP	CR		; EN OF THE LINE?
	JP	Z,R.DBUF17
	CP	LF
	JP	Z,R.DBUF17
	CP	BS		; HOW ABOUT A BACKSPACE?
	JP	NZ,R.DBUF3
	LD	A,B		; YES, BUT IGNORE AT THE BEGINNING OF THE LINE.
	OR	A
	JP	Z,R.DBUF1
	DEC	B		; OK, UPDATE COUNTER.
	LD	A,(CURPOS)	; IF WE BACKSPACE TO THE START OF THE LINE,
	LD	(OUTFLAG),A	; TREAT AS A CANCEL (CONTROL-X).
	JP	R.DBUF10
R.DBUF3:	CP	DEL		; USER TYPED A RUBOUT?
	JP	NZ,R.DBUF4
	LD	A,B		; IGNORE AT THE START OF THE LINE.
	OR	A
	JP	Z,R.DBUF1
	LD	A,(HL)		; OK, ECHO THE PREVOIUS CHARACTER.
	DEC	B		; AND RESET POINTERS (COUNTERS).
	DEC	HL
	JP	R.DBUF15
R.DBUF4:	CP	CNTRLE		; PHYSICAL END OF LINE?
	JP	NZ,R.DBUF5
	PUSH	BC		; YES, DO IT.
	PUSH	HL
	CALL	OUTCRLF
	XOR	A		; AND UPDATE STARTING POSITION.
	LD	(STARTING),A
	JP	R.DBUF2
R.DBUF5:	CP	CNTRLP		; CONTROL-P?
	JP	NZ,R.DBUF6
	PUSH	HL		; YES, FLIP THE PRINT FLAG FILP-FLOP BYTE.
	LD	HL,PRTFLAG
	LD	A,1		; PRTFLAG=1-PRTFLAG
	SUB	(HL)
	LD	(HL),A
	POP	HL
	JP	R.DBUF1
R.DBUF6:	CP	CNTRLX		; CONTROL-X (CANCEL)?
	JP	NZ,R.DBUF8
	POP	HL
R.DBUF7:	LD	A,(STARTING)	; YES, BACKUP THE CURSOR TO HERE.
	LD	HL,CURPOS
	CP	(HL)
	JP	NC,R.DBUFF	; DONE YET?
	DEC	(HL)		; NO, DECREMENT POINTER AND OUTPUT BACK UP ONE SPACE.
	CALL	BACKUP
	JP	R.DBUF7
R.DBUF8:	CP	CNTRLU		; CNTROL-U (CANCEL LINE)?
	JP	NZ,R.DBUF9
	CALL	NEWLINE		; START A NEW LINE.
	POP	HL
	JP	R.DBUFF
R.DBUF9:	CP	CNTRLR		; CONTROL-R?
	JP	NZ,R.DBUF14
R.DBUF10:PUSH	BC		; YES, START A NEW LINE AND RETYPE THE OLD ONE.
	CALL	NEWLINE
	POP	BC
	POP	HL
	PUSH	HL
	PUSH	BC
R.DBUF11:LD	A,B		; DONE WHOLE LINE YET?
	OR	A
	JP	Z,R.DBUF12
	INC	HL		; NOPE, GET NEXT CHARACTER.
	LD	C,(HL)
	DEC	B		; COUNT IT.
	PUSH	BC
	PUSH	HL
	CALL	SHOWIT		; AND DISPLAY IT.
	POP	HL
	POP	BC
	JP	R.DBUF11
R.DBUF12:PUSH	HL		; DONE WITH LINE. IF WE WERE DISPLAYING
	LD	A,(OUTFLAG)	; THEN UPDATE CURSOR POSITION.
	OR	A
	JP	Z,R.DBUF2
	LD	HL,CURPOS	; BECAUSE THIS LINE IS SHORTER, WE MUST
	SUB	(HL)		; BACK UP THE CURSOR (NOT THE SCREEN HOWEVER)
	LD	(OUTFLAG),A	; SOME NUMBER OF POSITIONS.
R.DBUF13:CALL	BACKUP		; NOTE THAT AS LONG AS (OUTFLAG) IS NON
	LD	HL,OUTFLAG	; ZERO, THE SCREEN WILL NOT BE CHANGED.
	DEC	(HL)
	JP	NZ,R.DBUF13
	JP	R.DBUF2		; NOW JUST GET THE NEXT CHARACTER.
;
;   JUST A NORMAL CHARACTER, PUT THIS IN OUR BUFFER AND ECHO.
;
R.DBUF14:INC	HL
	LD	(HL),A		; STORE CHARACTER.
	INC	B		; AND COUNT IT.
R.DBUF15:PUSH	BC
	PUSH	HL
	LD	C,A		; ECHO IT NOW.
	CALL	SHOWIT
	POP	HL
	POP	BC
	LD	A,(HL)		; WAS IT AN ABORT REQUEST?
	CP	CNTRLC		; CONTROL-C ABORT?
	LD	A,B
	JP	NZ,R.DBUF16
	CP	1		; ONLY IF AT START OF LINE.
	JP	Z,0
R.DBUF16:CP	C		; NOPE, HAVE WE FILLED THE BUFFER?
	JP	C,R.DBUF1
R.DBUF17:POP	HL		; YES END THE LINE AND RETURN.
	LD	(HL),B
	LD	C,CR
	JP	OUTCHAR		; OUTPUT (CR) AND RETURN.
;
;   FUNCTION TO GET A CHARACTER FROM THE CONSOLE DEVICE.
;
GETCON:	CALL	GETECHO		; GET AND ECHO.
	JP	SETSTAT		; SAVE STATUS AND RETURN.
;
;   FUNCTION TO GET A CHARACTER FROM THE TAPE READER DEVICE.
;
GETRDR:	CALL	READER		; GET A CHARACTER FROM READER, SET STATUS AND RETURN.
	JP	SETSTAT
;
;  FUNCTION TO PERFORM DIRECT CONSOLE I/O. IF (C) CONTAINS (FF)
; THEN THIS IS AN INPUT REQUEST. IF (C) CONTAINS (FE) THEN
; THIS IS A STATUS REQUEST. OTHERWISE WE ARE TO OUTPUT (C).
;
DIRCIO:	LD	A,C		; TEST FOR (FF).
	INC	A
	JP	Z,DIRC1
	INC	A		; TEST FOR (FE).
	JP	Z,CONST
	JP	CONOUT		; JUST OUTPUT (C).
DIRC1:	CALL	CONST		; THIS IS AN INPUT REQUEST.
	OR	A
	JP	Z,GOBACK1	; NOT READY? JUST RETURN (DIRECTLY).
	CALL	CONIN		; YES, GET CHARACTER.
	JP	SETSTAT		; SET STATUS AND RETURN.
;
;   FUNCTION TO RETURN THE I/O BYTE.
;
GETIOB:	LD	A,(IOBYTE)
	JP	SETSTAT
;
;   FUNCTION TO SET THE I/O BYTE.
;
SETIOB:	LD	HL,IOBYTE
	LD	(HL),C
	RET
;
;   FUNCTION TO PRINT THE CHARACTER STRING POINTED TO BY (DE)
; ON THE CONSOLE DEVICE. THE STRING ENDS WITH A '$'.
;
PRTSTR:	EX	DE,HL
	LD	C,L
	LD	B,H		; NOW (BC) POINTS TO IT.
	JP	PRTMESG
;
;   FUNCTION TO INTERIGATE THE CONSOLE DEVICE.
;
GETCSTS:CALL	CKCONSOL
;
;   GET HERE TO SET THE STATUS AND RETURN TO THE CLEANUP
; SECTION. THEN BACK TO THE USER.
;
SETSTAT:LD	(STATUS),A
RTN:	RET
;
;   SET THE STATUS TO 1 (READ OR WRITE ERROR CODE).
;
IOERR1:	LD	A,1
	JP	SETSTAT
;
OUTFLAG:.DB 0			; OUTPUT FLAG (NON ZERO MEANS NO OUTPUT).
STARTING:
	.DB 2			; STARTING POSITION FOR CURSOR.
CURPOS:	.DB 0			; CURSOR POSITION (0=START OF LINE).
PRTFLAG:.DB 0			; PRINTER FLAG (CONTROL-P TOGGLE). LIST IF NON ZERO.
CHARBUF:.DB 0			; SINGLE INPUT CHARACTER BUFFER.
;
;   STACK AREA FOR BDOS CALLS.
;
USRSTACK:
	.DW 0			; SAVE USERS STACK POINTER HERE.
;
	.DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	.DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
STKAREA:.EQU $			; END OF STACK AREA.
;
USERNO:	.DB 0			; CURRENT USER NUMBER.
ACTIVE:	.DB 0			; CURRENTLY ACTIVE DRIVE.
PARAMS:	.DW 0			; SAVE (DE) PARAMETERS HERE ON ENTRY.
STATUS:	.DW 0			; STATUS RETURNED FROM BDOS FUNCTION.
;
;   SELECT ERROR OCCURED, JUMP TO ERROR ROUTINE.
;
SLCTERR:LD	HL,BADSLCT
;
;   JUMP TO (HL) INDIRECTLY.
;
JUMPHL:	LD	E,(HL)
	INC	HL
	LD	D,(HL)		; NOW (DE) CONTAIN THE DESIRED ADDRESS.
	EX	DE,HL
	JP	(HL)
;
;   BLOCK MOVE. (DE) TO (HL), (C) BYTES TOTAL.
;
DE2HL:	INC	C		; IS COUNT DOWN TO ZERO?
DE2HL1:	DEC	C
	RET	Z		; YES, WE ARE DONE.
	LD	A,(DE)		; NO, MOVE ONE MORE BYTE.
	LD	(HL),A
	INC	DE
	INC	HL
	JP	DE2HL1		; AND REPEAT.
;
;   SELECT THE DESIRED DRIVE.
;
SELECT:	LD	A,(ACTIVE)	; GET ACTIVE DISK.
	LD	C,A
	CALL	SELDSK		; SELECT IT.
	LD	A,H		; VALID DRIVE?
	OR	L		; VALID DRIVE?
	RET	Z		; RETURN IF NOT.
;
;   HERE, THE BIOS RETURNED THE ADDRESS OF THE PARAMETER BLOCK
; IN (HL). WE WILL EXTRACT THE NECESSARY POINTERS AND SAVE THEM.
;
	LD	E,(HL)		; YES, GET ADDRESS OF TRANSLATION TABLE INTO (DE).
	INC	HL
	LD	D,(HL)
	INC	HL
	LD	(SCRATCH1),HL	; SAVE POINTERS TO SCRATCH AREAS.
	INC	HL
	INC	HL
	LD	(SCRATCH2),HL	; DITTO.
	INC	HL
	INC	HL
	LD	(SCRATCH3),HL	; DITTO.
	INC	HL
	INC	HL
	EX	DE,HL		; NOW SAVE THE TRANSLATION TABLE ADDRESS.
	LD	(XLATE),HL
	LD	HL,DIRBUF	; PUT THE NEXT 8 BYTES HERE.
	LD	C,8		; THEY CONSIST OF THE DIRECTORY BUFFER
	CALL	DE2HL		; POINTER, PARAMETER BLOCK POINTER,
	LD	HL,(DISKPB)	; CHECK AND ALLOCATION VECTORS.
	EX	DE,HL
	LD	HL,SECTORS	; MOVE PARAMETER BLOCK INTO OUR RAM.
	LD	C,15		; IT IS 15 BYTES LONG.
	CALL	DE2HL
	LD	HL,(DSKSIZE)	; CHECK DISK SIZE.
	LD	A,H		; MORE THAN 256 BLOCKS ON THIS?
	LD	HL,BIGDISK
	LD	(HL),0FFH	; SET TO SAMLL.
	OR	A
	JP	Z,SELECT1
	LD	(HL),0		; WRONG, SET TO LARGE.
SELECT1:LD	A,0FFH		; CLEAR THE ZERO FLAG.
	OR	A
	RET
;
;   ROUTINE TO HOME THE DISK TRACK HEAD AND CLEAR POINTERS.
;
HOMEDRV:CALL	HOME		; HOME THE HEAD.
	XOR	A
	LD	HL,(SCRATCH2)	; SET OUR TRACK POINTER ALSO.
	LD	(HL),A
	INC	HL
	LD	(HL),A
	LD	HL,(SCRATCH3)	; AND OUR SECTOR POINTER.
	LD	(HL),A
	INC	HL
	LD	(HL),A
	RET
;
;   DO THE ACTUAL DISK READ AND CHECK THE ERROR RETURN STATUS.
;
DOREAD:	CALL	READ
	JP	IORET
;
;   DO THE ACTUAL DISK WRITE AND HANDLE ANY BIOS ERROR.
;
DOWRITE:CALL	WRITE
IORET:	OR	A
	RET	Z		; RETURN UNLESS AN ERROR OCCURED.
	LD	HL,BADSCTR	; BAD READ/WRITE ON THIS SECTOR.
	JP	JUMPHL
;
;   ROUTINE TO SELECT THE TRACK AND SECTOR THAT THE DESIRED
; BLOCK NUMBER FALLS IN.
;
TRKSEC:	LD	HL,(FILEPOS)	; GET POSITION OF LAST ACCESSED FILE
	LD	C,2		; IN DIRECTORY AND COMPUTE SECTOR #.
	CALL	SHIFTR		; SECTOR #=FILE-POSITION/4.
	LD	(BLKNMBR),HL	; SAVE THIS AS THE BLOCK NUMBER OF INTEREST.
	LD	(CKSUMTBL),HL	; WHAT'S IT DOING HERE TOO?
;
;   IF THE SECTOR NUMBER HAS ALREADY BEEN SET (BLKNMBR), ENTER
; AT THIS POINT.
;
TRKSEC1:LD	HL,BLKNMBR
	LD	C,(HL)		; MOVE SECTOR NUMBER INTO (BC).
	INC	HL
	LD	B,(HL)
	LD	HL,(SCRATCH3)	; GET CURRENT SECTOR NUMBER AND
	LD	E,(HL)		; MOVE THIS INTO (DE).
	INC	HL
	LD	D,(HL)
	LD	HL,(SCRATCH2)	; GET CURRENT TRACK NUMBER.
	LD	A,(HL)		; AND THIS INTO (HL).
	INC	HL
	LD	H,(HL)
	LD	L,A
TRKSEC2:LD	A,C		; IS DESIRED SECTOR BEFORE CURRENT ONE?
	SUB	E
	LD	A,B
	SBC	A,D
	JP	NC,TRKSEC3
	PUSH	HL		; YES, DECREMENT SECTORS BY ONE TRACK.
	LD	HL,(SECTORS)	; GET SECTORS PER TRACK.
	LD	A,E
	SUB	L
	LD	E,A
	LD	A,D
	SBC	A,H
	LD	D,A		; NOW WE HAVE BACKED UP ONE FULL TRACK.
	POP	HL
	DEC	HL		; ADJUST TRACK COUNTER.
	JP	TRKSEC2
TRKSEC3:PUSH	HL		; DESIRED SECTOR IS AFTER CURRENT ONE.
	LD	HL,(SECTORS)	; GET SECTORS PER TRACK.
	ADD	HL,DE		; BUMP SECTOR POINTER TO NEXT TRACK.
	JP	C,TRKSEC4
	LD	A,C		; IS DESIRED SECTOR NOW BEFORE CURRENT ONE?
	SUB	L
	LD	A,B
	SBC	A,H
	JP	C,TRKSEC4
	EX	DE,HL		; NOT YES, INCREMENT TRACK COUNTER
	POP	HL		; AND CONTINUE UNTIL IT IS.
	INC	HL
	JP	TRKSEC3
;
;   HERE WE HAVE DETERMINED THE TRACK NUMBER THAT CONTAINS THE
; DESIRED SECTOR.
;
TRKSEC4:POP	HL		; GET TRACK NUMBER (HL).
	PUSH	BC
	PUSH	DE
	PUSH	HL
	EX	DE,HL
	LD	HL,(OFFSET)	; ADJUST FOR FIRST TRACK OFFSET.
	ADD	HL,DE
	LD	B,H
	LD	C,L
	CALL	SETTRK		; SELECT THIS TRACK.
	POP	DE		; RESET CURRENT TRACK POINTER.
	LD	HL,(SCRATCH2)
	LD	(HL),E
	INC	HL
	LD	(HL),D
	POP	DE
	LD	HL,(SCRATCH3)	; RESET THE FIRST SECTOR ON THIS TRACK.
	LD	(HL),E
	INC	HL
	LD	(HL),D
	POP	BC
	LD	A,C		; NOW SUBTRACT THE DESIRED ONE.
	SUB	E		; TO MAKE IT RELATIVE (1-# SECTORS/TRACK).
	LD	C,A
	LD	A,B
	SBC	A,D
	LD	B,A
	LD	HL,(XLATE)	; TRANSLATE THIS SECTOR ACCORDING TO THIS TABLE.
	EX	DE,HL
	CALL	SECTRN		; LET THE BIOS TRANSLATE IT.
	LD	C,L
	LD	B,H
	JP	SETSEC		; AND SELECT IT.
;
;   COMPUTE BLOCK NUMBER FROM RECORD NUMBER (SAVNREC) AND
; EXTENT NUMBER (SAVEXT).
;
GETBLOCK:
	LD	HL,BLKSHFT	; GET LOGICAL TO PHYSICAL CONVERSION.
	LD	C,(HL)		; NOTE THAT THIS IS BASE 2 LOG OF RATIO.
	LD	A,(SAVNREC)	; GET RECORD NUMBER.
GETBLK1:OR	A		; COMPUTE (A)=(A)/2^BLKSHFT.
	RRA
	DEC	C
	JP	NZ,GETBLK1
	LD	B,A		; SAVE RESULT IN (B).
	LD	A,8
	SUB	(HL)
	LD	C,A		; COMPUTE (C)=8-BLKSHFT.
	LD	A,(SAVEXT)
GETBLK2:DEC	C		; COMPUTE (A)=SAVEXT*2^(8-BLKSHFT).
	JP	Z,GETBLK3
	OR	A
	RLA
	JP	GETBLK2
GETBLK3:ADD	A,B
	RET
;
;   ROUTINE TO EXTRACT THE (BC) BLOCK BYTE FROM THE FCB POINTED
; TO BY (PARAMS). IF THIS IS A BIG-DISK, THEN THESE ARE 16 BIT
; BLOCK NUMBERS, ELSE THEY ARE 8 BIT NUMBERS.
; NUMBER IS RETURNED IN (HL).
;
EXTBLK:	LD	HL,(PARAMS)	; GET FCB ADDRESS.
	LD	DE,16		; BLOCK NUMBERS START 16 BYTES INTO FCB.
	ADD	HL,DE
	ADD	HL,BC
	LD	A,(BIGDISK)	; ARE WE USING A BIG-DISK?
	OR	A
	JP	Z,EXTBLK1
	LD	L,(HL)		; NO, EXTRACT AN 8 BIT NUMBER FROM THE FCB.
	LD	H,0
	RET
EXTBLK1:ADD	HL,BC		; YES, EXTRACT A 16 BIT NUMBER.
	LD	E,(HL)
	INC	HL
	LD	D,(HL)
	EX	DE,HL		; RETURN IN (HL).
	RET
;
;   COMPUTE BLOCK NUMBER.
;
COMBLK:	CALL	GETBLOCK
	LD	C,A
	LD	B,0
	CALL	EXTBLK
	LD	(BLKNMBR),HL
	RET
;
;   CHECK FOR A ZERO BLOCK NUMBER (UNUSED).
;
CHKBLK:	LD	HL,(BLKNMBR)
	LD	A,L		; IS IT ZERO?
	OR	H
	RET
;
;   ADJUST PHYSICAL BLOCK (BLKNMBR) AND CONVERT TO LOGICAL
; SECTOR (LOGSECT). THIS IS THE STARTING SECTOR OF THIS BLOCK.
; THE ACTUAL SECTOR OF INTEREST IS THEN ADDED TO THIS AND THE
; RESULTING SECTOR NUMBER IS STORED BACK IN (BLKNMBR). THIS
; WILL STILL HAVE TO BE ADJUSTED FOR THE TRACK NUMBER.
;
LOGICAL:LD	A,(BLKSHFT)	; GET LOG2(PHYSICAL/LOGICAL SECTORS).
	LD	HL,(BLKNMBR)	; GET PHYSICAL SECTOR DESIRED.
LOGICL1:ADD	HL,HL		; COMPUTE LOGICAL SECTOR NUMBER.
	DEC	A		; NOTE LOGICAL SECTORS ARE 128 BYTES LONG.
	JP	NZ,LOGICL1
	LD	(LOGSECT),HL	; SAVE LOGICAL SECTOR.
	LD	A,(BLKMASK)	; GET BLOCK MASK.
	LD	C,A
	LD	A,(SAVNREC)	; GET NEXT SECTOR TO ACCESS.
	AND	C		; EXTRACT THE RELATIVE POSITION WITHIN PHYSICAL BLOCK.
	OR	L		; AND ADD IT TOO LOGICAL SECTOR.
	LD	L,A
	LD	(BLKNMBR),HL	; AND STORE.
	RET
;
;   SET (HL) TO POINT TO EXTENT BYTE IN FCB.
;
SETEXT:	LD	HL,(PARAMS)
	LD	DE,12		; IT IS THE TWELTH BYTE.
	ADD	HL,DE
	RET
;
;   SET (HL) TO POINT TO RECORD COUNT BYTE IN FCB AND (DE) TO
; NEXT RECORD NUMBER BYTE.
;
SETHLDE:LD	HL,(PARAMS)
	LD	DE,15		; RECORD COUNT BYTE (#15).
	ADD	HL,DE
	EX	DE,HL
	LD	HL,17		; NEXT RECORD NUMBER (#32).
	ADD	HL,DE
	RET
;
;   SAVE CURRENT FILE DATA FROM FCB.
;
STRDATA:CALL	SETHLDE
	LD	A,(HL)		; GET AND STORE RECORD COUNT BYTE.
	LD	(SAVNREC),A
	EX	DE,HL
	LD	A,(HL)		; GET AND STORE NEXT RECORD NUMBER BYTE.
	LD	(SAVNXT),A
	CALL	SETEXT		; POINT TO EXTENT BYTE.
	LD	A,(EXTMASK)	; GET EXTENT MASK.
	AND	(HL)
	LD	(SAVEXT),A	; AND SAVE EXTENT HERE.
	RET
;
;   SET THE NEXT RECORD TO ACCESS. IF (MODE) IS SET TO 2, THEN
; THE LAST RECORD BYTE (SAVNREC) HAS THE CORRECT NUMBER TO ACCESS.
; FOR S.EQUENTIAL ACCESS, (MODE) WILL BE .EQUAL TO 1.
;
SETNREC:CALL	SETHLDE
	LD	A,(MODE)	; GET S.EQUENTIAL FLAG (=1).
	CP	2		; A 2 INDICATES THAT NO ADDER IS NEEDED.
	JP	NZ,STNREC1
	XOR	A		; CLEAR ADDER (RANDOM ACCESS?).
STNREC1:LD	C,A
	LD	A,(SAVNREC)	; GET LAST RECORD NUMBER.
	ADD	A,C		; INCREMENT RECORD COUNT.
	LD	(HL),A		; AND SET FCB'S NEXT RECORD BYTE.
	EX	DE,HL
	LD	A,(SAVNXT)	; GET NEXT RECORD BYTE FROM STORAGE.
	LD	(HL),A		; AND PUT THIS INTO FCB AS NUMBER OF RECORDS USED.
	RET
;
;   SHIFT (HL) RIGHT (C) BITS.
;
SHIFTR:	INC	C
SHIFTR1:DEC	C
	RET	Z
	LD	A,H
	OR	A
	RRA
	LD	H,A
	LD	A,L
	RRA
	LD	L,A
	JP	SHIFTR1
;
;   COMPUTE THE CHECK-SUM FOR THE DIRECTORY BUFFER. RETURN
; INTEGER SUM IN (A).
;
CHECKSUM:
	LD	C,128		; LENGTH OF BUFFER.
	LD	HL,(DIRBUF)	; GET ITS LOCATION.
	XOR	A		; CLEAR SUMMATION BYTE.
CHKSUM1:ADD	A,(HL)		; AND COMPUTE SUM IGNORING CARRIES.
	INC	HL
	DEC	C
	JP	NZ,CHKSUM1
	RET
;
;   SHIFT (HL) LEFT (C) BITS.
;
SHIFTL:	INC	C
SHIFTL1:DEC	C
	RET	Z
	ADD	HL,HL		; SHIFT LEFT 1 BIT.
	JP	SHIFTL1
;
;   ROUTINE TO SET A BIT IN A 16 BIT VALUE CONTAINED IN (BC).
; THE BIT SET DEPENDS ON THE CURRENT DRIVE SELECTION.
;
SETBIT:	PUSH	BC		; SAVE 16 BIT WORD.
	LD	A,(ACTIVE)	; GET ACTIVE DRIVE.
	LD	C,A
	LD	HL,1
	CALL	SHIFTL		; SHIFT BIT 0 INTO PLACE.
	POP	BC		; NOW 'OR' THIS WITH THE ORIGINAL WORD.
	LD	A,C
	OR	L
	LD	L,A		; LOW BYTE DONE, DO HIGH BYTE.
	LD	A,B
	OR	H
	LD	H,A
	RET
;
;   EXTRACT THE WRITE PROTECT STATUS BIT FOR THE CURRENT DRIVE.
; THE RESULT IS RETURNED IN (A), BIT 0.
;
GETWPRT:LD	HL,(WRTPRT)	; GET STATUS BYTES.
	LD	A,(ACTIVE)	; WHICH DRIVE IS CURRENT?
	LD	C,A
	CALL	SHIFTR		; SHIFT STATUS SUCH THAT BIT 0 IS THE
	LD	A,L		; ONE OF INTEREST FOR THIS DRIVE.
	AND	01H		; AND ISOLATE IT.
	RET
;
;   FUNCTION TO WRITE PROTECT THE CURRENT DISK.
;
WRTPRTD:LD	HL,WRTPRT	; POINT TO STATUS WORD.
	LD	C,(HL)		; SET (BC) .EQUAL TO THE STATUS.
	INC	HL
	LD	B,(HL)
	CALL	SETBIT		; AND SET THIS BIT ACCORDING TO CURRENT DRIVE.
	LD	(WRTPRT),HL	; THEN SAVE.
	LD	HL,(DIRSIZE)	; NOW SAVE DIRECTORY SIZE LIMIT.
	INC	HL		; REMEMBER THE LAST ONE.
	EX	DE,HL
	LD	HL,(SCRATCH1)	; AND STORE IT HERE.
	LD	(HL),E		; PUT LOW BYTE.
	INC	HL
	LD	(HL),D		; THEN HIGH BYTE.
	RET
;
;   CHECK FOR A READ ONLY FILE.
;
CHKROFL:CALL	FCB2HL		; SET (HL) TO FILE ENTRY IN DIRECTORY BUFFER.
CKROF1:	LD	DE,9		; LOOK AT BIT 7 OF THE NINTH BYTE.
	ADD	HL,DE
	LD	A,(HL)
	RLA
	RET	NC		; RETURN IF OK.
	LD	HL,ROFILE	; ELSE, PRINT ERROR MESSAGE AND TERMINATE.
	JP	JUMPHL
;
;   CHECK THE WRITE PROTECT STATUS OF THE ACTIVE DISK.
;
CHKWPRT:CALL	GETWPRT
	RET	Z		; RETURN IF OK.
	LD	HL,RODISK	; ELSE PRINT MESSAGE AND TERMINATE.
	JP	JUMPHL
;
;   ROUTINE TO SET (HL) POINTING TO THE PROPER ENTRY IN THE
; DIRECTORY BUFFER.
;
FCB2HL:	LD	HL,(DIRBUF)	; GET ADDRESS OF BUFFER.
	LD	A,(FCBPOS)	; RELATIVE POSITION OF FILE.
;
;   ROUTINE TO ADD (A) TO (HL).
;
ADDA2HL:ADD	A,L
	LD	L,A
	RET	NC
	INC	H		; TAKE CARE OF ANY CARRY.
	RET
;
;   ROUTINE TO GET THE 'S2' BYTE FROM THE FCB SUPPLIED IN
; THE INITIAL PARAMETER SPECIFICATION.
;
GETS2:	LD	HL,(PARAMS)	; GET ADDRESS OF FCB.
	LD	DE,14		; RELATIVE POSITION OF 'S2'.
	ADD	HL,DE
	LD	A,(HL)		; EXTRACT THIS BYTE.
	RET
;
;   CLEAR THE 'S2' BYTE IN THE FCB.
;
CLEARS2:CALL	GETS2		; THIS SETS (HL) POINTING TO IT.
	LD	(HL),0		; NOW CLEAR IT.
	RET
;
;   SET BIT 7 IN THE 'S2' BYTE OF THE FCB.
;
SETS2B7:CALL	GETS2		; GET THE BYTE.
	OR	80H		; AND SET BIT 7.
	LD	(HL),A		; THEN STORE.
	RET
;
;   COMPARE (FILEPOS) WITH (SCRATCH1) AND SET FLAGS BASED ON
; THE DIFFERENCE. THIS CHECKS TO SEE IF THERE ARE MORE FILE
; NAMES IN THE DIRECTORY. WE ARE AT (FILEPOS) AND THERE ARE
; (SCRATCH1) OF THEM TO CHECK.
;
MOREFLS:LD	HL,(FILEPOS)	; WE ARE HERE.
	EX	DE,HL
	LD	HL,(SCRATCH1)	; AND DON'T GO PAST HERE.
	LD	A,E		; COMPUTE DIFFERENCE BUT DON'T KEEP.
	SUB	(HL)
	INC	HL
	LD	A,D
	SBC	A,(HL)		; SET CARRY IF NO MORE NAMES.
	RET
;
;   CALL THIS ROUTINE TO PREVENT (SCRATCH1) FROM BEING GREATER
; THAN (FILEPOS).
;
CHKNMBR:CALL	MOREFLS		; SCRATCH1 TOO BIG?
	RET	C
	INC	DE		; YES, RESET IT TO (FILEPOS).
	LD	(HL),D
	DEC	HL
	LD	(HL),E
	RET
;
;   COMPUTE (HL)=(DE)-(HL)
;
SUBHL:	LD	A,E		; COMPUTE DIFFERENCE.
	SUB	L
	LD	L,A		; STORE LOW BYTE.
	LD	A,D
	SBC	A,H
	LD	H,A		; AND THEN HIGH BYTE.
	RET
;
;   SET THE DIRECTORY CHECKSUM BYTE.
;
SETDIR:	LD	C,0FFH
;
;   ROUTINE TO SET OR COMPARE THE DIRECTORY CHECKSUM BYTE. IF
; (C)=0FFH, THEN THIS WILL SET THE CHECKSUM BYTE. ELSE THE BYTE
; WILL BE CHECKED. IF THE CHECK FAILS (THE DISK HAS BEEN CHANGED),
; THEN THIS DISK WILL BE WRITE PROTECTED.
;
CHECKDIR:
	LD	HL,(CKSUMTBL)
	EX	DE,HL
	LD	HL,(ALLOC1)
	CALL	SUBHL
	RET	NC		; OK IF (CKSUMTBL) > (ALLOC1), SO RETURN.
	PUSH	BC
	CALL	CHECKSUM	; ELSE COMPUTE CHECKSUM.
	LD	HL,(CHKVECT)	; GET ADDRESS OF CHECKSUM TABLE.
	EX	DE,HL
	LD	HL,(CKSUMTBL)
	ADD	HL,DE		; SET (HL) TO POINT TO BYTE FOR THIS DRIVE.
	POP	BC
	INC	C		; SET OR CHECK ?
	JP	Z,CHKDIR1
	CP	(HL)		; CHECK THEM.
	RET	Z		; RETURN IF THEY ARE THE SAME.
	CALL	MOREFLS		; NOT THE SAME, DO WE CARE?
	RET	NC
	CALL	WRTPRTD		; YES, MARK THIS AS WRITE PROTECTED.
	RET
CHKDIR1:LD	(HL),A		; JUST SET THE BYTE.
	RET
;
;   DO A WRITE TO THE DIRECTORY OF THE CURRENT DISK.
;
DIRWRITE:
	CALL	SETDIR		; SET CHECKSUM BYTE.
	CALL	DIRDMA		; SET DIRECTORY DMA ADDRESS.
	LD	C,1		; TELL THE BIOS TO ACTUALLY WRITE.
	CALL	DOWRITE		; THEN DO THE WRITE.
	JP	DEFDMA
;
;   READ FROM THE DIRECTORY.
;
DIRREAD:CALL	DIRDMA		; SET THE DIRECTORY DMA ADDRESS.
	CALL	DOREAD		; AND READ IT.
;
;   ROUTINE TO SET THE DMA ADDRESS TO THE USERS CHOICE.
;
DEFDMA:	LD	HL,USERDMA	; RESET THE DEFAULT DMA ADDRESS AND RETURN.
	JP	DIRDMA1
;
;   ROUTINE TO SET THE DMA ADDRESS FOR DIRECTORY WORK.
;
DIRDMA:	LD	HL,DIRBUF
;
;   SET THE DMA ADDRESS. ON ENTRY, (HL) POINTS TO
; WORD CONTAINING THE DESIRED DMA ADDRESS.
;
DIRDMA1:LD	C,(HL)
	INC	HL
	LD	B,(HL)		; SETUP (BC) AND GO TO THE BIOS TO SET IT.
	JP	SETDMA
;
;   MOVE THE DIRECTORY BUFFER INTO USER'S DMA SPACE.
;
MOVEDIR:LD	HL,(DIRBUF)	; BUFFER IS LOCATED HERE, AND
	EX	DE,HL
	LD	HL,(USERDMA)	; PUT IT HERE.
	LD	C,128		; THIS IS ITS LENGTH.
	JP	DE2HL		; MOVE IT NOW AND RETURN.
;
;   CHECK (FILEPOS) AND SET THE ZERO FLAG IF IT .EQUALS 0FFFFH.
;
CKFILPOS:
	LD	HL,FILEPOS
	LD	A,(HL)
	INC	HL
	CP	(HL)		; ARE BOTH BYTES THE SAME?
	RET	NZ
	INC	A		; YES, BUT ARE THEY EACH 0FFH?
	RET
;
;   SET LOCATION (FILEPOS) TO 0FFFFH.
;
STFILPOS:
	LD	HL,0FFFFH
	LD	(FILEPOS),HL
	RET
;
;   MOVE ON TO THE NEXT FILE POSITION WITHIN THE CURRENT
; DIRECTORY BUFFER. IF NO MORE EXIST, SET POINTER TO 0FFFFH
; AND THE CALLING ROUTINE WILL CHECK FOR THIS. ENTER WITH (C)
; .EQUAL TO 0FFH TO CAUSE THE CHECKSUM BYTE TO BE SET, ELSE WE
; WILL CHECK THIS DISK AND SET WRITE PROTECT IF CHECKSUMS ARE
; NOT THE SAME (APPLIES ONLY IF ANOTHER DIRECTORY SECTOR MUST
; BE READ).
;
NXENTRY:LD	HL,(DIRSIZE)	; GET DIRECTORY ENTRY SIZE LIMIT.
	EX	DE,HL
	LD	HL,(FILEPOS)	; GET CURRENT COUNT.
	INC	HL		; GO ON TO THE NEXT ONE.
	LD	(FILEPOS),HL
	CALL	SUBHL		; (HL)=(DIRSIZE)-(FILEPOS)
	JP	NC,NXENT1	; IS THERE MORE ROOM LEFT?
	JP	STFILPOS	; NO. SET THIS FLAG AND RETURN.
NXENT1:	LD	A,(FILEPOS)	; GET FILE POSITION WITHIN DIRECTORY.
	AND	03H		; ONLY LOOK WITHIN THIS SECTOR (ONLY 4 ENTRIES FIT).
	LD	B,5		; CONVERT TO RELATIVE POSITION (32 BYTES EACH).
NXENT2:	ADD	A,A		; NOTE THAT THIS IS NOT EFFICIENT CODE.
	DEC	B		; 5 'ADD A'S WOULD BE BETTER.
	JP	NZ,NXENT2
	LD	(FCBPOS),A	; SAVE IT AS POSITION OF FCB.
	OR	A
	RET	NZ		; RETURN IF WE ARE WITHIN BUFFER.
	PUSH	BC
	CALL	TRKSEC		; WE NEED THE NEXT DIRECTORY SECTOR.
	CALL	DIRREAD
	POP	BC
	JP	CHECKDIR
;
;   ROUTINE TO TO GET A BIT FROM THE DISK SPACE ALLOCATION
; MAP. IT IS RETURNED IN (A), BIT POSITION 0. ON ENTRY TO HERE,
; SET (BC) TO THE BLOCK NUMBER ON THE DISK TO CHECK.
; ON RETURN, (D) WILL CONTAIN THE ORIGINAL BIT POSITION FOR
; THIS BLOCK NUMBER AND (HL) WILL POINT TO THE ADDRESS FOR IT.
;
CKBITMAP:
	LD	A,C		; DETERMINE BIT NUMBER OF INTEREST.
	AND	07H		; COMPUTE (D)=(E)=(C AND 7)+1.
	INC	A
	LD	E,A		; SAVE PARTICULAR BIT NUMBER.
	LD	D,A
;
;   COMPUTE (BC)=(BC)/8.
;
	LD	A,C
	RRCA			; NOW SHIFT RIGHT 3 BITS.
	RRCA
	RRCA
	AND	1FH		; AND CLEAR BITS 7,6,5.
	LD	C,A
	LD	A,B
	ADD	A,A		; NOW SHIFT (B) INTO BITS 7,6,5.
	ADD	A,A
	ADD	A,A
	ADD	A,A
	ADD	A,A
	OR	C		; AND ADD IN (C).
	LD	C,A		; OK, (C) HA BEEN COMPLETED.
	LD	A,B		; IS THERE A BETTER WAY OF DOING THIS?
	RRCA
	RRCA
	RRCA
	AND	1FH
	LD	B,A		; AND NOW (B) IS COMPLETED.
;
;   USE THIS AS AN OFFSET INTO THE DISK SPACE ALLOCATION
; TABLE.
;
	LD	HL,(ALOCVECT)
	ADD	HL,BC
	LD	A,(HL)		; NOW GET CORRECT BYTE.
CKBMAP1:RLCA			; GET CORRECT BIT INTO POSITION 0.
	DEC	E
	JP	NZ,CKBMAP1
	RET
;
;   SET OR CLEAR THE BIT MAP SUCH THAT BLOCK NUMBER (BC) WILL BE MARKED
; AS USED. ON ENTRY, IF (E)=0 THEN THIS BIT WILL BE CLEARED, IF IT .EQUALS
; 1 THEN IT WILL BE SET (DON'T USE ANYOTHER VALUES).
;
STBITMAP:
	PUSH	DE
	CALL	CKBITMAP	; GET THE BYTE OF INTEREST.
	AND	0FEH		; CLEAR THE AFFECTED BIT.
	POP	BC
	OR	C		; AND NOW SET IT ACORDING TO (C).
;
;  ENTRY TO RESTORE THE ORIGINAL BIT POSITION AND THEN STORE
; IN TABLE. (A) CONTAINS THE VALUE, (D) CONTAINS THE BIT
; POSITION (1-8), AND (HL) POINTS TO THE ADDRESS WITHIN THE
; SPACE ALLOCATION TABLE FOR THIS BYTE.
;
STBMAP1:RRCA			; RESTORE ORIGINAL BIT POSITION.
	DEC	D
	JP	NZ,STBMAP1
	LD	(HL),A		; AND STOR BYTE IN TABLE.
	RET
;
;   SET/CLEAR SPACE USED BITS IN ALLOCATION MAP FOR THIS FILE.
; ON ENTRY, (C)=1 TO SET THE MAP AND (C)=0 TO CLEAR IT.
;
SETFILE:CALL	FCB2HL		; GET ADDRESS OF FCB
	LD	DE,16
	ADD	HL,DE		; GET TO BLOCK NUMBER BYTES.
	PUSH	BC
	LD	C,17		; CHECK ALL 17 BYTES (MAX) OF TABLE.
SETFL1:	POP	DE
	DEC	C		; DONE ALL BYTES YET?
	RET	Z
	PUSH	DE
	LD	A,(BIGDISK)	; CHECK DISK SIZE FOR 16 BIT BLOCK NUMBERS.
	OR	A
	JP	Z,SETFL2
	PUSH	BC		; ONLY 8 BIT NUMBERS. SET (BC) TO THIS ONE.
	PUSH	HL
	LD	C,(HL)		; GET LOW BYTE FROM TABLE, ALWAYS
	LD	B,0		; SET HIGH BYTE TO ZERO.
	JP	SETFL3
SETFL2:	DEC	C		; FOR 16 BIT BLOCK NUMBERS, ADJUST COUNTER.
	PUSH	BC
	LD	C,(HL)		; NOW GET BOTH THE LOW AND HIGH BYTES.
	INC	HL
	LD	B,(HL)
	PUSH	HL
SETFL3:	LD	A,C		; BLOCK USED?
	OR	B
	JP	Z,SETFL4
	LD	HL,(DSKSIZE)	; IS THIS BLOCK NUMBER WITHIN THE
	LD	A,L		; SPACE ON THE DISK?
	SUB	C
	LD	A,H
	SBC	A,B
	CALL	NC,STBITMAP	; YES, SET THE PROPER BIT.
SETFL4:	POP	HL		; POINT TO NEXT BLOCK NUMBER IN FCB.
	INC	HL
	POP	BC
	JP	SETFL1
;
;   CONSTRUCT THE SPACE USED ALLOCATION BIT MAP FOR THE ACTIVE
; DRIVE. IF A FILE NAME STARTS WITH '$' AND IT IS UNDER THE
; CURRENT USER NUMBER, THEN (STATUS) IS SET TO MINUS 1. OTHERWISE
; IT IS NOT SET AT ALL.
;
BITMAP:	LD	HL,(DSKSIZE)	; COMPUTE SIZE OF ALLOCATION TABLE.
	LD	C,3
	CALL	SHIFTR		; (HL)=(HL)/8.
	INC	HL		; AT LEASE 1 BYTE.
	LD	B,H
	LD	C,L		; SET (BC) TO THE ALLOCATION TABLE LENGTH.
;
;   INITIALIZE THE BITMAP FOR THIS DRIVE. RIGHT NOW, THE FIRST
; TWO BYTES ARE SPECIFIED BY THE DISK PARAMETER BLOCK. HOWEVER
; A PATCH COULD BE ENTERED HERE IF IT WERE NECESSARY TO SETUP
; THIS TABLE IN A SPECIAL MANNOR. FOR EXAMPLE, THE BIOS COULD
; DETERMINE LOCATIONS OF 'BAD BLOCKS' AND SET THEM AS ALREADY
; 'USED' IN THE MAP.
;
	LD	HL,(ALOCVECT)	; NOW ZERO OUT THE TABLE NOW.
BITMAP1:LD	(HL),0
	INC	HL
	DEC	BC
	LD	A,B
	OR	C
	JP	NZ,BITMAP1
	LD	HL,(ALLOC0)	; GET INITIAL SPACE USED BY DIRECTORY.
	EX	DE,HL
	LD	HL,(ALOCVECT)	; AND PUT THIS INTO MAP.
	LD	(HL),E
	INC	HL
	LD	(HL),D
;
;   END OF INITIALIZATION PORTION.
;
	CALL	HOMEDRV		; NOW HOME THE DRIVE.
	LD	HL,(SCRATCH1)
	LD	(HL),3		; FORCE NEXT DIRECTORY REQUEST TO READ
	INC	HL		; IN A SECTOR.
	LD	(HL),0
	CALL	STFILPOS	; CLEAR INITIAL FILE POSITION ALSO.
BITMAP2:LD	C,0FFH		; READ NEXT FILE NAME IN DIRECTORY
	CALL	NXENTRY		; AND SET CHECKSUM BYTE.
	CALL	CKFILPOS	; IS THERE ANOTHER FILE?
	RET	Z
	CALL	FCB2HL		; YES, GET ITS ADDRESS.
	LD	A,0E5H
	CP	(HL)		; EMPTY FILE ENTRY?
	JP	Z,BITMAP2
	LD	A,(USERNO)	; NO, CORRECT USER NUMBER?
	CP	(HL)
	JP	NZ,BITMAP3
	INC	HL
	LD	A,(HL)		; YES, DOES NAME START WITH A '$'?
	SUB	'$'
	JP	NZ,BITMAP3
	DEC	A		; YES, SET ATATUS TO MINUS ONE.
	LD	(STATUS),A
BITMAP3:LD	C,1		; NOW SET THIS FILE'S SPACE AS USED IN BIT MAP.
	CALL	SETFILE
	CALL	CHKNMBR		; KEEP (SCRATCH1) IN BOUNDS.
	JP	BITMAP2
;
;   SET THE STATUS (STATUS) AND RETURN.
;
STSTATUS:
	LD	A,(FNDSTAT)
	JP	SETSTAT
;
;   CHECK EXTENTS IN (A) AND (C). SET THE ZERO FLAG IF THEY
; ARE THE SAME. THE NUMBER OF 16K CHUNKS OF DISK SPACE THAT
; THE DIRECTORY EXTENT COVERS IS EXPRESSAD IS (EXTMASK+1).
; NO REGISTERS ARE MODIFIED.
;
SAMEXT:	PUSH	BC
	PUSH	AF
	LD	A,(EXTMASK)	; GET EXTENT MASK AND USE IT TO
	CPL			; TO COMPARE BOTH EXTENT NUMBERS.
	LD	B,A		; SAVE RESULTING MASK HERE.
	LD	A,C		; MASK FIRST EXTENT AND SAVE IN (C).
	AND	B
	LD	C,A
	POP	AF		; NOW MASK SECOND EXTENT AND COMPARE
	AND	B		; WITH THE FIRST ONE.
	SUB	C
	AND	1FH		; (* ONLY CHECK BUTS 0-4 *)
	POP	BC		; THE ZERO FLAG IS SET IF THEY ARE THE SAME.
	RET			; RESTORE (BC) AND RETURN.
;
;   SEARCH FOR THE FIRST OCCURENCE OF A FILE NAME. ON ENTRY,
; REGISTER (C) SHOULD CONTAIN THE NUMBER OF BYTES OF THE FCB
; THAT MUST MATCH.
;
FINDFST:LD	A,0FFH
	LD	(FNDSTAT),A
	LD	HL,COUNTER	; SAVE CHARACTER COUNT.
	LD	(HL),C
	LD	HL,(PARAMS)	; GET FILENAME TO MATCH.
	LD	(SAVEFCB),HL	; AND SAVE.
	CALL	STFILPOS	; CLEAR INITIAL FILE POSITION (SET TO 0FFFFH).
	CALL	HOMEDRV		; HOME THE DRIVE.
;
;   ENTRY TO LOCATE THE NEXT OCCURENCE OF A FILENAME WITHIN THE
; DIRECTORY. THE DISK IS NOT EXPECTED TO HAVE BEEN CHANGED. IF
; IT WAS, THEN IT WILL BE WRITE PROTECTED.
;
FINDNXT:LD	C,0		; WRITE PROTECT THE DISK IF CHANGED.
	CALL	NXENTRY		; GET NEXT FILENAME ENTRY IN DIRECTORY.
	CALL	CKFILPOS	; IS FILE POSITION = 0FFFFH?
	JP	Z,FNDNXT6	; YES, EXIT NOW THEN.
	LD	HL,(SAVEFCB)	; SET (DE) POINTING TO FILENAME TO MATCH.
	EX	DE,HL
	LD	A,(DE)
	CP	0E5H		; EMPTY DIRECTORY ENTRY?
	JP	Z,FNDNXT1	; (* ARE WE TRYING TO RESERECT ERASED ENTRIES? *)
	PUSH	DE
	CALL	MOREFLS		; MORE FILES IN DIRECTORY?
	POP	DE
	JP	NC,FNDNXT6	; NO MORE. EXIT NOW.
FNDNXT1:CALL	FCB2HL		; GET ADDRESS OF THIS FCB IN DIRECTORY.
	LD	A,(COUNTER)	; GET NUMBER OF BYTES (CHARACTERS) TO CHECK.
	LD	C,A
	LD	B,0		; INITIALIZE BYTE POSITION COUNTER.
FNDNXT2:LD	A,C		; ARE WE DONE WITH THE COMPARE?
	OR	A
	JP	Z,FNDNXT5
	LD	A,(DE)		; NO, CHECK NEXT BYTE.
	CP	'?'		; DON'T CARE ABOUT THIS CHARACTER?
	JP	Z,FNDNXT4
	LD	A,B		; GET BYTES POSITION IN FCB.
	CP	13		; DON'T CARE ABOUT THE THIRTEENTH BYTE EITHER.
	JP	Z,FNDNXT4
	CP	12		; EXTENT BYTE?
	LD	A,(DE)
	JP	Z,FNDNXT3
	SUB	(HL)		; OTHERWISE COMPARE CHARACTERS.
	AND	7FH
	JP	NZ,FINDNXT	; NOT THE SAME, CHECK NEXT ENTRY.
	JP	FNDNXT4		; SO FAR SO GOOD, KEEP CHECKING.
FNDNXT3:PUSH	BC		; CHECK THE EXTENT BYTE HERE.
	LD	C,(HL)
	CALL	SAMEXT
	POP	BC
	JP	NZ,FINDNXT	; NOT THE SAME, LOOK SOME MORE.
;
;   SO FAR THE NAMES COMPARE. BUMP POINTERS TO THE NEXT BYTE
; AND CONTINUE UNTIL ALL (C) CHARACTERS HAVE BEEN CHECKED.
;
FNDNXT4:INC	DE		; BUMP POINTERS.
	INC	HL
	INC	B
	DEC	C		; ADJUST CHARACTER COUNTER.
	JP	FNDNXT2
FNDNXT5:LD	A,(FILEPOS)	; RETURN THE POSITION OF THIS ENTRY.
	AND	03H
	LD	(STATUS),A
	LD	HL,FNDSTAT
	LD	A,(HL)
	RLA
	RET	NC
	XOR	A
	LD	(HL),A
	RET
;
;   FILENAME WAS NOT FOUND. SET APPROPRIATE STATUS.
;
FNDNXT6:CALL	STFILPOS	; SET (FILEPOS) TO 0FFFFH.
	LD	A,0FFH		; SAY NOT LOCATED.
	JP	SETSTAT
;
;   ERASE FILES FROM THE DIRECTORY. ONLY THE FIRST BYTE OF THE
; FCB WILL BE AFFECTED. IT IS SET TO (E5).
;
ERAFILE:CALL	CHKWPRT		; IS DISK WRITE PROTECTED?
	LD	C,12		; ONLY COMPARE FILE NAMES.
	CALL	FINDFST		; GET FIRST FILE NAME.
ERAFIL1:CALL	CKFILPOS	; ANY FOUND?
	RET	Z		; NOPE, WE MUST BE DONE.
	CALL	CHKROFL		; IS FILE READ ONLY?
	CALL	FCB2HL		; NOPE, GET ADDRESS OF FCB AND
	LD	(HL),0E5H	; SET FIRST BYTE TO 'EMPTY'.
	LD	C,0		; CLEAR THE SPACE FROM THE BIT MAP.
	CALL	SETFILE
	CALL	DIRWRITE	; NOW WRITE THE DIRECTORY SECTOR BACK OUT.
	CALL	FINDNXT		; FIND THE NEXT FILE NAME.
	JP	ERAFIL1		; AND REPEAT PROCESS.
;
;   LOOK THROUGH THE SPACE ALLOCATION MAP (BIT MAP) FOR THE
; NEXT AVAILABLE BLOCK. START SEARCHING AT BLOCK NUMBER (BC-1).
; THE SEARCH PROCEDURE IS TO LOOK FOR AN EMPTY BLOCK THAT IS
; BEFORE THE STARTING BLOCK. IF NOT EMPTY, LOOK AT A LATER
; BLOCK NUMBER. IN THIS WAY, WE RETURN THE CLOSEST EMPTY BLOCK
; ON EITHER SIDE OF THE 'TARGET' BLOCK NUMBER. THIS WILL SPEED
; ACCESS ON RANDOM DEVICES. FOR SERIAL DEVICES, THIS SHOULD BE
; CHANGED TO LOOK IN THE FORWARD DIRECTION FIRST AND THEN START
; AT THE FRONT AND SEARCH SOME MORE.
;
;   ON RETURN, (DE)= BLOCK NUMBER THAT IS EMPTY AND (HL) =0
; IF NO EMPRY BLOCK WAS FOUND.
;
FNDSPACE:
	LD	D,B		; SET (DE) AS THE BLOCK THAT IS CHECKED.
	LD	E,C
;
;   LOOK BEFORE TARGET BLOCK. REGISTERS (BC) ARE USED AS THE LOWER
; POINTER AND (DE) AS THE UPPER POINTER.
;
FNDSPA1:LD	A,C		; IS BLOCK 0 SPECIFIED?
	OR	B
	JP	Z,FNDSPA2
	DEC	BC		; NOPE, CHECK PREVIOUS BLOCK.
	PUSH	DE
	PUSH	BC
	CALL	CKBITMAP
	RRA			; IS THIS BLOCK EMPTY?
	JP	NC,FNDSPA3	; YES. USE THIS.
;
;   NOTE THAT THE ABOVE LOGIC GETS THE FIRST BLOCK THAT IT FINDS
; THAT IS EMPTY. THUS A FILE COULD BE WRITTEN 'BACKWARD' MAKING
; IT VERY SLOW TO ACCESS. THIS COULD BE CHANGED TO LOOK FOR THE
; FIRST EMPTY BLOCK AND THEN CONTINUE UNTIL THE START OF THIS
; EMPTY SPACE IS LOCATED AND THEN USED THAT STARTING BLOCK.
; THIS SHOULD HELP SPEED UP ACCESS TO SOME FILES ESPECIALLY ON
; A WELL USED DISK WITH LOTS OF FAIRLY SMALL 'HOLES'.
;
	POP	BC		; NOPE, CHECK SOME MORE.
	POP	DE
;
;   NOW LOOK AFTER TARGET BLOCK.
;
FNDSPA2:LD	HL,(DSKSIZE)	; IS BLOCK (DE) WITHIN DISK LIMITS?
	LD	A,E
	SUB	L
	LD	A,D
	SBC	A,H
	JP	NC,FNDSPA4
	INC	DE		; YES, MOVE ON TO NEXT ONE.
	PUSH	BC
	PUSH	DE
	LD	B,D
	LD	C,E
	CALL	CKBITMAP	; CHECK IT.
	RRA			; EMPTY?
	JP	NC,FNDSPA3
	POP	DE		; NOPE, CONTINUE SEARCHING.
	POP	BC
	JP	FNDSPA1
;
;   EMPTY BLOCK FOUND. SET IT AS USED AND RETURN WITH (HL)
; POINTING TO IT (TRUE?).
;
FNDSPA3:RLA			; RESET BYTE.
	INC	A		; AND SET BIT 0.
	CALL	STBMAP1		; UPDATE BIT MAP.
	POP	HL		; SET RETURN REGISTERS.
	POP	DE
	RET
;
;   FREE BLOCK WAS NOT FOUND. IF (BC) IS NOT ZERO, THEN WE HAVE
; NOT CHECKED ALL OF THE DISK SPACE.
;
FNDSPA4:LD	A,C
	OR	B
	JP	NZ,FNDSPA1
	LD	HL,0		; SET 'NOT FOUND' STATUS.
	RET
;
;   MOVE A COMPLETE FCB ENTRY INTO THE DIRECTORY AND WRITE IT.
;
FCBSET:	LD	C,0
	LD	E,32		; LENGTH OF EACH ENTRY.
;
;   MOVE (E) BYTES FROM THE FCB POINTED TO BY (PARAMS) INTO
; FCB IN DIRECTORY STARTING AT RELATIVE BYTE (C). THIS UPDATED
; DIRECTORY BUFFER IS THEN WRITTEN TO THE DISK.
;
UPDATE:	PUSH	DE
	LD	B,0		; SET (BC) TO RELATIVE BYTE POSITION.
	LD	HL,(PARAMS)	; GET ADDRESS OF FCB.
	ADD	HL,BC		; COMPUTE STARTING BYTE.
	EX	DE,HL
	CALL	FCB2HL		; GET ADDRESS OF FCB TO UPDATE IN DIRECTORY.
	POP	BC		; SET (C) TO NUMBER OF BYTES TO CHANGE.
	CALL	DE2HL
UPDATE1:CALL	TRKSEC		; DETERMINE THE TRACK AND SECTOR AFFECTED.
	JP	DIRWRITE	; THEN WRITE THIS SECTOR OUT.
;
;   ROUTINE TO CHANGE THE NAME OF ALL FILES ON THE DISK WITH A
; SPECIFIED NAME. THE FCB CONTAINS THE CURRENT NAME AS THE
; FIRST 12 CHARACTERS AND THE NEW NAME 16 BYTES INTO THE FCB.
;
CHGNAMES:
	CALL	CHKWPRT		; CHECK FOR A WRITE PROTECTED DISK.
	LD	C,12		; MATCH FIRST 12 BYTES OF FCB ONLY.
	CALL	FINDFST		; GET FIRST NAME.
	LD	HL,(PARAMS)	; GET ADDRESS OF FCB.
	LD	A,(HL)		; GET USER NUMBER.
	LD	DE,16		; MOVE OVER TO DESIRED NAME.
	ADD	HL,DE
	LD	(HL),A		; KEEP SAME USER NUMBER.
CHGNAM1:CALL	CKFILPOS	; ANY MATCHING FILE FOUND?
	RET	Z		; NO, WE MUST BE DONE.
	CALL	CHKROFL		; CHECK FOR READ ONLY FILE.
	LD	C,16		; START 16 BYTES INTO FCB.
	LD	E,12		; AND UPDATE THE FIRST 12 BYTES OF DIRECTORY.
	CALL	UPDATE
	CALL	FINDNXT		; GET TE NEXT FILE NAME.
	JP	CHGNAM1		; AND CONTINUE.
;
;   UPDATE A FILES ATTRIBUTES. THE PROCEDURE IS TO SEARCH FOR
; EVERY FILE WITH THE SAME NAME AS SHOWN IN FCB (IGNORING BIT 7)
; AND THEN TO UPDATE IT (WHICH INCLUDES BIT 7). NO OTHER CHANGES
; ARE MADE.
;
SAVEATTR:
	LD	C,12		; MATCH FIRST 12 BYTES.
	CALL	FINDFST		; LOOK FOR FIRST FILENAME.
SAVATR1:CALL	CKFILPOS	; WAS ONE FOUND?
	RET	Z		; NOPE, WE MUST BE DONE.
	LD	C,0		; YES, UPDATE THE FIRST 12 BYTES NOW.
	LD	E,12
	CALL	UPDATE		; UPDATE FILENAME AND WRITE DIRECTORY.
	CALL	FINDNXT		; AND GET THE NEXT FILE.
	JP	SAVATR1		; THEN CONTINUE UNTIL DONE.
;
;  OPEN A FILE (NAME SPECIFIED IN FCB).
;
OPENIT:	LD	C,15		; COMPARE THE FIRST 15 BYTES.
	CALL	FINDFST		; GET THE FIRST ONE IN DIRECTORY.
	CALL	CKFILPOS	; ANY AT ALL?
	RET	Z
OPENIT1:CALL	SETEXT		; POINT TO EXTENT BYTE WITHIN USERS FCB.
	LD	A,(HL)		; AND GET IT.
	PUSH	AF		; SAVE IT AND ADDRESS.
	PUSH	HL
	CALL	FCB2HL		; POINT TO FCB IN DIRECTORY.
	EX	DE,HL
	LD	HL,(PARAMS)	; THIS IS THE USERS COPY.
	LD	C,32		; MOVE IT INTO USERS SPACE.
	PUSH	DE
	CALL	DE2HL
	CALL	SETS2B7		; SET BIT 7 IN 'S2' BYTE (UNMODIFIED).
	POP	DE		; NOW GET THE EXTENT BYTE FROM THIS FCB.
	LD	HL,12
	ADD	HL,DE
	LD	C,(HL)		; INTO (C).
	LD	HL,15		; NOW GET THE RECORD COUNT BYTE INTO (B).
	ADD	HL,DE
	LD	B,(HL)
	POP	HL		; KEEP THE SAME EXTENT AS THE USER HAD ORIGINALLY.
	POP	AF
	LD	(HL),A
	LD	A,C		; IS IT THE SAME AS IN THE DIRECTORY FCB?
	CP	(HL)
	LD	A,B		; IF YES, THEN USE THE SAME RECORD COUNT.
	JP	Z,OPENIT2
	LD	A,0		; IF THE USER SPECIFIED AN EXTENT GREATER THAN
	JP	C,OPENIT2	; THE ONE IN THE DIRECTORY, THEN SET RECORD COUNT TO 0.
	LD	A,128		; OTHERWISE SET TO MAXIMUM.
OPENIT2:LD	HL,(PARAMS)	; SET RECORD COUNT IN USERS FCB TO (A).
	LD	DE,15
	ADD	HL,DE		; COMPUTE RELATIVE POSITION.
	LD	(HL),A		; AND SET THE RECORD COUNT.
	RET
;
;   MOVE TWO BYTES FROM (DE) TO (HL) IF (AND ONLY IF) (HL)
; POINT TO A ZERO VALUE (16 BIT).
;   RETURN WITH ZERO FLAG SET IT (DE) WAS MOVED. REGISTERS (DE)
; AND (HL) ARE NOT CHANGED. HOWEVER (A) IS.
;
MOVEWORD:
	LD	A,(HL)		; CHECK FOR A ZERO WORD.
	INC	HL
	OR	(HL)		; BOTH BYTES ZERO?
	DEC	HL
	RET	NZ		; NOPE, JUST RETURN.
	LD	A,(DE)		; YES, MOVE TWO BYTES FROM (DE) INTO
	LD	(HL),A		; THIS ZERO SPACE.
	INC	DE
	INC	HL
	LD	A,(DE)
	LD	(HL),A
	DEC	DE		; DON'T DISTURB THESE REGISTERS.
	DEC	HL
	RET
;
;   GET HERE TO CLOSE A FILE SPECIFIED BY (FCB).
;
CLOSEIT:XOR	A		; CLEAR STATUS AND FILE POSITION BYTES.
	LD	(STATUS),A
	LD	(FILEPOS),A
	LD	(FILEPOS+1),A
	CALL	GETWPRT		; GET WRITE PROTECT BIT FOR THIS DRIVE.
	RET	NZ		; JUST RETURN IF IT IS SET.
	CALL	GETS2		; ELSE GET THE 'S2' BYTE.
	AND	80H		; AND LOOK AT BIT 7 (FILE UNMODIFIED?).
	RET	NZ		; JUST RETURN IF SET.
	LD	C,15		; ELSE LOOK UP THIS FILE IN DIRECTORY.
	CALL	FINDFST
	CALL	CKFILPOS	; WAS IT FOUND?
	RET	Z		; JUST RETURN IF NOT.
	LD	BC,16		; SET (HL) POINTING TO RECORDS USED SECTION.
	CALL	FCB2HL
	ADD	HL,BC
	EX	DE,HL
	LD	HL,(PARAMS)	; DO THE SAME FOR USERS SPECIFIED FCB.
	ADD	HL,BC
	LD	C,16		; THIS MANY BYTES ARE PRESENT IN THIS EXTENT.
CLOSEIT1:
	LD	A,(BIGDISK)	; 8 OR 16 BIT RECORD NUMBERS?
	OR	A
	JP	Z,CLOSEIT4
	LD	A,(HL)		; JUST 8 BIT. GET ONE FROM USERS FCB.
	OR	A
	LD	A,(DE)		; NOW GET ONE FROM DIRECTORY FCB.
	JP	NZ,CLOSEIT2
	LD	(HL),A		; USERS BYTE WAS ZERO. UPDATE FROM DIRECTORY.
CLOSEIT2:
	OR	A
	JP	NZ,CLOSEIT3
	LD	A,(HL)		; DIRECTORIES BYTE WAS ZERO, UPDATE FROM USERS FCB.
	LD	(DE),A
CLOSEIT3:
	CP	(HL)		; IF NEITHER ONE OF THESE BYTES WERE ZERO,
	JP	NZ,CLOSEIT7	; THEN CLOSE ERROR IF THEY ARE NOT THE SAME.
	JP	CLOSEIT5	; OK SO FAR, GET TO NEXT BYTE IN FCBS.
CLOSEIT4:
	CALL	MOVEWORD	; UPDATE USERS FCB IF IT IS ZERO.
	EX	DE,HL
	CALL	MOVEWORD	; UPDATE DIRECTORIES FCB IF IT IS ZERO.
	EX	DE,HL
	LD	A,(DE)		; IF THESE TWO VALUES ARE NO DIFFERENT,
	CP	(HL)		; THEN A CLOSE ERROR OCCURED.
	JP	NZ,CLOSEIT7
	INC	DE		; CHECK SECOND BYTE.
	INC	HL
	LD	A,(DE)
	CP	(HL)
	JP	NZ,CLOSEIT7
	DEC	C		; REMEMBER 16 BIT VALUES.
CLOSEIT5:
	INC	DE		; BUMP TO NEXT ITEM IN TABLE.
	INC	HL
	DEC	C		; THERE ARE 16 ENTRIES ONLY.
	JP	NZ,CLOSEIT1	; CONTINUE IF MORE TO DO.
	LD	BC,0FFECH	; BACKUP 20 PLACES (EXTENT BYTE).
	ADD	HL,BC
	EX	DE,HL
	ADD	HL,BC
	LD	A,(DE)
	CP	(HL)		; DIRECTORY'S EXTENT ALREADY GREATER THAN THE
	JP	C,CLOSEIT6	; USERS EXTENT?
	LD	(HL),A		; NO, UPDATE DIRECTORY EXTENT.
	LD	BC,3		; AND UPDATE THE RECORD COUNT BYTE IN
	ADD	HL,BC		; DIRECTORIES FCB.
	EX	DE,HL
	ADD	HL,BC
	LD	A,(HL)		; GET FROM USER.
	LD	(DE),A		; AND PUT IN DIRECTORY.
CLOSEIT6:
	LD	A,0FFH		; SET 'WAS OPEN AND IS NOW CLOSED' BYTE.
	LD	(CLOSEFLG),A
	JP	UPDATE1		; UPDATE THE DIRECTORY NOW.
CLOSEIT7:
	LD	HL,STATUS	; SET RETURN STATUS AND THEN RETURN.
	DEC	(HL)
	RET
;
;   ROUTINE TO GET THE NEXT EMPTY SPACE IN THE DIRECTORY. IT
; WILL THEN BE CLEARED FOR USE.
;
GETEMPTY:
	CALL	CHKWPRT		; MAKE SURE DISK IS NOT WRITE PROTECTED.
	LD	HL,(PARAMS)	; SAVE CURRENT PARAMETERS (FCB).
	PUSH	HL
	LD	HL,EMPTYFCB	; USE SPECIAL ONE FOR EMPTY SPACE.
	LD	(PARAMS),HL
	LD	C,1		; SEARCH FOR FIRST EMPTY SPOT IN DIRECTORY.
	CALL	FINDFST		; (* ONLY CHECK FIRST BYTE *)
	CALL	CKFILPOS	; NONE?
	POP	HL
	LD	(PARAMS),HL	; RESTORE ORIGINAL FCB ADDRESS.
	RET	Z		; RETURN IF NO MORE SPACE.
	EX	DE,HL
	LD	HL,15		; POINT TO NUMBER OF RECORDS FOR THIS FILE.
	ADD	HL,DE
	LD	C,17		; AND CLEAR ALL OF THIS SPACE.
	XOR	A
GETMT1:	LD	(HL),A
	INC	HL
	DEC	C
	JP	NZ,GETMT1
	LD	HL,13		; CLEAR THE 'S1' BYTE ALSO.
	ADD	HL,DE
	LD	(HL),A
	CALL	CHKNMBR		; KEEP (SCRATCH1) WITHIN BOUNDS.
	CALL	FCBSET		; WRITE OUT THIS FCB ENTRY TO DIRECTORY.
	JP	SETS2B7		; SET 'S2' BYTE BIT 7 (UNMODIFIED AT PRESENT).
;
;   ROUTINE TO CLOSE THE CURRENT EXTENT AND OPEN THE NEXT ONE
; FOR READING.
;
GETNEXT:XOR	A
	LD	(CLOSEFLG),A	; CLEAR CLOSE FLAG.
	CALL	CLOSEIT		; CLOSE THIS EXTENT.
	CALL	CKFILPOS
	RET	Z		; NOT THERE???
	LD	HL,(PARAMS)	; GET EXTENT BYTE.
	LD	BC,12
	ADD	HL,BC
	LD	A,(HL)		; AND INCREMENT IT.
	INC	A
	AND	1FH		; KEEP WITHIN RANGE 0-31.
	LD	(HL),A
	JP	Z,GTNEXT1	; OVERFLOW?
	LD	B,A		; MASK EXTENT BYTE.
	LD	A,(EXTMASK)
	AND	B
	LD	HL,CLOSEFLG	; CHECK CLOSE FLAG (0FFH IS OK).
	AND	(HL)
	JP	Z,GTNEXT2	; IF ZERO, WE MUST READ IN NEXT EXTENT.
	JP	GTNEXT3		; ELSE, IT IS ALREADY IN MEMORY.
GTNEXT1:LD	BC,2		; POINT TO THE 'S2' BYTE.
	ADD	HL,BC
	INC	(HL)		; AND BUMP IT.
	LD	A,(HL)		; TOO MANY EXTENTS?
	AND	0FH
	JP	Z,GTNEXT5	; YES, SET ERROR CODE.
;
;   GET HERE TO OPEN THE NEXT EXTENT.
;
GTNEXT2:LD	C,15		; SET TO CHECK FIRST 15 BYTES OF FCB.
	CALL	FINDFST		; FIND THE FIRST ONE.
	CALL	CKFILPOS	; NONE AVAILABLE?
	JP	NZ,GTNEXT3
	LD	A,(R.DWRTFLG)	; NO EXTENT PRESENT. CAN WE OPEN AN EMPTY ONE?
	INC	A		; 0FFH MEANS READING (SO NOT POSSIBLE).
	JP	Z,GTNEXT5	; OR AN ERROR.
	CALL	GETEMPTY	; WE ARE WRITING, GET AN EMPTY ENTRY.
	CALL	CKFILPOS	; NONE?
	JP	Z,GTNEXT5	; ERROR IF TRUE.
	JP	GTNEXT4		; ELSE WE ARE ALMOST DONE.
GTNEXT3:CALL	OPENIT1		; OPEN THIS EXTENT.
GTNEXT4:CALL	STRDATA		; MOVE IN UPDATED DATA (REC #, EXTENT #, ETC.)
	XOR	A		; CLEAR STATUS AND RETURN.
	JP	SETSTAT
;
;   ERROR IN EXTENDING THE FILE. TOO MANY EXTENTS WERE NEEDED
; OR NOT ENOUGH SPACE ON THE DISK.
;
GTNEXT5:CALL	IOERR1		; SET ERROR CODE, CLEAR BIT 7 OF 'S2'
	JP	SETS2B7		; SO THIS IS NOT WRITTEN ON A CLOSE.
;
;   READ A S.EQUENTIAL FILE.
;
RDSEQ:	LD	A,1		; SET S.EQUENTIAL ACCESS MODE.
	LD	(MODE),A
RDSEQ1:	LD	A,0FFH		; DON'T ALLOW READING UNWRITTEN SPACE.
	LD	(R.DWRTFLG),A
	CALL	STRDATA		; PUT REC# AND EXT# INTO FCB.
	LD	A,(SAVNREC)	; GET NEXT RECORD TO READ.
	LD	HL,SAVNXT	; GET NUMBER OF RECORDS IN EXTENT.
	CP	(HL)		; WITHIN THIS EXTENT?
	JP	C,RDSEQ2
	CP	128		; NO. IS THIS EXTENT FULLY USED?
	JP	NZ,RDSEQ3	; NO. END-OF-FILE.
	CALL	GETNEXT		; YES, OPEN THE NEXT ONE.
	XOR	A		; RESET NEXT RECORD TO READ.
	LD	(SAVNREC),A
	LD	A,(STATUS)	; CHECK ON OPEN, SUCCESSFUL?
	OR	A
	JP	NZ,RDSEQ3	; NO, ERROR.
RDSEQ2:	CALL	COMBLK		; OK. COMPUTE BLOCK NUMBER TO READ.
	CALL	CHKBLK		; CHECK IT. WITHIN BOUNDS?
	JP	Z,RDSEQ3	; NO, ERROR.
	CALL	LOGICAL		; CONVERT (BLKNMBR) TO LOGICAL SECTOR (128 BYTE).
	CALL	TRKSEC1		; SET THE TRACK AND SECTOR FOR THIS BLOCK #.
	CALL	DOREAD		; AND READ IT.
	JP	SETNREC		; AND SET THE NEXT RECORD TO BE ACCESSED.
;
;   READ ERROR OCCURED. SET STATUS AND RETURN.
;
RDSEQ3:	JP	IOERR1
;
;   WRITE THE NEXT S.EQUENTIAL RECORD.
;
WTSEQ:	LD	A,1		; SET S.EQUENTIAL ACCESS MODE.
	LD	(MODE),A
WTSEQ1:	LD	A,0		; ALLOW AN ADDITION EMPTY EXTENT TO BE OPENED.
	LD	(R.DWRTFLG),A
	CALL	CHKWPRT		; CHECK WRITE PROTECT STATUS.
	LD	HL,(PARAMS)
	CALL	CKROF1		; CHECK FOR READ ONLY FILE, (HL) ALREADY SET TO FCB.
	CALL	STRDATA		; PUT UPDATED DATA INTO FCB.
	LD	A,(SAVNREC)	; GET RECORD NUMBER TO WRITE.
	CP	128		; WITHIN RANGE?
	JP	NC,IOERR1	; NO, ERROR(?).
	CALL	COMBLK		; COMPUTE BLOCK NUMBER.
	CALL	CHKBLK		; CHECK NUMBER.
	LD	C,0		; IS THERE ONE TO WRITE TO?
	JP	NZ,WTSEQ6	; YES, GO DO IT.
	CALL	GETBLOCK	; GET NEXT BLOCK NUMBER WITHIN FCB TO USE.
	LD	(RELBLOCK),A	; AND SAVE.
	LD	BC,0		; START LOOKING FOR SPACE FROM THE START
	OR	A		; IF NONE ALLOCATED AS YET.
	JP	Z,WTSEQ2
	LD	C,A		; EXTRACT PREVIOUS BLOCK NUMBER FROM FCB
	DEC	BC		; SO WE CAN BE CLOSEST TO IT.
	CALL	EXTBLK
	LD	B,H
	LD	C,L
WTSEQ2:	CALL	FNDSPACE	; FIND THE NEXT EMPTY BLOCK NEAREST NUMBER (BC).
	LD	A,L		; CHECK FOR A ZERO NUMBER.
	OR	H
	JP	NZ,WTSEQ3
	LD	A,2		; NO MORE SPACE?
	JP	SETSTAT
WTSEQ3:	LD	(BLKNMBR),HL	; SAVE BLOCK NUMBER TO ACCESS.
	EX	DE,HL		; PUT BLOCK NUMBER INTO (DE).
	LD	HL,(PARAMS)	; NOW WE MUST UPDATE THE FCB FOR THIS
	LD	BC,16		; NEWLY ALLOCATED BLOCK.
	ADD	HL,BC
	LD	A,(BIGDISK)	; 8 OR 16 BIT BLOCK NUMBERS?
	OR	A
	LD	A,(RELBLOCK)	; (* UPDATE THIS ENTRY *)
	JP	Z,WTSEQ4	; ZERO MEANS 16 BIT ONES.
	CALL	ADDA2HL		; (HL)=(HL)+(A)
	LD	(HL),E		; STORE NEW BLOCK NUMBER.
	JP	WTSEQ5
WTSEQ4:	LD	C,A		; COMPUTE SPOT IN THIS 16 BIT TABLE.
	LD	B,0
	ADD	HL,BC
	ADD	HL,BC
	LD	(HL),E		; STUFF BLOCK NUMBER (DE) THERE.
	INC	HL
	LD	(HL),D
WTSEQ5:	LD	C,2		; SET (C) TO INDICATE WRITING TO UN-USED DISK SPACE.
WTSEQ6:	LD	A,(STATUS)	; ARE WE OK SO FAR?
	OR	A
	RET	NZ
	PUSH	BC		; YES, SAVE WRITE FLAG FOR BIOS (REGISTER C).
	CALL	LOGICAL		; CONVERT (BLKNMBR) OVER TO LOICAL SECTORS.
	LD	A,(MODE)	; GET ACCESS MODE FLAG (1=S.EQUENTIAL,
	DEC	A		; 0=RANDOM, 2=SPECIAL?).
	DEC	A
	JP	NZ,WTSEQ9
;
;   SPECIAL RANDOM I/O FROM FUNCTION #40. MAYBE FOR M/PM, BUT THE
; CURRENT BLOCK, IF IT HAS NOT BEEN WRITTEN TO, WILL BE ZEROED
; OUT AND THEN WRITTEN (REASON?).
;
	POP	BC
	PUSH	BC
	LD	A,C		; GET WRITE STATUS FLAG (2=WRITING UNUSED SPACE).
	DEC	A
	DEC	A
	JP	NZ,WTSEQ9
	PUSH	HL
	LD	HL,(DIRBUF)	; ZERO OUT THE DIRECTORY BUFFER.
	LD	D,A		; NOTE THAT (A) IS ZERO HERE.
WTSEQ7:	LD	(HL),A
	INC	HL
	INC	D		; DO 128 BYTES.
	JP	P,WTSEQ7
	CALL	DIRDMA		; TELL THE BIOS THE DMA ADDRESS FOR DIRECTORY ACCESS.
	LD	HL,(LOGSECT)	; GET SECTOR THAT STARTS CURRENT BLOCK.
	LD	C,2		; SET 'WRITING TO UNUSED SPACE' FLAG.
WTSEQ8:	LD	(BLKNMBR),HL	; SAVE SECTOR TO WRITE.
	PUSH	BC
	CALL	TRKSEC1		; DETERMINE ITS TRACK AND SECTOR NUMBERS.
	POP	BC
	CALL	DOWRITE		; NOW WRITE OUT 128 BYTES OF ZEROS.
	LD	HL,(BLKNMBR)	; GET SECTOR NUMBER.
	LD	C,0		; SET NORMAL WRITE FLAG.
	LD	A,(BLKMASK)	; DETERMINE IF WE HAVE WRITTEN THE ENTIRE
	LD	B,A		; PHYSICAL BLOCK.
	AND	L
	CP	B
	INC	HL		; PREPARE FOR THE NEXT ONE.
	JP	NZ,WTSEQ8	; CONTINUE UNTIL (BLKMASK+1) SECTORS WRITTEN.
	POP	HL		; RESET NEXT SECTOR NUMBER.
	LD	(BLKNMBR),HL
	CALL	DEFDMA		; AND RESET DMA ADDRESS.
;
;   NORMAL DISK WRITE. SET THE DESIRED TRACK AND SECTOR THEN
; DO THE ACTUAL WRITE.
;
WTSEQ9:	CALL	TRKSEC1		; DETERMINE TRACK AND SECTOR FOR THIS WRITE.
	POP	BC		; GET WRITE STATUS FLAG.
	PUSH	BC
	CALL	DOWRITE		; AND WRITE THIS OUT.
	POP	BC
	LD	A,(SAVNREC)	; GET NUMBER OF RECORDS IN FILE.
	LD	HL,SAVNXT	; GET LAST RECORD WRITTEN.
	CP	(HL)
	JP	C,WTSEQ10
	LD	(HL),A		; WE HAVE TO UPDATE RECORD COUNT.
	INC	(HL)
	LD	C,2
;
;*   THIS AREA HAS BEEN PATCHED TO CORRECT DISK UPDATE PROBLEM
;* WHEN USING BLOCKING AND DE-BLOCKING IN THE BIOS.
;
WTSEQ10:NOP			; WAS 'DCR C'
	NOP			; WAS 'DCR C'
	LD	HL,0		; WAS 'JNZ WTSEQ99'
;
; *   END OF PATCH.
;
	PUSH	AF
	CALL	GETS2		; SET 'EXTENT WRITTEN TO' FLAG.
	AND	7FH		; (* CLEAR BIT 7 *)
	LD	(HL),A
	POP	AF		; GET RECORD COUNT FOR THIS EXTENT.
WTSEQ99:CP	127		; IS IT FULL?
	JP	NZ,WTSEQ12
	LD	A,(MODE)	; YES, ARE WE IN S.EQUENTIAL MODE?
	CP	1
	JP	NZ,WTSEQ12
	CALL	SETNREC		; YES, SET NEXT RECORD NUMBER.
	CALL	GETNEXT		; AND GET NEXT EMPTY SPACE IN DIRECTORY.
	LD	HL,STATUS	; OK?
	LD	A,(HL)
	OR	A
	JP	NZ,WTSEQ11
	DEC	A		; YES, SET RECORD COUNT TO -1.
	LD	(SAVNREC),A
WTSEQ11:LD	(HL),0		; CLEAR STATUS.
WTSEQ12:JP	SETNREC		; SET NEXT RECORD TO ACCESS.
;
;   FOR RANDOM I/O, SET THE FCB FOR THE DESIRED RECORD NUMBER
; BASED ON THE 'R0,R1,R2' BYTES. THESE BYTES IN THE FCB ARE
; USED AS FOLLOWS:
;
;       FCB+35            FCB+34            FCB+33
;  |     'R-2'      |      'R-1'      |      'R-0'     |
;  |7             0 | 7             0 | 7             0|
;  |0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0|
;  |    OVERFLOW   | | EXTRA |  EXTENT   |   RECORD #  |
;  | ______________| |_EXTENT|__NUMBER___|_____________|
;                     ALSO 'S2'
;
;   ON ENTRY, REGISTER (C) CONTAINS 0FFH IF THIS IS A READ
; AND THUS WE CAN NOT ACCESS UNWRITTEN DISK SPACE. OTHERWISE,
; ANOTHER EXTENT WILL BE OPENED (FOR WRITING) IF REQUIRED.
;
POSITION:
	XOR	A		; SET RANDOM I/O FLAG.
	LD	(MODE),A
;
;   SPECIAL ENTRY (FUNCTION #40). M/PM ?
;
POSITN1:PUSH	BC		; SAVE READ/WRITE FLAG.
	LD	HL,(PARAMS)	; GET ADDRESS OF FCB.
	EX	DE,HL
	LD	HL,33		; NOW GET BYTE 'R0'.
	ADD	HL,DE
	LD	A,(HL)
	AND	7FH		; KEEP BITS 0-6 FOR THE RECORD NUMBER TO ACCESS.
	PUSH	AF
	LD	A,(HL)		; NOW GET BIT 7 OF 'R0' AND BITS 0-3 OF 'R1'.
	RLA
	INC	HL
	LD	A,(HL)
	RLA
	AND	1FH		; AND SAVE THIS IN BITS 0-4 OF (C).
	LD	C,A		; THIS IS THE EXTENT BYTE.
	LD	A,(HL)		; NOW GET THE EXTRA EXTENT BYTE.
	RRA
	RRA
	RRA
	RRA
	AND	0FH
	LD	B,A		; AND SAVE IT IN (B).
	POP	AF		; GET RECORD NUMBER BACK TO (A).
	INC	HL		; CHECK OVERFLOW BYTE 'R2'.
	LD	L,(HL)
	INC	L
	DEC	L
	LD	L,6		; PREPARE FOR ERROR.
	JP	NZ,POSITN5	; OUT OF DISK SPACE ERROR.
	LD	HL,32		; STORE RECORD NUMBER INTO FCB.
	ADD	HL,DE
	LD	(HL),A
	LD	HL,12		; AND NOW CHECK THE EXTENT BYTE.
	ADD	HL,DE
	LD	A,C
	SUB	(HL)		; SAME EXTENT AS BEFORE?
	JP	NZ,POSITN2
	LD	HL,14		; YES, CHECK EXTRA EXTENT BYTE 'S2' ALSO.
	ADD	HL,DE
	LD	A,B
	SUB	(HL)
	AND	7FH
	JP	Z,POSITN3	; SAME, WE ARE ALMOST DONE THEN.
;
;  GET HERE WHEN ANOTHER EXTENT IS REQUIRED.
;
POSITN2:PUSH	BC
	PUSH	DE
	CALL	CLOSEIT		; CLOSE CURRENT EXTENT.
	POP	DE
	POP	BC
	LD	L,3		; PREPARE FOR ERROR.
	LD	A,(STATUS)
	INC	A
	JP	Z,POSITN4	; CLOSE ERROR.
	LD	HL,12		; PUT DESIRED EXTENT INTO FCB NOW.
	ADD	HL,DE
	LD	(HL),C
	LD	HL,14		; AND STORE EXTRA EXTENT BYTE 'S2'.
	ADD	HL,DE
	LD	(HL),B
	CALL	OPENIT		; TRY AND GET THIS EXTENT.
	LD	A,(STATUS)	; WAS IT THERE?
	INC	A
	JP	NZ,POSITN3
	POP	BC		; NO. CAN WE CREATE A NEW ONE (WRITING?).
	PUSH	BC
	LD	L,4		; PREPARE FOR ERROR.
	INC	C
	JP	Z,POSITN4	; NOPE, READING UNWRITTEN SPACE ERROR.
	CALL	GETEMPTY	; YES WE CAN, TRY TO FIND SPACE.
	LD	L,5		; PREPARE FOR ERROR.
	LD	A,(STATUS)
	INC	A
	JP	Z,POSITN4	; OUT OF SPACE?
;
;   NORMAL RETURN LOCATION. CLEAR ERROR CODE AND RETURN.
;
POSITN3:POP	BC		; RESTORE STACK.
	XOR	A		; AND CLEAR ERROR CODE BYTE.
	JP	SETSTAT
;
;   ERROR. SET THE 'S2' BYTE TO INDICATE THIS (WHY?).
;
POSITN4:PUSH	HL
	CALL	GETS2
	LD	(HL),0C0H
	POP	HL
;
;   RETURN WITH ERROR CODE (PRESENTLY IN L).
;
POSITN5:POP	BC
	LD	A,L		; GET ERROR CODE.
	LD	(STATUS),A
	JP	SETS2B7
;
;   READ A RANDOM RECORD.
;
READRAN:LD	C,0FFH		; SET 'READ' STATUS.
	CALL	POSITION	; POSITION THE FILE TO PROPER RECORD.
	CALL	Z,RDSEQ1	; AND READ IT AS USUAL (IF NO ERRORS).
	RET
;
;   WRITE TO A RANDOM RECORD.
;
WRITERAN:
	LD	C,0		; SET 'WRITING' FLAG.
	CALL	POSITION	; POSITION THE FILE TO PROPER RECORD.
	CALL	Z,WTSEQ1	; AND WRITE AS USUAL (IF NO ERRORS).
	RET
;
;   COMPUTE THE RANDOM RECORD NUMBER. ENTER WITH (HL) POINTING
; TO A FCB AN (DE) CONTAINS A RELATIVE LOCATION OF A RECORD
; NUMBER. ON EXIT, (C) CONTAINS THE 'R0' BYTE, (B) THE 'R1'
; BYTE, AND (A) THE 'R2' BYTE.
;
;   ON RETURN, THE ZERO FLAG IS SET IF THE RECORD IS WITHIN
; BOUNDS. OTHERWISE, AN OVERFLOW OCCURED.
;
COMPRAND:
	EX	DE,HL		; SAVE FCB POINTER IN (DE).
	ADD	HL,DE		; COMPUTE RELATIVE POSITION OF RECORD #.
	LD	C,(HL)		; GET RECORD NUMBER INTO (BC).
	LD	B,0
	LD	HL,12		; NOW GET EXTENT.
	ADD	HL,DE
	LD	A,(HL)		; COMPUTE (BC)=(RECORD #)+(EXTENT)*128.
	RRCA			; MOVE LOWER BIT INTO BIT 7.
	AND	80H		; AND IGNORE ALL OTHER BITS.
	ADD	A,C		; ADD TO OUR RECORD NUMBER.
	LD	C,A
	LD	A,0		; TAKE CARE OF ANY CARRY.
	ADC	A,B
	LD	B,A
	LD	A,(HL)		; NOW GET THE UPPER BITS OF EXTENT INTO
	RRCA			; BIT POSITIONS 0-3.
	AND	0FH		; AND IGNORE ALL OTHERS.
	ADD	A,B		; ADD THIS IN TO 'R1' BYTE.
	LD	B,A
	LD	HL,14		; GET THE 'S2' BYTE (EXTRA EXTENT).
	ADD	HL,DE
	LD	A,(HL)
	ADD	A,A		; AND SHIFT IT LEFT 4 BITS (BITS 4-7).
	ADD	A,A
	ADD	A,A
	ADD	A,A
	PUSH	AF		; SAVE CARRY FLAG (BIT 0 OF FLAG BYTE).
	ADD	A,B		; NOW ADD EXTRA EXTENT INTO 'R1'.
	LD	B,A
	PUSH	AF		; AND SAVE CARRY (OVERFLOW BYTE 'R2').
	POP	HL		; BIT 0 OF (L) IS THE OVERFLOW INDICATOR.
	LD	A,L
	POP	HL		; AND SAME FOR FIRST CARRY FLAG.
	OR	L		; EITHER ONE OF THESE SET?
	AND	01H		; ONLY CHECK THE CARRY FLAGS.
	RET
;
;   ROUTINE TO SETUP THE FCB (BYTES 'R0', 'R1', 'R2') TO
; REFLECT THE LAST RECORD USED FOR A RANDOM (OR OTHER) FILE.
; THIS READS THE DIRECTORY AND LOOKS AT ALL EXTENTS COMPUTING
; THE LARGERST RECORD NUMBER FOR EACH AND KEEPING THE MAXIMUM
; VALUE ONLY. THEN 'R0', 'R1', AND 'R2' WILL REFLECT THIS
; MAXIMUM RECORD NUMBER. THIS IS USED TO COMPUTE THE SPACE USED
; BY A RANDOM FILE.
;
RANSIZE:LD	C,12		; LOOK THRU DIRECTORY FOR FIRST ENTRY WITH
	CALL	FINDFST		; THIS NAME.
	LD	HL,(PARAMS)	; ZERO OUT THE 'R0, R1, R2' BYTES.
	LD	DE,33
	ADD	HL,DE
	PUSH	HL
	LD	(HL),D		; NOTE THAT (D)=0.
	INC	HL
	LD	(HL),D
	INC	HL
	LD	(HL),D
RANSIZ1:CALL	CKFILPOS	; IS THERE AN EXTENT TO PROCESS?
	JP	Z,RANSIZ3	; NO, WE ARE DONE.
	CALL	FCB2HL		; SET (HL) POINTING TO PROPER FCB IN DIR.
	LD	DE,15		; POINT TO LAST RECORD IN EXTENT.
	CALL	COMPRAND	; AND COMPUTE RANDOM PARAMETERS.
	POP	HL
	PUSH	HL		; NOW CHECK THESE VALUES AGAINST THOSE
	LD	E,A		; ALREADY IN FCB.
	LD	A,C		; THE CARRY FLAG WILL BE SET IF THOSE
	SUB	(HL)		; IN THE FCB REPRESENT A LARGER SIZE THAN
	INC	HL		; THIS EXTENT DOES.
	LD	A,B
	SBC	A,(HL)
	INC	HL
	LD	A,E
	SBC	A,(HL)
	JP	C,RANSIZ2
	LD	(HL),E		; WE FOUND A LARGER (IN SIZE) EXTENT.
	DEC	HL		; STUFF THESE VALUES INTO FCB.
	LD	(HL),B
	DEC	HL
	LD	(HL),C
RANSIZ2:CALL	FINDNXT		; NOW GET THE NEXT EXTENT.
	JP	RANSIZ1		; CONTINUE TIL ALL DONE.
RANSIZ3:POP	HL		; WE ARE DONE, RESTORE THE STACK AND
	RET			; RETURN.
;
;   FUNCTION TO RETURN THE RANDOM RECORD POSITION OF A GIVEN
; FILE WHICH HAS BEEN READ IN S.EQUENTIAL MODE UP TO NOW.
;
SETRAN:	LD	HL,(PARAMS)	; POINT TO FCB.
	LD	DE,32		; AND TO LAST USED RECORD.
	CALL	COMPRAND	; COMPUTE RANDOM POSITION.
	LD	HL,33		; NOW STUFF THESE VALUES INTO FCB.
	ADD	HL,DE
	LD	(HL),C		; MOVE 'R0'.
	INC	HL
	LD	(HL),B		; AND 'R1'.
	INC	HL
	LD	(HL),A		; AND LASTLY 'R2'.
	RET
;
;   THIS ROUTINE SELECT THE DRIVE SPECIFIED IN (ACTIVE) AND
; UPDATE THE LOGIN VECTOR AND BITMAP TABLE IF THIS DRIVE WAS
; NOT ALREADY ACTIVE.
;
LOGINDRV:
	LD	HL,(LOGIN)	; GET THE LOGIN VECTOR.
	LD	A,(ACTIVE)	; GET THE DEFAULT DRIVE.
	LD	C,A
	CALL	SHIFTR		; POSITION ACTIVE BIT FOR THIS DRIVE
	PUSH	HL		; INTO BIT 0.
	EX	DE,HL
	CALL	SELECT		; SELECT THIS DRIVE.
	POP	HL
	CALL	Z,SLCTERR	; VALID DRIVE?
	LD	A,L		; IS THIS A NEWLY ACTIVATED DRIVE?
	RRA
	RET	C
	LD	HL,(LOGIN)	; YES, UPDATE THE LOGIN VECTOR.
	LD	C,L
	LD	B,H
	CALL	SETBIT
	LD	(LOGIN),HL	; AND SAVE.
	JP	BITMAP		; NOW UPDATE THE BITMAP.
;
;   FUNCTION TO SET THE ACTIVE DISK NUMBER.
;
SETDSK:	LD	A,(EPARAM)	; GET PARAMETER PASSED AND SEE IF THIS
	LD	HL,ACTIVE	; REPRESENTS A CHANGE IN DRIVES.
	CP	(HL)
	RET	Z
	LD	(HL),A		; YES IT DOES, LOG IT IN.
	JP	LOGINDRV
;
;   THIS IS THE 'AUTO DISK SELECT' ROUTINE. THE FIRSST BYTE
; OF THE FCB IS EXAMINED FOR A DRIVE SPECIFICATION. IF NON
; ZERO THEN THE DRIVE WILL BE SELECTED AND LOGED IN.
;
AUTOSEL:LD	A,0FFH		; SAY 'AUTO-SELECT ACTIVATED'.
	LD	(AUTO),A
	LD	HL,(PARAMS)	; GET DRIVE SPECIFIED.
	LD	A,(HL)
	AND	1FH		; LOOK AT LOWER 5 BITS.
	DEC	A		; ADJUST FOR (1=A, 2=B) ETC.
	LD	(EPARAM),A	; AND SAVE FOR THE SELECT ROUTINE.
	CP	1EH		; CHECK FOR 'NO CHANGE' CONDITION.
	JP	NC,AUTOSL1	; YES, DON'T CHANGE.
	LD	A,(ACTIVE)	; WE MUST CHANGE, SAVE CURRENTLY ACTIVE
	LD	(OLDDRV),A	; DRIVE.
	LD	A,(HL)		; AND SAVE FIRST BYTE OF FCB ALSO.
	LD	(AUTOFLAG),A	; THIS MUST BE NON-ZERO.
	AND	0E0H		; WHATS THIS FOR (BITS 6,7 ARE USED FOR
	LD	(HL),A		; SOMETHING)?
	CALL	SETDSK		; SELECT AND LOG IN THIS DRIVE.
AUTOSL1:LD	A,(USERNO)	; MOVE USER NUMBER INTO FCB.
	LD	HL,(PARAMS)	; (* UPPER HALF OF FIRST BYTE *)
	OR	(HL)
	LD	(HL),A
	RET			; AND RETURN (ALL DONE).
;
;   FUNCTION TO RETURN THE CURRENT CP/M VERSION NUMBER.
;
GETVER:	LD	A,022H		; VERSION 2.2
	JP	SETSTAT
;
;   FUNCTION TO RESET THE DISK SYSTEM.
;
RSTDSK:	LD	HL,0		; CLEAR WRITE PROTECT STATUS AND LOG
	LD	(WRTPRT),HL	; IN VECTOR.
	LD	(LOGIN),HL
	XOR	A		; SELECT DRIVE 'A'.
	LD	(ACTIVE),A
	LD	HL,TBUFF	; SETUP DEFAULT DMA ADDRESS.
	LD	(USERDMA),HL
	CALL	DEFDMA
	JP	LOGINDRV	; NOW LOG IN DRIVE 'A'.
;
;   FUNCTION TO OPEN A SPECIFIED FILE.
;
OPENFIL:CALL	CLEARS2		; CLEAR 'S2' BYTE.
	CALL	AUTOSEL		; SELECT PROPER DISK.
	JP	OPENIT		; AND OPEN THE FILE.
;
;   FUNCTION TO CLOSE A SPECIFIED FILE.
;
CLOSEFIL:
	CALL	AUTOSEL		; SELECT PROPER DISK.
	JP	CLOSEIT		; AND CLOSE THE FILE.
;
;   FUNCTION TO RETURN THE FIRST OCCURENCE OF A SPECIFIED FILE
; NAME. IF THE FIRST BYTE OF THE FCB IS '?' THEN THE NAME WILL
; NOT BE CHECKED (GET THE FIRST ENTRY NO MATTER WHAT).
;
GETFST:	LD	C,0		; PREPARE FOR SPECIAL SEARCH.
	EX	DE,HL
	LD	A,(HL)		; IS FIRST BYTE A '?'?
	CP	'?'
	JP	Z,GETFST1	; YES, JUST GET VERY FIRST ENTRY (ZERO LENGTH MATCH).
	CALL	SETEXT		; GET THE EXTENSION BYTE FROM FCB.
	LD	A,(HL)		; IS IT '?'? IF YES, THEN WE WANT
	CP	'?'		; AN ENTRY WITH A SPECIFIC 'S2' BYTE.
	CALL	NZ,CLEARS2	; OTHERWISE, LOOK FOR A ZERO 'S2' BYTE.
	CALL	AUTOSEL		; SELECT PROPER DRIVE.
	LD	C,15		; COMPARE BYTES 0-14 IN FCB (12&13 EXCLUDED).
GETFST1:CALL	FINDFST		; FIND AN ENTRY AND THEN MOVE IT INTO
	JP	MOVEDIR		; THE USERS DMA SPACE.
;
;   FUNCTION TO RETURN THE NEXT OCCURENCE OF A FILE NAME.
;
GETNXT:	LD	HL,(SAVEFCB)	; RESTORE POINTERS. NOTE THAT NO
	LD	(PARAMS),HL	; OTHER .DBOS CALLS ARE ALLOWED.
	CALL	AUTOSEL		; NO ERROR WILL BE RETURNED, BUT THE
	CALL	FINDNXT		; RESULTS WILL BE WRONG.
	JP	MOVEDIR
;
;   FUNCTION TO DELETE A FILE BY NAME.
;
DELFILE:CALL	AUTOSEL		; SELECT PROPER DRIVE.
	CALL	ERAFILE		; ERASE THE FILE.
	JP	STSTATUS	; SET STATUS AND RETURN.
;
;   FUNCTION TO EXECUTE A S.EQUENTIAL READ OF THE SPECIFIED
; RECORD NUMBER.
;
READSEQ:CALL	AUTOSEL		; SELECT PROPER DRIVE THEN READ.
	JP	RDSEQ
;
;   FUNCTION TO WRITE THE NET S.EQUENTIAL RECORD.
;
WRTSEQ:	CALL	AUTOSEL		; SELECT PROPER DRIVE THEN WRITE.
	JP	WTSEQ
;
;   CREATE A FILE FUNCTION.
;
FCREATE:CALL	CLEARS2		; CLEAR THE 'S2' BYTE ON ALL CREATES.
	CALL	AUTOSEL		; SELECT PROPER DRIVE AND GET THE NEXT
	JP	GETEMPTY	; EMPTY DIRECTORY SPACE.
;
;   FUNCTION TO RENAME A FILE.
;
RENFILE:CALL	AUTOSEL		; SELECT PROPER DRIVE AND THEN SWITCH
	CALL	CHGNAMES	; FILE NAMES.
	JP	STSTATUS
;
;   FUNCTION TO RETURN THE LOGIN VECTOR.
;
GETLOG:	LD	HL,(LOGIN)
	JP	GETPRM1
;
;   FUNCTION TO RETURN THE CURRENT DISK ASSIGNMENT.
;
GETCRNT:LD	A,(ACTIVE)
	JP	SETSTAT
;
;   FUNCTION TO SET THE DMA ADDRESS.
;
PUTDMA:	EX	DE,HL
	LD	(USERDMA),HL	; SAVE IN OUR SPACE AND THEN GET TO
	JP	DEFDMA		; THE BIOS WITH THIS ALSO.
;
;   FUNCTION TO RETURN THE ALLOCATION VECTOR.
;
GETALOC:LD	HL,(ALOCVECT)
	JP	GETPRM1
;
;   FUNCTION TO RETURN THE READ-ONLY STATUS VECTOR.
;
GETROV:	LD	HL,(WRTPRT)
	JP	GETPRM1
;
;   FUNCTION TO SET THE FILE ATTRIBUTES (READ-ONLY, SYSTEM).
;
SETATTR:CALL	AUTOSEL		; SELECT PROPER DRIVE THEN SAVE ATTRIBUTES.
	CALL	SAVEATTR
	JP	STSTATUS
;
;   FUNCTION TO RETURN THE ADDRESS OF THE DISK PARAMETER BLOCK
; FOR THE CURRENT DRIVE.
;
GETPARM:LD	HL,(DISKPB)
GETPRM1:LD	(STATUS),HL
	RET
;
;   FUNCTION TO GET OR SET THE USER NUMBER. IF (E) WAS (FF)
; THEN THIS IS A REQUEST TO RETURN THE CURRENT USER NUMBER.
; ELSE SET THE USER NUMBER FROM (E).
;
GETUSER:LD	A,(EPARAM)	; GET PARAMETER.
	CP	0FFH		; GET USER NUMBER?
	JP	NZ,SETUSER
	LD	A,(USERNO)	; YES, JUST DO IT.
	JP	SETSTAT
SETUSER:AND	1FH		; NO, WE SHOULD SET IT INSTEAD. KEEP LOW
	LD	(USERNO),A	; BITS (0-4) ONLY.
	RET
;
;   FUNCTION TO READ A RANDOM RECORD FROM A FILE.
;
RDRANDOM:
	CALL	AUTOSEL		; SELECT PROPER DRIVE AND READ.
	JP	READRAN
;
;   FUNCTION TO COMPUTE THE FILE SIZE FOR RANDOM FILES.
;
WTRANDOM:
	CALL	AUTOSEL		; SELECT PROPER DRIVE AND WRITE.
	JP	WRITERAN
;
;   FUNCTION TO COMPUTE THE SIZE OF A RANDOM FILE.
;
FILESIZE:
	CALL	AUTOSEL		; SELECT PROPER DRIVE AND CHECK FILE LENGTH
	JP	RANSIZE
;
;   FUNCTION #37. THIS ALLOWS A PROGRAM TO LOG OFF ANY DRIVES.
; ON ENTRY, SET (DE) TO CONTAIN A WORD WITH BITS SET FOR THOSE
; DRIVES THAT ARE TO BE LOGGED OFF. THE LOG-IN VECTOR AND THE
; WRITE PROTECT VECTOR WILL BE UPDATED. THIS MUST BE A M/PM
; SPECIAL FUNCTION.
;
LOGOFF:	LD	HL,(PARAMS)	; GET DRIVES TO LOG OFF.
	LD	A,L		; FOR EACH BIT THAT IS SET, WE WANT
	CPL			; TO CLEAR THAT BIT IN (LOGIN)
	LD	E,A		; AND (WRTPRT).
	LD	A,H
	CPL
	LD	HL,(LOGIN)	; RESET THE LOGIN VECTOR.
	AND	H
	LD	D,A
	LD	A,L
	AND	E
	LD	E,A
	LD	HL,(WRTPRT)
	EX	DE,HL
	LD	(LOGIN),HL	; AND SAVE.
	LD	A,L		; NOW DO THE WRITE PROTECT VECTOR.
	AND	E
	LD	L,A
	LD	A,H
	AND	D
	LD	H,A
	LD	(WRTPRT),HL	; AND SAVE. ALL DONE.
	RET
;
;   GET HERE TO RETURN TO THE USER.
;
GOBACK:	LD	A,(AUTO)	; WAS AUTO SELECT ACTIVATED?
	OR	A
	JP	Z,GOBACK1
	LD	HL,(PARAMS)	; YES, BUT WAS A CHANGE MADE?
	LD	(HL),0		; (* RESET FIRST BYTE OF FCB *)
	LD	A,(AUTOFLAG)
	OR	A
	JP	Z,GOBACK1
	LD	(HL),A		; YES, RESET FIRST BYTE PROPERLY.
	LD	A,(OLDDRV)	; AND GET THE OLD DRIVE AND SELECT IT.
	LD	(EPARAM),A
	CALL	SETDSK
GOBACK1:LD	HL,(USRSTACK)	; RESET THE USERS STACK POINTER.
	LD	SP,HL
	LD	HL,(STATUS)	; GET RETURN STATUS.
	LD	A,L		; FORCE VERSION 1.4 COMPATABILITY.
	LD	B,H
	RET			; AND GO BACK TO USER.
;
;   FUNCTION #40. THIS IS A SPECIAL ENTRY TO DO RANDOM I/O.
; FOR THE CASE WHERE WE ARE WRITING TO UNUSED DISK SPACE, THIS
; SPACE WILL BE ZEROED OUT FIRST. THIS MUST BE A M/PM SPECIAL
; PURPOSE FUNCTION, BECAUSE WHY WOULD ANY NORMAL PROGRAM EVEN
; CARE ABOUT THE PREVIOUS CONTENTS OF A SECTOR ABOUT TO BE
; WRITTEN OVER.
;
WTSPECL:CALL	AUTOSEL		; SELECT PROPER DRIVE.
	LD	A,2		; USE SPECIAL WRITE MODE.
	LD	(MODE),A
	LD	C,0		; SET WRITE INDICATOR.
	CALL	POSITN1		; POSITION THE FILE.
	CALL	Z,WTSEQ1	; AND WRITE (IF NO ERRORS).
	RET
;
;**************************************************************
;*
;*     BDOS DATA STORAGE POOL.
;*
;**************************************************************
;
EMPTYFCB:
	.DB 0E5H		; EMPTY DIRECTORY SEGMENT INDICATOR.
WRTPRT:	.DW 0			; WRITE PROTECT STATUS FOR ALL 16 DRIVES.
LOGIN:	.DW 0			; DRIVE ACTIVE WORD (1 BIT PER DRIVE).
USERDMA:.DW 080H		; USER'S DMA ADDRESS (DEFAULTS TO 80H).
;
;   SCRATCH AREAS FROM PARAMETER BLOCK.
;
SCRATCH1:
	.DW 0			; RELATIVE POSITION WITHIN DIR SEGMENT FOR FILE (0-3).
SCRATCH2:
	.DW 0			; LAST SELECTED TRACK NUMBER.
SCRATCH3:
	.DW 0			; LAST SELECTED SECTOR NUMBER.
;
;   DISK STORAGE AREAS FROM PARAMETER BLOCK.
;
DIRBUF:	.DW 0			; ADDRESS OF DIRECTORY BUFFER TO USE.
DISKPB:	.DW 0			; CONTAINS ADDRESS OF DISK PARAMETER BLOCK.
CHKVECT:.DW 0			; ADDRESS OF CHECK VECTOR.
ALOCVECT:
	.DW 0			; ADDRESS OF ALLOCATION VECTOR (BIT MAP).
;
;   PARAMETER BLOCK RETURNED FROM THE BIOS.
;
SECTORS:.DW 0			; SECTORS PER TRACK FROM BIOS.
BLKSHFT:.DB 0			; BLOCK SHIFT.
BLKMASK:.DB 0			; BLOCK MASK.
EXTMASK:.DB 0			; EXTENT MASK.
DSKSIZE:.DW 0			; DISK SIZE FROM BIOS (NUMBER OF BLOCKS-1).
DIRSIZE:.DW 0			; DIRECTORY SIZE.
ALLOC0:	.DW 0			; STORAGE FOR FIRST BYTES OF BIT MAP (DIR SPACE USED).
ALLOC1:	.DW 0
OFFSET:	.DW 0			; FIRST USABLE TRACK NUMBER.
XLATE:	.DW 0			; SECTOR TRANSLATION TABLE ADDRESS.
;
;
CLOSEFLG:
	.DB 0			; CLOSE FLAG (=0FFH IS EXTENT WRITTEN OK).
R.DWRTFLG:
	.DB 0			; READ/WRITE FLAG (0FFH=READ, 0=WRITE).
FNDSTAT:.DB 0			; FILENAME FOUND STATUS (0=FOUND FIRST ENTRY).
MODE:	.DB 0			; I/O MODE SELECT (0=RANDOM, 1=S.EQUENTIAL, 2=SPECIAL RANDOM).
EPARAM:	.DB 0			; STORAGE FOR REGISTER (E) ON ENTRY TO BDOS.
RELBLOCK:
	.DB 0			; RELATIVE POSITION WITHIN FCB OF BLOCK NUMBER WRITTEN.
COUNTER:.DB 0			; BYTE COUNTER FOR DIRECTORY NAME SEARCHES.
SAVEFCB:.DW 0,0			; SAVE SPACE FOR ADDRESS OF FCB (FOR DIRECTORY SEARCHES).
BIGDISK:.DB 0			; IF =0 THEN DISK IS > 256 BLOCKS LONG.
AUTO:	.DB 0			; IF NON-ZERO, THEN AUTO SELECT ACTIVATED.
OLDDRV:	.DB 0			; ON AUTO SELECT, STORAGE FOR PREVIOUS DRIVE.
AUTOFLAG:
	.DB 0			; IF NON-ZERO, THEN AUTO SELECT CHANGED DRIVES.
SAVNXT:	.DB 0			; STORAGE FOR NEXT RECORD NUMBER TO ACCESS.
SAVEXT:	.DB 0			; STORAGE FOR EXTENT NUMBER OF FILE.
SAVNREC:.DW 0			; STORAGE FOR NUMBER OF RECORDS IN FILE.
BLKNMBR:.DW 0			; BLOCK NUMBER (PHYSICAL SECTOR) USED WITHIN A FILE OR LOGICAL SEC
LOGSECT:.DW 0			; STARTING LOGICAL (128 BYTE) SECTOR OF BLOCK (PHYSICAL SECTOR).
FCBPOS:	.DB 0			; RELATIVE POSITION WITHIN BUFFER FOR FCB OF FILE OF INTEREST.
FILEPOS:.DW 0			; FILES POSITION WITHIN DIRECTORY (0 TO MAX ENTRIES -1).
;
;   DISK DIRECTORY BUFFER CHECKSUM BYTES. ONE FOR EACH OF THE
; 16 POSSIBLE DRIVES.
;
CKSUMTBL:
	.DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;
;**************************************************************
;*
;*        B I O S   J U M P   T A B L E
;*
;**************************************************************
;
BIOS:	.EQU	BIOSO		;BIOS ORIGIN
;
BOOT:	.EQU	BIOS		;(BOOT) Cold boot entry
WBOOT:	.EQU	BIOS+3		;Warm boot entry
CONST:	.EQU	BIOS+6		;Console status
CONIN:	.EQU	BIOS+9		;Console char in
CONOUT:	.EQU	BIOS+12		;Console char out
LIST:	.EQU	BIOS+15		;List char out
PUNCH:	.EQU	BIOS+18		;Punch char out
READER:	.EQU	BIOS+21		;Reader char in
HOME:	.EQU	BIOS+24		;Home disk
SELDSK:	.EQU	BIOS+27		;Select disk
SETTRK:	.EQU	BIOS+30		;Set disk track addr
SETSEC:	.EQU	BIOS+33		;Set disk sector addr
SETDMA:	.EQU	BIOS+36		;Set DMA buffer addr
READ:	.EQU	BIOS+39		;Read sector
WRITE:	.EQU	BIOS+42		;Write sector
SECTRN:	.EQU	BIOS+48		;Sector translation routine
;
	.IF	ENDFIL
	.FILL	((BDOSO + 0E00H) - $),055H
	.ENDIF

	.END
