00010 00020 ; 86-DOS High-performance operating system for the 8086 version 1.00 04/28/81 00030 ; by Tim Paterson 00040 00050 ; ****************** Revision History ************************* 00060 ; >> EVERY change must noted below!! << 00070 ; 00080 ; 0.34 12/29/80 General release, updating all past customers 00090 ; 0.42 02/25/81 32-byte directory entries added 00100 ; 0.56 03/23/81 Variable record and sector sizes 00110 ; 0.60 03/27/81 Ctrl-C exit changes, including register save on user stack 00120 ; 0.74 04/15/81 Recognize I/O devices with file names 00130 ; 0.75 04/17/81 Improve and correct buffer handling 00140 ; 0.76 04/23/81 Correct directory size when not 2^N entries 00150 ; 0.80 04/27/81 Add console input without echo, Functions 7 & 8 00160 ; 1.00 04/28/81 Renumber for general release 00170 ; 00180 ; ************************************************************* 00190 00200 ; Use the switch below to generate code to accept the old 16-byte 00210 ; directory entry as well as the new 32-byte entry. 00220 00230 SMALLDIR: EQU 1 ;1 to enable, 0 to disable 00240 00250 00260 ; Turn on switch below to allow testing disk code with DEBUG. It sets 00270 ; up a different stack for disk I/O (functions > 11) than that used for 00280 ; character I/O which effectively makes the DOS re-entrant. 00290 00300 DSKTEST: EQU 0 ;1 to enable, 0 to disable 00310 00320 00330 ; Interrupt Entry Points: 00340 00350 ; INTBASE: ABORT 00360 ; INTBASE+4: COMMAND 00370 ; INTBASE+8: BASE EXIT ADDRESS 00380 ; INTBASE+C: CONTROL-C ABORT 00390 ; INTBASE+10H: FATAL ERROR ABORT 00400 ; INTBASE+14H: BIOS DISK READ 00410 ; INTBASE+18H: BIOS DISK WRITE 00420 ; INTBASE+40H: Long jump to CALL entry point 00430 00440 00450 MAXCALL:EQU 36 00460 MAXCOM: EQU 41 00470 ESCCH: EQU 1BH 00480 INTBASE:EQU 80H 00490 INTTAB: EQU 20H 00500 ENTRYPOINTSEG: EQU 0CH 00510 ENTRYPOINT: EQU INTBASE+40H 00520 CONTC: EQU INTTAB+3 00530 EXIT: EQU INTBASE+8 00540 LONGJUMP:EQU 0EAH 00550 LONGCALL:EQU 9AH 00560 MAXDIF: EQU 0FFFH 00570 SAVEXIT:EQU 10 00580 00590 ; Field definition for FCBs 00600 00610 ORG 0 00620 DS 12 ;Drive code and name 00630 EXTENT: DS 2 00640 RECSIZ: DS 2 ;Size of record (user settable) 00650 FILSIZ: DS 4 ;Size of file in bytes 00660 FDATE: DS 2 ;Date of last writing 00670 FILDIRBLK:DS 2 ;Location in directory 00680 FIRCLUS:DS 2 ;First cluster of file 00690 LSTCLUS:DS 2 ;Last cluster accessed 00700 CLUSPOS:DS 2 ;Position of last cluster accessed 00710 DIRTYFIL:DS 1 ;File has been written to if <>0 00720 ORG 32 00730 NR: DS 1 ;Next record 00740 RR: DS 3 ;Random record 00750 00760 00770 ; Description of 32-byte directory entry (same as returned by SEARCH FIRST 00780 ; and SEARCH NEXT, functions 17 and 18). 00790 ; 00800 ; Location bytes Description 00810 ; 00820 ; 0 11 File name and extension ( 0E5H if empty) 00830 ; 11 13 Zero field (for expansion) 00840 ; 24 2 Date. Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980 00850 ; 26 2 First allocation unit ( < 4080 ) 00860 ; 28 4 File size, in bytes (LSB first, 30 bits max.) 00870 ; 00880 ; The File Allocation Table uses a 12-bit entry for each allocation unit on 00890 ; the disk. These entries are packed, two for every three bytes. The contents 00900 ; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result 00910 ; to the base address of the Allocation Table; 3) fetching the 16-bit word at 00920 ; this address; 4) If N was odd (so that N*1.5 was not an integer), shift the 00930 ; word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry number 00940 ; zero is used as an end-of-file trap in the OS and as a flag for directory 00950 ; entry size (if SMALLDIR selected). Entry 1 is reserved for future use. The 00960 ; first available allocation unit is assigned entry number two, and for Drive Parameter Block 00970 00980 ORG 0 00990 DRVNUM: DS 1 ;Drive number 01000 SECSIZ: DS 2 ;Size of physical sector in bytes 01010 CLUSMSK:DS 1 ;Sectors/cluster - 1 01020 CLUSSHFT:DS 1 ;Log2 of sectors/cluster 01030 FIRFAT: DS 2 ;Starting record of FATs 01040 FATCNT: DS 1 ;Number of FATs for this drive 01050 MAXENT: DS 2 ;Number of directory entries 01060 DIRSEC: ;Number of dir. sectors (init temporary) 01070 FIRREC: DS 2 ;First sector of first cluster 01080 DSKSIZ: ;Size of disk (temp used during init only) 01090 MAXCLUS:DS 2 ;Number of clusters on drive + 1 01100 FATSIZ: DS 1 ;Number of records occupied by FAT 01110 FIRDIR: DS 2 ;Starting record of directory 01120 01130 IF SMALLDIR 01140 FIRREC1:DS 2 ;First data sector with 16-byte dir. entries 01150 MAXCLUS1:DS 2 ;No. of clusters + 1 with 16-byte dir. entries 01160 FIRREC2:DS 2 ;First data sector with 32-byte dir. entries 01170 MAXCLUS2:DS 2 ;No. of clusters + 1 with 32-byte dir entries 01180 ENDIF 01190 01200 DIRTYFAT:DS 1 ;1=FAT has been changed, -1=never been read 01210 FAT: ;Start of FAT 01220 DIRSIZ: ;-1=small dir. entry, else large 01230 01240 01250 ; BIOS entry point defintions 01260 01270 BIOSSEG: EQU 40H 01280 ORG 0 01290 DS 3 01300 BIOSSTAT: DS 3 01310 BIOSIN: DS 3 01320 BIOSOUT: DS 3 01330 BIOSPRINT: DS 3 01340 BIOSAUXIN: DS 3 01350 BIOSAUXOUT: DS 3 01360 BIOSREAD: DS 3 01370 BIOSWRITE: DS 3 01380 BIOSDSKCHG: DS 3 01390 01400 01410 ; Location of user registers relative user stack pointer 01420 01430 ORG 0 01440 AXSAVE: DS 2 01450 BXSAVE: DS 2 01460 CXSAVE: DS 2 01470 DXSAVE: DS 2 01480 SISAVE: DS 2 01490 DISAVE: DS 2 01500 BPSAVE: DS 2 01510 DSSAVE: DS 2 01520 ESSAVE: DS 2 01530 IPSAVE: DS 2 01540 CSSAVE: DS 2 01550 FSAVE: DS 2 01560 01570 01580 ; Start of code 01590 01600 ORG 0 01610 PUT 100H 01620 01630 JMP DOSINIT 01640 01650 ESCTAB: 01660 DB "SC" ;Copy one char 01670 DB "VN" ;Skip one char 01680 DB "TA" ;Copy to char 01690 DB "WB" ;Skip to char 01700 DB "UH" ;Copy line 01710 DB "HH" ;Kill line (no change in template) 01720 DB "RM" ;Reedit line (new template) 01730 DB "DD" ;Backspace 01740 DB "P@" ;Enter insert mode 01750 DB "QL" ;Exit insert mode 01760 DB ESCCH,ESCCH ;Escape character 01770 DB ESCCH,ESCCH ;End of table 01780 01790 ESCTABLEN:EQU $-ESCTAB 01800 01810 HEADER: DB 13,10,"86-DOS version 1.00" 01820 01830 IF DSKTEST 01840 DB "D" 01850 ENDIF 01860 01870 DB 13,10 01880 DB "Copyright 1980,81 Seattle Computer Products, Inc.",13,10,"$" 01890 01900 QUIT: 01910 MOV AH,0 01920 JP SAVREGS 01930 01940 COMMAND: ;Interrupt call entry point 01950 CMP AH,MAXCOM 01960 JBE SAVREGS 01970 BADCALL: 01980 MOV AL,0 01990 IRET: IRET 02000 02010 ENTRY: ;System call entry point and dispatcher 02020 POP AX ;IP from the long call at 5 02030 POP AX ;Segment from the long call at 5 02040 SEG CS 02050 POP [TEMP] ;IP from the CALL 5 02060 PUSHF ;Start re-ordering the stack 02070 DI 02080 PUSH AX ;Save segment 02090 SEG CS 02100 PUSH [TEMP] ;Stack now ordered as if INT had been used 02110 CMP CL,MAXCALL ;This entry point doesn't get as many calls 02120 JA BADCALL 02130 MOV AH,CL 02140 SAVREGS: 02150 PUSH ES 02160 PUSH DS 02170 PUSH BP 02180 PUSH DI 02190 PUSH SI 02200 PUSH DX 02210 PUSH CX 02220 PUSH BX 02230 PUSH AX 02240 02250 IF DSKTEST 02260 SEG CS 02270 MOV AX,[SPSAVE] 02280 SEG CS 02290 MOV [NSP],AX 02300 SEG CS 02310 MOV AX,[SSSAVE] 02320 SEG CS 02330 MOV [NSS],AX 02340 POP AX 02350 PUSH AX 02360 ENDIF 02370 02380 SEG CS 02390 MOV [SPSAVE],SP 02400 SEG CS 02410 MOV [SSSAVE],SS 02420 MOV BP,SP 02430 MOV BX,[BP+CSSAVE] 02440 SEG CS 02450 MOV [CSLOC],BX 02460 MOV SP,CS 02470 MOV SS,SP 02480 MOV SP,STACK 02490 EI ;Stack OK now 02500 SEG CS 02510 MOV [FUNC],AH 02520 MOV BL,AH 02530 MOV BH,0 02540 SHL BX 02550 UP 02560 02570 IF DSKTEST 02580 CMP AH,12 02590 JL SAMSTK 02600 MOV SP,TESTSTK 02610 SAMSTK: 02620 ENDIF 02630 02640 SEG CS 02650 CALL [BX+DISPATCH] 02660 LEAVE: 02670 DI 02680 SEG CS 02690 MOV SP,[SPSAVE] 02700 SEG CS 02710 MOV SS,[SSSAVE] 02720 MOV BP,SP 02730 MOV [BP+AXSAVE],AL 02740 02750 IF DSKTEST 02760 SEG CS 02770 MOV AX,[NSP] 02780 SEG CS 02790 MOV [SPSA ENDIF 02800 02810 PBX 02820 POP CX 02830 POP DX 02840 POP SI 02850 POP DI 02860 POP BP 02870 POP DS 02880 POP ES 02890 IRET 02900 02910 DISPATCH: 02920 ; Standard Functions 02930 DW ABORT ;0 02940 DW CONIN 02950 DW CONOUT 02960 DW READER 02970 DW PUNCH 02980 DW LIST ;5 02990 DW RAWIO 03000 DW RAWINP 03010 DW IN 03020 DW PRTBUF 03030 DW BUFIN ;10 03040 DW CONSTAT 03050 DW VERSION 03060 DW DSKRESET 03070 DW SELDSK 03080 DW OPEN ;15 03090 DW CLOSE 03100 DW SRCHFRST 03110 DW SRCHNXT 03120 DW DELETE 03130 DW SEQRD ;20 03140 DW SEQWRT 03150 DW CREATE 03160 DW RENAME 03170 DW INUSE 03180 DW CURDRV ;25 03190 DW SETDMA 03200 DW GETFATPT 03210 DW WRTPROT 03220 DW GETRDONLY 03230 DW SETATTRIB ;30 03240 DW GETDSKPT 03250 DW USERCODE 03260 DW RNDRD 03270 DW RNDWRT 03280 DW FILESIZE ;35 03290 DW SETRNDREC 03300 ; Extended Functions 03310 DW SETVECT 03320 DW NEWBASE 03330 DW BLKRD 03340 DW BLKWRT ;40 03350 DW MAKEFCB 03360 03370 VERSION: 03380 GETIO: 03390 SETIO: 03400 WRTPROT: 03410 GETRDONLY: 03420 SETATTRIB: 03430 USERCODE: 03440 MOV AL,0 03450 RET 03460 03470 03480 READER: 03490 CALL BIOSAUXIN,BIOSSEG 03500 RET 03510 03520 PUNCH: 03530 MOV AL,DL 03540 CALL BIOSAUXOUT,BIOSSEG 03550 RET 03560 03570 03580 UNPACK: 03590 03600 ; Inputs: 03610 ; DS = CS 03620 ; BX = Cluster number 03630 ; BP = Base of drive parameters 03640 ; SI = Pointer to drive FAT 03650 ; Outputs: 03660 ; DI = Contents of FAT for given cluster 03670 ; Zero set means DI=0 (free cluster) 03680 ; No other registers affected. Fatal error if cluster too big. 03690 03700 CMP BX,[BP+MAXCLUS] 03710 JA HURTFAT 03720 LEA DI,[SI+BX] 03730 SHR BX 03740 MOV DI,[DI+BX] 03750 JNC HAVCLUS 03760 SHR DI 03770 SHR DI 03780 SHR DI 03790 SHR DI 03800 STC 03810 HAVCLUS: 03820 RCL BX 03830 AND DI,0FFFH 03840 RET 03850 HURTFAT: 03860 MOV SI,BADMES 03870 CALL OUTMES 03880 JMP ERROR 03890 03900 03910 PACK: 03920 03930 ; Inputs: 03940 ; DS = CS 03950 ; BX = Cluster number 03960 ; DX = Data 03970 ; SI = Pointer to drive FAT 03980 ; Outputs: 03990 ; The data is stored in the FAT at the given cluster. 04000 ; BX,DX,DI all destroyed 04010 ; No other registers affected 04020 04030 MOV DI,BX 04040 SHR BX 04050 ADD BX,SI 04060 ADD BX,DI 04070 SHR DI 04080 MOV DI,[BX] 04090 JNC ALIGNED 04100 SHL DX 04110 SHL DX 04120 SHL DX 04130 SHL DX 04140 AND DI,0FH 04150 JP PACKIN 04160 ALIGNED: 04170 AND DI,0F000H 04180 PACKIN: 04190 OR DI,DX 04200 MOV [BX],DI 04210 RET 04220 04230 IOCHK: 04240 MOV CX,5 ;Check rest of name but not extension 04250 CMP B,[DI],":" 04260 JNZ NOCOL 04270 INC DI ;Skip over colon 04280 DEC CX 04290 NOCOL: 04300 MOV AL," " 04310 REPE 04320 SCAB ;Make sure rest of name is blanks 04330 JNZ FILSRCH 04340 DEC BL 04350 RET 04360 04370 GETFILE: 04380 04390 ; Inputs: 04400 ; DS,DX point to FCB 04410 ; Function: 04420 ; Find file name in disk directory. First byte is 04430 ; drive number (0=current disk). "?" matches any 04440 ; character. 04450 ; Outputs: 04460 ; Carry set if file not found 04470 ; ELSE 04480 ; BP = Base of drive parameters 04490 ; DS = CS 04500 ; ES = CS 04510 ; BX = Pointer into directory buffer 04520 ; SI = Pointer to First Cluster field in directory entry 04530 ; [DIRBUF] has directory record with match 04540 ; [NAME1] has file name 04550 ; All other registers destroyed. 04560 04570 CALL MOVNAME 04580 JC RET ;Bad file name? 04590 FINDNAME: 04600 MOV AX,CS 04610 MOV DS,AX 04620 MOV SI,IONAME ;List of I/O devices with file names 04630 MOV BX,0FF04H ;BL = number of devices 04640 LOOKIO: 04650 MOV DI,NAME1 04660 MOV CX,3 ;All device names are 3 letters 04670 REPE 04680 CMPB ;Check for name in list 04690 JZ IOCHK ;If first 3 letters OK, check the rest 04700 ADD SI,CX ;Point to next device name 04710 DEC BL 04720 JNZ LOOKIO 04730 FILSRCH: ;Not a device name 04740 CALL STARTSRCH 04750 CONTSRCH: 04760 CALL GETENTRY 04770 JC RET 04780 SRCH: 04790 CMP B,[BX],0E5H 04800 JZ NEXTENT 04810 MOV SI,BX 04820 MOV DI,NAME1 04830 MOV CX,11 04840 WILDCRD: 04850 REPE 04860 CMPB 04870 JZ FOUND 04880 CMP B,[DI-1],"?" 04890 JZ WILDCRD 04900 NEXTENT: 04910 CALL NEXTENTRY 04920 JNC SRCH 04930 RET 04940 04950 FOUND: 04960 IF SMALLDIR 04970 CMP B,[BP+DIRSIZ],-1 04980 JZ RET 04990 ENDIF 05000 05010 ADD SI,15 05020 RET 05030 05040 05050 GETENTRY: 05060 05070 ; Inputs: 05080 ; [LASTENT] has previously searched directory entry 05090 ; Function: 05100 ; Locates next sequential directory entry in preparation for search 05110 ; Outputs: 05120 ; Carry set if none 05130 ; ELSE 05140 ; AL = Current directory block 05150 ; BX = Pointer to next directory entry in [DIRBUF] 05160 ; DX = Pointer to first byte after end of DIRBUF 05170 ; [LASTENT] = New directory entry number 05180 05190 MOV AX,[LASTENT] 05200 INC AX ;Start with next entry 05210 CMP AX,[BP+MAXENT] 05220 JAE NONE 05230 MOV [LASTENT],AX 05240 MOV CL,4 05250 SHL AX,CL 05260 XOR DX,DX 05270 05280 IF SMALLDIR 05290 CMP B,[BP+DIRSIZ],-1 05300 JZ SMALENT1 05310 ENDIF 05320 05330 SHL AX 05340 RCL DX ;Account for overflow in last shift 05350 SMALENT1: 05360 MOV BX,[BP+SECSIZ] 05370 AND BL,255-31 ;Must be multiple of 32 05380 DIV AX,BX 05390 MOV BX,DX ;Position within sector 05400 MOV AH,[BP+DRVNUM] ;AL=Directory sector no. 05410 CMP AX,[DIRBUFID] 05420 JZ HAVDIRBUF 05430 PUSH BX 05440 CALL DIRREAD 05450 POP BX 05460 HAVDIRBUF: 05470 MOV DX,DIRBUF 05480 ADD BX,DX 05490 ADD DX,[BP+SECSIZ] 05500 RET 05510 05520 NEXTENTRY: 05530 05540 ; Inputs: 05550 ; Same as outputs of GETENTRY, above 05560 ; Function: 05570 ; Update AL, BX, and [LASTENT] for next directory entry. 05580 ; Carry set if no more. 05590 05600 MOV DI,[LASTENT] 05610 INC DI 05620 CMP DI,[BP+MAXENT] 05630 JAE NONE 05640 MOV [LASTENT],DI 05650 ADD BX,32 05660 05670 IF SMALLDIR 05680 CMP B,[BP+DIRSIZ],-1 05690 JNZ BIGENT3 05700 SUB BX,16 05710 BIGENT3: 05720 ENDIF 05730 05740 CMP BX,DX 05750 JB HAVIT 05760 INC AL ;Next directory sector 05770 PUSH DX ;Save limit 05780 CALL DIRREAD 05790 POP DX 05800 MOV BX,DIRBUF 05810 HAVIT: 05820 CLC 05830 RET 05840 05850 NONE: 05860 CALL CHKDIRWRITE 05870 STC 05880 RET 05890 05900 05910 DELETE: ; System call 19 05920 CALL GETFILE 05930 JC ERRET 05940 CMP BH,-1 ;Check if device name 05950 JZ ERRET ;Can't delete I/O devices 05960 DELFILE: 05970 MOV B,[DIRTYDIR],-1 05980 MOV B,[BX],0E5H 05990 MOV BX,[SI] 06000 LEA SI,[BP+FAT] 06010 OR BX,BX 06020 JZ DELNXT 06030 CMP BX,[BP+MAXCLUS] 06040 JA DELNXT 06050 CALL RELEASE 06060 DELNXT: 06070 CALL CONTSRCH 06080 JNC DELFILE 06090 CALL FATWRT 06100 CALL CHKDIRWRITE 06110 XOR AL,AL 06120 RET 06130 06140 06150 RENAME: ;System call 23 06160 CALL MOVNAME 06170 JC ERRET 06180 CMP BH,-1 ;Check if I/O device name 06190 JZ ERRET ;If so, can't rename it 06200 ADD SI,5 06210 MOV DI,NAME2 06220 CALL LODNAME 06230 CALL FINDNAME 06240 JC ERRET 06250 RENFIL: 06260 MOV B,[DIRTYDIR],-1 06270 MOV DI,BX 06280 MOV SI,NAME2 06290 MOV CX,11 06300 NEWNAM: 06310 LODB 06320 CMP AL,"?" 06330 JZ NOCHG 06340 MOV [DI],AL 06350 NOCHG: 06360 INC DI 06370 LOOP NEWNAM 06380 CALL CONTSRCH 06390 JNC RENFIL 06400 CALL CHKDIRWRITE 06410 XOR AL,AL 06420 RET 06430 06440 ERRET: 06450 MOV AL,-1 06460 RET 06470 06480 06490 MOVNAME: 06500 06510 ; Inputs: 06520 ; DS, DX point to FCB 06530 ; Outputs: 06540 ; ES = CS 06550 ; If file name OK: 06560 ; BP has base of driver parameters 06570 ; [NAME1] has name in upper case 06580 ; All registers except DX destroyed 06590 ; Carry set if bad file name or drive 06600 06610 MOV AX,CS 06620 MOV ES,AX 06630 MOV DI,NAME1 06640 MOV SI,DX 06650 LODB 06660 CALL GETBP 06670 JB RET 06680 LODNAME: 06690 ; This entry point copies a file name from DS,SI 06700 ; to ES,DI converting to upper case. 06710 MOV CX,11 06720 MOVCHK: 06730 LODB 06740 AND AL,7FH 06750 CMP AL,60H 06760 JLE CASEOK 06770 AND AL,5FH 06780 CASEOK: 06790 CMP AL,20H 06800 JC RET 06810 STOB 06820 LOOP MOVCHK 06830 RET 06840 06850 GETBP: 06860 SEG CS 06870 CMP [NUMDRV],AL 06880 JC RET 06890 CBW 06900 XCHG BP,AX 06910 SHL BP 06920 MOV BP,[BP+CURDRVPT] 06930 RET 06940 06950 06960 OPEN: ;System call 15 06970 PUSH DX 06980 PUSH DS 06990 CALL GETFILE 07000 DOOPEN: 07010 ; Enter here to perform OPEN on file already found 07020 ; in directory. DS=ES=CS, BX points to directory 07030 ; entry in DIRBUF, SI points to First Cluster field, and 07040 ; the top of the stack has the address and segment 07050 ; of the FCB to be opened. This entry point is used 07060 ; by CREATE. 07070 POP ES 07080 POP DI 07090 JC ERRET 07100 CMP BH,-1 ;Check if file is I/O device 07110 JZ OPENDEV ;Special handler if so 07120 MOV AL,[BP+DRVNUM] 07130 INC AL 07140 STOB 07150 ADD DI,11 ;Point to extent field 07160 XOR AX,AX 07170 STOW ;Set extent field to 0 07180 MOV AX,128 ;Default record size 07190 STOW ;Set record size 07200 LODW ;Get starting cluster 07210 MOV DX,AX ;Save it for the moment 07220 MOVW ;Transfer size to FCB 07230 MOVW 07240 MOV AX,[SI-8] ;Get date 07250 07260 IF SMALLDIR 07270 CMP B,[BP+DIRSIZ],-1 07280 JNZ BIGENT10 07290 SEG ES 07300 MOV [DI-1],0 07310 XOR AX,AX ;Date not available in small entry 07320 BIGENT10: 07330 ENDIF 07340 07350 STOW ;Save date in FCB 07360 MOV AX,[LASTENT] 07370 STOW ;directory location 07380 MOV AX,DX ;Restore starting cluster 07390 STOW ; first cluster 07400 STOW ; last cluster accessed 07410 XOR AX,AX 07420 STOW ; position of last cluster 07430 STOB ; dirty flag 07440 RET 07450 07460 OPENDEV: 07470 SEG ES 07480 MOV [DI+FILDIRBLK],BX ;Use dir. entry number as flag 07490 XOR AL,AL 07500 RET 07510 07520 07530 STARTSRCH: 07540 MOV [LASTENT],-1 07550 FATREAD: 07560 07570 ; Inputs: 07580 ; DS = CS 07590 ; BP = Base of drive parameters 07600 ; Function: 07610 ; If disk may have been changed, FAT is read in and buffers are 07620 ; flagged invalid. If not, no action is taken. 07630 ; Outputs: 07640 ; AL = 0 07650 ; BP unchanged 07660 ; All other registers destroyed 07670 07680 MOV AL,[BP+DRVNUM] 07690 CALL BIOSDSKCHG,BIOSSEG ;See what BIOS has to say 07700 MOV AL,[BP+DRVNUM] 07710 OR AH,[BP+DIRTYFAT] 07720 JS NEWDSK ;If either say new disk, then it's so 07730 DEC AH ;Check for AH=1 (disk not changed) 07740 JZ RET 07750 MOV AH,1 07760 CMP AX,[BUFDRVNO] ;Does buffer have dirty sector of this drive? 07770 JZ RET ;If so, disk has not been changed 07780 NEWDSK: 07790 CMP AL,[BUFDRVNO] ;See if buffer is for this drive 07800 JNZ BUFOK ;If not, don't touch it 07810 MOV [BUFSECNO],0 ;Flag buffers invalid 07820 MOV [BUFDRVNO],00FFH 07830 BUFOK: 07840 MOV [DIRBUFID],-1 07850 CALL FIGFAT 07860 NEXTFAT: 07870 PUSH DX 07880 PUSH CX 07890 PUSH BX 07900 PUSH AX 07910 CALL DREAD 07920 OR AL,AL 07930 POP AX 07940 POP BX 07950 POP CX 07960 POP DX 07970 JNZ BADFAT 07980 07990 IF SMALLDIR 08000 MOV DL,AL 08010 LEA SI,[BP+FIRREC1] ;FIRREC and MAXCLUS for 16-byte dir entries 08020 CMP B,[BP+DIRSIZ],-1 08030 JZ SETSIZ 08040 ADD SI,4 ;FIRREC and MAXCLUS for 32-byte entries 08050 SETSIZ: 08060 LODW 08070 MOV [BP+FIRREC],AX 08080 LODW 08090 MOV [BP+MAXCLUS],AX 08100 MOV AL,DL 08110 ENDIF 08120 08130 SUB AL,[BP+FATCNT] 08140 JZ RET 08150 NEG AL 08160 ;{Insert error code here. AL=number of bad fats. 08170 ;Since one good FAT was read, should include option 08180 ;to rewrite all FATs.} 08190 JMP FATWRT 08200 08210 BADFAT: 08220 ADD DX,CX 08230 DEC AL 08240 JNZ NEXTFAT 08250 POP BP 08260 ;{Insert error code here. All FATs on drive are bad.} 08270 MOV SI,BADFATMES 08280 CALL HARDERR 08290 JP FATREAD 08300 08310 OKRET1: 08320 MOV AL,0 08330 RET 08340 08350 CLOSE: ;System call 16 08360 MOV DI,DX 08370 CMP B,[DI+FILDIRBLK],-1 ;Check for I/O device 08380 JZ OKRET1 ;Can't close I/O device 08390 TEST B,[DI+DIRTYFIL],-1 08400 JZ OKRET1 ;If not written to, do nothing 08410 MOV AL,[DI] ;Get drive number 08420 CALL GETBP ;Get base of drive parameters 08430 JC BADCLOSEJ 08440 MOV AL,[BP+DRVNUM] 08450 MOV AH,1 ;Look for dirty buffer 08460 SEG CS 08470 CMP AX,[BUFDRVNO] 08480 JNZ FNDDIR 08490 ;Write back dirty buffer if on same drive 08500 PUSH DX 08510 PUSH DS 08520 PUSH CS 08530 POP DS 08540 MOV B,[DIRTYBUF],0 08550 MOV BX,[BUFFER] 08560 MOV CX,1 08570 MOV DX,[BUFSECNO] 08580 CALL DWRITE 08590 POP DS 08600 POP DX 08610 FNDDIR: 08620 PUSH DX 08630 PUSH DS 08640 CALL GETFILE 08650 POP ES 08660 POP DI 08670 BADCLOSEJ: 08680 JC BADCLOSE 08690 MOV AX,[LASTENT] 08700 SEG ES 08710 CMP AX,[DI+FILDIRBLK] 08720 JNZ BADCLOSE 08730 SEG ES 08740 MOV CX,[DI+FIRCLUS] 08750 MOV [SI],CX 08760 SEG ES 08770 MOV DX,[DI+FILSIZ] 08780 MOV [SI+2],DX 08790 SEG ES 08800 MOV DX,[DI+FILSIZ+2] 08810 08820 IF SMALLDIR 08830 CMP B,[BP+DIRSIZ],-1 08840 JNZ BIGENT11 08850 MOV [SI+4],DL 08860 JP SMALLENT2 08870 BIGENT11: 08880 ENDIF 08890 08900 MOV [SI+4],DX 08910 SEG ES 08920 MOV DX,[DI+FDATE] 08930 MOV [SI-2],DX 08940 SMALLENT2: 08950 CALL DIRWRITE 08960 08970 CHKFATWRT: 08980 ; Do FATWRT only if FAT is dirty 08990 09000 CMP B,[BP+DIRTYFAT],1 09010 JNZ OKRET 09020 09030 FATWRT: 09040 09050 ; Inputs: 09060 ; DS = CS 09070 ; BP = Base of drive parameter table 09080 ; Function: 09090 ; Write the FAT back to disk and reset FAT 09100 ; dirty bit. 09110 ; Outputs: 09120 ; AL = 0 09130 ; BP unchanged 09140 ; All other registers destroyed 09150 09160 MOV B,[BP+DIRTYFAT],0 09170 CALL FIGFAT 09180 EACHFAT: 09190 PUSH DX 09200 PUSH CX 09210 PUSH BX 09220 PUSH AX 09230 CALL DWRITE 09240 POP AX 09250 POP BX 09260 POP CX 09270 POP DX 09280 ADD DX,CX 09290 DEC AL 09300 JNZ EACHFAT 09310 OKRET: 09320 MOV AL,0 09330 RET 09340 09350 BADCLOSE: 09360 MOV B,[BP+DIRTYFAT],0 09370 MOV AL,-1 09380 RET 09390 09400 09410 FIGFAT: 09420 ; Loads registers with values needed to read or 09430 ; write a FAT. 09440 MOV AL,[BP+FATCNT] 09450 LEA BX,[BP+FAT] 09460 MOV CL,[BP+FATSIZ] ;No. of records occupied by FAT 09470 MOV CH,0 09480 MOV DX,[BP+FIRFAT] ;Record number of start of FATs 09490 RET 09500 09510 09520 DIRCOMP: 09530 ; Prepare registers for directory read or write 09540 CBW 09550 ADD AX,[BP+FIRDIR] 09560 MOV DX,AX 09570 MOV BX,DIRBUF 09580 MOV CX,1 09590 RET 09600 09610 09620 CREATE: ;System call 22 09630 CALL MOVNAME 09640 JC ERRET3 09650 MOV DI,NAME1 09660 MOV CX,11 09670 MOV AL,"?" 09680 REPNE 09690 SCAB 09700 JZ ERRET3 09710 PUSH DX 09720 PUSH DS 09730 CALL FINDNAME 09740 JNC EXISTENT 09750 CALL STARTSRCH 09760 CALL GETENTRY 09770 LOOKFRE: 09780 CMP B,[BX],0E5H 09790 JZ FREESPOT 09800 CALL NEXTENTRY 09810 JNC LOOKFRE 09820 POP DS 09830 POP DX 09840 ERRET3: 09850 MOV AL,-1 09860 RET 09870 09880 EXISTENT: 09890 CMP BH,-1 ;Check if file is I/O device 09900 JZ OPENJMP ;If so, no action 09910 XOR CX,CX 09920 MOV [SI+2],CX 09930 MOV AX,[DATE] 09940 09950 IF SMALLDIR 09960 MOV [SI+4],CL 09970 CMP B,[BP+DIRSIZ],-1 09980 JZ SMLENT 09990 MOV [SI+5],CL 10000 MOV [SI-2],AX 10010 SMLENT: 10020 ENDIF 10030 10040 IF 1-SMALLDIR 10050 MOV [SI+4],CX 10060 MOV [SI-2],AX 10070 ENDIF 10080 10090 XCHG CX,[SI] 10100 PUSH SI 10110 PUSH BX 10120 JCXZ WRTBACK 10130 CMP CX,[BP+MAXCLUS] 10140 JA WRTBACK 10150 MOV BX,CX 10160 LEA SI,[BP+FAT] 10170 CALL RELEASE 10180 CALL FATWRT 10190 JP WRTBACK 10200 10210 FREESPOT: 10220 MOV DI,BX 10230 MOV SI,NAME1 10240 MOV CX,5 10250 MOVB 10260 REP 10270 MOVW 10280 XOR AX,AX 10290 10300 IF SMALLDIR 10310 CMP B,[BP+DIRSIZ],-1 10320 JNZ BIGENT4 10330 PUSH DI 10340 MOV CL,5 10350 JP SMALLENT 10360 BIGENT4: 10370 ENDIF 10380 10390 MOV CL,13 10400 REP 10410 STOB 10420 MOV AX,[DATE] 10430 STOW 10440 XOR AX,AX 10450 PUSH DI 10460 MOV CL,6 10470 SMALLENT: 10480 REP 10490 STOB 10500 PUSH BX 10510 WRTBACK: 10520 CALL DIRWRITE 10530 POP BX 10540 POP SI 10550 OPENJMP: 10560 CLC ;Clear carry so OPEN won't fail 10570 JMP DOOPEN 10580 10590 10600 DIRREAD: 10610 10620 ; Inputs: 10630 ; DS = CS 10640 ; AL = Directory block number 10650 ; BP = Base of drive parameters 10660 ; Function: 10670 ; Read the directory block into DIRBUF. 10680 ; Outputs: 10690 ; AX,BP unchanged 10700 ; All other registers destroyed. 10710 10720 PUSH AX 10730 CALL CHKDIRWRITE 10740 POP AX 10750 PUSH AX 10760 MOV AH,[BP+DRVNUM] 10770 MOV [DIRBUFID],AX 10780 CALL DIRCOMP 10790 CALL DREAD 10800 POP AX 10810 RET 10820 10830 10840 DREAD: 10850 10860 ; Inputs: 10870 ; BX,DS = Transfer address 10880 ; CX = Number of sectors 10890 ; DX = Absolute record number 10900 ; BP = Base of drive parameters 10910 ; Function: 10920 ; Calls BIOS to perform disk read. If BIOS reports 10930 ; errors, will call HARDERR for further action. 10940 ; Outputs: 10950 ; AL = 0 if no error, otherwise non-zero 10960 ; BP preserved. All other registers destroyed. 10970 10980 MOV AL,[BP+DRVNUM] 10990 PUSH BP 11000 PUSH BX 11010 PUSH CX 11020 PUSH DX 11030 CALL BIOSREAD,BIOSSEG 11040 POP DX 11050 POP DI 11060 POP BX 11070 POP BP 11080 JC HARDREAD 11090 XOR AL,AL 11100 RET 11110 11120 HARDREAD: 11130 MOV SI,RDERRMES 11140 CALL HARDERR 11150 JP DREAD 11160 11170 11180 CHKDIRWRITE: 11190 TEST B,[DIRTYDIR],-1 11200 JZ RET 11210 11220 DIRWRITE: 11230 11240 ; Inputs: 11250 ; DS = CS 11260 ; AL = Directory block number 11270 ; BP = Base of drive parameters 11280 ; Function: 11290 ; Write the directory block into DIRBUF. 11300 ; Outputs: 11310 ; BP unchanged 11320 ; All other registers destroyed. 11330 11340 MOV B,[DIRTYDIR],0 11350 MOV AL,[DIRBUFID] 11360 CALL DIRCOMP 11370 11380 11390 DWRITE: 11400 11410 ; Inputs: 11420 ; BX,DS = Transfer address 11430 ; CX = Number of sectors 11440 ; DX = Absolute record number 11450 ; BP = Base of drive parameters 11460 ; Function: 11470 ; Calls BIOS to perform disk write. If BIOS reports 11480 ; errors, will call HARDERR for further action. 11490 ; Outputs: 11500 ; AL = 0 if no error, otherwise non-zero 11510 ; BP preserved. All other registers destroyed. 11520 11530 MOV AL,[BP+DRVNUM] 11540 WRTDRV: 11550 PUSH AX 11560 PUSH BP 11570 PUSH BX 11580 PUSH CX 11590 PUSH DX 11600 CALL BIOSWRITE,BIOSSEG 11610 POP DX 11620 POP DI 11630 POP BX 11640 POP BP 11650 POP AX 11660 JC HARDWRITE 11670 XOR AL,AL 11680 RET 11690 HARDWRITE: 11700 MOV SI,WRTERRMES 11710 CALL HARDERR 11720 JP WRTDRV 11730 11740 11750 HARDERR: 11760 SUB DI,CX 11770 ADD DX,DI 11780 CALL SHFTDI7 11790 ADD BX,DI 11800 MOV AH,AL ;Save drive number 11810 CALL OUTMES 11820 GETINSTR: 11830 CALL IN 11840 OR AL,20H 11850 CMP AL,"a" 11860 JZ ERROR 11870 CMP AL,"r" 11880 JZ RETRY 11890 CMP AL,"i" 11900 JZ IGNORE 11910 CMP AL,"c" 11920 JNZ GETINSTR 11930 CONTINUE: 11940 POP AX 11950 MOV AL,1 11960 RET 11970 IGNORE: 11980 POP AX 11990 MOV AL,0 12000 RET 12010 RETRY: 12020 MOV AL,AH ;Restore drive number 12030 RET 12040 12050 12060 ABORT: 12070 SEG CS 12080 MOV DS,[CSLOC] 12090 XOR AX,AX 12100 MOV ES,AX 12110 MOV SI,SAVEXIT 12120 MOV DI,EXIT 12130 MOVW 12140 MOVW 12150 MOVW 12160 MOVW 12170 ERROR: 12180 MOV AX,CS 12190 MOV DS,AX 12200 MOV ES,AX 12210 CALL WRTFATS 12220 XOR AX,AX 12230 DI 12240 MOV SS,[SSSAVE] 12250 MOV SP,[SPSAVE] 12260 MOV DS,AX 12270 MOV SI,EXIT 12280 MOV DI,EXITHOLD 12290 MOVW 12300 MOVW 12310 POP AX 12320 POP BX 12330 POP CX 12340 POP DX 12350 POP SI 12360 POP DI 12370 POP BP 12380 POP DS 12390 POP ES 12400 EI ;Stack OK now 12410 SEG CS 12420 JMP L,[EXITHOLD] 12430 12440 12450 SEQRD: ;System call 20 12460 CALL GETREC 12470 CALL LOAD 12480 JP FINSEQ 12490 12500 SEQWRT: ;System call 21 12510 CALL GETREC 12520 CALL STORE 12530 FINSEQ: 12540 JCXZ SETNREX 12550 ADD AX,1 12560 ADC DX,0 12570 JP SETNREX 12580 12590 RNDRD: ;System call 33 12600 CALL GETRRPOS1 12610 CALL LOAD 12620 JP FINRND 12630 12640 RNDWRT: ;System call 34 12650 CALL GETRRPOS1 12660 CALL STORE 12670 JP FINRND 12680 12690 BLKRD: ;System call 39 12700 CALL GETRRPOS 12710 CALL LOAD 12720 JP FINBLK 12730 12740 BLKWRT: ;System call 40 12750 CALL GETRRPOS 12760 CALL STORE 12770 FINBLK: 12780 LDS SI,[SPSAVE] 12790 MOV [SI+CXSAVE],CX 12800 JCXZ FINRND 12810 ADD AX,1 12820 ADC DX,0 12830 FINRND: 12840 SEG ES 12850 MOV [DI+RR],AX 12860 SEG ES 12870 MOV [DI+RR+2],DL 12880 OR DH,DH 12890 JZ SETNREX 12900 SEG ES 12910 MOV [DI+RR+3],DH ;Save 4 byte of RECPOS only if significant 12920 SETNREX: 12930 MOV CX,AX 12940 AND AL,7FH 12950 SEG ES 12960 MOV [DI+NR],AL 12970 AND CL,80H 12980 SHL CX 12990 RCL DX 13000 MOV AL,CH 13010 MOV AH,DL 13020 SEG ES 13030 MOV [DI+EXTENT],AX 13040 SEG CS 13050 MOV AL,[DSKERR] 13060 RET 13070 13080 GETRRPOS1: 13090 MOV CX,1 13100 GETRRPOS: 13110 MOV DI,DX 13120 MOV AX,[DI+RR] 13130 MOV DX,[DI+RR+2] 13140 RET 13150 13160 NOFILERR: 13170 XOR CX,CX 13180 MOV B,[DSKERR],-2 13190 POP BX 13200 RET 13210 13220 SETUP: 13230 13240 ; Inputs: 13250 ; DS:DI point to FCB 13260 ; DX:AX = Record position in file of disk transfer 13270 ; CX = Record count 13280 ; Outputs: 13290 ; DS = CS 13300 ; ES:DI point to FCB 13310 ; CX = No. of bytes to transfer 13320 ; BP = Base of drive parameters 13330 ; SI = FAT pointer 13340 ; [RECCNT] = Record count 13350 ; [RECPOS] = Record position in file 13360 ; [FCB] = DI 13370 ; [NEXTADD] = Displacement of disk transfer within segment 13380 ; [SECPOS] = Position of first sector 13390 ; [BYTPOS] = Byte position in file 13400 ; [BYTSECPOS] = Byte position in first sector 13410 ; [CLUSNUM] = First cluster 13420 ; [SECCLUSPOS] = Sector within first cluster 13430 ; [DSKERR] = 0 (no errors yet) 13440 ; [TRANS] = 0 (No transfers yet) 13450 ; If SETUP detects no records will be transfered, it returns 1 level up 13460 ; with CX = 0. 13470 13480 PUSH AX 13490 MOV AL,[DI] 13500 MOV SI,[DI+RECSIZ] 13510 OR SI,SI 13520 JNZ HAVRECSIZ 13530 MOV SI,128 13540 MOV [DI+RECSIZ],SI 13550 HAVRECSIZ: 13560 MOV BX,DS 13570 MOV ES,BX 13580 MOV BX,CS 13590 MOV DS,BX 13600 CALL GETBP 13610 POP AX 13620 JC NOFILERR 13630 CMP SI,64 ;Check if highest byte of RECPOS is significant 13640 JB SMALREC 13650 MOV DH,0 ;Ignore MSB if record >= 64 bytes 13660 SMALREC: 13670 MOV [RECCNT],CX 13680 MOV [RECPOS],AX 13690 MOV [RECPOS+2],DX 13700 MOV [FCB],DI 13710 MOV BX,[DMAADD] 13720 MOV [NEXTADD],BX 13730 MOV B,[DSKERR],0 13740 MOV B,[TRANS],0 13750 MOV BX,DX 13760 MUL AX,SI 13770 MOV [BYTPOS],AX 13780 PUSH DX 13790 MOV AX,BX 13800 MUL AX,SI 13810 POP BX 13820 ADD AX,BX 13830 ADC DX,0 ;Ripple carry 13840 JNZ EOFERR 13850 MOV [BYTPOS+2],AX 13860 MOV DX,AX 13870 MOV AX,[BYTPOS] 13880 DIV AX,[BP+SECSIZ] 13890 MOV [SECPOS],AX 13900 MOV [BYTSECPOS],DX 13910 MOV DX,AX 13920 AND AL,[BP+CLUSMSK] 13930 MOV [SECCLUSPOS],AL 13940 MOV AX,CX ;Record count 13950 MOV CL,[BP+CLUSSHFT] 13960 SHR DX,CL 13970 MOV [CLUSNUM],DX 13980 MUL AX,SI ;Multiply by bytes per record 13990 MOV CX,AX 14000 ADD AX,[DMAADD] ;See if it will fit in one segment 14010 ADC DX,0 14020 JZ OK ;Must stay within 64K 14030 MOV AX,[DMAADD] 14040 NEG AX ;Amount of room left in segment 14050 XOR DX,DX 14060 DIV AX,SI ;How many records will fit? 14070 MUL AX,SI ;Translate that back into bytes 14080 MOV B,[DSKERR],2 ;Flag that trimming took place 14090 MOV CX,AX 14100 JCXZ NOROOM 14110 OK: 14120 LEA SI,[BP+FAT] 14130 RET 14140 14150 EOFERR: 14160 MOV B,[DSKERR],1 14170 XOR CX,CX 14180 NOROOM: 14190 POP BX ;Kill return address 14200 RET 14210 14220 BREAKDOWN: 14230 14240 ;Inputs: 14250 ; DS = CS 14260 ; CX = Length of disk transfer in bytes 14270 ; BP = Base of drive parameters 14280 ; [BYTSECPOS] = Byte position witin first sector 14290 ;Outputs: 14300 ; [BYTCNT1] = Bytes to transfer in first sector 14310 ; [SECCNT] = No. of whole sectors to transfer 14320 ; [BYTCNT2] = Bytes to transfer in last sector 14330 ;AX, BX, DX destroyed. No other registers affected. 14340 14350 MOV AX,[BYTSECPOS] 14360 MOV BX,CX 14370 OR AX,AX 14380 JZ SAVFIR ;Partial first sector? 14390 SUB AX,[BP+SECSIZ] 14400 NEG AX ;Max number of bytes left in first sector 14410 SUB BX,AX ;Subtract from total length 14420 JAE SAVFIR 14430 ADD AX,BX ;Don't use all of the rest of the sector 14440 XOR BX,BX ;And no bytes are left 14450 SAVFIR: 14460 MOV [BYTCNT1],AX 14470 MOV AX,BX 14480 XOR DX,DX 14490 DIV AX,[BP+SECSIZ] ;How many whole sectors? 14500 MOV [SECCNT],AX 14510 MOV [BYTCNT2],DX ;Bytes remaining for last sector 14520 RET 14530 14540 14550 FNDCLUS: 14560 14570 ; Inputs: 14580 ; DS = CS 14590 ; CX = No. of clusters to skip 14600 ; BP = Base of drive parameters 14610 ; SI = FAT pointer 14620 ; ES:DI point to FCB 14630 ; Outputs: 14640 ; BX = Last cluster skipped to 14650 ; CX = No. of clusters remaining (0 unless EOF) 14660 ; DX = Position of last cluster 14670 ; DI destroyed. No other registers affected. 14680 14690 SEG ES 14700 MOV BX,[DI+LSTCLUS] 14710 SEG ES 14720 MOV DX,[DI+CLUSPOS] 14730 OR BX,BX 14740 JZ NOCLUS 14750 SUB CX,DX 14760 JNB FINDIT 14770 ADD CX,DX 14780 XOR DX,DX 14790 SEG ES 14800 MOV BX,[DI+FIRCLUS] 14810 FINDIT: 14820 JCXZ RET 14830 SKPCLP: 14840 CALL UNPACK 14850 CMP DI,0FF8H 14860 JAE RET 14870 XCHG BX,DI 14880 INC DX 14890 LOOP SKPCLP 14900 RET 14910 NOCLUS: 14920 INC CX 14930 DEC DX 14940 RET 14950 14960 14970 BUFSEC: 14980 ; Inputs: 14990 ; AL = 0 if buffer must be read, 1 if no pre-read needed 15000 ; BP = Base of drive parameters 15010 ; [CLUSNUM] = Physical cluster number 15020 ; [SECCLUSPOS] = Sector position of transfer within cluster 15030 ; [BYTCNT1] = Size of transfer 15040 ; Function: 15050 ; Insure specified sector is in buffer, flushing buffer before 15060 ; read if necessary. 15070 ; Outputs: 15080 ; SI = Pointer to buffer 15090 ; DI = Pointer to transfer address 15100 ; CX = Number of bytes 15110 ; [NEXTADD] updated 15120 ; [TRANS] set to indicate a transfer will occur 15130 15140 MOV DX,[CLUSNUM] 15150 MOV BL,[SECCLUSPOS] 15160 CALL FIGREC 15170 OR AL,AL 15180 JNZ SETBUF 15190 CMP DX,[BUFSECNO] 15200 JNZ GETSEC 15210 MOV AL,[BUFDRVNO] 15220 CMP AL,[BP+DRVNUM] 15230 JZ FINBUF ;Already have it? 15240 GETSEC: 15250 TEST B,[DIRTYBUF],-1 15260 JZ RDSEC 15270 PUSH DX 15280 MOV AL,[BUFDRVNO] 15290 MOV BX,[BUFFER] 15300 MOV CX,1 15310 MOV DX,[BUFSECNO] 15320 CALL WRTDRV 15330 POP DX 15340 RDSEC: 15350 MOV BX,[BUFFER] 15360 MOV CX,1 15370 PUSH DX 15380 CALL DREAD 15390 POP DX 15400 SETBUF: 15410 MOV [BUFSECNO],DX 15420 MOV AL,[BP+DRVNUM] 15430 MOV AH,0 15440 MOV [BUFDRVNO],AX 15450 FINBUF: 15460 MOV B,[TRANS],1 ;A transfer is taking place 15470 MOV DI,[NEXTADD] 15480 MOV SI,DI 15490 MOV CX,[BYTCNT1] 15500 ADD SI,CX 15510 MOV [NEXTADD],SI 15520 MOV SI,[BUFFER] 15530 ADD SI,[BYTSECPOS] 15540 RET 15550 15560 BUFRD: 15570 XOR AL,AL ;Pre-read necessary 15580 CALL BUFSEC 15590 PUSH ES 15600 MOV ES,[DMAADD+2] 15610 SHR CX 15620 JNC EVENRD 15630 MOVB 15640 EVENRD: 15650 REP 15660 MOVW 15670 POP ES 15680 RET 15690 15700 BUFWRT: 15710 MOV AX,[SECPOS] 15720 INC AX ;Set for next sector 15730 MOV [SECPOS],AX 15740 CMP AX,[VALSEC] ;Has sector been written before? 15750 MOV AL,1 15760 JA NOREAD ;Skip preread if SECPOS>VALSEC 15770 MOV AL,0 15780 NOREAD: 15790 CALL BUFSEC 15800 XCHG DI,SI 15810 PUSH DS 15820 PUSH ES 15830 PUSH CS 15840 POP ES 15850 MOV DS,[DMAADD+2] 15860 SHR CX 15870 JNC EVENWRT 15880 MOVB 15890 EVENWRT: 15900 REP 15910 MOVW 15920 POP ES 15930 POP DS 15940 MOV B,[DIRTYBUF],1 15950 RET 15960 15970 NEXTSEC: 15980 TEST B,[TRANS],-1 15990 JZ CLRET 16000 MOV AL,[SECCLUSPOS] 16010 INC AL 16020 CMP AL,[BP+CLUSMSK] 16030 JBE SAVPOS 16040 MOV BX,[CLUSNUM] 16050 CMP BX,0FF8H 16060 JAE NONEXT 16070 LEA SI,[BP+FAT] 16080 CALL UNPACK 16090 MOV [CLUSNUM],DI 16100 INC [LASTPOS] 16110 MOV AL,0 16120 SAVPOS: 16130 MOV [SECCLUSPOS],AL 16140 CLRET: 16150 CLC 16160 RET 16170 NONEXT: 16180 STC 16190 RET 16200 16210 TRANBUF: 16220 LODB 16230 STOB 16240 CMP AL,13 ;Check for carriage return 16250 JNZ NORMCH 16260 MOV [SI],10 16270 NORMCH: 16280 CMP AL,10 16290 LOOPNZ TRANBUF 16300 JNZ ENDRDCON 16310 CALL OUT ;Transmit linefeed 16320 XOR SI,SI 16330 OR CX,CX 16340 JNZ GETBUF 16350 OR AL,1 ;Clear zero flag--not end of file 16360 ENDRDCON: 16370 MOV [CONTPOS],SI 16380 ENDRDDEV: 16390 MOV [NEXTADD],DI 16400 POP ES 16410 JNZ SETFCBJ ;Zero set if Ctrl-Z found in input 16420 MOV DI,[FCB] 16430 SEG ES 16440 OR B,[DI+FILDIRBLK],80H ;Mark as no more data available 16450 SETFCBJ: 16460 JMP SETFCB 16470 16480 READDEV: 16490 PUSH ES 16500 LES DI,[DMAADD] 16510 OR BL,BL 16520 JZ READCON 16530 DEC BL 16540 JNZ ENDRDDEV 16550 READAUX: 16560 CALL BIOSAUXIN,BIOSSEG 16570 STOB 16580 CMP AL,1AH 16590 LOOPNZ READAUX 16600 JP ENDRDDEV 16610 16620 READCON: 16630 PUSH CS 16640 POP DS 16650 MOV SI,[CONTPOS] 16660 OR SI,SI 16670 JNZ TRANBUF 16680 CMP B,[CONBUF],128 16690 JZ GETBUF 16700 MOV [CONBUF],0FF80H ;Set up 128-byte buffer with no template 16710 GETBUF: 16720 PUSH CX 16730 PUSH ES 16740 PUSH DI 16750 MOV DX,CONBUF 16760 CALL BUFIN ;Get input buffer 16770 POP DI 16780 POP ES 16790 POP CX 16800 MOV SI,CONBUF+2 16810 CMP B,[SI],1AH ;Check for Ctrl-Z in first character 16820 JNZ TRANBUF 16830 MOV AL,1AH 16840 STOB 16850 MOV AL,10 16860 CALL OUT ;Send linefeed 16870 XOR SI,SI 16880 JP ENDRDCON 16890 16900 RDERR: 16910 XOR CX,CX 16920 JMP WRTERR 16930 16940 RDLASTJ:JMP RDLAST 16950 16960 LOAD: 16970 16980 ; Inputs: 16990 ; DS:DI point to FCB 17000 ; DX:AX = Position in file to read 17010 ; CX = No. of records to read 17020 ; Outputs: 17030 ; DX:AX = Position of last record read 17040 ; CX = No. of bytes read 17050 ; ES:DI point to FCB 17060 ; LSTCLUS, CLUSPOS fields in FCB set 17070 17080 CALL SETUP 17090 SEG ES 17100 MOV BX,[DI+FILDIRBLK] 17110 CMP BH,-1 ;Check for named device I/O 17120 JZ READDEV 17130 SEG ES 17140 MOV AX,[DI+FILSIZ] 17150 SEG ES 17160 MOV BX,[DI+FILSIZ+2] 17170 SUB AX,[BYTPOS] 17180 SBC BX,[BYTPOS+2] 17190 JB RDERR 17200 JNZ ENUF 17210 OR AX,AX 17220 JZ RDERR 17230 CMP AX,CX 17240 JAE ENUF 17250 MOV CX,AX 17260 ENUF: 17270 CALL BREAKDOWN 17280 MOV CX,[CLUSNUM] 17290 CALL FNDCLUS 17300 OR CX,CX 17310 JNZ RDERR 17320 MOV [LASTPOS],DX 17330 MOV [CLUSNUM],BX 17340 CMP [BYTCNT1],0 17350 JZ RDMID 17360 CALL BUFRD 17370 RDMID: 17380 CMP [SECCNT],0 17390 JZ RDLASTJ 17400 CALL NEXTSEC 17410 JC SETFCB 17420 MOV B,[TRANS],1 ;A transfer is taking place 17430 ONSEC: 17440 MOV DL,[SECCLUSPOS] 17450 MOV CX,[SECCNT] 17460 MOV BX,[CLUSNUM] 17470 RDLP: 17480 CALL OPTIMIZE 17490 PUSH DI 17500 PUSH AX 17510 PUSH DS 17520 MOV DS,[DMAADD+2] 17530 CALL DREAD 17540 POP DS 17550 POP CX 17560 POP BX 17570 JCXZ RDLAST 17580 CMP BX,0FF8H 17590 JAE SETFCB 17600 MOV DL,0 17610 INC [LASTPOS] ;We'll be using next cluster 17620 JP RDLP 17630 17640 SETFCB: 17650 MOV SI,[FCB] 17660 MOV AX,[NEXTADD] 17670 MOV DI,AX 17680 SUB AX,[DMAADD] ;Number of bytes transfered 17690 XOR DX,DX 17700 SEG ES 17710 MOV CX,[SI+RECSIZ] 17720 DIV AX,CX ;Number of records 17730 CMP AX,[RECCNT] ;Check if all records transferred 17740 JZ FULLREC 17750 MOV B,[DSKERR],1 17760 OR DX,DX 17770 JZ FULLREC ;If remainder 0, then full record transfered 17780 MOV B,[DSKERR],3 ;Flag partial last record 17790 SUB CX,DX ;Bytes left in last record 17800 PUSH ES 17810 MOV ES,[DMAADD+2] 17820 XCHG AX,BX ;Save the record count temporarily 17830 XOR AX,AX ;Fill with zeros 17840 SHR CX 17850 JNC EVENFIL 17860 STOB 17870 EVENFIL: 17880 REP 17890 STOW 17900 XCHG AX,BX ;Restore record count to AX 17910 POP ES 17920 INC AX ;Add last (partial) record to total 17930 FULLREC: 17940 MOV CX,AX 17950 MOV DI,SI ;ES:DI point to FCB 17960 SETCLUS: 17970 MOV AX,[CLUSNUM] 17980 SEG ES 17990 MOV [DI+LSTCLUS],AX 18000 MOV AX,[LASTPOS] 18010 SEG ES 18020 MOV [DI+CLUSPOS],AX 18030 ADDREC: 18040 MOV AX,[RECPOS] 18050 MOV DX,[RECPOS+2] 18060 DEC CX 18070 ADD AX,CX ;Update current record position 18080 ADC DX,0 18090 INC CX 18100 RET 18110 18120 RDLAST: 18130 MOV AX,[BYTCNT2] 18140 OR AX,AX 18150 JZ SETFCB 18160 MOV [BYTCNT1],AX 18170 CALL NEXTSEC 18180 JC SETFCB 18190 MOV [BYTSECPOS],0 18200 CALL BUFRD 18210 JP SETFCB 18220 18230 WRTDEV: 18240 PUSH DS 18250 LDS SI,[DMAADD] 18260 AND BL,7FH 18270 OR BL,BL 18280 JZ WRTCON 18290 DEC BL 18300 JZ WRTAUX 18310 WRTLST: 18320 LODB 18330 CMP AL,1AH 18340 JZ ENDWRDEV 18350 CALL BIOSPRINT,BIOSSEG 18360 LOOP WRTLST 18370 JP ENDWRDEV 18380 18390 WRTAUX: 18400 LODB 18410 CALL BIOSAUXOUT,BIOSSEG 18420 CMP AL,1AH 18430 LOOPNZ WRTAUX 18440 JP ENDWRDEV 18450 18460 WRTCON: 18470 LODB 18480 CMP AL,1AH 18490 JZ ENDWRDEV 18500 CALL OUT 18510 LOOP WRTCON 18520 ENDWRDEV: 18530 POP DS 18540 MOV CX,[RECCNT] 18550 MOV DI,[FCB] 18560 JP ADDREC 18570 18580 HAVSTART: 18590 MOV CX,AX 18600 CALL SKPCLP 18610 JCXZ DOWRTJ 18620 CALL ALLOCATE 18630 JNC DOWRTJ 18640 WRTERR: 18650 MOV B,[DSKERR],1 18660 LVDSK: 18670 MOV AX,[RECPOS] 18680 MOV DX,[RECPOS+2] 18690 MOV DI,[FCB] 18700 RET 18710 18720 DOWRTJ: JMP DOWRT 18730 18740 WRTEOFJ: 18750 JMP WRTEOF 18760 18770 STORE: 18780 18790 ; Inputs: 18800 ; DS:DI point to FCB 18810 ; DX:AX = Position in file of disk transfer 18820 ; CX = Record count 18830 ; Outputs: 18840 ; DX:AX = Position of last record written 18850 ; CX = No. of records written 18860 ; ES:DI point to FCB 18870 ; LSTCLUS, CLUSPOS fields in FCB set 18880 18890 MOV B,[DI+DIRTYFIL],1 18900 SEG CS 18910 MOV BX,[DATE] 18920 MOV [DI+FDATE],BX 18930 CALL SETUP 18940 SEG ES 18950 MOV BX,[DI+FILDIRBLK] 18960 CMP BH,-1 18970 JZ WRTDEV 18980 CALL BREAKDOWN 18990 MOV AX,[BYTPOS] 19000 MOV DX,[BYTPOS+2] 19010 JCXZ WRTEOFJ 19020 DEC CX 19030 ADD AX,CX 19040 ADC DX,0 ;AX:DX=last byte accessed 19050 DIV AX,[BP+SECSIZ] ;AX=last sector accessed 19060 MOV CL,[BP+CLUSSHFT] 19070 SHR AX,CL ;Last cluster to be accessed 19080 PUSH AX 19090 SEG ES 19100 MOV AX,[DI+FILSIZ] 19110 SEG ES 19120 MOV DX,[DI+FILSIZ] 19130 DIV AX,[BP+SECSIZ] 19140 OR DX,DX 19150 JZ NORNDUP 19160 INC AX ;Round up if any remainder 19170 NORNDUP: 19180 MOV [VALSEC],AX ;Number of sectors that have been written 19190 POP AX 19200 MOV CX,[CLUSNUM] ;First cluster accessed 19210 CALL FNDCLUS 19220 MOV [CLUSNUM],BX 19230 MOV [LASTPOS],DX 19240 SUB AX,DX ;Last cluster minus current cluster 19250 JZ DOWRT ;If we have last clus, we must have first 19260 JCXZ HAVSTART 19270 PUSH CX ;No. of clusters short of first 19280 MOV CX,AX 19290 CALL ALLOCATE 19300 POP AX 19310 JC WRTERR 19320 MOV CX,AX 19330 MOV DX,[LASTPOS] 19340 INC DX 19350 DEC CX 19360 JZ NOSKIP 19370 CALL SKPCLP 19380 NOSKIP: 19390 MOV [CLUSNUM],BX 19400 MOV [LASTPOS],DX 19410 DOWRT: 19420 CMP [BYTCNT1],0 19430 JZ WRTMID 19440 MOV BX,[CLUSNUM] 19450 CALL BUFWRT 19460 WRTMID: 19470 MOV AX,[SECCNT] 19480 OR AX,AX 19490 JZ WRTLAST 19500 ADD [SECPOS],AX 19510 CALL NEXTSEC 19520 MOV B,[TRANS],1 ;A transfer is taking place 19530 MOV DL,[SECCLUSPOS] 19540 MOV BX,[CLUSNUM] 19550 MOV CX,[SECCNT] 19560 WRTLP: 19570 CALL OPTIMIZE 19580 PUSH DI 19590 PUSH AX 19600 PUSH DS 19610 MOV DS,[DMAADD+2] 19620 CALL DWRITE 19630 POP DS 19640 POP CX 19650 POP BX 19660 JCXZ WRTLAST 19670 MOV DL,0 19680 INC [LASTPOS] ;We'll be using next cluster 19690 JP WRTLP 19700 WRTLAST: 19710 MOV AX,[BYTCNT2] 19720 OR AX,AX 19730 JZ FINWRT 19740 MOV [BYTCNT1],AX 19750 CALL NEXTSEC 19760 MOV [BYTSECPOS],0 19770 CALL BUFWRT 19780 FINWRT: 19790 MOV AX,[NEXTADD] 19800 SUB AX,[DMAADD] 19810 ADD AX,[BYTPOS] 19820 MOV DX,[BYTPOS+2] 19830 ADC DX,0 19840 MOV CX,DX 19850 MOV DI,[FCB] 19860 SEG ES 19870 CMP AX,[DI+FILSIZ] 19880 SEG ES 19890 SBB CX,[DI+FILSIZ+2] 19900 JB SAMSIZ 19910 SEG ES 19920 MOV [DI+FILSIZ],AX 19930 SEG ES 19940 MOV [DI+FILSIZ+2],DX 19950 SAMSIZ: 19960 MOV CX,[RECCNT] 19970 JMP SETCLUS 19980 19990 20000 WRTERRJ:JMP WRTERR 20010 20020 WRTEOF: 20030 MOV CX,AX 20040 OR CX,DX 20050 JZ KILLFIL 20060 SUB AX,1 20070 SBC DX,0 20080 DIV AX,[BP+SECSIZ] 20090 MOV CL,[BP+CLUSSHFT] 20100 SHR AX,CL 20110 MOV CX,AX 20120 CALL FNDCLUS 20130 JCXZ RELFILE 20140 CALL ALLOCATE 20150 JC WRTERRJ 20160 UPDATE: 20170 MOV DI,[FCB] 20180 MOV AX,[BYTPOS] 20190 SEG ES 20200 MOV [DI+FILSIZ],AX 20210 MOV AX,[BYTPOS+2] 20220 SEG ES 20230 MOV [DI+FILSIZ+2],AX 20240 XOR CX,CX 20250 RET 20260 20270 RELFILE: 20280 MOV DX,0FFFH 20290 CALL RELBLKS 20300 SETDIRT: 20310 MOV B,[BP+DIRTYFAT],1 20320 JP UPDATE 20330 20340 KILLFIL: 20350 XOR BX,BX 20360 SEG ES 20370 XCHG BX,[DI+FIRCLUS] 20380 OR BX,BX 20390 JZ UPDATE 20400 CALL RELEASE 20410 JP SETDIRT 20420 20430 20440 OPTIMIZE: 20450 20460 ; Inputs: 20470 ; DS = CS 20480 ; BX = Physical cluster 20490 ; CX = No. of records 20500 ; DL = sector within cluster 20510 ; BP = Base of drives parameters 20520 ; [NEXTADD] = transfer address 20530 ; Outputs: 20540 ; AX = No. of records remaining 20550 ; BX = Transfer address 20560 ; CX = No. or records to be transferred 20570 ; DX = Physical sector address 20580 ; DI = Next cluster 20590 ; [CLUSNUM] = Last cluster accessed 20600 ; [NEXTADD] updated 20610 ; BP unchanged. Note that segment of transfer not set. 20620 20630 PUSH DX 20640 PUSH BX 20650 MOV AL,[BP+CLUSMSK] 20660 INC AL ;Number of sectors per cluster 20670 MOV AH,AL 20680 SUB AL,DL ;AL = Number of sectors left in first cluster 20690 MOV DX,CX 20700 LEA SI,[BP+FAT] 20710 MOV CX,0 20720 OPTCLUS: 20730 ;AL has number of sectors available in current cluster 20740 ;AH has number of sectors available in next cluster 20750 ;BX has current physical cluster 20760 ;CX has number of sequential sectors found so far 20770 ;DX has number of sectors left to transfer 20780 ;SI has FAT pointer 20790 CALL UNPACK 20800 ADD CL,AL 20810 ADC CH,0 20820 CMP CX,DX 20830 JAE BLKDON 20840 MOV AL,AH 20850 INC BX 20860 CMP DI,BX 20870 JZ OPTCLUS 20880 DEC BX 20890 FINCLUS: 20900 MOV [CLUSNUM],BX ;Last cluster accessed 20910 SUB DX,CX ;Number of sectors still needed 20920 PUSH DX 20930 MOV AX,CX 20940 MUL AX,[BP+SECSIZ] ;Number of sectors times sector size 20950 MOV SI,[NEXTADD] 20960 ADD AX,SI ;Adjust by size of transfer 20970 MOV [NEXTADD],AX 20980 POP AX ;Number of sectors still needed 20990 POP DX ;Starting cluster 21000 SUB BX,DX ;Number of new clusters accessed 21010 ADD [LASTPOS],BX 21020 POP BX ;BL = sector postion within cluster 21030 CALL FIGREC 21040 MOV BX,SI 21050 RET 21060 BLKDON: 21070 SUB CX,DX ;Number of sectors in cluster we don't want 21080 SUB AH,CL ;Number of sectors in cluster we accepted 21090 DEC AH ;Adjust to mean position within cluster 21100 MOV [SECCLUSPOS],AH 21110 MOV CX,DX ;Anyway, make the total equal to the request 21120 JP FINCLUS 21130 21140 21150 FIGREC: 21160 21170 ;Inputs: 21180 ; DX = Physical cluster number 21190 ; BL = Sector postion within cluster 21200 ; BP = Base of drive parameters 21210 ;Outputs: 21220 ; DX = physical sector number 21230 ;No other registers affected. 21240 21250 PUSH CX 21260 MOV CL,[BP+CLUSSHFT] 21270 DEC DX 21280 DEC DX 21290 SHL DX,CL 21300 OR DL,BL 21310 ADD DX,[BP+FIRREC] 21320 POP CX 21330 RET 21340 21350 GETREC: 21360 21370 ; Inputs: 21380 ; DS:DX point to FCB 21390 ; Outputs: 21400 ; CX = 1 21410 ; DX:AX = Record number determined by EXTENT and NR fields 21420 ; DS:DI point to FCB 21430 ; No other registers affected. 21440 21450 MOV DI,DX 21460 MOV CX,1 21470 MOV AL,[DI+NR] 21480 MOV DX,[DI+EXTENT] 21490 SHL AL 21500 SHR DX 21510 RCR AL 21520 MOV AH,DL 21530 MOV DL,DH 21540 MOV DH,0 21550 RET 21560 21570 21580 ALLOCATE: 21590 21600 ; Inputs: 21610 ; DS = CS 21620 ; ES = Segment of FCB 21630 ; BX = Last cluster of file (0 if null file) 21640 ; CX = No. of clusters to allocate 21650 ; DX = Position of cluster BX 21660 ; BP = Base of drive parameters 21670 ; SI = FAT pointer 21680 ; [FCB] = Displacement of FCB within segment 21690 ; Outputs: 21700 ; IF insufficient space 21710 ; THEN 21720 ; Carry set 21730 ; CX = max. no. of records that could be added to file 21740 ; ELSE 21750 ; Carry clear 21760 ; BX = First cluster allocated 21770 ; FAT is fully updated including dirty bit 21780 ; FIRCLUS field of FCB set if file was null 21790 ; SI,BP unchanged. All other registers destroyed. 21800 21810 PUSH [SI] 21820 PUSH DX 21830 PUSH CX 21840 PUSH BX 21850 MOV AX,BX 21860 ALLOC: 21870 MOV DX,BX 21880 FINDFRE: 21890 INC BX 21900 CMP BX,[BP+MAXCLUS] 21910 JLE TRYOUT 21920 CMP AX,1 21930 JG TRYIN 21940 POP BX 21950 MOV DX,0FFFH 21960 CALL RELBLKS 21970 POP AX ;No. of clusters requested 21980 SUB AX,CX ;AX=No. of clusters allocated 21990 POP DX 22000 POP [SI] 22010 INC DX ;Position of first cluster allocated 22020 ADD AX,DX ;AX=max no. of cluster in file 22030 MOV DL,[BP+CLUSMSK] 22040 MOV DH,0 22050 INC DX ;DX=records/cluster 22060 MUL AX,DX ;AX=max no. of records in file 22070 MOV CX,AX 22080 SUB CX,[RECPOS] ;CX=max no. of records that could be written 22090 JA MAXREC 22100 XOR CX,CX ;If CX was negative, zero it 22110 MAXREC: 22120 STC 22130 RET 22140 22150 TRYOUT: 22160 CALL UNPACK 22170 JZ HAVFRE 22180 TRYIN: 22190 DEC AX 22200 JLE FINDFRE 22210 XCHG AX,BX 22220 CALL UNPACK 22230 JZ HAVFRE 22240 XCHG AX,BX 22250 JP FINDFRE 22260 HAVFRE: 22270 XCHG BX,DX 22280 MOV AX,DX 22290 CALL PACK 22300 MOV BX,AX 22310 LOOP ALLOC 22320 MOV DX,0FFFH 22330 CALL PACK 22340 MOV B,[BP+DIRTYFAT],1 22350 POP BX 22360 POP CX ;Don't need this stuff since we're successful 22370 POP DX 22380 CALL UNPACK 22390 POP [SI] 22400 XCHG BX,DI 22410 OR DI,DI 22420 JNZ RET 22430 MOV DI,[FCB] 22440 SEG ES 22450 MOV [DI+FIRCLUS],BX 22460 RET 22470 22480 22490 RELEASE: 22500 22510 ; Inputs: 22520 ; DS = CS 22530 ; BX = Cluster in file 22540 ; SI = FAT pointer 22550 ; BP = Base of drive parameters 22560 ; Function: 22570 ; Frees cluster chain starting with [BX] 22580 ; AX,BX,DX,DI all destroyed. Other registers unchanged. 22590 22600 XOR DX,DX 22610 RELBLKS: 22620 ; Enter here with DX=0FFFH to put an end-of-file mark 22630 ; in the first cluster and free the rest in the chain. 22640 CALL UNPACK 22650 JZ RET 22660 MOV AX,DI 22670 CALL PACK 22680 CMP AX,0FF8H 22690 MOV BX,AX 22700 JB RELEASE 22710 RET 22720 22730 22740 GETEOF: 22750 22760 ; Inputs: 22770 ; BX = Cluster in a file 22780 ; SI = Base of drive FAT 22790 ; DS = CS 22800 ; Outputs: 22810 ; BX = Last cluster in the file 22820 ; DI destroyed. No other registers affected. 22830 22840 CALL UNPACK 22850 CMP DI,0FF8H 22860 JAE RET 22870 MOV BX,DI 22880 JP GETEOF 22890 22900 22910 SRCHFRST: ;System call 17 22920 PUSH DX 22930 PUSH DS 22940 CALL GETFILE 22950 SAVPLCE: 22960 ; Search-for-next enters here to save place and report 22970 ; findings. 22980 POP ES 22990 POP DI 23000 JC KILLSRCH 23010 CMP BH,-1 23020 JZ SRCHDEV 23030 MOV AX,[LASTENT] 23040 SEG ES 23050 MOV [DI+FILDIRBLK],AX 23060 ;Information in directory entry must be copied into the first 23070 ; 33 bytes starting at the disk transfer address. 23080 MOV SI,BX 23090 LES DI,[DMAADD] 23100 MOV AL,[BP+DRVNUM] 23110 INC AL 23120 STOB ;Set drive number 23130 MOVB ;Copy first character of name 23140 MOV CX,5 23150 REP 23160 MOVW ;Copy remaining 10 characters of name 23170 XOR AX,AX 23180 23190 IF SMALLDIR 23200 CMP B,[BP+DIRSIZ],-1 23210 JNZ BIGENT5 23220 STOB ;Zero out unused portion 23230 MOV CX,7 23240 REP 23250 STOW ;Zero a total of 15 bytes 23260 MOVW ;Copy first cluster pointer 23270 MOVW ;Copy low word of length 23280 MOVB ;Copy 3rd byte of length 23290 STOB ;4th byte of length must be zero 23300 RET 23310 BIGENT5: 23320 ENDIF 23330 23340 MOV CX,10 23350 REP 23360 MOVW 23370 MOVB 23380 RET 23390 23400 KILLSRCH: 23410 SEG ES 23420 KILLSRCH1: 23430 MOV [DI+FILDIRBLK],-2 23440 MOV AL,-1 23450 RET 23460 23470 SRCHDEV: 23480 SEG ES 23490 MOV [DI+FILDIRBLK],BX 23500 LES DI,[DMAADD] 23510 XOR AX,AX 23520 STOB ;Zero drive byte 23530 SUB SI,3 ;Point to device name 23540 MOVW 23550 MOVB 23560 MOV AX,2020H 23570 MOV CX,4 23580 REP 23590 STOW ;Fill with 8 blanks 23600 XOR AX,AX 23610 MOV CX,10 23620 REP 23630 STOW 23640 STOB 23650 RET 23660 23670 SRCHNXT: ;System call 18 23680 CALL MOVNAME 23690 MOV DI,DX 23700 JC KILLSRCH1 23710 PUSH DX 23720 PUSH DS 23730 MOV AX,[DI+FILDIRBLK] 23740 PUSH CS 23750 POP DS 23760 MOV [LASTENT],AX 23770 CALL CONTSRCH 23780 JMP SAVPLCE 23790 23800 23810 FILESIZE: ;System call 35 23820 PUSH DS 23830 PUSH DX 23840 CALL GETFILE 23850 POP DI 23860 POP ES 23870 MOV AL,-1 23880 JC RET 23890 ADD DI,33 ;Write size in RR field 23900 SEG ES 23910 MOV CX,[DI-33+RECSIZ] 23920 OR CX,CX 23930 JNZ RECOK 23940 MOV CX,128 23950 RECOK: 23960 XOR AX,AX 23970 XOR DX,DX ;Intialize size to zero 23980 CMP BH,-1 ;Check for named I/O device 23990 JZ DEVSIZ 24000 INC SI 24010 INC SI ;Point to length field 24020 MOV AX,[SI+2] ;Get high word of size 24030 24040 IF SMALLDIR 24050 CMP B,[BP+DIRSIZ],-1 24060 JNZ BIGSIZ 24070 MOV AH,0 24080 BIGSIZ: 24090 ENDIF 24100 24110 DIV AX,CX 24120 PUSH AX ;Save high part of result 24130 LODW ;Get low word of size 24140 DIV AX,CX 24150 OR DX,DX ;Check for zero remainder 24160 POP DX 24170 JZ DEVSIZ 24180 INC AX ;Round up for partial record 24190 JNZ DEVSIZ ;Propagate carry? 24200 INC DX 24210 DEVSIZ: 24220 STOW 24230 MOV AX,DX 24240 STOB 24250 MOV AL,0 24260 CMP CX,64 24270 JAE RET ;Only 3-byte field if RECSIZ >= 64 24280 SEG ES 24290 MOV [DI],AH 24300 RET 24310 24320 24330 SETDMA: ;System call 26 24340 SEG CS 24350 MOV [DMAADD],DX 24360 SEG CS 24370 MOV [DMAADD+2],DS 24380 RET 24390 24400 24410 GETFATPT: ;System call 27 24420 MOV AX,CS 24430 MOV DS,AX 24440 MOV BP,[CURDRVPT] 24450 CALL FATREAD 24460 LEA BX,[BP+FAT] 24470 MOV AL,[BP+CLUSMSK] 24480 INC AL 24490 MOV DX,[BP+MAXCLUS] 24500 DEC DX 24510 MOV B,[BP+DIRTYFAT],1 24520 MOV CX,[BP+SECSIZ] 24530 LDS SI,[SPSAVE] 24540 MOV [SI+BXSAVE],BX 24550 MOV [SI+DXSAVE],DX 24560 MOV [SI+CXSAVE],CX 24570 MOV [SI+DSSAVE],CS 24580 RET 24590 24600 24610 GETDSKPT: ;System call 31 24620 SEG CS 24630 MOV BX,[CURDRVPT] 24640 SEG CS 24650 LDS SI,[SPSAVE] 24660 MOV [SI+BXSAVE],BX 24670 MOV [SI+DSSAVE],CS 24680 RET 24690 24700 24710 DSKRESET: ;System call 13 24720 SEG CS 24730 MOV [DMAADD+2],DS 24740 MOV AX,CS 24750 MOV DS,AX 24760 MOV [DMAADD],80H 24770 MOV AX,[CURDRVPT+2] 24780 MOV [CURDRVPT],AX 24790 WRTFATS: 24800 ; DS=CS. Writes back all dirty FATs. All registers destroyed. 24810 MOV CL,[NUMDRV] 24820 MOV CH,0 24830 MOV SI,CURDRVPT+2 24840 WRTFAT: 24850 LODW 24860 PUSH CX 24870 PUSH SI 24880 MOV BP,AX 24890 CALL CHKFATWRT 24900 POP SI 24910 POP CX 24920 LOOP WRTFAT 24930 MOV AX,[BUFDRVNO] 24940 OR AH,AH 24950 JZ RET 24960 CBW 24970 MOV BX,AX 24980 SHL BX 24990 MOV BP,[BX+DRVTAB] 25000 MOV B,[DIRTYBUF],0 25010 MOV DX,[BUFSECNO] 25020 MOV BX,BUFFER 25030 MOV CX,1 25040 JMP DWRITE 25050 25060 25070 CURDRV: ;System call 25 25080 SEG CS 25090 MOV BP,[CURDRVPT] 25100 MOV AL,[BP+DRVNUM] 25110 RET 25120 25130 25140 INUSE: ;System call 24 25150 MOV AX,CS 25160 MOV DS,AX 25170 MOV CL,[NUMDRV] 25180 MOV CH,0 25190 MOV SI,CX 25200 SHL SI 25210 ADD SI,CURDRVPT 25220 MOV BX,0 25230 DOWN 25240 CHKUSE: 25250 LODW 25260 MOV BP,AX 25270 CMP B,[BP+DIRTYFAT],-1 ;Carry set if not equal 25280 RCL BX 25290 LOOP CHKUSE 25300 MOV AL,BL 25310 RET 25320 25330 25340 SETRNDREC: ;System call 36 25350 CALL GETREC 25360 MOV [DI+33],AX 25370 MOV [DI+35],DL 25380 RET 25390 25400 25410 SELDSK: ;System call 14 25420 MOV DH,0 25430 MOV BX,DX 25440 PUSH CS 25450 POP DS 25460 MOV AL,[NUMDRV] 25470 CMP BL,AL 25480 JNB RET 25490 SHL BX 25500 MOV DX,[BX+CURDRVPT+2] 25510 MOV [CURDRVPT],DX 25520 RET 25530 25540 25550 BUFIN: ;System call 10 25560 MOV AX,CS 25570 MOV ES,AX 25580 MOV SI,DX 25590 MOV CH,0 25600 LODW 25610 OR AL,AL 25620 JZ RET 25630 MOV BL,AH 25640 MOV BH,CH 25650 CMP AL,BL 25660 JBE NOEDIT 25670 CMP B,[BX+SI],0DH 25680 JZ EDITON 25690 NOEDIT: 25700 MOV BL,CH 25710 EDITON: 25720 MOV DL,AL 25730 DEC DX 25740 NEWLIN: 25750 SEG CS 25760 MOV AL,[CARPOS] 25770 SEG CS 25780 MOV [STARTPOS],AL 25790 PUSH SI 25800 MOV DI,INBUF 25810 MOV AH,CH 25820 MOV BH,CH 25830 MOV DH,CH 25840 GETCH: 25850 CALL IN 25860 CMP AL,7FH 25870 JZ BACKSP 25880 CMP AL,8 25890 JZ BACKSP 25900 CMP AL,13 25910 JZ ENDLIN 25920 CMP AL,10 25930 JZ PHYCRLF 25940 CMP AL,"X"-"@" 25950 JZ KILNEW 25960 CMP AL,ESCCH 25970 JZ ESC 25980 SAVCH: 25990 CMP DH,DL 26000 JAE GETCH 26010 STOB 26020 INC DH 26030 CALL BUFOUT 26040 OR AH,AH 26050 JNZ GETCH 26060 CMP BH,BL 26070 JAE GETCH 26080 INC SI 26090 INC BH 26100 JP GETCH 26110 26120 ESC: 26130 CALL IN 26140 MOV CL,ESCTABLEN 26150 PUSH DI 26160 MOV DI,ESCTAB 26170 REPNE 26180 SCAB 26190 POP DI 26200 AND CL,0FEH 26210 MOV BP,CX 26220 SEG CS ;To work in init 26230 JMP [BP+ESCFUNC] 26240 26250 ENDLIN: 26260 STOB 26270 CALL OUT 26280 POP DI 26290 MOV [DI-1],DH 26300 INC DH 26310 COPYNEW: 26320 MOV BP,ES 26330 MOV BX,DS 26340 MOV ES,BX 26350 MOV DS,BP 26360 MOV SI,INBUF 26370 MOV CL,DH 26380 REP 26390 MOVB 26400 RET 26410 CRLF: 26420 MOV AL,13 26430 CALL OUT 26440 MOV AL,10 26450 JMP OUT 26460 26470 PHYCRLF: 26480 CALL CRLF 26490 JP GETCH 26500 26510 KILNEW: 26520 MOV AL,"\" 26530 CALL OUT 26540 POP SI 26550 PUTNEW: 26560 CALL CRLF 26570 SEG CS 26580 MOV AL,[STARTPOS] 26590 CALL TAB 26600 JMP NEWLIN 26610 26620 BACKSP: 26630 OR DH,DH 26640 JZ OLDBAK 26650 CALL BACKUP 26660 SEG ES 26670 MOV AL,[DI] 26680 CMP AL," " 26690 JAE OLDBAK 26700 CMP AL,9 26710 JZ BAKTAB 26720 CALL BACKMES 26730 OLDBAK: 26740 OR AH,AH 26750 JNZ GETCH1 26760 OR BH,BH 26770 JZ GETCH1 26780 DEC BH 26790 DEC SI 26800 GETCH1: 26810 JMP GETCH 26820 BAKTAB: 26830 PUSH DI 26840 DEC DI 26850 DOWN 26860 MOV CL,DH 26870 MOV AL," " 26880 PUSH BX 26890 MOV BL,7 26900 JCXZ FIGTAB 26910 FNDPOS: 26920 SCAB 26930 JNA CHKCNT 26940 SEG ES 26950 CMP B,[DI+1],9 26960 JZ HAVTAB 26970 DEC BL 26980 CHKCNT: 26990 LOOP FNDPOS 27000 FIGTAB: 27010 SEG CS 27020 SUB BL,[STARTPOS] 27030 HAVTAB: 27040 SUB BL,DH 27050 ADD CL,BL 27060 AND CL,7 27070 UP 27080 POP BX 27090 POP DI 27100 JZ OLDBAK 27110 TABBAK: 27120 CALL BACKMES 27130 LOOP TABBAK 27140 JP OLDBAK 27150 BACKUP: 27160 DEC DH 27170 DEC DI 27180 BACKMES: 27190 MOV AL,8 27200 CALL OUT 27210 MOV AL," " 27220 CALL OUT 27230 MOV AL,8 27240 JMP OUT 27250 27260 TWOESC: 27270 MOV AL,ESCCH 27280 JMP SAVCH 27290 27300 COPYLIN: 27310 MOV CL,BL 27320 SUB CL,BH 27330 JP COPYEACH 27340 27350 COPYSTR: 27360 CALL FINDOLD 27370 JP COPYEACH 27380 27390 COPYONE: 27400 MOV CL,1 27410 COPYEACH: 27420 CMP DH,DL 27430 JZ GETCH2 27440 CMP BH,BL 27450 JZ GETCH2 27460 LODB 27470 STOB 27480 CALL BUFOUT 27490 INC BH 27500 INC DH 27510 LOOP COPYEACH 27520 GETCH2: 27530 JMP GETCH 27540 27550 SKIPONE: 27560 CMP BH,BL 27570 JZ GETCH2 27580 INC BH 27590 INC SI 27600 JMP GETCH 27610 27620 SKIPSTR: 27630 CALL FINDOLD 27640 ADD SI,CX 27650 ADD BH,CL 27660 JMP GETCH 27670 27680 FINDOLD: 27690 CALL IN 27700 MOV CL,BL 27710 SUB CL,BH 27720 JZ NOTFND 27730 DEC CX 27740 JZ NOTFND 27750 PUSH ES 27760 PUSH DS 27770 POP ES 27780 PUSH DI 27790 MOV DI,SI 27800 INC DI 27810 REPNE 27820 SCAB 27830 POP DI 27840 POP ES 27850 JNZ NOTFND 27860 NOT CL 27870 ADD CL,BL 27880 SUB CL,BH 27890 RET 27900 NOTFND: 27910 POP BP 27920 JMP GETCH 27930 27940 REEDIT: 27950 MOV AL,"@" 27960 CALL OUT 27970 POP DI 27980 PUSH DI 27990 PUSH ES 28000 PUSH DS 28010 CALL COPYNEW 28020 POP DS 28030 POP ES 28040 POP SI 28050 MOV BL,DH 28060 JMP PUTNEW 28070 28080 ENTERINS: 28090 MOV AH,-1 28100 JMP GETCH 28110 28120 EXITINS: 28130 MOV AH,0 28140 JMP GETCH 28150 28160 ESCFUNC: 28170 DW GETCH 28180 DW TWOESC 28190 DW EXITINS 28200 DW ENTERINS 28210 DW BACKSP 28220 DW REEDIT 28230 DW KILNEW 28240 DW COPYLIN 28250 DW SKIPSTR 28260 DW COPYSTR 28270 DW SKIPONE 28280 DW COPYONE 28290 28300 BUFOUT: 28310 CMP AL," " 28320 JAE OUT 28330 CMP AL,9 28340 JZ OUT 28350 PUSH AX 28360 MOV AL,"^" 28370 CALL OUT 28380 POP AX 28390 OR AL,40H 28400 JP OUT 28410 28420 CONOUT: ;System call 2 28430 MOV AL,DL 28440 OUT: 28450 CMP AL,20H 28460 JB CTRLOUT 28470 CMP AL,7FH 28480 JZ OUTCH 28490 SEG CS 28500 INC B,[CARPOS] 28510 OUTCH: 28520 CALL BIOSOUT,BIOSSEG 28530 SEG CS 28540 TEST B,[PFLAG],-1 28550 JZ STATCHK 28560 CALL BIOSPRINT,BIOSSEG 28570 STATCHK: 28580 CALL BIOSSTAT,BIOSSEG 28590 JZ RET 28600 INCHK: 28610 CALL BIOSIN,BIOSSEG 28620 CMP AL,'S'-'@' 28630 JNZ NOSTOP 28640 CALL BIOSIN,BIOSSEG 28650 NOSTOP: 28660 CMP AL,'P'-'@' 28670 JZ PRINTON 28680 CMP AL,'N'-'@' 28690 JZ PRINTOFF 28700 CMP AL,'C'-'@' 28710 JNZ RET 28720 ; Ctrl-C handler. 28730 ; If function 9 or 10 was in progress, a backslash, CR, and LF are printed 28740 ; to show line is canceled. Then the user registers are restored and the 28750 ; user CTRL-C handler is executed. At this point the top of the stack has 28760 ; 1) the interrupt return address should the user CTRL-C handler wish to 28770 ; allow processing to continue; 2) the original interrupt return address 28780 ; to the code that performed the function call in the first place. If the 28790 ; user CTRL-C handler wishes to continue, it must leave all registers 28800 ; unchanged and IRET. The function that was interrupted will simply be 28810 ; repeated, except for console output (function 2), which has already output 28820 ; its character before the interrupt. 28830 SEG CS 28840 MOV AL,[FUNC] ;Get currently executing function 28850 CMP AL,10 ;Check if buffered line input 28860 JZ CANLIN 28870 CMP AL,9 ;Check if buffered line output 28880 JNZ RESTREG 28890 CANLIN: 28900 MOV AL,"\" ;Display cancel line symbol 28910 CALL OUT 28920 CALL CRLF 28930 RESTREG: 28940 DI ;Prepare to play with stack 28950 SEG CS 28960 MOV SS,[SSSAVE] 28970 SEG CS 28980 MOV SP,[SPSAVE] ;User stack now restored 28990 POP AX 29000 POP BX 29010 POP CX 29020 POP DX 29030 POP SI 29040 POP DI 29050 POP BP 29060 POP DS 29070 POP ES ;User registers now restored 29080 INT CONTC ;Execute user Ctrl-C handler 29090 CMP AH,2 ;Check if function was console output 29100 JZ SETAL 29110 JMP COMMAND ;Repeat command otherwise 29120 SETAL: 29130 MOV AL,DL 29140 IRET ;Return to user program 29150 29160 PRINTON: 29170 SEG CS 29180 MOV B,[PFLAG],1 29190 RET 29200 PRINTOFF: 29210 SEG CS 29220 MOV B,[PFLAG],0 29230 RET 29240 CTRLOUT: 29250 CMP AL,13 29260 JZ ZERPOS 29270 CMP AL,8 29280 JZ BACKPOS 29290 CMP AL,9 29300 JNZ OUTCHJ 29310 SEG CS 29320 MOV AL,[CARPOS] 29330 OR AL,0F8H 29340 NEG AL 29350 TAB: 29360 PUSH CX 29370 MOV CL,AL 29380 MOV CH,0 29390 TABLP: 29400 MOV AL," " 29410 CALL OUT 29420 LOOP TABLP 29430 POP CX 29440 RET 29450 29460 ZERPOS: 29470 SEG CS 29480 MOV B,[CARPOS],0 29490 OUTCHJ: JMP OUTCH 29500 29510 BACKPOS: 29520 SEG CS 29530 DEC B,[CARPOS] 29540 JMP OUTCH 29550 29560 29570 CONSTAT: ;System call 11 29580 CALL BIOSSTAT,BIOSSEG 29590 JZ RET 29600 OR AL,-1 29610 RET 29620 29630 29640 CONIN: ;System call 1 29650 CALL IN 29660 PUSH AX 29670 CALL OUT 29680 POP AX 29690 RET 29700 29710 29720 IN: ;Internal input routine 29730 CALL INCHK 29740 JZ IN 29750 RET 29760 29770 RAWIO: ;System call 6 29780 MOV AL,DL 29790 CMP AL,-1 29800 JNZ RAWOUT 29810 CALL BIOSSTAT,BIOSSEG 29820 JZ RET 29830 RAWINP: ;System call 7 29840 CALL BIOSIN,BIOSSEG 29850 RET 29860 RAWOUT: 29870 CALL BIOSOUT,BIOSSEG 29880 RET 29890 29900 LIST: ;System call 5 29910 MOV AL,DL 29920 CALL BIOSPRINT,BIOSSEG 29930 RET 29940 29950 PRTBUF: ;System call 9 29960 MOV SI,DX 29970 OUTSTR: 29980 LODB 29990 CMP AL,"$" 30000 JZ RET 30010 CALL OUT 30020 JP OUTSTR 30030 30040 OUTMES: ;String output for internal messages 30050 SEG CS 30060 LODB 30070 CMP AL,"$" 30080 JZ RET 30090 CALL OUT 30100 JP OUTMES 30110 30120 30130 MAKEFCB: ;Interrupt call 41 30140 MOV DL,0 ;Flag--not ambiguous file name 30150 OR AL,AL ;Scan off separators if not zero 30160 JZ NOSCAN 30170 SCAN: 30180 CALL GETLET 30190 JZ SCAN ;Get rid of leading separators (e.g., blanks) 30200 DEC SI ;Point back to first non-separator 30210 NOSCAN: 30220 CMP B,[SI+1],":" ;Check for potential drive specifier 30230 JNZ DEFAULT 30240 CALL GETLET 30250 SUB AL,"@" ;Convert drive letter to binary drive number 30260 JZ NODRV ;Valid drive numbers are 1-15 30270 INCcifier--back up pointer 30280 DEFAULT: 30290 XOR AL,AL 30300 HAVDRV: 30310 STOB ;Put drive specifier in first byte 30320 MOV CX,8 30330 CALL GETWORD ;Get 8-letter file name 30340 CMP B,[SI],"." 30350 JNZ NODOT 30360 INC SI ;Skip over dot if present 30370 NODOT: 30380 MOV CX,3 ;Get 3-letter extension 30390 CALL GETWORD 30400 SEG CS 30410 LDS BX,[SPSAVE] 30420 MOV [BX+SISAVE],SI 30430 XOR AX,AX 30440 STOW 30450 STOW 30460 MOV AL,DL 30470 RET 30480 30490 GETWORD: 30500 CALL GETLET 30510 JZ FILLNAM ;Exit if invalid character 30520 CMP AL," " 30530 JBE FILLNAM 30540 CMP AL,"*" ;Check for ambiguous file specifier 30550 JNZ NOSTAR 30560 MOV AL,"?" 30570 DEC CX 30580 REP 30590 STOB ;Fill rest of word with "?" 30600 INC CX 30610 NOSTAR: 30620 STOB 30630 CMP AL,"?" 30640 JNZ NOTQ 30650 MOV DL,1 ;Flag ambiguous file name 30660 NOTQ: 30670 LOOP GETWORD 30680 INC SI ;Point to "termination" character 30690 FILLNAM: 30700 MOV AL," " 30710 REP 30720 STOB 30730 DEC SI 30740 RET 30750 30760 GETLET: 30770 LODB 30780 CMP AL,"a" 30790 JB CHK 30800 CMP AL,"z" 30810 JA CHK 30820 SUB AL,20H ;Convert to upper case 30830 CHK: 30840 CMP AL," " 30850 JZ RET 30860 CMP AL,"=" 30870 JZ RET 30880 CMP AL,"," 30890 JZ RET 30900 CMP AL,";" 30910 JZ RET 30920 CMP AL,"." 30930 JZ RET 30940 CMP AL,":" 30950 JZ RET 30960 CMP AL,9 ;Filter out TABs too 30970 RET 30980 30990 31000 SETVECT: ; Interrupt call 37 31010 XOR BX,BX 31020 MOV ES,BX 31030 MOV BL,AL 31040 SHL BX 31050 SHL BX 31060 SEG ES 31070 MOV [BX],DX 31080 SEG ES 31090 MOV [BX+2],DS 31100 RET 31110 31120 31130 NEWBASE: ; Interrupt call 38 31140 MOV ES,DX 31150 SEG CS 31160 MOV DS,[CSLOC] 31170 XOR SI,SI 31180 MOV DI,SI 31190 MOV CX,80H 31200 REP 31210 MOVW 31220 31230 SETMEM: 31240 31250 ; Inputs: 31260 ; DX = Segment 31270 ; Function: 31280 ; Completely prepares a program base at the 31290 ; specified segment. 31300 ; Outputs: 31310 ; DS = DX 31320 ; ES = DX 31330 ; [0] has INT 20H 31340 ; [2] = First unavailable segment ([ENDMEM]) 31350 ; [5] to [9] form a long call to the entry point 31360 ; [10] to [13] have exit address (from INT 22H) 31370 ; [14] to [17] have ctrl-C exit address (from INT 23H) 31380 ; AX,DX,BP unchanged. All other registers destroyed. 31390 31400 XOR CX,CX 31410 MOV DS,CX 31420 MOV ES,DX 31430 MOV SI,EXIT 31440 MOV DI,SAVEXIT 31450 MOVW 31460 MOVW 31470 MOVW 31480 MOVW 31490 SEG CS 31500 MOV CX,[ENDMEM] 31510 SEG ES 31520 MOV [2],CX 31530 SUB CX,DX 31540 CMP CX,MAXDIF 31550 JBE HAVDIF 31560 MOV CX,MAXDIF 31570 HAVDIF: 31580 MOV BX,ENTRYPOINTSEG 31590 SUB BX,CX 31600 SHL CX 31610 SHL CX 31620 SHL CX 31630 SHL CX 31640 MOV DS,DX 31650 MOV [6],CX 31660 MOV [8],BX 31670 MOV [0],20CDH ;"INT INTTAB" 31680 MOV B,[5],LONGCALL 31690 RET 31700 31710 31720 SHFTDI7: 31730 SHL DI 31740 SHL DI 31750 SHL DI 31760 SHL DI 31770 SHL DI 31780 SHL DI 31790 SHL DI 31800 RET 31810 31820 31830 ; Default handler for division overflow trap 31840 DIVOV: 31850 XOR DX,DX ;Say no remainder 31860 MOV AX,-1 ;But large quotient 31870 IRET 31880 31890 31900 ;***** DATA AREA ***** 31910 31920 BADMES: DB 13,10,"Bad FAT",13,10,"$" 31930 BADFATMES:DB 13,10,"All FATs on disk are bad",13,10,"$" 31940 RDERRMES:DB 13,10,"Disk read error",13,10,"$" 31950 WRTERRMES:DB 13,10,"Disk write error",13,10,"$" 31960 IONAME: DB "PRN","LST","AUX","CON" 31970 31980 CARPOS: DB 0 31990 STARTPOS:DB 0 32000 PFLAG: DB 0 32010 DIRTYDIR:DB 0 ;Dirty buffer flag 32020 NUMDRV: DS 1 ;Number of drives 32030 CONTPOS:DW 0 32040 DMAADD: DW 80H ;User's disk transfer address (disp/seg) 32050 DS 2 32060 ENDMEM: DS 2 32070 MAXSEC: DW 0 32080 BUFFER: DS 2 32090 BUFSECNO:DW 0 32100 BUFDRVNO:DB -1 32110 DIRTYBUF:DB 0 32120 DIRBUFID:DW -1 32130 DATE: DS 2 32140 CURDRVPT:DS 2 32150 DRVTAB: DS 30 ;Enough for 15 drives 32160 INBUF: DS 15 ;Only the first part 32170 32180 ; Init code overlaps with data area below 32190 32200 INITCODE: 32210 32220 DS 128-15 ;More of INBUF 32230 CONBUF: DS 130 ;The rest of INBUF and console buffer 32240 FUNC: DS 1 ;Currently executing function code 32250 LASTENT:DS 2 32260 EXITHOLD:DS 4 32270 FATBASE:DS 2 32280 NAME1: DS 11 ;File name buffer 32290 NAME2: DS 11 32300 TEMP: 32310 CSLOC: DS 2 32320 SPSAVE: DS 2 32330 SSSAVE: DS 2 32340 SECCLUSPOS:DS 1 ;Position of first sector within cluster 32350 DSKERR: DS 1 32360 TRANS: DS 1 32370 32380 ALIGN 32390 FCB: DS 2 ;Address of user FCB 32400 NEXTADD:DS 2 32410 RECPOS: DS 4 32420 RECCNT: DS 2 32430 LASTPOS:DS 2 32440 CLUSNUM:DS 2 32450 SECPOS: DS 2 ;Position of first sector accessed 32460 VALSEC: DS 2 ;Number of valid (previously written) sectors 32470 BYTSECPOS:DS 2 ;Position of first byte within sector 32480 BYTPOS: DS 4 ;Byte position in file of access 32490 BYTCNT1:DS 2 ;No. of bytes in first sector 32500 BYTCNT2:DS 2 ;No. of bytes in last sector 32510 SECCNT: DS 2 ;No. of whole sectors 32520 32530 DS 60 ;Stack space 32540 STACK: 32550 32560 IF DSKTEST 32570 NSS: DS 2 32580 NSP: DS 2 32590 DS 60 32600 TESTSTK: 32610 ENDIF 32620 32630 DIRBUF: 32640 32650 ;Init code below overlaps with data area above 32660 32670 ORG INITCODE 32680 PUT $+100H 32690 32700 MOVFAT: 32710 ;This section of code is safe from being overwritten by block move 32720 SEG ES 32730 REP 32740 MOVB 32750 UP 32760 FININIT: 32770 CALL SETMEM ;Set up segment 32780 RET L 32790 32800 DOSINIT: 32810 DI 32820 UP 32830 PUSH CS 32840 POP ES 32850 LODB 32860 SEG ES 32870 MOV [NUMDRV],AL 32880 MOV BX,DRVTAB 32890 MOV DI,MEMSTRT 32900 PERDRV: 32910 SEG ES 32920 MOV [BX],DI 32930 MOV BP,DI 32940 INC BX 32950 INC BX 32960 SEG ES 32970 MOV AL,[DRVCNT] 32980 STOB ;DRVNUM 32990 LODW ;Pointer to DPT 33000 PUSH SI 33010 MOV SI,AX 33020 LODW 33030 STOW ;SECSIZ 33040 MOV DX,AX 33050 SEG ES 33060 CMP AX,[MAXSEC] 33070 JBE NOTMAX 33080 SEG ES 33090 MOV [MAXSEC],AX 33100 NOTMAX: 33110 LODB 33120 DEC AL 33130 STOB ;CLUSMSK 33140 JZ HAVSHFT 33150 CBW 33160 FIGSHFT: 33170 INC AH 33180 SAR AL 33190 JNZ FIGSHFT 33200 MOV AL,AH 33210 HAVSHFT: 33220 STOB ;CLUSSHFT 33230 MOVW ;FIRFAT (= number of reserved sectors) 33240 MOVB ;FATCNT 33250 MOVW ;MAXENT 33260 MOV AX,DX ;SECSIZ again 33270 MOV CL,5 33280 SHR AX,CL 33290 MOV CX,AX ;Directory entries per sector 33300 DEC AX 33310 SEG ES 33320 ADD AX,[BP+MAXENT] 33330 XOR DX,DX 33340 DIV AX,CX 33350 STOW ;DIRSEC (temporarily) 33360 SHR AX ;Divide by two 33370 ADC AX,0 ;Round up 33380 SEG ES 33390 MOV [SDIRSEC],AX ;Number of directory records for small entries 33400 MOVW ;DSKSIZ (temporarily) 33410 FNDFATSIZ: 33420 MOV AL,1 33430 MOV DX,1 33440 GETFATSIZ: 33450 PUSH DX 33460 CALL FIGFATSIZ 33470 POP DX 33480 CMP AL,DL ;Compare newly computed FAT size with trial 33490 JZ HAVFATSIZ ;Has sequence converged? 33500 CMP AL,DH ;Compare with previous trial 33510 MOV DH,DL 33520 MOV DL,AL ;Shuffle trials 33530 JNZ GETFATSIZ ;Continue iterations if not oscillating 33540 SEG ES 33550 DEC [BP+DSKSIZ] ;Damp those oscillations 33560 JP FNDFATSIZ ;Try again 33570 HAVFATSIZ: 33580 STOB ;FATSIZ 33590 SEG ES 33600 MUL AL,[BP+FATCNT] ;Space occupied by all FATs 33610 SEG ES 33620 ADD AX,[BP+FIRFAT] 33630 STOW ;FIRDIR 33640 33650 IF SMALLDIR-1 33660 SEG ES 33670 ADD AX,[BP+DIRSEC] 33680 SEG ES 33690 MOV [BP+FIRREC],AX ;Destroys DIRSEC 33700 CALL FIGMAX 33710 SEG ES 33720 MOV [BP+MAXCLUS],CX 33730 ENDIF 33740 33750 IF SMALLDIR 33760 MOV DX,AX ;Save FIRDIR momentarily 33770 SEG ES 33780 ADD AX,[SDIRSEC] ;Add number of dir. sectors for 16-byte entry 33790 STOW ;FIRREC1 33800 XCHG AX,CX ;Previously computed MAXCLUS 33810 STOW ;MAXCLUS1 33820 XCHG DX,AX 33830 SEG ES 33840 ADD AX,[BP+DIRSEC] ;Add number of dir. sectores for 32-byte entry 33850 STOW ;FIRREC2 33860 CALL FIGMAX 33870 XCHG AX,CX 33880 STOW ;MAXCLUS2 33890 ENDIF 33900 33910 MOV AX,0FFH 33920 STOB ;DIRTYFAT 33930 SEG ES 33940 MOV AL,[BP+FATSIZ] 33950 SEG ES 33960 MUL AX,[BP+SECSIZ] 33970 ADD DI,AX ;Allocate FAT 33980 POP SI ;Restore pointer to init. table 33990 SEG ES 34000 MOV AL,[DRVCNT] 34010 INC AL 34020 SEG ES 34030 MOV [DRVCNT],AL 34040 SEG ES 34050 CMP AL,[NUMDRV] 34060 JAE CONTINIT 34070 JMP PERDRV 34080 CONTINIT: 34090 LODW ;Max. buffer size 34100 SEG ES 34110 MOV BX,[MAXSEC] 34120 MOV AX,DIRBUF 34130 ADD AX,BX 34140 SEG ES 34150 MOV [BUFFER],AX ;Start of buffer 34160 PUSH DI ;Save ending location 34170 ADD DI,BX ;Allocate directory buffer 34180 ADD DI,BX ;Allocate buffer space 34190 ADD DI,ADJFAC+15 ;True start of free space 34200 MOV CL,4 34210 SHR DI,CL ;First free segment 34220 MOV BP,DI 34230 XOR AX,AX 34240 MOV DS,AX 34250 MOV ES,AX 34260 MOV DI,INTBASE 34270 MOV AX,QUIT 34280 STOW ;Set abort address--displacement 34290 MOV AX,CS 34300 MOV B,[ENTRYPOINT],LONGJUMP 34310 MOV [ENTRYPOINT+1],ENTRY 34320 MOV [ENTRYPOINT+3],AX 34330 MOV [0],DIVOV ;Set default divide trap address 34340 MOV [2],AX 34350 MOV CX,9 34360 REP 34370 STOW ;Set 5 segments (skip 2 between each) 34380 MOV [INTBASE+4],COMMAND 34390 MOV [INTBASE+12],IRET ;CTRL-C exit 34400 MOV [INTBASE+16],IRET ;Fatal error exit 34410 MOV AX,BIOSREAD 34420 STOW 34430 MOV AX,BIOSSEG 34440 STOW 34450 STOW ;Add 2 to DI 34460 STOW 34470 MOV [INTBASE+18H],BIOSWRITE 34480 MOV DX,CS 34490 MOV DS,DX 34500 ADD DX,BP 34510 MOV [DMAADD],80H 34520 MOV [DMAADD+2],DX 34530 MOV AX,[DRVTAB] 34540 MOV [CURDRVPT],AX 34550 MOV CX,DX 34560 MOV BX,0FH 34570 MEMSCAN: 34580 INC CX 34590 JZ HAVMEM 34600 MOV DS,CX 34610 MOV AL,[BX] 34620 NOT AL 34630 MOV [BX],AL 34640 CMP AL,[BX] 34650 NOT AL 34660 MOV [BX],AL 34670 JZ MEMSCAN 34680 HAVMEM: 34690 SEG CS 34700 MOV [ENDMEM],CX 34710 XOR CX,CX 34720 MOV DS,CX 34730 MOV [EXIT],100H 34740 MOV [EXIT+2],DX 34750 MOV SI,HEADER 34760 CALL OUTMES 34770 PUSH CS 34780 POP DS 34790 PUSH CS 34800 POP ES 34810 PUSH DX 34820 GETDAT: 34830 MOV SI,DATMES 34840 CALL OUTMES 34850 MOV DX,DATBUF 34860 CALL BUFIN 34870 CALL CRLF 34880 MOV SI,DATBUF+2 34890 MOV DX,12 34900 CALL MYD 34910 JC GETDAT 34920 MOV CL,5 34930 SHL AX,CL 34940 MOV [DATE],AX 34950 MOV DX,31 34960 CALL MYD 34970 JC GETDAT 34980 OR [DATE],AL 34990 MOV DX,2100 35000 CALL MYD 35010 JC GETDAT 35020 SUB AX,80 35030 JC GETDAT 35040 CMP AX,19 35050 JBE SAVYR 35060 SUB AX,1900 35070 JC GETDAT 35080 SAVYR: 35090 SHL AL 35100 OR [DATE+1],AL 35110 ;Move the FATs into position and adjust the drive pointer table 35120 POP DX 35130 POP SI 35140 MOV AX,[MAXSEC] 35150 SHL AX ;Allocate two buffers 35160 ADD AX,ADJFAC 35170 JZ FINJMP 35180 MOV DI,DRVTAB 35190 MOV CX,15 35200 ADJLP: 35210 ADD [DI],AX 35220 INC DI 35230 INC DI 35240 LOOP ADJLP 35250 MOV CX,SI 35260 MOV SI,MEMSTRT ;Place to move FATs from 35270 SUB CX,SI ;Total length of FATs 35280 MOV DI,AX 35290 ADD DI,SI ;Place to move FATs to 35300 OR AX,AX 35310 JS MOVJMP 35320 DEC CX 35330 ADD DI,CX 35340 ADD SI,CX 35350 INC CX 35360 DOWN 35370 MOVJMP: 35380 JMP MOVFAT 35390 FINJMP: JMP FININIT 35400 35410 FIGFATSIZ: 35420 SEG ES 35430 MUL AL,[BP+FATCNT] 35440 SEG ES 35450 ADD AX,[BP+FIRFAT] 35460 SEG ES 35470 ADD AX,[SDIRSEC] ;Use small dir. entry to figure FAT size 35480 FIGMAX: 35490 ;AX has equivalent of FIRREC 35500 SEG ES 35510 SUB AX,[BP+DSKSIZ] 35520 NEG AX 35530 SEG ES 35540 MOV CL,[BP+CLUSSHFT] 35550 SHR AX,CL 35560 INC AX 35570 MOV CX,AX ;MAXCLUS 35580 INC AX 35590 MOV DX,AX 35600 SHR DX 35610 ADC AX,DX ;Size of FAT in bytes 35620 SEG ES 35630 MOV SI,[BP+SECSIZ] 35640 ADD AX,SI 35650 DEC AX 35660 XOR DX,DX 35670 DIV AX,SI 35680 RET 35690 35700 MYD: 35710 ;SI points to input buffer. Get decimal number < DX and return it 35720 ;in AX. Carry set on error. 35730 XOR BX,BX 35740 MOV AH,0 35750 GETDIG: 35760 LODB 35770 SUB AL,"0" 35780 JC CHKRET 35790 CMP AL,10 35800 JNC CHKRET 35810 SHL BX 35820 MOV CX,BX 35830 SHL BX 35840 SHL BX 35850 ADD BX,CX 35860 ADD BX,AX 35870 JP GETDIG 35880 CHKRET: 35890 MOV AX,BX 35900 OR AX,AX 35910 STC 35920 JZ RET 35930 CMP DX,AX 35940 RET 35950 35960 DRVCNT: DB 0 35970 35980 DATMES: DB "Enter today's date (m-d-y): $" 35990 DATBUF: DB 12,8,"04-28-81",13 36000 DS 5 36010 36020 SDIRSEC:DS 2 36030 36040 MEMSTRT: 36050 ADJFAC: EQU DIRBUF-MEMSTRT