You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2586 lines
71 KiB

.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