; QDOS High-performance operating system for the 8086 version 0.11 ; by Tim Paterson ; Interrupt Entry Points: ; INTBASE: ABORT ; INTBASE+4: COMMAND ; INTBASE+8: BASE EXIT ADDRESS ; INTBASE+C: CONTROL-C ABORT ; INTBASE+10H: FATAL ERROR ABORT ; INTBASE+14H: BIOS DISK READ ; INTBASE+18H: BIOS DISK WRITE ; INTBASE+40H: Long jump to CALL entry point MAXCALL:EQU 36 MAXCOM: EQU 40 ESCCH: EQU 1BH INTBASE:EQU 80H INTTAB: EQU 20H ENTRYPOINTSEG: EQU 0CH ENTRYPOINT: EQU INTBASE+40H CONTC: EQU INTTAB+3 EXIT: EQU INTBASE+8 LONGJUMP:EQU 0EAH LONGCALL:EQU 9AH MAXDIF: EQU 0FFFH SAVEXIT:EQU 10 ; Field definition for FCBs ORG 0 DS 12 ;Drive code and name EXTENT: DS 4 ENTPOS: DS 2 ;Position of entry in directory DRVBP: DS 2 ;BP for SEARCH FIRST and SEARCH NEXT FIRCLUS:DS 2 ;First cluster of file LSTCLUS:DS 2 ;Last cluster accessed FILSIZ: DS 2 ;Size of file in records CLUSPOS:DS 2 ;Position of last cluster accessed DIRTYFIL:DS 1 ;File has been written to if <>0 SIZCHG: DS 1 ;Directory needs update if <>0 ORG 32 NR: DS 1 ;Next record RR: DS 3 ;Random record ; Description of 16-byte directory entry (same as returned by SEARCH FIRST ; and SEARCH NEXT, functions 17 and 18). ; ; Location bytes Description ; ; 0 11 File name and extension ( 0E5H if empty) ; 11 2 First allocation unit ( < 4080 ) ; 13 3 File size, in bytes (LSB first, 24 bits max.) ; Field definition for Drive Parameter Block ORG 0 DRVNUM: DS 1 ;Drive number SECSIZ: DS 1 ;Size of physical sector in records CLUSMSK:DS 1 ;Records/cluster - 1 CLUSSHFT:DS 1 ;Log2 of records/cluster FIRFAT: DS 2 ;Starting record of FATs FATSIZ: DS 1 ;Number of records occupied by FAT FATCNT: DS 1 ;Number of FATs for this drive FIRDIR: DS 2 ;Starting record of directory DIRSIZ: DS 1 ;Number of records occupied by directory FIRREC: DS 2 ;First record of first cluster MAXCLUS:DS 2 ;Number of clusters on drive + 1 DIRTYFAT:DS 1 ;-1=FAT has been changed FAT: DS 2 ;Start of FAT DPBSIZ: EQU $ ; BIOS entry point defintions BIOSSEG: EQU 40H ORG 0 DS 3 BIOSSTAT: DS 3 BIOSIN: DS 3 BIOSOUT: DS 3 BIOSPRINT: DS 3 BIOSAUXIN: DS 3 BIOSAUXOUT: DS 3 BIOSREAD: DS 3 BIOSWRITE: DS 3 BIOSFLUSH: DS 3 ; Start of code ORG 0 PUT 100H JMP DOSINIT ESCTAB: DB "SC" ;Copy one char DB "VN" ;Skip one char DB "TA" ;Copy to char DB "WB" ;Skip to char DB "UH" ;Copy line DB "HH" ;Kill line (no change in template) DB "RM" ;Reedit line (new template) DB "DD" ;Backspace DB "P@" ;Enter insert mode DB "QL" ;Exit insert mode DB ESCCH,ESCCH ;Escape character DB ESCCH,ESCCH ;End of table ESCTABLEN:EQU $-ESCTAB HEADER: DB 13,10,"86-DOS version 0.11" DB 13,10 DB "Copyright 1980 Seattle Computer Products, Inc.",13,10,"$" DOSINIT: DI UP MOV AX,CS MOV ES,AX LODB CBW MOV CX,AX SEG CS MOV [NUMDRV],AL MOV DI,AX SHL DI MOV AH,DPBSIZ MUL AX,AH MOV BX,DRVTAB ADD DI,BX ADD AX,DI MOV BP,AX SEG CS MOV [FATBASE],AX PERDEV: SEG CS MOV [BX],DI INC BX INC BX MOV AL,CH STOB ;DRVNUM LODW ;Pointer to DPT PUSH SI MOV SI,AX MOVB ;SECSIZ LODB DEC AL STOB ;CLUSMSK CBW FIGSHFT: INC AH SAR AL JNZ FIGSHFT MOV AL,AH STOB ;CLUSSHFT LODW STOW ;FIRFAT (= number of reserved records) MOV DX,AX LODB STOB ;FATSIZ MOV AH,AL PUSH AX LODB STOB ;FATCNT MUL AX,AH ADD AX,DX STOW ;FIRDIR MOV DX,AX LODB STOB ;DIRSIZ CBW ADD AX,DX STOW ;FIRREC POP DX LODW INC AX STOW ;MAXCLUS XOR AL,AL STOB POP SI ;Restore pointer to init. table LODW ;Allocation table displacement SEG CS ADD AX,[FATBASE] STOW ;FAT MOV DL,0 SHR DX ;FAT size in bytes ADD AX,DX CMP AX,BP ;Bigger than already allocated JBE SMFAT MOV BP,AX SMFAT: INC CH ;Next I/O device number DEC CL JNZ PERDEV ADD BP,15 ;True start of free space MOV CL,4 SHR BP,CL ;First free segment XOR AX,AX MOV DS,AX MOV ES,AX MOV DI,INTBASE MOV AX,QUIT STOW ;Set abort address--displacement MOV AX,CS MOV B,[ENTRYPOINT],LONGJUMP MOV [ENTRYPOINT+1],ENTRY MOV [ENTRYPOINT+3],CS STOW STOW STOW MOV [INTBASE+4],COMMAND MOV DI,INTBASE+14H MOV AX,BIOSREAD STOW MOV AX,BIOSSEG STOW STOW ;Add 2 to DI STOW MOV [INTBASE+18H],BIOSWRITE MOV DX,CS MOV DS,DX ADD DX,BP MOV [DMAADD],80H MOV [DMAADD+2],DX MOV AX,[DRVTAB] MOV [CURDRVPT],AX MOV CX,DX MOV BX,0FH MEMSCAN: INC CX JZ HAVMEM MOV DS,CX MOV AL,[BX] NOT AL MOV [BX],AL CMP AL,[BX] NOT AL MOV [BX],AL JZ MEMSCAN HAVMEM: SEG CS MOV [ENDMEM],CX XOR CX,CX MOV DS,CX MOV [EXIT],100H MOV [EXIT+2],DX MOV [INTBASE+0CH],100H MOV [INTBASE+0EH],DX CALL SETMEM MOV SI,HEADER CALL OUTMES RET L QUIT: MOV AH,0 JP SAVREGS COMMAND: ;Interrupt call entry point CMP AH,MAXCOM JBE SAVREGS BADCALL: MOV AL,0 IRET: IRET ENTRY: ;System call entry point and dispatcher POP AX ;IP from the long call at 5 POP AX ;Segment from the long call at 5 SEG CS POP [TEMP] ;IP from the CALL 5 PUSHF ;Start re-ordering the stack DI PUSH AX ;Save segment SEG CS PUSH [TEMP] ;Stack now ordered as if INT had been used CMP CL,MAXCALL ;This entry point doesn't get as many calls JA BADCALL MOV AH,CL SAVREGS: SEG CS MOV [SPSAVE],SP SEG CS MOV [SSSAVE],SS INC SP INC SP SEG CS POP [TEMP] MOV SP,CS MOV SS,SP MOV SP,STACK PUSH ES PUSH DS PUSH BP PUSH DI PUSH SI PUSH DX PUSH CX PUSH BX PUSH AX MOV BL,AH MOV BH,0 SHL BX UP SEG CS CALL [BX+DISPATCH] SEG CS MOV [AXSAVE],AL POP AX POP BX POP CX POP DX POP SI POP DI POP BP POP DS POP ES POP SS SEG CS MOV SP,[SPSAVE] IRET DISPATCH: ; Standard Functions DW ABORT ;0 DW CONIN DW CONOUT DW READER DW PUNCH DW LIST ;5 DW RAWIO DW GETIO DW SETIO DW PRTBUF DW BUFIN ;10 DW CONSTAT DW VERSION DW DSKRESET DW SELDSK DW OPEN ;15 DW CLOSE DW SRCHFRST DW SRCHNXT DW DELETE DW SEQRD ;20 DW SEQWRT DW CREATE DW RENAME DW INUSE DW CURDRV ;25 DW SETDMA DW GETFATPT DW WRTPROT DW GETRDONLY DW SETATTRIB ;30 DW GETDSKPT DW USERCODE DW RNDRD DW RNDWRT DW FILESIZE ;35 DW SETRNDREC ; Extended Functions DW SETVECT DW NEWBASE DW BLKRD DW BLKWRT ;40 VERSION: GETIO: SETIO: WRTPROT: GETRDONLY: SETATTRIB: USERCODE: MOV AL,0 RET READER: CALL BIOSAUXIN,BIOSSEG RET PUNCH: MOV AL,DL CALL BIOSAUXOUT,BIOSSEG RET UNPACK: ; Inputs: ; DS = CS ; BX = Cluster number ; BP = Base of drive parameters ; SI = Pointer to drive FAT ; Outputs: ; DI = Contents of FAT for given cluster ; Zero set means DI=0 (free cluster) ; No other registers affected. Fatal error if cluster too big. CMP BX,[BP+MAXCLUS] JA HURTFAT LEA DI,[SI+BX] SHR BX MOV DI,[DI+BX] JNC HAVCLUS SHR DI SHR DI SHR DI SHR DI STC HAVCLUS: RCL BX AND DI,0FFFH RET HURTFAT: MOV SI,BADMES CALL OUTMES JMP ERROR PACK: ; Inputs: ; DS = CS ; BX = Cluster number ; DX = Data ; SI = Pointer to drive FAT ; Outputs: ; The data is stored in the FAT at the given cluster. ; BX,DX,DI all destroyed ; No other registers affected MOV DI,BX SHR BX ADD BX,SI ADD BX,DI SHR DI MOV DI,[BX] JNC ALIGNED SHL DX SHL DX SHL DX SHL DX AND DI,0FH JP PACKIN ALIGNED: AND DI,0F000H PACKIN: OR DI,DX MOV [BX],DI RET GETFILE: ; Inputs: ; DS,DX point to FCB ; Function: ; Find file name in disk directory. First byte is ; drive number (0=current disk). "?" matches any ; character. ; Outputs: ; Carry set if file not found ; ELSE ; BP = Base of drive parameters ; DS = CS ; ES = CS ; AL = Directory record number ; BX = Pointer into directory buffer ; SI = Pointer to First Cluster field in directory entry ; [DIRBUF] has directory record with match ; [NAME1] has file name ; All other registers destroyed. CALL MOVNAME JC RET ;Bad file name? FINDNAME: MOV AX,CS MOV DS,AX MOV AL,0 RDIRREC: PUSH AX CALL DIRREAD POP AX MOV BX,DIRBUF-16 CONTSRCH: CALL NEXTENT JZ RET NDIRREC: INC AL ;Next directory record CMP AL,[BP+DIRSIZ] JB RDIRREC STC RET NEXTENT: ADD BX,16 CMP BX,DIRBUF+127 JA RET CMP B,[BX],0E5H JZ NEXTENT MOV SI,BX MOV DI,NAME1 MOV CX,11 WILDCRD: REPE CMPB JZ RET CMP B,[DI-1],"?" JZ WILDCRD JP NEXTENT DELETE: ; System call 19 CALL GETFILE JC ERRET PUSH AX PUSH BX CALL FATREAD POP BX DELFILE: MOV B,[BX],0E5H PUSH BX MOV BX,[BX+11] MOV SI,[BP+FAT] OR BX,BX JZ DELNXT CMP BX,[BP+MAXCLUS] JA DELNXT CALL RELEASE DELNXT: POP BX CALL NEXTENT JZ DELFILE POP AX PUSH AX CALL DIRWRITE POP AX CALL NDIRREC PUSH AX JNC DELFILE POP AX CALL FATWRT XOR AL,AL RET RENAME: ;System call 23 CALL MOVNAME JC ERRET ADD SI,5 MOV DI,NAME2 CALL LODNAME CALL FINDNAME JC ERRET SAVDREC: MOV AH,AL RENFIL: MOV DI,BX MOV SI,NAME2 MOV CX,11 NEWNAM: LODB CMP AL,"?" JZ NOCHG MOV [DI],AL NOCHG: INC DI LOOP NEWNAM CALL NEXTENT JZ RENFIL MOV AL,AH PUSH AX CALL DIRWRITE POP AX CALL NDIRREC JNC SAVDREC ;New record read, save current number XOR AL,AL RET ERRET: MOV AL,-1 RET MOVNAME: ; Inputs: ; DS, DX point to FCB ; Outputs: ; ES = CS ; If file name OK: ; BP has base of driver parameters ; [NAME1] has name in upper case ; All registers except DX destroyed ; Carry set if bad file name or drive MOV AX,CS MOV ES,AX MOV DI,NAME1 MOV SI,DX LODB SEG ES CMP [NUMDRV],AL JC RET CBW XCHG AX,BP SHL BP MOV BP,[BP+CURDRVPT] LODNAME: ; This entry point copies a file name from DS,SI ; to ES,DI converting to upper case. MOV CX,11 MOVCHK: LODB AND AL,7FH CMP AL,60H JLE CASEOK AND AL,5FH CASEOK: CMP AL,20H JC RET STOB LOOP MOVCHK RET OPEN: ;System call 15 PUSH DX PUSH DS CALL GETFILE DOOPEN: ; Enter here to perform OPEN on file already found ; in directory. DS=ES=CS, BX points to directory ; entry in DIRBUF, and the top of the stack has the ; address and segment of the FCB to be opened. This ; entry point is used by CREATE. POP ES POP DI JC ERRET MOV AH,[BP+DRVNUM] INC AH SEG ES MOV [DI],AH SEG ES MOV [DI+EXTENT],0 ;Set extent field to 0 ADD DI,16 ;Point to entry pos. field MOV CX,BX SUB CX,DIRBUF MOV AH,CL STOW ;directory location MOV AX,BP STOW ;pointer to driver parameters LEA SI,[BX+11] LODW ;Get starting cluster STOW ; first cluster STOW ; last cluster accessed LODB SHL AL LODW RCL AX STOW ; size of file in records XOR AX,AX STOW ; position of last cluster STOW ; file not dirty FATREAD: TEST B,[BP+DIRTYFAT],-1 JNZ RET CALL FIGFAT NEXTFAT: PUSH DX PUSH CX PUSH BX PUSH AX CALL DREAD OR AL,AL POP AX POP BX POP CX POP DX JNZ BADFAT SUB AL,[BP+FATCNT] JZ RET NEG AL ;{Insert error code here. AL=number of bad fats. ;Since one good FAT was read, should include option ;to rewrite all FATs.} JP FATWRT BADFAT: ADD DX,CX DEC AL JNZ NEXTFAT POP BP ;{Insert error code here. All FATs on drive are bad.} MOV SI,BADFATMES CALL HARDERR JP FATREAD CLOSE: ;System call 16 MOV DI,DX TEST B,[DI+DIRTYFIL],-1 JZ NOFLSH PUSH DI MOV BP,[DI+DRVBP] MOV AL,[BP+DRVNUM] CALL BIOSFLUSH,BIOSSEG POP DI NOFLSH: TEST B,[DI+SIZCHG],-1 JZ OKRET MOV DX,DI PUSH DX PUSH DS CALL GETFILE POP ES POP DI JC BADCLOSE MOV CX,BX SUB CX,DIRBUF MOV AH,CL SEG ES CMP AX,[DI+ENTPOS] JNZ BADCLOSE SEG ES MOV CX,[DI+FIRCLUS] MOV [BX+11],CX SEG ES MOV DX,[DI+FILSIZ] SHR DX MOV [BX+14],DX MOV DL,0 RCR DL MOV [BX+13],DL CALL DIRWRITE CHKFATWRT: ; Do FATWRT only if FAT is dirty TEST B,[BP+DIRTYFAT],-1 JZ OKRET FATWRT: ; Inputs: ; DS = CS ; BP = Base of drive parameter table ; Function: ; Write the FAT back to disk and reset FAT ; dirty bit. ; Outputs: ; AL = 0 ; BP unchanged ; All other registers destroyed MOV B,[BP+DIRTYFAT],0 CALL FIGFAT EACHFAT: PUSH DX PUSH CX PUSH BX PUSH AX CALL DWRITE POP AX POP BX POP CX POP DX ADD DX,CX DEC AL JNZ EACHFAT OKRET: MOV AL,0 RET BADCLOSE: MOV B,[BP+DIRTYFAT],0 MOV AL,-1 RET FIGFAT: ; Loads registers with values needed to read or ; write a FAT. MOV AL,[BP+FATCNT] MOV BX,[BP+FAT] MOV CL,[BP+FATSIZ] ;No. of records occupied by FAT MOV CH,0 MOV DX,[BP+FIRFAT] ;Record number of start of FATs RET DIRCOMP: ; Prepare registers for directory read or write CBW ADD AX,[BP+FIRDIR] MOV DX,AX MOV BX,DIRBUF MOV CX,1 RET CREATE: ;System call 22 CALL MOVNAME JC ERRET3 MOV DI,NAME1 MOV CX,11 MOV AL,"?" REPNE SCAB JZ ERRET3 PUSH DX PUSH DS MOV AX,CS MOV DS,AX XOR AX,AX RDIRREC2: PUSH AX CALL DIRREAD POP AX MOV DI,DIRBUF-16 MOV CX,8 FNDFRE: ADD DI,16 CMP B,[DI],0E5H LOOPNE FNDFRE JZ FREESPOT INC AL CMP AL,[BP+DIRSIZ] JC RDIRREC2 POP DS POP DX ERRET3: MOV AL,-1 RET FREESPOT: MOV BX,DI MOV SI,NAME1 MOV CX,5 MOVB REP MOVW XCHG AL,AH MOV CL,5 REP STOB XCHG AL,AH PUSH AX PUSH BX CALL DIRWRITE POP BX POP AX JMP DOOPEN DIRREAD: ; Inputs: ; DS = CS ; AL = Directory block number ; BP = Base of drive parameters ; Function: ; Read the directory block into DIRBUF. ; Outputs: ; BP unchanged ; All other registers destroyed. CALL DIRCOMP DREAD: ; Inputs: ; BX,DS = Transfer address ; CX = Number of records ; DX = Absolute record number ; BP = Base of drive parameters ; Function: ; Calls BIOS to perform disk read. If BIOS reports ; errors, will call HARDERR for further action. ; Outputs: ; AL = 0 if no error, otherwise non-zero ; BP preserved. All other registers destroyed. MOV AL,[BP+DRVNUM] PUSH BP PUSH BX PUSH CX PUSH DX CALL BIOSREAD,BIOSSEG POP DX POP DI POP BX POP BP JC HARDREAD XOR AL,AL RET HARDREAD: MOV SI,RDERRMES CALL HARDERR JP DREAD DIRWRITE: ; Inputs: ; DS = CS ; AL = Directory block number ; BP = Base of drive parameters ; Function: ; Write the directory block into DIRBUF. ; Outputs: ; BP unchanged ; All other registers destroyed. CALL DIRCOMP DWRITE: ; Inputs: ; BX,DS = Transfer address ; CX = Number of records ; DX = Absolute record number ; BP = Base of drive parameters ; Function: ; Calls BIOS to perform disk write. If BIOS reports ; errors, will call HARDERR for further action. ; Outputs: ; AL = 0 if no error, otherwise non-zero ; BP preserved. All other registers destroyed. MOV AL,[BP+DRVNUM] MOV AH,0 CMP DX,[BP+FIRREC] RCR AH PUSH BP PUSH BX PUSH CX PUSH DX CALL BIOSWRITE,BIOSSEG POP DX POP DI POP BX POP BP JC HARDWRITE XOR AL,AL RET HARDWRITE: MOV SI,WRTERRMES CALL HARDERR JP DWRITE HARDERR: SUB DI,CX ADD DX,DI CALL SHFTDI7 ADD BX,DI CALL OUTMES GETINSTR: CALL IN OR AL,20H CMP AL,"a" JZ ERROR CMP AL,"r" JZ RET CMP AL,"i" JZ IGNORE CMP AL,"c" JNZ GETINSTR POP AX MOV AL,1 RET IGNORE: POP AX MOV AL,0 RET ABORT: SEG CS MOV DS,[CSLOC] XOR AX,AX MOV ES,AX MOV SI,SAVEXIT MOV DI,EXIT MOVW MOVW MOVW MOVW ERROR: MOV SP,BPSAVE MOV AX,CS MOV DS,AX MOV ES,AX CALL WRTFATS XOR AX,AX MOV DS,AX MOV SI,EXIT MOV DI,EXITHOLD MOVW MOVW POP BP POP ES POP ES POP DS POP SS MOV SP,[SPSAVE] MOV DS,[DSSAVE] SEG CS JMP L,[EXITHOLD] SEQRD: ;System call 20 CALL GETREC MOV CX,1 CALL LOAD JCXZ SETNREX INC AX JP SETNREX SEQWRT: ;System call 21 CALL GETREC MOV CX,1 CALL STORE JCXZ SETNREX INC AX JP SETNREX RNDRD: ;System call 33 MOV CX,1 MOV DI,DX MOV AX,[DI+RR] CALL LOAD JP FINRND RNDWRT: ;System call 34 MOV CX,1 MOV DI,DX MOV AX,[DI+RR] CALL STORE JP FINRND BLKRD: ;System call 39 MOV DI,DX MOV AX,[DI+RR] CALL LOAD JP FINBLK BLKWRT: ;System call 40 MOV DI,DX MOV AX,[DI+RR] CALL STORE FINBLK: MOV [CXSAVE],CX JCXZ FINRND INC AX FINRND: SEG ES MOV [DI+RR],AX SETNREX: MOV CX,AX AND AL,7FH SEG ES MOV [DI+NR],AL AND CL,80H ROL CX XCHG CL,CH SEG ES MOV [DI+EXTENT],CX MOV AL,[DSKERR] RET SETUP: ; Inputs: ; DS:DI point to FCB ; AX = Record position in file of disk transfer ; CX = Record count ; Outputs: ; DS = CS ; ES:DI point to FCB ; CX = No. of records to transfer ; BP = Base of drive parameters ; SI = FAT pointer ; [RECCNT] = Record count ; [RECPOS] = Record position in file ; [FCB] = DX ; [NEXTADD] = Displacement of disk transfer within segment ; [DSKERR] = 0 (no errors yet) ; [TRANS] = 0 (No transfers yet) ; If SETUP detects no records will be transfered, it returns 1 level up ; with CX = 0. MOV BP,[DI+DRVBP] MOV BX,DS MOV ES,BX MOV BX,CS MOV DS,BX MOV [RECPOS],AX MOV [FCB],DX MOV BX,[DMAADD] MOV [NEXTADD],BX MOV B,[DSKERR],0 MOV [TRANS],0 MOV SI,[BP+FAT] ADD BX,7FH ;See if there is any space left JC SEGEND AND BL,80H NEG BX ;These instructions divide by 128 ROL BX XCHG BL,BH JNZ CHKMAX MOV BH,2 ;All 512 records OK CHKMAX: CMP CX,BX JBE SAVCNT MOV CX,BX MOV B,[DSKERR],2 ;Flag that trimming took place SAVCNT: MOV [RECCNT],CX RET SEGEND: MOV B,[DSKERR],2 MOV CX,0 POP BX RET FNDCLUS: ; Inputs: ; DS = CS ; CX = No. of clusters to skip ; BP = Base of drive parameters ; SI = FAT pointer ; ES:DI point to FCB ; Outputs: ; BX = Last cluster skipped to ; CX = No. of clusters remaining (0 unless EOF) ; DX = Position of last cluster ; DI destroyed. No other registers affected. SEG ES MOV BX,[DI+LSTCLUS] SEG ES MOV DX,[DI+CLUSPOS] OR BX,BX JZ NOCLUS SUB CX,DX JNB FINDIT ADD CX,DX XOR DX,DX SEG ES MOV BX,[DI+FIRCLUS] FINDIT: JCXZ RET SKPCLP: CALL UNPACK CMP DI,0FFFH JZ RET XCHG BX,DI INC DX LOOP SKPCLP RET NOCLUS: INC CX DEC DX RET LOAD: ; Inputs: ; DS:DI point to FCB ; AX = Position in file to read ; CX = No. of records to read ; Outputs: ; AX = Position of last record read ; CX = No. of records read ; ES:DI point to FCB ; LSTCLUS, CLUSPOS fields in FCB set CALL SETUP SEG ES MOV BX,[DI+FILSIZ] SUB BX,AX JBE WRTERRJ CMP BX,CX JNB ENUF MOV B,[DSKERR],1 MOV [RECCNT],BX ENUF: MOV CL,[BP+CLUSSHFT] SHR AX,CL MOV CX,AX CALL FNDCLUS OR CX,CX JNZ WRTERR MOV DL,[RECPOS] AND DL,[BP+CLUSMSK] MOV CX,[RECCNT] RDLP: CALL OPTIMIZE PUSH DI PUSH AX PUSH DS MOV DS,[DMAADD+2] CALL DREAD POP DS POP CX POP BX JCXZ SETFCB MOV DL,0 CMP BX,0FFFH JNZ RDLP MOV B,[DSKERR],1 SETFCB: MOV AX,[CLUSNUM] MOV DI,[FCB] SEG ES MOV [DI+LSTCLUS],AX MOV AX,[RECPOS] MOV BX,[TRANS] ADD AX,BX SEG ES CMP AX,[DI+FILSIZ] JBE SAMSIZ SEG ES MOV [DI+FILSIZ],AX SEG ES MOV B,[DI+SIZCHG],-1 SAMSIZ: DEC AX MOV DX,AX MOV CL,[BP+CLUSSHFT] SHR DX,CL SEG ES MOV [DI+CLUSPOS],DX MOV CX,BX RET WRTERRJ:JP WRTERR HAVSTART: MOV CX,AX PUSH BX CALL FNDCLUS JCXZ WRCLUS CALL ALLOCATE POP BX JNC NOSKIP WRTERR: MOV B,[DSKERR],1 LVDSK: MOV AX,[RECPOS] XOR CX,CX MOV DI,[FCB] RET WRTEOF: MOV CL,[BP+CLUSSHFT] SHR AX,CL MOV CX,AX CALL FNDCLUS OR CX,CX JNZ LVDSK MOV DX,0FFFH MOV B,[BP+DIRTYFAT],-1 MOV DI,[FCB] MOV AX,[RECPOS] SEG ES MOV [DI+FILSIZ],AX SEG ES MOV B,[DI+SIZCHG],-1 XOR CX,CX RET STORE: ; Inputs: ; DS:DI point to FCB ; AX = Position in file of disk transfer ; CX = Record count ; Outputs: ; AX = Position of last record written ; CX = No. of records written ; ES:DI point to FCB ; LSTCLUS, CLUSPOS fields in FCB set CALL SETUP JCXZ WRTEOF MOV BX,CX ADD BX,AX DEC BX MOV CL,[BP+CLUSSHFT] SHR AX,CL SHR BX,CL MOV CX,AX MOV AX,BX CALL FNDCLUS SUB AX,DX ;Last cluster minus current cluster JCXZ HAVSTART ;See if no more data PUSH CX ;No. of clusters of first MOV CX,AX CALL ALLOCATE POP CX JC WRTERR DEC CX JZ NOSKIP CALL SKPCLP PUSH BX WRCLUS: POP BX NOSKIP: MOV DL,[RECPOS] AND DL,[BP+CLUSMSK] MOV CX,[RECCNT] WRTLP: CALL OPTIMIZE PUSH DI PUSH AX PUSH DS MOV DS,[DMAADD+2] CALL DWRITE POP DS POP CX POP BX MOV DL,0 OR CX,CX JNZ WRTLP CALL SETFCB SEG ES MOV B,[DI+DIRTYFIL],-1 RET OPTIMIZE: ; Inputs: ; DS = CS ; BX = Physical cluster ; CX = No. of records ; DL = record within cluster ; BP = Base of drives parameters ; [NEXTADD] = transfer address ; Outputs: ; AX = No. of records remaining ; BX = Transfer address ; CX = No. or records to be transferred ; DX = Physical record address ; DI = Next cluster ; [CLUSNUM] = Last cluster accessed ; [NEXTADD] updated ; BP unchanged. Note that segment of transfer not set. PUSH DX PUSH BX MOV AL,[BP+CLUSMSK] INC AL ;Number of records per cluster MOV AH,AL SUB AL,DL ;AL = Number of records left in first cluster MOV DX,CX MOV SI,[BP+FAT] MOV CX,0 OPTCLUS: ;AL has number of records available in current cluster ;AH has number of records available in next cluster ;BX has current physical cluster ;CX has number of sequential records found so far ;DX has number of records left to transfer ;SI has FAT pointer CALL UNPACK ADD CL,AL ADC CH,0 CMP CX,DX JAE BLKDON MOV AL,AH INC BX CMP DI,BX JZ OPTCLUS DEC BX FINCLUS: MOV [CLUSNUM],BX ;Last cluster accessed SUB DX,CX ;Number of records still needed MOV AX,DX MOV BX,CX XCHG BL,BH ROR BX MOV SI,[NEXTADD] ADD BX,SI ;Adjust by size of transfer MOV [NEXTADD],BX ADD [TRANS],CX POP DX POP BX PUSH CX MOV CL,[BP+CLUSSHFT] DEC DX DEC DX SHL DX,CL OR DL,BL ADD DX,[BP+FIRREC] POP CX MOV BX,SI RET BLKDON: MOV CX,DX ;Make the total equal to the request JP FINCLUS GETREC: ; Inputs: ; DS:DX point to FCB ; Outputs: ; AX = Record number determined by EXTENT and NR fields ; DS:DI point to FCB ; BX destroyed. No other registers affected. MOV DI,DX MOV AL,[DI+NR] MOV BX,[DI+EXTENT] SHL AL SHR BX RCR AL MOV AH,BL RET ALLOCATE: ; Inputs: ; DS = CS ; ES = Segment of FCB ; BX = Last cluster of file (0 if null file) ; CX = No. of clusters to allocate ; DX = Position of cluster BX ; BP = Base of drive parameters ; SI = FAT pointer ; [FCB] = Displacement of FCB within segment ; Outputs: ; IF insufficient space ; THEN ; Carry set ; ELSE ; Carry clear ; BX = First cluster allocated ; FAT is fully updated including dirty bit ; FIRCLUS field of FCB set if file was null ; SI,BP unchanged. All other registers destroyed. PUSH BX MOV AX,BX ALLOC: MOV DX,BX FINDFRE: INC BX CMP BX,[BP+MAXCLUS] JL TRYOUT CMP AX,1 JG TRYIN POP BX MOV DX,0FFFH CALL RELBLKS OR [SI],0FFFH STC RET TRYOUT: CALL UNPACK JZ HAVFRE TRYIN: DEC AX JLE FINDFRE XCHG AX,BX CALL UNPACK JZ HAVFRE XCHG AX,BX JP FINDFRE HAVFRE: XCHG BX,DX MOV AX,DX CALL PACK MOV BX,AX LOOP ALLOC MOV DX,0FFFH CALL PACK MOV B,[BP+DIRTYFAT],-1 POP BX CALL UNPACK XCHG BX,DI OR DI,DI JNZ RET MOV DI,[FCB] SEG ES MOV [DI+FIRCLUS],BX OR [SI],0FFFH RET RELEASE: ; Inputs: ; DS = CS ; BX = Cluster in file ; SI = FAT pointer ; BP = Base of drive parameters ; Function: ; Frees cluster chain starting with [BX] ; AX,BX,DX,DI all destroyed. Other registers unchanged. XOR DX,DX RELBLKS: ; Enter here with DX=0FFFH to put an end-of-file mark ; in the first cluster and free the rest in the chain. CALL UNPACK JZ RET MOV AX,DI CALL PACK CMP AX,0FFFH MOV BX,AX JNZ RELEASE RET GETEOF: ; Inputs: ; BX = Cluster in a file ; SI = Base of drive FAT ; DS = CS ; Outputs: ; BX = Last cluster in the file ; DI destroyed. No other registers affected. CALL UNPACK CMP DI,0FFFH JZ RET MOV BX,DI JP GETEOF SRCHFRST: ;System call 17 CALL GETFILE SAVPLCE: ; Search-for-next enters here to save place and report ; findings. JC KILLSRCH MOV [SRCHDON],AL MOV [PDIR],BX MOV [SRCHBP],BP ;Information in directory entry must be copied into the first ; 16 bytes starting at the disk transfer address. MOV SI,BX LES DI,[DMAADD] MOV CX,8 REP MOVW MOV AL,0 RET KILLSRCH: MOV AL,-1 MOV [SRCHDON],AL RET SRCHNXT: ;System call 18 MOV AX,CS MOV ES,AX MOV DS,AX MOV AL,[SRCHDON] CMP AL,-1 JZ RET MOV BX,[PDIR] MOV BP,[SRCHBP] CALL CONTSRCH JP SAVPLCE FILESIZE: ;System call 35 PUSH DI PUSH DX CALL GETFILE POP DI POP ES MOV AL,-1 JC RET ADD DI,33 ;Write size in RR field LEA SI,[BX+13] LODB SHL AL LODW RCL AX ;Round to nearest record STOW MOV AL,0 RCL AL STOB RET SETDMA: ;System call 26 SEG CS MOV [DMAADD],DX SEG CS MOV [DMAADD+2],DS RET GETFATPT: ;System call 27 MOV AX,CS MOV DS,AX MOV [DSSAVE],CS MOV BP,[CURDRVPT] CALL FATREAD MOV BX,[BP+FAT] MOV AL,[BP+CLUSMSK] INC AL MOV DX,[BP+MAXCLUS] DEC DX MOV B,[BP+DIRTYFAT],-1 MOV [BXSAVE],BX MOV [DXSAVE],DX RET GETDSKPT: ;System call 31 SEG CS MOV [DSSAVE],CS SEG CS MOV BX,[CURDRVPT] SEG CS MOV [BXSAVE],BX RET DSKRESET: ;System call 13 SEG CS MOV [DMAADD+2],DS MOV AX,CS MOV DS,AX MOV [DMAADD],80H MOV AX,[CURDRVPT+2] MOV [CURDRVPT],AX WRTFATS: ; DS=CS. Writes back all dirty FATs. All registers destroyed. MOV CL,[NUMDRV] MOV CH,0 MOV SI,CURDRVPT+2 WRTFAT: LODW PUSH CX PUSH SI MOV BP,AX CALL CHKFATWRT POP SI POP CX LOOP WRTFAT MOV AL,-1 CALL BIOSFLUSH,BIOSSEG RET CURDRV: ;System call 25 SEG CS MOV BP,[CURDRVPT] MOV AL,[BP+DRVNUM] RET INUSE: ;System call 24 MOV AX,CS MOV DS,AX MOV CL,[NUMDRV] MOV CH,0 MOV SI,CX SHL SI ADD SI,CURDRVPT MOV BX,0 DOWN CHKUSE: LODW MOV BP,AX TEST B,[BP+DIRTYFAT],-1 JZ SETBIT STC SETBIT: RCL BX LOOP CHKUSE MOV AL,BL RET SETRNDREC: ;System call 36 CALL GETREC MOV [DI+33],AX MOV AL,0 JZ BIGRR INC AL BIGRR: MOV [DI+35],AL RET SELDSK: ;System call 14 MOV DH,0 MOV BX,DX PUSH CS POP DS CMP BL,[NUMDRV] JGE RET SHL BX MOV AX,[BX+CURDRVPT+2] MOV [CURDRVPT],AX RET BUFIN: ;System call 10 MOV AX,CS MOV ES,AX MOV SI,DX MOV CH,0 LODW OR AL,AL JZ RET MOV BL,AH MOV BH,CH CMP AL,BL JBE NOEDIT CMP B,[BX+SI],0DH JZ EDITON NOEDIT: MOV BL,CH EDITON: MOV DL,AL DEC DX NEWLIN: SEG CS MOV AL,[CARPOS] SEG CS MOV [STARTPOS],AL PUSH SI MOV DI,INBUF MOV AH,CH MOV BH,CH MOV DH,CH GETCH: CALL IN CMP AL,7FH JZ BACKSP CMP AL,8 JZ BACKSP CMP AL,13 JZ ENDLIN CMP AL,10 JZ PHYCRLF CMP AL,"X"-"@" JZ KILNEW CMP AL,ESCCH JZ ESC SAVCH: CMP DH,DL JAE GETCH STOB INC DH CALL OUT OR AH,AH JNZ GETCH CMP BH,BL JAE GETCH INC SI INC BH JP GETCH ESC: CALL IN MOV CL,ESCTABLEN PUSH DI MOV DI,ESCTAB REPNE SCAB POP DI AND CL,0FEH MOV BP,CX JMP [BP+ESCFUNC] ENDLIN: STOB CALL OUT POP DI MOV [DI-1],DH INC DH COPYNEW: MOV BP,ES MOV BX,DS MOV ES,BX MOV DS,BP MOV SI,INBUF MOV CL,DH REP MOVB RET CRLF: MOV AL,13 CALL OUT MOV AL,10 JMP OUT PHYCRLF: CALL CRLF JP GETCH KILNEW: MOV AL,"\" CALL OUT POP SI PUTNEW: CALL CRLF JMP NEWLIN BACKSP: OR DH,DH JZ OLDBAK CALL BACKUP SEG ES MOV AL,[DI] CMP AL," " JAE OLDBAK CMP AL,9 JZ BAKTAB CALL BACKMES OLDBAK: OR AH,AH JNZ GETCH1 OR BH,BH JZ GETCH1 DEC BH DEC SI GETCH1: JMP GETCH BAKTAB: PUSH DI DEC DI DOWN MOV CL,DH MOV AL," " PUSH BX MOV BL,7 JCXZ FIGTAB FNDPOS: SCAB JNA CHKCNT SEG ES CMP B,[DI+1],9 JZ HAVTAB DEC BL CHKCNT: LOOP FNDPOS FIGTAB: SEG CS SUB BL,[STARTPOS] HAVTAB: SUB BL,DH ADD CL,BL AND CL,7 UP POP BX POP DI JZ OLDBAK TABBAK: CALL BACKMES LOOP TABBAK JP OLDBAK BACKUP: DEC DH DEC DI BACKMES: MOV AL,8 CALL OUT MOV AL," " CALL OUTCH MOV AL,8 JMP OUTCH TWOESC: MOV AL,ESCCH JMP SAVCH COPYLIN: MOV CL,BL SUB CL,BH JP COPYEACH COPYSTR: CALL FINDOLD JP COPYEACH COPYONE: MOV CL,1 COPYEACH: CMP DH,DL JZ GETCH2 CMP BH,BL JZ GETCH2 LODB STOB CALL OUT INC BH INC DH LOOP COPYEACH GETCH2: JMP GETCH SKIPONE: CMP BH,BL JZ GETCH2 INC BH INC SI JMP GETCH SKIPSTR: CALL FINDOLD ADD SI,CX ADD BH,CL JMP GETCH FINDOLD: CALL IN MOV CL,BL SUB CL,BH JZ NOTFND DEC CX JZ NOTFND PUSH ES PUSH DS POP ES PUSH DI MOV DI,SI INC DI REPNE SCAB POP DI POP ES JNZ NOTFND NOT CL ADD CL,BL SUB CL,BH RET NOTFND: POP BP JMP GETCH REEDIT: MOV AL,"@" CALL OUT POP DI PUSH DI PUSH ES PUSH DS CALL COPYNEW POP DS POP ES POP SI MOV BL,DH JMP PUTNEW ENTERINS: MOV AH,-1 JMP GETCH EXITINS: MOV AH,0 JMP GETCH ESCFUNC: DW GETCH DW TWOESC DW EXITINS DW ENTERINS DW BACKSP DW REEDIT DW KILNEW DW COPYLIN DW SKIPSTR DW COPYSTR DW SKIPONE DW COPYONE CONOUT: ;System call 2 MOV AL,DL OUT: CMP AL,20H JB CTRLOUT CMP AL,7FH JZ OUTCH SEG CS INC B,[CARPOS] OUTCH: CALL BIOSOUT,BIOSSEG SEG CS TEST B,[PFLAG],-1 JZ STATCHK CALL BIOSPRINT,BIOSSEG STATCHK: CALL BIOSSTAT,BIOSSEG JZ RET INCHK: CALL BIOSIN,BIOSSEG CMP AL,'S'-'@' JNZ NOSTOP CALL BIOSIN,BIOSSEG NOSTOP: CMP AL,'P'-'@' JZ PRINTON CMP AL,'N'-'@' JZ PRINTOFF CMP AL,'C'-'@' JNZ RET INT CONTC ;Execute user Ctrl-C handler RET PRINTON: SEG CS MOV B,[PFLAG],1 RET PRINTOFF: SEG CS MOV B,[PFLAG],0 RET CTRLOUT: CMP AL,10 JZ OUTCH CMP AL,13 JZ ZERPOS CMP AL,8 JZ BACKPOS CMP AL,9 JZ TAB PUSH AX MOV AL,"^" CALL OUT POP AX OR AL,40H JP OUT ZERPOS: SEG CS MOV B,[CARPOS],0 JP OUTCH BACKPOS: SEG CS DEC B,[CARPOS] JP OUTCH TAB: MOV AL,0 SEG CS XCHG AL,[CARPOS] OR AL,0F8H NEG AL PUSH CX MOV CL,AL MOV CH,0 TABLP: MOV AL," " CALL OUTCH LOOP TABLP POP CX RET CONSTAT: ;System call 11 CALL BIOSSTAT,BIOSSEG JZ RET OR AL,-1 RET CONIN: ;System call 1 CALL INCHK PUSH AX CALL OUT POP AX RET IN: ;Internal input routine CALL INCHK JZ IN RET RAWIO: ;System call 6 MOV AL,DL CMP AL,-1 JNZ RAWOUT CALL BIOSSTAT,BIOSSEG JZ RET CALL BIOSIN,BIOSSEG RET RAWOUT: CALL BIOSOUT,BIOSSEG RET LIST: ;System call 5 MOV AL,DL CALL BIOSPRINT,BIOSSEG RET PRTBUF: ;System call 9 MOV SI,DX OUTSTR: LODB CMP AL,"$" JZ RET CALL OUT JP OUTSTR OUTMES: ;String output for internal messages SEG CS LODB CMP AL,"$" JZ RET CALL OUT JP OUTMES SETVECT: ; Interrupt call 37 XOR BX,BX MOV ES,BX MOV BL,AL SHL BX SHL BX SEG ES MOV [BX],DX SEG ES MOV [BX+2],DS RET NEWBASE: ; Interrupt call 38 MOV ES,DX SEG CS MOV DS,[CSLOC] XOR SI,SI MOV DI,SI MOV CX,80H REP MOVW SETMEM: ; Inputs: ; DX = Segment ; Function: ; Completely prepares a program base at the ; specified segment. ; Outputs: ; DS = DX ; ES = DX ; [0] has INT 20H ; [2] = First unavailable segment ([ENDMEM]) ; [5] to [9] form a long call to the entry point ; [10] to [13] have exit address (from INT 22H) ; [14] to [17] have ctrl-C exit address (from INT 23H) ; AX,DX,BP unchanged. All other registers destroyed. XOR CX,CX MOV DS,CX MOV ES,DX MOV SI,EXIT MOV DI,SAVEXIT MOVW MOVW MOVW MOVW SEG CS MOV CX,[ENDMEM] SEG ES MOV [2],CX SUB CX,DX CMP CX,MAXDIF JBE HAVDIF MOV CX,MAXDIF HAVDIF: MOV BX,ENTRYPOINTSEG SUB BX,CX SHL CX SHL CX SHL CX SHL CX MOV DS,DX MOV [6],CX MOV [8],BX MOV [0],20CDH ;"INT INTTAB" MOV B,[5],LONGCALL RET SHFTDI7: SHL DI SHL DI SHL DI SHL DI SHL DI SHL DI SHL DI RET ;***** DATA AREA ***** BADMES: DB 13,10,"Bad FAT",13,10,"$" BADFATMES:DB 13,10,"All FATs on disk are bad",13,10,"$" RDERRMES:DB 13,10,"Disk read error",13,10,"$" WRTERRMES:DB 13,10,"Disk write error",13,10,"$" CARPOS: DB 0 STARTPOS:DB 0 PFLAG: DB 0 SRCHDON:DB -1 PDIR: DS 2 SRCHBP: DS 2 EXITHOLD:DS 4 ENDMEM: DS 2 FATBASE:DS 2 INBUF: DS 255 DIRBUF: DS 128 NUMDRV: DS 1 ;Number of drives NAME1: DS 11 ;File name buffer NAME2: DS 11 DMAADD: DS 4 ;User's disk transfer address (disp/seg) TEMP: CSLOC: DS 2 DSKERR: DS 1 FCB: DS 2 ;Address of user FCB RECPOS: DS 2 NEXTADD:DS 2 RECCNT: DS 2 CLUSNUM:DS 2 TRANS: DS 2 DS 50 ;Stack space AXSAVE: DS 2 BXSAVE: DS 2 CXSAVE: DS 2 DXSAVE: DS 2 SISAVE: DS 2 DISAVE: DS 2 BPSAVE: DS 2 DSSAVE: DS 2 ESSAVE: DS 2 STACK: SSSAVE: DS 2 SPSAVE: DS 2 CURDRVPT:DS 2 DRVTAB: ;Address of start of DPBs