.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