mirror of https://github.com/wwarthen/RomWBW.git
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
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
|
|
|