<em id="0a85b"><option id="0a85b"></option></em>

<abbr id="0a85b"></abbr>

      <nobr id="0a85b"></nobr>
        <tr id="0a85b"></tr>
        9久久伊人精品综合,亚洲一区精品视频在线,成 人免费va视频,国产一区二区三区黄网,99国产精品永久免费视频,亚洲毛片多多影院,精品久久久无码人妻中文字幕,无码国产欧美一区二区三区不卡
        學(xué)習(xí)啦 > 學(xué)習(xí)電腦 > 操作系統(tǒng) > 操作系統(tǒng)基礎(chǔ)知識 > DOS操作系統(tǒng)源碼相關(guān)資料知識

        DOS操作系統(tǒng)源碼相關(guān)資料知識

        時間: 志藝942 分享

        DOS操作系統(tǒng)源碼相關(guān)資料知識

          你還在為不知道DOS操作系統(tǒng)源碼相關(guān)資料知識而煩惱么?接下來是小編為大家收集的DOS操作系統(tǒng)源碼相關(guān)資料知識教程,希望能幫到大家。

          DOS操作系統(tǒng)源碼相關(guān)資料知識

          微軟DOS早期源碼,現(xiàn)已公開;下了一份,看下其大致結(jié)構(gòu);

          包括1.1和2.0版本的源碼和編譯后的結(jié)果;

          貼出其1.1版本 MSDOS.ASM 源碼;有空研究;

        [plain] view plain copy ; 86-DOS High-performance operating system for the 8086 version 1.25

          ; by Tim Paterson

          ; ****************** Revision History *************************

          ; >> EVERY change must noted below!! <<

          ;

          ; 0.34 12/29/80 General release, updating all past customers

          ; 0.42 02/25/81 32-byte directory entries added

          ; 0.56 03/23/81 Variable record and sector sizes

          ; 0.60 03/27/81 Ctrl-C exit changes, including register save on user stack

          ; 0.74 04/15/81 Recognize I/O devices with file names

          ; 0.75 04/17/81 Improve and correct buffer handling

          ; 0.76 04/23/81 Correct directory size when not 2^N entries

          ; 0.80 04/27/81 Add console input without echo, Functions 7 & 8

          ; 1.00 04/28/81 Renumber for general release

          ; 1.01 05/12/81 Fix bug in `STORE'

          ; 1.10 07/21/81 Fatal error trapping, NUL device, hidden files, date & time,

          ; RENAME fix, general cleanup

          ; 1.11 09/03/81 Don't set CURRENT BLOCK to 0 on open; fix SET FILE SIZE

          ; 1.12 10/09/81 Zero high half of CURRENT BLOCK after all (CP/M programs don't)

          ; 1.13 10/29/81 Fix classic "no write-through" error in buffer handling

          ; 1.20 12/31/81 Add time to FCB; separate FAT from DPT; Kill SMALLDIR;

          ; Add FLUSH and MAPDEV calls; allow disk mapping in DSKCHG;

          ; Lots of smaller improvements

          ; 1.21 01/06/82 HIGHMEM switch to run DOS in high memory

          ; 1.22 01/12/82 Add VERIFY system call to enable/disable verify after write

          ; 1.23 02/11/82 Add defaulting to parser; use variable escape character

          ; Don't zero extent field in IBM version (back to 1.01!)

          ; 1.24 03/01/82 Restore fcn. 27 to 1.0 level; add fcn. 28

          ; 1.25 03/03/82 Put marker (00) at end of directory to speed searches

          ;

          ; *************************************************************

          ; 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

          IF IBM

          ESCCH EQU 0

          CANCEL EQU 1BH ;Cancel with ESC

          TOGLINS EQU TRUE ;One key toggles insert mode

          TOGLPRN EQU TRUE ;One key toggles printer echo

          NUMDEV EQU 6 ;Include "COM1" as I/O device name

          ZEROEXT EQU TRUE

          ELSE

          ESCCH EQU 1BH

          CANCEL EQU "X"-"@" ;Cancel with Ctrl-X

          TOGLINS EQU FALSE ;Separate keys for insert mode on and off

          TOGLPRN EQU FALSE ;Separate keys for printer echo on and off

          NUMDEV EQU 5 ;Number of I/O device names

          ZEROEXT EQU FALSE

          ENDIF

          MAXCALL EQU 36

          MAXCOM EQU 46

          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

          FCBLOCK STRUC

          DB 12 DUP (?) ;Drive code and name

          EXTENT DW ?

          RECSIZ DW ? ;Size of record (user settable)

          FILSIZ DW ? ;Size of file in bytes

          DRVBP DW ? ;BP for SEARCH FIRST and SEARCH NEXT

          FDATE DW ? ;Date of last writing

          FTIME DW ? ;Time of last writing

          DEVID DB ? ;Device ID number, bits 0-5

          ;bit 7=0 for file, bit 7=1 for I/O device

          ;If file, bit 6=0 if dirty

          ;If I/O device, bit 6=0 if EOF (input)

          FIRCLUS DW ? ;First cluster of file

          LSTCLUS DW ? ;Last cluster accessed

          CLUSPOS DW ? ;Position of last cluster accessed

          DB ? ;Forces NR to offset 32

          NR DB ? ;Next record

          RR DB 3 DUP (?) ;Random record

          FCBLOCK ENDS

          FILDIRENT = FILSIZ ;Used only by SEARCH FIRST and SEARCH NEXT

          ; Description of 32-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 1 Attributes. Bits 1 or 2 make file hidden

          ; 12 10 Zero field (for expansion)

          ; 22 2 Time. Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour

          ; 24 2 Date. Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980

          ; 26 2 First allocation unit ( < 4080 )

          ; 28 4 File size, in bytes (LSB first, 30 bits max.)

          ;

          ; The File Allocation Table uses a 12-bit entry for each allocation unit on

          ; the disk. These entries are packed, two for every three bytes. The contents

          ; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result

          ; to the base address of the Allocation Table; 3) fetching the 16-bit word at

          ; this address; 4) If N was odd (so that N*1.5 was not an integer), shift the

          ; word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry number

          ; zero is used as an end-of-file trap in the OS and as a flag for directory

          ; entry size (if SMALLDIR selected). Entry 1 is reserved for future use. The

          ; first available allocation unit is assigned entry number two, and even

          ; though it is the first, is called cluster 2. Entries greater than 0FF8H are

          ; end of file marks; entries of zero are unallocated. Otherwise, the contents

          ; of a FAT entry is the number of the next cluster in the file.

          ; Field definition for Drive Parameter Block

          DPBLOCK STRUC

          DEVNUM DB ? ;I/O driver number

          DRVNUM DB ? ;Physical Unit number

          SECSIZ DW ? ;Size of physical sector in bytes

          CLUSMSK DB ? ;Sectors/cluster - 1

          CLUSSHFT DB ? ;Log2 of sectors/cluster

          FIRFAT DW ? ;Starting record of FATs

          FATCNT DB ? ;Number of FATs for this drive

          MAXENT DW ? ;Number of directory entries

          FIRREC DW ? ;First sector of first cluster

          MAXCLUS DW ? ;Number of clusters on drive + 1

          FATSIZ DB ? ;Number of records occupied by FAT

          FIRDIR DW ? ;Starting record of directory

          FAT DW ? ;Pointer to start of FAT

          DPBLOCK ENDS

          DPBSIZ EQU 20 ;Size of the structure in bytes

          DIRSEC = FIRREC ;Number of dir. sectors (init temporary)

          DSKSIZ = MAXCLUS ;Size of disk (temp used during init only)

          ;The following are all of the segments used

          ;They are declared in the order that they should be placed in the executable

          CODE SEGMENT

          CODE ENDS

          CONSTANTS SEGMENT BYTE

          CONSTANTS ENDS

          DATA SEGMENT WORD

          DATA ENDS

          DOSGROUP GROUP CODE,CONSTANTS,DATA

          SEGBIOS SEGMENT

          SEGBIOS ENDS

          ; BOIS entry point definitions

          IF IBM

          BIOSSEG EQU 60H

          ENDIF

          IF NOT IBM

          BIOSSEG EQU 40H

          ENDIF

          SEGBIOS SEGMENT AT BIOSSEG

          ORG 0

          DB 3 DUP (?) ;Reserve room for jump to init code

          BIOSSTAT DB 3 DUP (?) ;Console input status check

          BIOSIN DB 3 DUP (?) ;Get console character

          BIOSOUT DB 3 DUP (?) ;Output console character

          BIOSPRINT DB 3 DUP (?) ;Output to printer

          BIOSAUXIN DB 3 DUP (?) ;Get byte from auxilliary

          BIOSAUXOUT DB 3 DUP (?) ;Output byte to auxilliary

          BIOSREAD DB 3 DUP (?) ;Disk read

          BIOSWRITE DB 3 DUP (?) ;Disk write

          BIOSDSKCHG DB 3 DUP (?) ;Dsik-change status

          BIOSSETDATE DB 3 DUP (?) ;Set date

          BIOSSETTIME DB 3 DUP (?) ;Set time

          BIOSGETTIME DB 3 DUP (?) ;Get time and date

          BIOSFLUSH DB 3 DUP (?) ;Clear console input buffer

          BIOSMAPDEV DB 3 DUP (?) ;Dynamic disk table mapper

          SEGBIOS ENDS

          ; Location of user registers relative user stack pointer

          STKPTRS STRUC

          AXSAVE DW ?

          BXSAVE DW ?

          CXSAVE DW ?

          DXSAVE DW ?

          SISAVE DW ?

          DISAVE DW ?

          BPSAVE DW ?

          DSSAVE DW ?

          ESSAVE DW ?

          IPSAVE DW ?

          CSSAVE DW ?

          FSAVE DW ?

          STKPTRS ENDS

          ; Start of code

          CODE SEGMENT

          ASSUME CS:DOSGROUP,DS:DOSGROUP,ES:DOSGROUP,SS:DOSGROUP

          ORG 0

          CODSTRT EQU $

          JMP DOSINIT

          ESCCHAR DB ESCCH ;Lead-in character for escape sequences

          ESCTAB:

          IF NOT IBM

          DB "S" ;Copy one char

          DB "V" ;Skip one char

          DB "T" ;Copy to char

          DB "W" ;Skip to char

          DB "U" ;Copy line

          DB "E" ;Kill line (no change in template)

          DB "J" ;Reedit line (new template)

          DB "D" ;Backspace

          DB "P" ;Enter insert mode

          DB "Q" ;Exit insert mode

          DB "R" ;Escape character

          DB "R" ;End of table

          ENDIF

          IF IBM

          DB 64 ;Crtl-Z - F6

          DB 77 ;Copy one char - -->

          DB 59 ;Copy one char - F1

          DB 83 ;Skip one char - DEL

          DB 60 ;Copy to char - F2

          DB 62 ;Skip to char - F4

          DB 61 ;Copy line - F3

          DB 61 ;Kill line (no change to template ) - Not used

          DB 63 ;Reedit line (new template) - F5

          DB 75 ;Backspace - <--

          DB 82 ;Enter insert mode - INS (toggle)

          DB 65 ;Escape character - F7

          DB 65 ;End of table

          ENDIF

          ESCTABLEN EQU $-ESCTAB

          IF NOT IBM

          HEADER DB 13,10,"MS-DOS version 1.25"

          IF HIGHMEM

          DB "H"

          ENDIF

          IF DSKTEST

          DB "D"

          ENDIF

          DB 13,10

          DB "Copyright 1981,82 Microsoft, Inc.",13,10,"$"

          ENDIF

          QUIT:

          MOV AH,0

          JMP SHORT 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

          POP CS:[TEMP] ;IP from the CALL 5

          PUSHF ;Start re-ordering the stack

          CLI

          PUSH AX ;Save segment

          PUSH CS:[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:

          PUSH ES

          PUSH DS

          PUSH BP

          PUSH DI

          PUSH SI

          PUSH DX

          PUSH CX

          PUSH BX

          PUSH AX

          IF DSKTEST

          MOV AX,CS:[SPSAVE]

          MOV CS:[NSP],AX

          MOV AX,CS:[SSSAVE]

          MOV CS:[NSS],AX

          POP AX

          PUSH AX

          ENDIF

          MOV CS:[SPSAVE],SP

          MOV CS:[SSSAVE],SS

          MOV SP,CS

          MOV SS,SP

          REDISP:

          MOV SP,OFFSET DOSGROUP:IOSTACK

          STI ;Stack OK now

          MOV BL,AH

          MOV BH,0

          SHL BX,1

          CLD

          CMP AH,12

          JLE SAMSTK

          MOV SP,OFFSET DOSGROUP:DSKSTACK

          SAMSTK:

          CALL CS:[BX+DISPATCH]

          LEAVE:

          CLI

          MOV SP,CS:[SPSAVE]

          MOV SS,CS:[SSSAVE]

          MOV BP,SP

          MOV BYTE PTR [BP.AXSAVE],AL

          IF DSKTEST

          MOV AX,CS:[NSP]

          MOV CS:[SPSAVE],AX

          MOV AX,CS:[NSS]

          MOV CS:[SSSAVE],AX

          ENDIF

          POP AX

          POP BX

          POP CX

          POP DX

          POP SI

          POP DI

          POP BP

          POP DS

          POP ES

          IRET

          ; Standard Functions

          DISPATCH DW ABORT ;0

          DW CONIN

          DW CONOUT

          DW READER

          DW PUNCH

          DW LIST ;5

          DW RAWIO

          DW RAWINP

          DW IN

          DW PRTBUF

          DW BUFIN ;10

          DW CONSTAT

          DW FLUSHKB

          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 GETDRV ;25

          DW SETDMA

          DW GETFATPT

          DW GETFATPTDL

          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

          DW MAKEFCB

          DW GETDATE

          DW SETDATE

          DW GETTIME

          DW SETTIME ;45

          DW VERIFY

          INUSE:

          GETIO:

          SETIO:

          GETRDONLY:

          SETATTRIB:

          USERCODE:

          MOV AL,0

          RET

          VERIFY:

          AND AL,1

          MOV CS:VERFLG,AL

          RET

          FLUSHKB:

          PUSH AX

          CALL FAR PTR BIOSFLUSH

          POP AX

          MOV AH,AL

          CMP AL,1

          JZ REDISPJ

          CMP AL,6

          JZ REDISPJ

          CMP AL,7

          JZ REDISPJ

          CMP AL,8

          JZ REDISPJ

          CMP AL,10

          JZ REDISPJ

          MOV AL,0

          RET

          REDISPJ:JMP REDISP

          READER:

          AUXIN:

          CALL STATCHK

          CALL FAR PTR BIOSAUXIN

          RET

          PUNCH:

          MOV AL,DL

          AUXOUT:

          PUSH AX

          CALL STATCHK

          POP AX

          CALL FAR PTR BIOSAUXOUT

          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,1

          MOV DI,[DI+BX]

          JNC HAVCLUS

          SHR DI,1

          SHR DI,1

          SHR DI,1

          SHR DI,1

          STC

          HAVCLUS:

          RCL BX,1

          AND DI,0FFFH

          RET

          HURTFAT:

          PUSH AX

          MOV AH,80H ;Signal Bad FAT to INT 24H handler

          MOV DI,0FFFH ;In case INT 24H returns (it shouldn't)

          CALL FATAL

          POP AX ;Try to ignore bad FAT

          RET

          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,1

          ADD BX,SI

          ADD BX,DI

          SHR DI,1

          MOV DI,[BX]

          JNC ALIGNED

          SHL DX,1

          SHL DX,1

          SHL DX,1

          SHL DX,1

          AND DI,0FH

          JMP SHORT PACKIN

          ALIGNED:

          AND DI,0F000H

          PACKIN:

          OR DI,DX

          MOV [BX],DI

          RET

          DEVNAME:

          MOV SI,OFFSET DOSGROUP:IONAME ;List of I/O devices with file names

          MOV BH,NUMDEV ;BH = number of device names

          LOOKIO:

          MOV DI,OFFSET DOSGROUP:NAME1

          MOV CX,4 ;All devices are 4 letters

          REPE CMPSB ;Check for name in list

          JZ IOCHK ;If first 3 letters OK, check for the rest

          ADD SI,CX ;Point to next device name

          DEC BH

          JNZ LOOKIO

          CRET:

          STC ;Not found

          RET

          IOCHK:

          IF IBM

          CMP BH,NUMDEV ;Is it the first device?

          JNZ NOTCOM1

          MOV BH,2 ;Make it the same as AUX

          NOTCOM1:

          ENDIF

          NEG BH

          MOV CX,2 ;Check rest of name but not extension

          MOV AX,2020H

          REPE SCASW ;Make sure rest of name is blanks

          JNZ CRET

          RET1: RET ;Zero set so CREATE works

          GETFILE:

          ; Same as GETNAME except ES:DI points to FCB on successful return

          CALL MOVNAME

          JC RET1

          PUSH DX

          PUSH DS

          CALL FINDNAME

          POP ES

          POP DI

          RET2: RET

          GETNAME:

          ; 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

          ; Zero set if attributes match (always except when creating)

          ; BP = Base of drive parameters

          ; DS = CS

          ; ES = CS

          ; 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 RET2 ;Bad file name?

          FINDNAME:

          MOV AX,CS

          MOV DS,AX

          CALL DEVNAME

          JNC RET2

          CALL STARTSRCH

          CONTSRCH:

          CALL GETENTRY

          JC RET2

          SRCH:

          MOV AH,BYTE PTR [BX]

          OR AH,AH ;End of directory?

          JZ FREE

          CMP AH,[DELALL] ;Free entry?

          JZ FREE

          MOV SI,BX

          MOV DI,OFFSET DOSGROUP:NAME1

          MOV CX,11

          WILDCRD:

          REPE CMPSB

          JZ FOUND

          CMP BYTE PTR [DI-1],"?"

          JZ WILDCRD

          NEXTENT:

          CALL NEXTENTRY

          JNC SRCH

          RET3: RET

          FREE:

          CMP [ENTFREE],-1 ;Found a free entry before?

          JNZ TSTALL ;If so, ignore this one

          MOV CX,[LASTENT]

          MOV [ENTFREE],CX

          TSTALL:

          CMP AH,[DELALL] ;At end of directory?

          JZ NEXTENT ;No - continue search

          STC ;Report not found

          RET

          FOUND:

          ;Check if attributes allow finding it

          MOV AH,[ATTRIB] ;Attributes of search

          NOT AH

          AND AH,[SI] ;Compare with attributes of file

          ADD SI,15

          AND AH,6 ;Only look at bits 1 and 2

          JZ RET3

          TEST BYTE PTR [CREATING],-1 ;Pass back mismatch if creating

          JZ NEXTENT ;Otherwise continue searching

          RET

          GETENTRY:

          ; Inputs:

          ; [LASTENT] has previously searched directory entry

          ; Function:

          ; Locates next sequential directory entry in preparation for search

          ; Outputs:

          ; Carry set if none

          ; ELSE

          ; AL = Current directory block

          ; BX = Pointer to next directory entry in [DIRBUF]

          ; DX = Pointer to first byte after end of DIRBUF

          ; [LASTENT] = New directory entry number

          MOV AX,[LASTENT]

          INC AX ;Start with next entry

          CMP AX,[BP.MAXENT]

          JAE NONE

          GETENT:

          MOV [LASTENT],AX

          MOV CL,4

          SHL AX,CL

          XOR DX,DX

          SHL AX,1

          RCL DX,1 ;Account for overflow in last shift

          MOV BX,[BP.SECSIZ]

          AND BL,255-31 ;Must be multiple of 32

          DIV BX

          MOV BX,DX ;Position within sector

          MOV AH,[BP.DEVNUM] ;AL=Directory sector no.

          CMP AX,[DIRBUFID]

          JZ HAVDIRBUF

          PUSH BX

          CALL DIRREAD

          POP BX

          HAVDIRBUF:

          MOV DX,OFFSET DOSGROUP:DIRBUF

          ADD BX,DX

          ADD DX,[BP.SECSIZ]

          RET

          NEXTENTRY:

          ; Inputs:

          ; Same as outputs of GETENTRY, above

          ; Function:

          ; Update AL, BX, and [LASTENT] for next directory entry.

          ; Carry set if no more.

          MOV DI,[LASTENT]

          INC DI

          CMP DI,[BP.MAXENT]

          JAE NONE

          MOV [LASTENT],DI

          ADD BX,32

          CMP BX,DX

          JB HAVIT

          INC AL ;Next directory sector

          PUSH DX ;Save limit

          CALL DIRREAD

          POP DX

          MOV BX,OFFSET DOSGROUP:DIRBUF

          HAVIT:

          CLC

          RET

          NONE:

          CALL CHKDIRWRITE

          STC

          RET4: RET

          DELETE: ; System call 19

          CALL MOVNAME

          MOV AL,-1

          JC RET4

          MOV AL,CS:[ATTRIB]

          AND AL,6 ;Look only at hidden bits

          CMP AL,6 ;Both must be set

          JNZ NOTALL

          MOV CX,11

          MOV AL,"?"

          MOV DI,OFFSET DOSGROUP:NAME1

          REPE SCASB ;See if name is *.*

          JNZ NOTALL

          MOV BYTE PTR CS:[DELALL],0 ;DEL *.* - flag deleting all

          NOTALL:

          CALL FINDNAME

          MOV AL,-1

          JC RET4

          OR BH,BH ;Check if device name

          JS RET4 ;Can't delete I/O devices

          DELFILE:

          MOV BYTE PTR [DIRTYDIR],-1

          MOV AH,[DELALL]

          MOV BYTE PTR [BX],AH

          MOV BX,[SI]

          MOV SI,[BP.FAT]

          OR BX,BX

          JZ DELNXT

          CMP BX,[BP.MAXCLUS]

          JA DELNXT

          CALL RELEASE

          DELNXT:

          CALL CONTSRCH

          JNC DELFILE

          CALL FATWRT

          CALL CHKDIRWRITE

          XOR AL,AL

          RET

          RENAME: ;System call 23

          CALL MOVNAME

          JC ERRET

          ADD SI,5

          MOV DI,OFFSET DOSGROUP:NAME2

          CALL LODNAME

          JC ERRET ;Report error if second name invalid

          CALL FINDNAME

          JC ERRET

          OR BH,BH ;Check if I/O device name

          JS ERRET ;If so, can't rename it

          MOV SI,OFFSET DOSGROUP:NAME1

          MOV DI,OFFSET DOSGROUP:NAME3

          MOV CX,6 ;6 words (12 bytes)--include attribute byte

          REP MOVSW ;Copy name to search for

          RENFIL:

          MOV DI,OFFSET DOSGROUP:NAME1

          MOV SI,OFFSET DOSGROUP:NAME2

          MOV CX,11

          NEWNAM:

          LODSB

          CMP AL,"?"

          JNZ NOCHG

          MOV AL,[BX]

          NOCHG:

          STOSB

          INC BX

          LOOP NEWNAM

          MOV BYTE PTR [DI],6 ;Stop duplicates with any attributes

          CALL DEVNAME ;Check if giving it a device name

          JNC RENERR

          PUSH [LASTENT] ;Save position of match

          MOV [LASTENT],-1 ;Search entire directory for duplicate

          CALL CONTSRCH ;See if new name already exists

          POP AX

          JNC RENERR ;Error if found

          CALL GETENT ;Re-read matching entry

          MOV DI,BX

          MOV SI,OFFSET DOSGROUP:NAME1

          MOV CX,5

          MOVSB

          REP MOVSW ;Replace old name with new one

          MOV BYTE PTR [DIRTYDIR],-1 ;Flag change in directory

          MOV SI,OFFSET DOSGROUP:NAME3

          MOV DI,OFFSET DOSGROUP:NAME1

          MOV CX,6 ;Include attribute byte

          REP MOVSW ;Copy name back into search buffer

          CALL CONTSRCH

          JNC RENFIL

          CALL CHKDIRWRITE

          XOR AL,AL

          RET

          RENERR:

          CALL CHKDIRWRITE

          ERRET:

          MOV AL,-1

          RET5: RET

          MOVNAME:

          ; Inputs:

          ; DS, DX point to FCB or extended FCB

          ; Outputs:

          ; DS:DX point to normal FCB

          ; 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 CS:WORD PTR [CREATING],0E500H ;Not creating, not DEL *.*

          MOV AX,CS

          MOV ES,AX

          MOV DI,OFFSET DOSGROUP:NAME1

          MOV SI,DX

          LODSB

          MOV CS:[EXTFCB],AL ;Set flag if extended FCB in use

          MOV AH,0 ;Set default attributes

          CMP AL,-1 ;Is it an extended FCB?

          JNZ HAVATTRB

          ADD DX,7 ;Adjust to point to normal FCB

          ADD SI,6 ;Point to drive select byte

          MOV AH,[SI-1] ;Get attribute byte

          LODSB ;Get drive select byte

          HAVATTRB:

          MOV CS:[ATTRIB],AH ;Save attributes

          CALL GETTHISDRV

          LODNAME:

          ; This entry point copies a file name from DS,SI

          ; to ES,DI converting to upper case.

          CMP BYTE PTR [SI]," " ;Don't allow blank as first letter

          STC ;In case of error

          JZ RET5

          MOV CX,11

          MOVCHK:

          CALL GETLET

          JB RET5

          JNZ STOLET ;Is it a delimiter?

          CMP AL," " ;This is the only delimiter allowed

          STC ;In case of error

          JNZ RET5

          STOLET:

          STOSB

          LOOP MOVCHK

          CLC ;Got through whole name - no error

          RET6: RET

          GETTHISDRV:

          CMP CS:[NUMDRV],AL

          JC RET6

          DEC AL

          JNS PHYDRV

          MOV AL,CS:[CURDRV]

          PHYDRV:

          MOV CS:[THISDRV],AL

          RET

          OPEN: ;System call 15

          CALL GETFILE

          DOOPEN:

          ; Enter here to perform OPEN on file already found

          ; in directory. DS=CS, BX points to directory

          ; entry in DIRBUF, SI points to First Cluster field, and

          ; ES:DI point to the FCB to be opened. This entry point

          ; is used by CREATE.

          JC ERRET

          OR BH,BH ;Check if file is I/O device

          JS OPENDEV ;Special handler if so

          MOV AL,[THISDRV]

          INC AX

          STOSB

          XOR AX,AX

          IF ZEROEXT

          ADD DI,11

          STOSW ;Zero low byte of extent field if IBM only

          ENDIF

          IF NOT ZEROEXT

          ADD DI,12 ;Point to high half of CURRENT BLOCK field

          STOSB ;Set it to zero (CP/M programs set low byte)

          ENDIF

          MOV AL,128 ;Default record size

          STOSW ;Set record size

          LODSW ;Get starting cluster

          MOV DX,AX ;Save it for the moment

          MOVSW ;Transfer size to FCB

          MOVSW

          MOV AX,[SI-8] ;Get date

          STOSW ;Save date in FCB

          MOV AX,[SI-10] ;Get time

          STOSW ;Save it in FCB

          MOV AL,[BP.DEVNUM]

          OR AL,40H

          STOSB

          MOV AX,DX ;Restore starting cluster

          STOSW ; first cluster

          STOSW ; last cluster accessed

          XOR AX,AX

          STOSW ; position of last cluster

          RET

          OPENDEV:

          ADD DI,13 ;point to 2nd half of extent field

          XOR AX,AX

          STOSB ;Set it to zero

          MOV AL,128

          STOSW ;Set record size to 128

          XOR AX,AX

          STOSW

          STOSW ;Set current size to zero

          CALL DATE16

          STOSW ;Date is todays

          XCHG AX,DX

          STOSW ;Use current time

          MOV AL,BH ;Get device number

          STOSB

          XOR AL,AL ;No error

          RET

          FATERR:

          XCHG AX,DI ;Put error code in DI

          MOV AH,2 ;While trying to read FAT

          MOV AL,[THISDRV] ;Tell which drive

          CALL FATAL1

          JMP SHORT FATREAD

          STARTSRCH:

          MOV AX,-1

          MOV [LASTENT],AX

          MOV [ENTFREE],AX

          FATREAD:

          ; Inputs:

          ; DS = CS

          ; Function:

          ; If disk may have been changed, FAT is read in and buffers are

          ; flagged invalid. If not, no action is taken.

          ; Outputs:

          ; BP = Base of drive parameters

          ; Carry set if invalid drive returned by MAPDEV

          ; All other registers destroyed

          MOV AL,[THISDRV]

          XOR AH,AH ;Set default response to zero & clear carry

          CALL FAR PTR BIOSDSKCHG ;See what BIOS has to say

          JC FATERR

          CALL GETBP

          MOV AL,[THISDRV] ;Use physical unit number

          MOV SI,[BP.FAT]

          OR AH,[SI-1] ;Dirty byte for FAT

          JS NEWDSK ;If either say new disk, then it's so

          JNZ MAPDRV

          MOV AH,1

          CMP AX,WORD PTR [BUFDRVNO] ;Does buffer have dirty sector of this drive?

          JZ MAPDRV

          NEWDSK:

          CMP AL,[BUFDRVNO] ;See if buffer is for this drive

          JNZ BUFOK ;If not, don't touch it

          MOV [BUFSECNO],0 ;Flag buffers invalid

          MOV WORD PTR [BUFDRVNO],00FFH

          BUFOK:

          MOV [DIRBUFID],-1

          CALL FIGFAT

          NEXTFAT:

          PUSH AX

          CALL DSKREAD

          POP AX

          JC BADFAT

          SUB AL,[BP.FATCNT]

          JZ NEWFAT

          CALL FATWRT

          NEWFAT:

          MOV SI,[BP.FAT]

          MOV AL,[BP.DEVNUM]

          MOV AH,[SI] ;Get first byte of FAT

          OR AH,0F8H ;Put in range

          CALL FAR PTR BIOSMAPDEV

          MOV AH,0

          MOV [SI-2],AX ;Set device no. and reset dirty bit

          MAPDRV:

          MOV AL,[SI-2] ;Get device number

          GETBP:

          MOV BP,[DRVTAB] ;Just in case drive isn't valid

          AND AL,3FH ;Mask out dirty bit

          CMP AL,[NUMIO]

          CMC

          JC RET7

          PUSH AX

          MOV AH,DPBSIZ

          MUL AH

          ADD BP,AX

          POP AX

          RET7: RET

          BADFAT:

          MOV CX,DI

          ADD DX,CX

          DEC AL

          JNZ NEXTFAT

          CALL FIGFAT ;Reset registers

          CALL DREAD ;Try first FAT once more

          JMP SHORT NEWFAT

          OKRET1:

          MOV AL,0

          RET

          CLOSE: ;System call 16

          MOV DI,DX

          CMP BYTE PTR [DI],-1 ;Check for extended FCB

          JNZ NORMFCB3

          ADD DI,7

          NORMFCB3:

          TEST BYTE PTR [DI.DEVID],0C0H ;Allow only dirty files

          JNZ OKRET1 ;can't close if I/O device, or not writen

          MOV AL,[DI] ;Get physical unit number

          DEC AL ;Make zero = drive A

          MOV AH,1 ;Look for dirty buffer

          CMP AX,CS:WORD PTR [BUFDRVNO]

          JNZ FNDDIR

          ;Write back dirty buffer if on same drive

          PUSH DX

          PUSH DS

          PUSH CS

          POP DS

          MOV BYTE PTR [DIRTYBUF],0

          MOV BX,[BUFFER]

          MOV CX,1

          MOV DX,[BUFSECNO]

          MOV BP,[BUFDRVBP]

          CALL DWRITE

          POP DS

          POP DX

          FNDDIR:

          CALL GETFILE

          BADCLOSEJ:

          JC BADCLOSE

          MOV CX,ES:[DI.FIRCLUS]

          MOV [SI],CX

          MOV DX,ES:WORD PTR [DI.FILSIZ]

          MOV [SI+2],DX

          MOV DX,ES:WORD PTR [DI.FILSIZ+2]

          MOV [SI+4],DX

          MOV DX,ES:[DI.FDATE]

          MOV [SI-2],DX

          MOV DX,ES:[DI.FTIME]

          MOV [SI-4],DX

          CALL DIRWRITE

          CHKFATWRT:

          ; Do FATWRT only if FAT is dirty and uses same I/O driver

          MOV SI,[BP.FAT]

          MOV AL,[BP.DEVNUM]

          MOV AH,1

          CMP [SI-2],AX ;See if FAT dirty and uses same driver

          JNZ 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

          CALL FIGFAT

          MOV BYTE PTR [BX-1],0

          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 SI,[BP.FAT]

          MOV BYTE PTR [SI-1],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,OFFSET DOSGROUP:DIRBUF

          MOV CX,1

          RET

          CREATE: ;System call 22

          CALL MOVNAME

          JC ERRET3

          MOV DI,OFFSET DOSGROUP:NAME1

          MOV CX,11

          MOV AL,"?"

          REPNE SCASB

          JZ ERRET3

          MOV CS:BYTE PTR [CREATING],-1

          PUSH DX

          PUSH DS

          CALL FINDNAME

          JNC EXISTENT

          MOV AX,[ENTFREE] ;First free entry found in FINDNAME

          CMP AX,-1

          JZ ERRPOP

          CALL GETENT ;Point at that free entry

          JMP SHORT FREESPOT

          ERRPOP:

          POP DS

          POP DX

          ERRET3:

          MOV AL,-1

          RET

          EXISTENT:

          JNZ ERRPOP ;Error if attributes don't match

          OR BH,BH ;Check if file is I/O device

          JS OPENJMP ;If so, no action

          MOV CX,[SI] ;Get pointer to clusters

          JCXZ FREESPOT

          CMP CX,[BP.MAXCLUS]

          JA FREESPOT

          PUSH BX

          MOV BX,CX

          MOV SI,[BP.FAT]

          CALL RELEASE ;Free any data already allocated

          CALL FATWRT

          POP BX

          FREESPOT:

          MOV DI,BX

          MOV SI,OFFSET DOSGROUP:NAME1

          MOV CX,5

          MOVSB

          REP MOVSW

          MOV AL,[ATTRIB]

          STOSB

          XOR AX,AX

          MOV CL,5

          REP STOSW

          CALL DATE16

          XCHG AX,DX

          STOSW

          XCHG AX,DX

          STOSW

          XOR AX,AX

          PUSH DI

          MOV CL,6

          SMALLENT:

          REP STOSB

          PUSH BX

          CALL DIRWRITE

          POP BX

          POP SI

          OPENJMP:

          CLC ;Clear carry so OPEN won't fail

          POP ES

          POP DI

          JMP DOOPEN

          DIRREAD:

          ; Inputs:

          ; DS = CS

          ; AL = Directory block number

          ; BP = Base of drive parameters

          ; Function:

          ; Read the directory block into DIRBUF.

          ; Outputs:

          ; AX,BP unchanged

          ; All other registers destroyed.

          PUSH AX

          CALL CHKDIRWRITE

          POP AX

          PUSH AX

          MOV AH,[BP.DEVNUM]

          MOV [DIRBUFID],AX

          CALL DIRCOMP

          CALL DREAD

          POP AX

          RET8: RET

          DREAD:

          ; Inputs:

          ; BX,DS = Transfer address

          ; CX = Number of sectors

          ; 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.

          ; BP preserved. All other registers destroyed.

          CALL DSKREAD

          JNC RET8

          MOV CS:BYTE PTR [READOP],0

          CALL HARDERR

          CMP AL,1 ;Check for retry

          JZ DREAD

          RET ;Ignore otherwise

          HARDERR:

          ;Hard disk error handler. Entry conditions:

          ; DS:BX = Original disk transfer address

          ; DX = Original logical sector number

          ; CX = Number of sectors to go (first one gave the error)

          ; AX = Hardware error code

          ; DI = Original sector transfer count

          ; BP = Base of drive parameters

          ; [READOP] = 0 for read, 1 for write

          XCHG AX,DI ;Error code in DI, count in AX

          SUB AX,CX ;Number of sectors successfully transferred

          ADD DX,AX ;First sector number to retry

          PUSH DX

          MUL [BP.SECSIZ] ;Number of bytes transferred

          POP DX

          ADD BX,AX ;First address for retry

          MOV AH,0 ;Flag disk section in error

          CMP DX,[BP.FIRFAT] ;In reserved area?

          JB ERRINT

          INC AH ;Flag for FAT

          CMP DX,[BP.FIRDIR] ;In FAT?

          JB ERRINT

          INC AH

          CMP DX,[BP.FIRREC] ;In directory?

          JB ERRINT

          INC AH ;Must be in data area

          ERRINT:

          SHL AH,1 ;Make room for read/write bit

          OR AH,CS:[READOP]

          FATAL:

          MOV AL,[BP.DRVNUM] ;Get drive number

          FATAL1:

          PUSH BP ;The only thing we preserve

          MOV CS:[CONTSTK],SP

          CLI ;Prepare to play with stack

          MOV SS,CS:[SSSAVE]

          MOV SP,CS:[SPSAVE] ;User stack pointer restored

          INT 24H ;Fatal error interrupt vector

          MOV CS:[SPSAVE],SP

          MOV CS:[SSSAVE],SS

          MOV SP,CS

          MOV SS,SP

          MOV SP,CS:[CONTSTK]

          STI

          POP BP

          CMP AL,2

          JZ ERROR

          RET

          DSKREAD:

          MOV AL,[BP.DEVNUM]

          PUSH BP

          PUSH BX

          PUSH CX

          PUSH DX

          CALL FAR PTR BIOSREAD

          POP DX

          POP DI

          POP BX

          POP BP

          RET9: RET

          CHKDIRWRITE:

          TEST BYTE PTR [DIRTYDIR],-1

          JZ RET9

          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.

          MOV BYTE PTR [DIRTYDIR],0

          MOV AL,BYTE PTR [DIRBUFID]

          CALL DIRCOMP

          DWRITE:

          ; Inputs:

          ; BX,DS = Transfer address

          ; CX = Number of sectors

          ; 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.

          ; BP preserved. All other registers destroyed.

          MOV AL,[BP.DEVNUM]

          MOV AH,CS:VERFLG

          PUSH BP

          PUSH BX

          PUSH CX

          PUSH DX

          CALL FAR PTR BIOSWRITE

          POP DX

          POP DI

          POP BX

          POP BP

          JNC RET9

          MOV CS:BYTE PTR [READOP],1

          CALL HARDERR

          CMP AL,1 ;Check for retry

          JZ DWRITE

          RET

          ABORT:

          LDS SI,CS:DWORD PTR [SPSAVE]

          MOV DS,[SI.CSSAVE]

          XOR AX,AX

          MOV ES,AX

          MOV SI,SAVEXIT

          MOV DI,EXIT

          MOVSW

          MOVSW

          MOVSW

          MOVSW

          MOVSW

          MOVSW

          ERROR:

          MOV AX,CS

          MOV DS,AX

          MOV ES,AX

          CALL WRTFATS

          XOR AX,AX

          CLI

          MOV SS,[SSSAVE]

          MOV SP,[SPSAVE]

          MOV DS,AX

          MOV SI,EXIT

          MOV DI,OFFSET DOSGROUP:EXITHOLD

          MOVSW

          MOVSW

          POP AX

          POP BX

          POP CX

          POP DX

          POP SI

          POP DI

          POP BP

          POP DS

          POP ES

          STI ;Stack OK now

          JMP CS:DWORD PTR [EXITHOLD]

          SEQRD: ;System call 20

          CALL GETREC

          CALL LOAD

          JMP SHORT FINSEQ

          SEQWRT: ;System call 21

          CALL GETREC

          CALL STORE

          FINSEQ:

          JCXZ SETNREX

          ADD AX,1

          ADC DX,0

          JMP SHORT SETNREX

          RNDRD: ;System call 33

          CALL GETRRPOS1

          CALL LOAD

          JMP SHORT FINRND

          RNDWRT: ;System call 34

          CALL GETRRPOS1

          CALL STORE

          JMP SHORT FINRND

          BLKRD: ;System call 39

          CALL GETRRPOS

          CALL LOAD

          JMP SHORT FINBLK

          BLKWRT: ;System call 40

          CALL GETRRPOS

          CALL STORE

          FINBLK:

          LDS SI,DWORD PTR [SPSAVE]

          MOV [SI.CXSAVE],CX

          JCXZ FINRND

          ADD AX,1

          ADC DX,0

          FINRND:

          MOV ES:WORD PTR [DI.RR],AX

          MOV ES:[DI.RR+2],DL

          OR DH,DH

          JZ SETNREX

          MOV ES:[DI.RR+3],DH ;Save 4 byte of RECPOS only if significant

          SETNREX:

          MOV CX,AX

          AND AL,7FH

          MOV ES:[DI.NR],AL

          AND CL,80H

          SHL CX,1

          RCL DX,1

          MOV AL,CH

          MOV AH,DL

          MOV ES:[DI.EXTENT],AX

          MOV AL,CS:[DSKERR]

          RET

          GETRRPOS1:

          MOV CX,1

          GETRRPOS:

          MOV DI,DX

          CMP BYTE PTR [DI],-1

          JNZ NORMFCB1

          ADD DI,7

          NORMFCB1:

          MOV AX,WORD PTR [DI.RR]

          MOV DX,WORD PTR [DI.RR+2]

          RET

          NOFILERR:

          XOR CX,CX

          MOV BYTE PTR [DSKERR],4

          POP BX

          RET

          SETUP:

          ; Inputs:

          ; DS:DI point to FCB

          ; DX:AX = Record position in file of disk transfer

          ; CX = Record count

          ; Outputs:

          ; DS = CS

          ; ES:DI point to FCB

          ; BL = DEVID from FCB

          ; CX = No. of bytes to transfer

          ; BP = Base of drive parameters

          ; SI = FAT pointer

          ; [RECCNT] = Record count

          ; [RECPOS] = Record position in file

          ; [FCB] = DI

          ; [NEXTADD] = Displacement of disk transfer within segment

          ; [SECPOS] = Position of first sector

          ; [BYTPOS] = Byte position in file

          ; [BYTSECPOS] = Byte position in first sector

          ; [CLUSNUM] = First cluster

          ; [SECCLUSPOS] = Sector within first cluster

          ; [DSKERR] = 0 (no errors yet)

          ; [TRANS] = 0 (No transfers yet)

          ; [THISDRV] = Physical drive unit number

          ; If SETUP detects no records will be transfered, it returns 1 level up

          ; with CX = 0.

          PUSH AX

          MOV AL,[DI]

          DEC AL

          MOV CS:[THISDRV],AL

          MOV AL,[DI.DEVID]

          MOV SI,[DI.RECSIZ]

          OR SI,SI

          JNZ HAVRECSIZ

          MOV SI,128

          MOV [DI.RECSIZ],SI

          HAVRECSIZ:

          PUSH DS

          POP ES ;Set ES to DS

          PUSH CS

          POP DS ;Set DS to CS

          OR AL,AL ;Is it a device?

          JNS NOTDEVICE

          MOV AL,0 ;Fake in drive 0 so we can get SP

          NOTDEVICE:

          CALL GETBP

          POP AX

          JC NOFILERR

          CMP SI,64 ;Check if highest byte of RECPOS is significant

          JB SMALREC

          MOV DH,0 ;Ignore MSB if record >= 64 bytes

          SMALREC:

          MOV [RECCNT],CX

          MOV WORD PTR [RECPOS],AX

          MOV WORD PTR [RECPOS+2],DX

          MOV [FCB],DI

          MOV BX,[DMAADD]

          MOV [NEXTADD],BX

          MOV BYTE PTR [DSKERR],0

          MOV BYTE PTR [TRANS],0

          MOV BX,DX

          MUL SI

          MOV WORD PTR [BYTPOS],AX

          PUSH DX

          MOV AX,BX

          MUL SI

          POP BX

          ADD AX,BX

          ADC DX,0 ;Ripple carry

          JNZ EOFERR

          MOV WORD PTR [BYTPOS+2],AX

          MOV DX,AX

          MOV AX,WORD PTR [BYTPOS]

          MOV BX,[BP.SECSIZ]

          CMP DX,BX ;See if divide will overflow

          JNC EOFERR

          DIV BX

          MOV [SECPOS],AX

          MOV [BYTSECPOS],DX

          MOV DX,AX

          AND AL,[BP.CLUSMSK]

          MOV [SECCLUSPOS],AL

          MOV AX,CX ;Record count

          MOV CL,[BP.CLUSSHFT]

          SHR DX,CL

          MOV [CLUSNUM],DX

          MUL SI ;Multiply by bytes per record

          MOV CX,AX

          ADD AX,[DMAADD] ;See if it will fit in one segment

          ADC DX,0

          JZ OK ;Must be less than 64K

          MOV AX,[DMAADD]

          NEG AX ;Amount of room left in segment

          JNZ PARTSEG ;All 64K available?

          DEC AX ;If so, reduce by one

          PARTSEG:

          XOR DX,DX

          DIV SI ;How many records will fit?

          MOV [RECCNT],AX

          MUL SI ;Translate that back into bytes

          MOV BYTE PTR [DSKERR],2 ;Flag that trimming took place

          MOV CX,AX

          JCXZ NOROOM

          OK:

          MOV BL,ES:[DI.DEVID]

          MOV SI,[BP.FAT]

          RET

          EOFERR:

          MOV BYTE PTR [DSKERR],1

          XOR CX,CX

          NOROOM:

          POP BX ;Kill return address

          RET

          BREAKDOWN:

          ;Inputs:

          ; DS = CS

          ; CX = Length of disk transfer in bytes

          ; BP = Base of drive parameters

          ; [BYTSECPOS] = Byte position witin first sector

          ;Outputs:

          ; [BYTCNT1] = Bytes to transfer in first sector

          ; [SECCNT] = No. of whole sectors to transfer

          ; [BYTCNT2] = Bytes to transfer in last sector

          ;AX, BX, DX destroyed. No other registers affected.

          MOV AX,[BYTSECPOS]

          MOV BX,CX

          OR AX,AX

          JZ SAVFIR ;Partial first sector?

          SUB AX,[BP.SECSIZ]

          NEG AX ;Max number of bytes left in first sector

          SUB BX,AX ;Subtract from total length

          JAE SAVFIR

          ADD AX,BX ;Don't use all of the rest of the sector

          XOR BX,BX ;And no bytes are left

          SAVFIR:

          MOV [BYTCNT1],AX

          MOV AX,BX

          XOR DX,DX

          DIV [BP.SECSIZ] ;How many whole sectors?

          MOV [SECCNT],AX

          MOV [BYTCNT2],DX ;Bytes remaining for last sector

          RET10: 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.

          MOV BX,ES:[DI.LSTCLUS]

          MOV DX,ES:[DI.CLUSPOS]

          OR BX,BX

          JZ NOCLUS

          SUB CX,DX

          JNB FINDIT

          ADD CX,DX

          XOR DX,DX

          MOV BX,ES:[DI.FIRCLUS]

          FINDIT:

          JCXZ RET10

          SKPCLP:

          CALL UNPACK

          CMP DI,0FF8H

          JAE RET10

          XCHG BX,DI

          INC DX

          LOOP SKPCLP

          RET

          NOCLUS:

          INC CX

          DEC DX

          RET

          BUFSEC:

          ; Inputs:

          ; AL = 0 if buffer must be read, 1 if no pre-read needed

          ; BP = Base of drive parameters

          ; [CLUSNUM] = Physical cluster number

          ; [SECCLUSPOS] = Sector position of transfer within cluster

          ; [BYTCNT1] = Size of transfer

          ; Function:

          ; Insure specified sector is in buffer, flushing buffer before

          ; read if necessary.

          ; Outputs:

          ; SI = Pointer to buffer

          ; DI = Pointer to transfer address

          ; CX = Number of bytes

          ; [NEXTADD] updated

          ; [TRANS] set to indicate a transfer will occur

          MOV DX,[CLUSNUM]

          MOV BL,[SECCLUSPOS]

          CALL FIGREC

          MOV [PREREAD],AL

          CMP DX,[BUFSECNO]

          JNZ GETSEC

          MOV AL,[BUFDRVNO]

          CMP AL,[THISDRV]

          JZ FINBUF ;Already have it?

          GETSEC:

          XOR AL,AL

          XCHG [DIRTYBUF],AL ;Read dirty flag and reset it

          OR AL,AL

          JZ RDSEC

          PUSH DX

          PUSH BP

          MOV BP,[BUFDRVBP]

          MOV BX,[BUFFER]

          MOV CX,1

          MOV DX,[BUFSECNO]

          CALL DWRITE

          POP BP

          POP DX

          RDSEC:

          TEST BYTE PTR [PREREAD],-1

          JNZ SETBUF

          XOR AX,AX

          MOV [BUFSECNO],AX ;Set buffer valid in case of disk error

          DEC AX

          MOV [BUFDRVNO],AL

          MOV BX,[BUFFER]

          MOV CX,1

          PUSH DX

          CALL DREAD

          POP DX

          SETBUF:

          MOV [BUFSECNO],DX

          MOV AL,[THISDRV]

          MOV [BUFDRVNO],AL

          MOV [BUFDRVBP],BP

          FINBUF:

          MOV BYTE PTR [TRANS],1 ;A transfer is taking place

          MOV DI,[NEXTADD]

          MOV SI,DI

          MOV CX,[BYTCNT1]

          ADD SI,CX

          MOV [NEXTADD],SI

          MOV SI,[BUFFER]

          ADD SI,[BYTSECPOS]

          RET

          BUFRD:

          XOR AL,AL ;Pre-read necessary

          CALL BUFSEC

          PUSH ES

          MOV ES,[DMAADD+2]

          SHR CX,1

          JNC EVENRD

          MOVSB

          EVENRD:

          REP MOVSW

          POP ES

          RET

          BUFWRT:

          MOV AX,[SECPOS]

          INC AX ;Set for next sector

          MOV [SECPOS],AX

          CMP AX,[VALSEC] ;Has sector been written before?

          MOV AL,1

          JA NOREAD ;Skip preread if SECPOS>VALSEC

          MOV AL,0

          NOREAD:

          CALL BUFSEC

          XCHG DI,SI

          PUSH DS

          PUSH ES

          PUSH CS

          POP ES

          MOV DS,[DMAADD+2]

          SHR CX,1

          JNC EVENWRT

          MOVSB

          EVENWRT:

          REP MOVSW

          POP ES

          POP DS

          MOV BYTE PTR [DIRTYBUF],1

          RET

          NEXTSEC:

          TEST BYTE PTR [TRANS],-1

          JZ CLRET

          MOV AL,[SECCLUSPOS]

          INC AL

          CMP AL,[BP.CLUSMSK]

          JBE SAVPOS

          MOV BX,[CLUSNUM]

          CMP BX,0FF8H

          JAE NONEXT

          MOV SI,[BP.FAT]

          CALL UNPACK

          MOV [CLUSNUM],DI

          INC [LASTPOS]

          MOV AL,0

          SAVPOS:

          MOV [SECCLUSPOS],AL

          CLRET:

          CLC

          RET

          NONEXT:

          STC

          RET

          TRANBUF:

          LODSB

          STOSB

          CMP AL,13 ;Check for carriage return

          JNZ NORMCH

          MOV BYTE PTR [SI],10

          NORMCH:

          CMP AL,10

          LOOPNZ TRANBUF

          JNZ ENDRDCON

          CALL OUT ;Transmit linefeed

          XOR SI,SI

          OR CX,CX

          JNZ GETBUF

          OR AL,1 ;Clear zero flag--not end of file

          ENDRDCON:

          MOV [CONTPOS],SI

          ENDRDDEV:

          MOV [NEXTADD],DI

          POP ES

          JNZ SETFCBJ ;Zero set if Ctrl-Z found in input

          MOV DI,[FCB]

          AND ES:BYTE PTR [DI.DEVID],0FFH-40H ;Mark as no more data available

          SETFCBJ:

          JMP SETFCB

          READDEV:

          PUSH ES

          LES DI,DWORD PTR [DMAADD]

          INC BL

          JZ READCON

          INC BL

          JNZ ENDRDDEV

          READAUX:

          CALL AUXIN

          STOSB

          CMP AL,1AH

          LOOPNZ READAUX

          JMP SHORT ENDRDDEV

          READCON:

          PUSH CS

          POP DS

          MOV SI,[CONTPOS]

          OR SI,SI

          JNZ TRANBUF

          CMP BYTE PTR [CONBUF],128

          JZ GETBUF

          MOV WORD PTR [CONBUF],0FF80H ;Set up 128-byte buffer with no template

          GETBUF:

          PUSH CX

          PUSH ES

          PUSH DI

          MOV DX,OFFSET DOSGROUP:CONBUF

          CALL BUFIN ;Get input buffer

          POP DI

          POP ES

          POP CX

          MOV SI,2 + OFFSET DOSGROUP:CONBUF

          CMP BYTE PTR [SI],1AH ;Check for Ctrl-Z in first character

          JNZ TRANBUF

          MOV AL,1AH

          STOSB

          MOV AL,10

          CALL OUT ;Send linefeed

          XOR SI,SI

          JMP SHORT ENDRDCON

          RDERR:

          XOR CX,CX

          JMP WRTERR

          RDLASTJ:JMP RDLAST

          LOAD:

          ; Inputs:

          ; DS:DI point to FCB

          ; DX:AX = Position in file to read

          ; CX = No. of records to read

          ; Outputs:

          ; DX:AX = Position of last record read

          ; CX = No. of bytes read

          ; ES:DI point to FCB

          ; LSTCLUS, CLUSPOS fields in FCB set

          CALL SETUP

          OR BL,BL ;Check for named device I/O

          JS READDEV

          MOV AX,ES:WORD PTR [DI.FILSIZ]

          MOV BX,ES:WORD PTR [DI.FILSIZ+2]

          SUB AX,WORD PTR [BYTPOS]

          SBB BX,WORD PTR [BYTPOS+2]

          JB RDERR

          JNZ ENUF

          OR AX,AX

          JZ RDERR

          CMP AX,CX

          JAE ENUF

          MOV CX,AX

          ENUF:

          CALL BREAKDOWN

          MOV CX,[CLUSNUM]

          CALL FNDCLUS

          OR CX,CX

          JNZ RDERR

          MOV [LASTPOS],DX

          MOV [CLUSNUM],BX

          CMP [BYTCNT1],0

          JZ RDMID

          CALL BUFRD

          RDMID:

          CMP [SECCNT],0

          JZ RDLASTJ

          CALL NEXTSEC

          JC SETFCB

          MOV BYTE PTR [TRANS],1 ;A transfer is taking place

          ONSEC:

          MOV DL,[SECCLUSPOS]

          MOV CX,[SECCNT]

          MOV BX,[CLUSNUM]

          RDLP:

          CALL OPTIMIZE

          PUSH DI

          PUSH AX

          PUSH DS

          MOV DS,[DMAADD+2]

          PUSH DX

          PUSH BX

          PUSHF ;Save carry flag

          CALL DREAD

          POPF ;Restore carry flag

          POP DI ;Initial transfer address

          POP AX ;First sector transfered

          POP DS

          JC NOTBUFFED ;Was one of those sectors in the buffer?

          CMP BYTE PTR [DIRTYBUF],0 ;Is buffer dirty?

          JZ NOTBUFFED ;If not no problem

          ;We have transfered in a sector from disk when a dirty copy of it is in the buffer.

          ;We must transfer the sector from the buffer to correct memory address

          SUB AX,[BUFSECNO] ;How many sectors into the transfer?

          NEG AX

          MOV CX,[BP.SECSIZ]

          MUL CX ;How many bytes into the transfer?

          ADD DI,AX

          MOV SI,[BUFFER]

          PUSH ES

          MOV ES,[DMAADD+2] ;Get disk transfer segment

          SHR CX,1

          REP MOVSW

          JNC EVENMOV

          MOVSB

          EVENMOV:

          POP ES

          NOTBUFFED:

          POP CX

          POP BX

          JCXZ RDLAST

          CMP BX,0FF8H

          JAE SETFCB

          MOV DL,0

          INC [LASTPOS] ;We'll be using next cluster

          JMP SHORT RDLP

          SETFCB:

          MOV SI,[FCB]

          MOV AX,[NEXTADD]

          MOV DI,AX

          SUB AX,[DMAADD] ;Number of bytes transfered

          XOR DX,DX

          MOV CX,ES:[SI.RECSIZ]

          DIV CX ;Number of records

          CMP AX,[RECCNT] ;Check if all records transferred

          JZ FULLREC

          MOV BYTE PTR [DSKERR],1

          OR DX,DX

          JZ FULLREC ;If remainder 0, then full record transfered

          MOV BYTE PTR [DSKERR],3 ;Flag partial last record

          SUB CX,DX ;Bytes left in last record

          PUSH ES

          MOV ES,[DMAADD+2]

          XCHG AX,BX ;Save the record count temporarily

          XOR AX,AX ;Fill with zeros

          SHR CX,1

          JNC EVENFIL

          STOSB

          EVENFIL:

          REP STOSW

          XCHG AX,BX ;Restore record count to AX

          POP ES

          INC AX ;Add last (partial) record to total

          FULLREC:

          MOV CX,AX

          MOV DI,SI ;ES:DI point to FCB

          SETCLUS:

          MOV AX,[CLUSNUM]

          MOV ES:[DI.LSTCLUS],AX

          MOV AX,[LASTPOS]

          MOV ES:[DI.CLUSPOS],AX

          ADDREC:

          MOV AX,WORD PTR [RECPOS]

          MOV DX,WORD PTR [RECPOS+2]

          JCXZ RET28 ;If no records read, don't change position

          DEC CX

          ADD AX,CX ;Update current record position

          ADC DX,0

          INC CX

          RET28: RET

          RDLAST:

          MOV AX,[BYTCNT2]

          OR AX,AX

          JZ SETFCB

          MOV [BYTCNT1],AX

          CALL NEXTSEC

          JC SETFCB

          MOV [BYTSECPOS],0

          CALL BUFRD

          JMP SHORT SETFCB

          WRTDEV:

          PUSH DS

          LDS SI,DWORD PTR [DMAADD]

          OR BL,40H

          INC BL

          JZ WRTCON

          INC BL

          JZ WRTAUX

          INC BL

          JZ ENDWRDEV ;Done if device is NUL

          WRTLST:

          LODSB

          CMP AL,1AH

          JZ ENDWRDEV

          CALL LISTOUT

          LOOP WRTLST

          JMP SHORT ENDWRDEV

          WRTAUX:

          LODSB

          CALL AUXOUT

          CMP AL,1AH

          LOOPNZ WRTAUX

          JMP SHORT ENDWRDEV

          WRTCON:

          LODSB

          CMP AL,1AH

          JZ ENDWRDEV

          CALL OUT

          LOOP WRTCON

          ENDWRDEV:

          POP DS

          MOV CX,[RECCNT]

          MOV DI,[FCB]

          JMP SHORT ADDREC

          HAVSTART:

          MOV CX,AX

          CALL SKPCLP

          JCXZ DOWRTJ

          CALL ALLOCATE

          JNC DOWRTJ

          WRTERR:

          MOV BYTE PTR [DSKERR],1

          LVDSK:

          MOV AX,WORD PTR [RECPOS]

          MOV DX,WORD PTR [RECPOS+2]

          MOV DI,[FCB]

          RET

          DOWRTJ: JMP DOWRT

          WRTEOFJ:

          JMP WRTEOF

          STORE:

          ; Inputs:

          ; DS:DI point to FCB

          ; DX:AX = Position in file of disk transfer

          ; CX = Record count

          ; Outputs:

          ; DX:AX = Position of last record written

          ; CX = No. of records written

          ; ES:DI point to FCB

          ; LSTCLUS, CLUSPOS fields in FCB set

          CALL SETUP

          CALL DATE16

          MOV ES:[DI.FDATE],AX

          MOV ES:[DI.FTIME],DX

          OR BL,BL

          JS WRTDEV

          AND BL,3FH ;Mark file as dirty

          MOV ES:[DI.DEVID],BL

          CALL BREAKDOWN

          MOV AX,WORD PTR [BYTPOS]

          MOV DX,WORD PTR [BYTPOS+2]

          JCXZ WRTEOFJ

          DEC CX

          ADD AX,CX

          ADC DX,0 ;AX:DX=last byte accessed

          DIV [BP.SECSIZ] ;AX=last sector accessed

          MOV CL,[BP.CLUSSHFT]

          SHR AX,CL ;Last cluster to be accessed

          PUSH AX

          MOV AX,ES:WORD PTR [DI.FILSIZ]

          MOV DX,ES:WORD PTR [DI.FILSIZ+2]

          DIV [BP.SECSIZ]

          OR DX,DX

          JZ NORNDUP

          INC AX ;Round up if any remainder

          NORNDUP:

          MOV [VALSEC],AX ;Number of sectors that have been written

          POP AX

          MOV CX,[CLUSNUM] ;First cluster accessed

          CALL FNDCLUS

          MOV [CLUSNUM],BX

          MOV [LASTPOS],DX

          SUB AX,DX ;Last cluster minus current cluster

          JZ DOWRT ;If we have last clus, we must have first

          JCXZ HAVSTART ;See if no more data

          PUSH CX ;No. of clusters short of first

          MOV CX,AX

          CALL ALLOCATE

          POP AX

          JC WRTERR

          MOV CX,AX

          MOV DX,[LASTPOS]

          INC DX

          DEC CX

          JZ NOSKIP

          CALL SKPCLP

          NOSKIP:

          MOV [CLUSNUM],BX

          MOV [LASTPOS],DX

          DOWRT:

          CMP [BYTCNT1],0

          JZ WRTMID

          MOV BX,[CLUSNUM]

          CALL BUFWRT

          WRTMID:

          MOV AX,[SECCNT]

          OR AX,AX

          JZ WRTLAST

          ADD [SECPOS],AX

          CALL NEXTSEC

          MOV BYTE PTR [TRANS],1 ;A transfer is taking place

          MOV DL,[SECCLUSPOS]

          MOV BX,[CLUSNUM]

          MOV CX,[SECCNT]

          WRTLP:

          CALL OPTIMIZE

          JC NOTINBUF ;Is one of the sectors buffered?

          MOV [BUFSECNO],0 ;If so, invalidate the buffer since we're

          MOV WORD PTR [BUFDRVNO],0FFH ; completely rewritting it

          NOTINBUF:

          PUSH DI

          PUSH AX

          PUSH DS

          MOV DS,[DMAADD+2]

          CALL DWRITE

          POP DS

          POP CX

          POP BX

          JCXZ WRTLAST

          MOV DL,0

          INC [LASTPOS] ;We'll be using next cluster

          JMP SHORT WRTLP

          WRTLAST:

          MOV AX,[BYTCNT2]

          OR AX,AX

          JZ FINWRT

          MOV [BYTCNT1],AX

          CALL NEXTSEC

          MOV [BYTSECPOS],0

          CALL BUFWRT

          FINWRT:

          MOV AX,[NEXTADD]

          SUB AX,[DMAADD]

          ADD AX,WORD PTR [BYTPOS]

          MOV DX,WORD PTR [BYTPOS+2]

          ADC DX,0

          MOV CX,DX

          MOV DI,[FCB]

          CMP AX,ES:WORD PTR [DI.FILSIZ]

          SBB CX,ES:WORD PTR [DI.FILSIZ+2]

          JB SAMSIZ

          MOV ES:WORD PTR [DI.FILSIZ],AX

          MOV ES:WORD PTR [DI.FILSIZ+2],DX

          SAMSIZ:

          MOV CX,[RECCNT]

          JMP SETCLUS

          WRTERRJ:JMP WRTERR

          WRTEOF:

          MOV CX,AX

          OR CX,DX

          JZ KILLFIL

          SUB AX,1

          SBB DX,0

          DIV [BP.SECSIZ]

          MOV CL,[BP.CLUSSHFT]

          SHR AX,CL

          MOV CX,AX

          CALL FNDCLUS

          JCXZ RELFILE

          CALL ALLOCATE

          JC WRTERRJ

          UPDATE:

          MOV DI,[FCB]

          MOV AX,WORD PTR [BYTPOS]

          MOV ES:WORD PTR [DI.FILSIZ],AX

          MOV AX,WORD PTR [BYTPOS+2]

          MOV ES:WORD PTR [DI.FILSIZ+2],AX

          XOR CX,CX

          JMP ADDREC

          RELFILE:

          MOV DX,0FFFH

          CALL RELBLKS

          SETDIRT:

          MOV BYTE PTR [SI-1],1

          JMP SHORT UPDATE

          KILLFIL:

          XOR BX,BX

          XCHG BX,ES:[DI.FIRCLUS]

          OR BX,BX

          JZ UPDATE

          CALL RELEASE

          JMP SHORT SETDIRT

          OPTIMIZE:

          ; Inputs:

          ; DS = CS

          ; BX = Physical cluster

          ; CX = No. of records

          ; DL = sector 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 sector address

          ; DI = Next cluster

          ; Carry clear if a sector to transfer is in the buffer

          ; Carry set otherwise

          ; [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 sectors per cluster

          MOV AH,AL

          SUB AL,DL ;AL = Number of sectors left in first cluster

          MOV DX,CX

          MOV SI,[BP.FAT]

          MOV CX,0

          OPTCLUS:

          ;AL has number of sectors available in current cluster

          ;AH has number of sectors available in next cluster

          ;BX has current physical cluster

          ;CX has number of sequential sectors found so far

          ;DX has number of sectors 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 sectors still needed

          PUSH DX

          MOV AX,CX

          MUL [BP.SECSIZ] ;Number of sectors times sector size

          MOV SI,[NEXTADD]

          ADD AX,SI ;Adjust by size of transfer

          MOV [NEXTADD],AX

          POP AX ;Number of sectors still needed

          POP DX ;Starting cluster

          SUB BX,DX ;Number of new clusters accessed

          ADD [LASTPOS],BX

          POP BX ;BL = sector postion within cluster

          CALL FIGREC

          MOV BX,SI

          ;Now let's see if any of these sectors are already in the buffer

          CMP [BUFSECNO],DX

          JC RET100 ;If DX > [BUFSECNO] then not in buffer

          MOV SI,DX

          ADD SI,CX ;Last sector + 1

          CMP [BUFSECNO],SI

          CMC

          JC RET100 ;If SI <= [BUFSECNO] then not in buffer

          PUSH AX

          MOV AL,[BP.DEVNUM]

          CMP AL,[BUFDRVNO] ;Is buffer for this drive?

          POP AX

          JZ RET100 ;If so, then we match

          STC ;No match

          RET100: RET

          BLKDON:

          SUB CX,DX ;Number of sectors in cluster we don't want

          SUB AH,CL ;Number of sectors in cluster we accepted

          DEC AH ;Adjust to mean position within cluster

          MOV [SECCLUSPOS],AH

          MOV CX,DX ;Anyway, make the total equal to the request

          JMP SHORT FINCLUS

          FIGREC:

          ;Inputs:

          ; DX = Physical cluster number

          ; BL = Sector postion within cluster

          ; BP = Base of drive parameters

          ;Outputs:

          ; DX = physical sector number

          ;No other registers affected.

          PUSH CX

          MOV CL,[BP.CLUSSHFT]

          DEC DX

          DEC DX

          SHL DX,CL

          OR DL,BL

          ADD DX,[BP.FIRREC]

          POP CX

          RET

          GETREC:

          ; Inputs:

          ; DS:DX point to FCB

          ; Outputs:

          ; CX = 1

          ; DX:AX = Record number determined by EXTENT and NR fields

          ; DS:DI point to FCB

          ; No other registers affected.

          MOV DI,DX

          CMP BYTE PTR [DI],-1 ;Check for extended FCB

          JNZ NORMFCB2

          ADD DI,7

          NORMFCB2:

          MOV CX,1

          MOV AL,[DI.NR]

          MOV DX,[DI.EXTENT]

          SHL AL,1

          SHR DX,1

          RCR AL,1

          MOV AH,DL

          MOV DL,DH

          MOV DH,0

          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

          ; CX = max. no. of records that could be added to file

          ; 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 [SI]

          PUSH DX

          PUSH CX

          PUSH BX

          MOV AX,BX

          ALLOC:

          MOV DX,BX

          FINDFRE:

          INC BX

          CMP BX,[BP.MAXCLUS]

          JLE TRYOUT

          CMP AX,1

          JG TRYIN

          POP BX

          MOV DX,0FFFH

          CALL RELBLKS

          POP AX ;No. of clusters requested

          SUB AX,CX ;AX=No. of clusters allocated

          POP DX

          POP [SI]

          INC DX ;Position of first cluster allocated

          ADD AX,DX ;AX=max no. of cluster in file

          MOV DL,[BP.CLUSMSK]

          MOV DH,0

          INC DX ;DX=records/cluster

          MUL DX ;AX=max no. of records in file

          MOV CX,AX

          SUB CX,WORD PTR [RECPOS] ;CX=max no. of records that could be written

          JA MAXREC

          XOR CX,CX ;If CX was negative, zero it

          MAXREC:

          STC

          RET11: RET

          TRYOUT:

          CALL UNPACK

          JZ HAVFRE

          TRYIN:

          DEC AX

          JLE FINDFRE

          XCHG AX,BX

          CALL UNPACK

          JZ HAVFRE

          XCHG AX,BX

          JMP SHORT FINDFRE

          HAVFRE:

          XCHG BX,DX

          MOV AX,DX

          CALL PACK

          MOV BX,AX

          LOOP ALLOC

          MOV DX,0FFFH

          CALL PACK

          MOV BYTE PTR [SI-1],1

          POP BX

          POP CX ;Don't need this stuff since we're successful

          POP DX

          CALL UNPACK

          POP [SI]

          XCHG BX,DI

          OR DI,DI

          JNZ RET11

          MOV DI,[FCB]

          MOV ES:[DI.FIRCLUS],BX

          RET12: 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 RET12

          MOV AX,DI

          CALL PACK

          CMP AX,0FF8H

          MOV BX,AX

          JB RELEASE

          RET13: 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,0FF8H

          JAE RET13

          MOV BX,DI

          JMP SHORT GETEOF

          SRCHFRST: ;System call 17

          CALL GETFILE

          SAVPLCE:

          ; Search-for-next enters here to save place and report

          ; findings.

          JC KILLSRCH

          OR BH,BH

          JS SRCHDEV

          MOV AX,[LASTENT]

          MOV ES:[DI.FILDIRENT],AX

          MOV ES:[DI.DRVBP],BP

          ;Information in directory entry must be copied into the first

          ; 33 bytes starting at the disk transfer address.

          MOV SI,BX

          LES DI,DWORD PTR [DMAADD]

          MOV AX,00FFH

          CMP AL,[EXTFCB]

          JNZ NORMFCB

          STOSW

          INC AL

          STOSW

          STOSW

          MOV AL,[ATTRIB]

          STOSB

          NORMFCB:

          MOV AL,[THISDRV]

          INC AL

          STOSB ;Set drive number

          MOV CX,16

          REP MOVSW ;Copy remaining 10 characters of name

          XOR AL,AL

          RET

          KILLSRCH:

          KILLSRCH1 EQU KILLSRCH+1

          ;The purpose of the KILLSRCH1 label is to provide a jump label to the following

          ; instruction which leaves out the segment override.

          MOV WORD PTR ES:[DI.FILDIRENT],-1

          MOV AL,-1

          RET

          SRCHDEV:

          MOV ES:[DI.FILDIRENT],BX

          LES DI,DWORD PTR [DMAADD]

          XOR AX,AX

          STOSB ;Zero drive byte

          SUB SI,4 ;Point to device name

          MOVSW

          MOVSW

          MOV AX,2020H

          STOSB

          STOSW

          STOSW

          STOSW ;Fill with 8 blanks

          XOR AX,AX

          MOV CX,10

          REP STOSW

          STOSB

          RET14: RET

          SRCHNXT: ;System call 18

          CALL MOVNAME

          MOV DI,DX

          JC NEAR PTR KILLSRCH1

          MOV BP,[DI.DRVBP]

          MOV AX,[DI.FILDIRENT]

          OR AX,AX

          JS NEAR PTR KILLSRCH1

          PUSH DX

          PUSH DS

          PUSH CS

          POP DS

          MOV [LASTENT],AX

          CALL CONTSRCH

          POP ES

          POP DI

          JMP SAVPLCE

          FILESIZE: ;System call 35

          CALL GETFILE

          MOV AL,-1

          JC RET14

          ADD DI,33 ;Write size in RR field

          MOV CX,ES:[DI.RECSIZ-33]

          OR CX,CX

          JNZ RECOK

          MOV CX,128

          RECOK:

          XOR AX,AX

          XOR DX,DX ;Intialize size to zero

          OR BH,BH ;Check for named I/O device

          JS DEVSIZ

          INC SI

          INC SI ;Point to length field

          MOV AX,[SI+2] ;Get high word of size

          DIV CX

          PUSH AX ;Save high part of result

          LODSW ;Get low word of size

          DIV CX

          OR DX,DX ;Check for zero remainder

          POP DX

          JZ DEVSIZ

          INC AX ;Round up for partial record

          JNZ DEVSIZ ;Propagate carry?

          INC DX

          DEVSIZ:

          STOSW

          MOV AX,DX

          STOSB

          MOV AL,0

          CMP CX,64

          JAE RET14 ;Only 3-byte field if RECSIZ >= 64

          MOV ES:[DI],AH

          RET

          SETDMA: ;System call 26

          MOV CS:[DMAADD],DX

          MOV CS:[DMAADD+2],DS

          RET

          NOSUCHDRV:

          MOV AL,-1

          RET

          GETFATPT: ;System call 27

          MOV DL,0 ;Use default drive

          GETFATPTDL: ;System call 28

          PUSH CS

          POP DS

          MOV AL,DL

          CALL GETTHISDRV

          JC NOSUCHDRV

          CALL FATREAD

          MOV BX,[BP.FAT]

          MOV AL,[BP.CLUSMSK]

          INC AL

          MOV DX,[BP.MAXCLUS]

          DEC DX

          MOV CX,[BP.SECSIZ]

          LDS SI,DWORD PTR [SPSAVE]

          MOV [SI.BXSAVE],BX

          MOV [SI.DXSAVE],DX

          MOV [SI.CXSAVE],CX

          MOV [SI.DSSAVE],CS

          RET

          GETDSKPT: ;System call 31

          PUSH CS

          POP DS

          MOV AL,[CURDRV]

          MOV [THISDRV],AL

          CALL FATREAD

          LDS SI,DWORD PTR [SPSAVE]

          MOV [SI.BXSAVE],BP

          MOV [SI.DSSAVE],CS

          RET

          DSKRESET: ;System call 13

          PUSH CS

          POP DS

          WRTFATS:

          ; DS=CS. Writes back all dirty FATs. All registers destroyed.

          XOR AL,AL

          XCHG AL,[DIRTYBUF]

          OR AL,AL

          JZ NOBUF

          MOV BP,[BUFDRVBP]

          MOV DX,[BUFSECNO]

          MOV BX,[BUFFER]

          MOV CX,1

          CALL DWRITE

          NOBUF:

          MOV CL,[NUMIO]

          MOV CH,0

          MOV BP,[DRVTAB]

          WRTFAT:

          PUSH CX

          CALL CHKFATWRT

          POP CX

          ADD BP,DPBSIZ

          LOOP WRTFAT

          RET

          GETDRV: ;System call 25

          MOV AL,CS:[CURDRV]

          RET15: RET

          SETRNDREC: ;System call 36

          CALL GETREC

          MOV [DI+33],AX

          MOV [DI+35],DL

          CMP [DI.RECSIZ],64

          JAE RET15

          MOV [DI+36],DH ;Set 4th byte only if record size < 64

          RET16: RET

          SELDSK: ;System call 14

          MOV AL,CS:[NUMDRV]

          CMP DL,AL

          JNB RET17

          MOV CS:[CURDRV],DL

          RET17: RET

          BUFIN: ;System call 10

          MOV AX,CS

          MOV ES,AX

          MOV SI,DX

          MOV CH,0

          LODSW

          OR AL,AL

          JZ RET17

          MOV BL,AH

          MOV BH,CH

          CMP AL,BL

          JBE NOEDIT

          CMP BYTE PTR [BX+SI],0DH

          JZ EDITON

          NOEDIT:

          MOV BL,CH

          EDITON:

          MOV DL,AL

          DEC DX

          NEWLIN:

          MOV AL,CS:[CARPOS]

          MOV CS:[STARTPOS],AL

          PUSH SI

          MOV DI,OFFSET DOSGROUP:INBUF

          MOV AH,CH

          MOV BH,CH

          MOV DH,CH

          GETCH:

          CALL IN

          CMP AL,"F"-"@" ;Ignore ^F

          JZ GETCH

          CMP AL,CS:ESCCHAR

          JZ ESC

          CMP AL,7FH

          JZ BACKSP

          CMP AL,8

          JZ BACKSP

          CMP AL,13

          JZ ENDLIN

          CMP AL,10

          JZ PHYCRLF

          CMP AL,CANCEL

          JZ KILNEW

          SAVCH:

          CMP DH,DL

          JAE BUFFUL

          STOSB

          INC DH

          CALL BUFOUT

          OR AH,AH

          JNZ GETCH

          CMP BH,BL

          JAE GETCH

          INC SI

          INC BH

          JMP SHORT GETCH

          BUFFUL:

          MOV AL,7

          CALL OUT

          JMP SHORT GETCH

          ESC:

          CALL IN

          MOV CL,ESCTABLEN

          PUSH DI

          MOV DI,OFFSET DOSGROUP:ESCTAB

          REPNE SCASB

          POP DI

          SHL CX,1

          MOV BP,CX

          JMP [BP+OFFSET DOSGROUP:ESCFUNC]

          ENDLIN:

          STOSB

          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,OFFSET DOSGROUP:INBUF

          MOV CL,DH

          REP MOVSB

          RET

          CRLF:

          MOV AL,13

          CALL OUT

          MOV AL,10

          JMP OUT

          PHYCRLF:

          CALL CRLF

          JMP SHORT GETCH

          KILNEW:

          MOV AL,"\"

          CALL OUT

          POP SI

          PUTNEW:

          CALL CRLF

          MOV AL,CS:[STARTPOS]

          CALL TAB

          JMP NEWLIN

          BACKSP:

          OR DH,DH

          JZ OLDBAK

          CALL BACKUP

          MOV AL,ES:[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

          STD

          MOV CL,DH

          MOV AL," "

          PUSH BX

          MOV BL,7

          JCXZ FIGTAB

          FNDPOS:

          SCASB

          JNA CHKCNT

          CMP ES:BYTE PTR [DI+1],9

          JZ HAVTAB

          DEC BL

          CHKCNT:

          LOOP FNDPOS

          FIGTAB:

          SUB BL,CS:[STARTPOS]

          HAVTAB:

          SUB BL,DH

          ADD CL,BL

          AND CL,7

          CLD

          POP BX

          POP DI

          JZ OLDBAK

          TABBAK:

          CALL BACKMES

          LOOP TABBAK

          JMP SHORT OLDBAK

          BACKUP:

          DEC DH

          DEC DI

          BACKMES:

          MOV AL,8

          CALL OUT

          MOV AL," "

          CALL OUT

          MOV AL,8

          JMP OUT

          TWOESC:

          MOV AL,ESCCH

          JMP SAVCH

          COPYLIN:

          MOV CL,BL

          SUB CL,BH

          JMP SHORT COPYEACH

          COPYSTR:

          CALL FINDOLD

          JMP SHORT COPYEACH

          COPYONE:

          MOV CL,1

          COPYEACH:

          MOV AH,0

          CMP DH,DL

          JZ GETCH2

          CMP BH,BL

          JZ GETCH2

          LODSB

          STOSB

          CALL BUFOUT

          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 SCASB

          POP DI

          POP ES

          JNZ NOTFND

          NOT CL

          ADD CL,BL

          SUB CL,BH

          RET30: 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:

          IF TOGLINS

          NOT AH

          JMP GETCH

          ENDIF

          IF NOT TOGLINS

          MOV AH,-1

          JMP GETCH

          EXITINS:

          MOV AH,0

          JMP GETCH

          ENDIF

          ESCFUNC DW GETCH

          DW TWOESC

          IF NOT TOGLINS

          DW EXITINS

          ENDIF

          DW ENTERINS

          DW BACKSP

          DW REEDIT

          DW KILNEW

          DW COPYLIN

          DW SKIPSTR

          DW COPYSTR

          DW SKIPONE

          DW COPYONE

          IF IBM

          DW COPYONE

          DW CTRLZ

          CTRLZ:

          MOV AL,"Z"-"@"

          JMP SAVCH

          ENDIF

          BUFOUT:

          CMP AL," "

          JAE OUT

          CMP AL,9

          JZ OUT

          PUSH AX

          MOV AL,"^"

          CALL OUT

          POP AX

          OR AL,40H

          JMP SHORT OUT

          NOSTOP:

          CMP AL,"P"-"@"

          JZ INCHK

          IF NOT TOGLPRN

          CMP AL,"N"-"@"

          JZ INCHK

          ENDIF

          CMP AL,"C"-"@"

          JZ INCHK

          RET

          CONOUT: ;System call 2

          MOV AL,DL

          OUT:

          CMP AL,20H

          JB CTRLOUT

          CMP AL,7FH

          JZ OUTCH

          INC CS:BYTE PTR [CARPOS]

          OUTCH:

          PUSH AX

          CALL STATCHK

          POP AX

          CALL FAR PTR BIOSOUT

          TEST CS:BYTE PTR [PFLAG],-1

          JZ RET18

          CALL FAR PTR BIOSPRINT

          RET18: RET

          STATCHK:

          CALL FAR PTR BIOSSTAT

          JZ RET18

          CMP AL,'S'-'@'

          JNZ NOSTOP

          CALL FAR PTR BIOSIN ;Eat Cntrl-S

          INCHK:

          CALL FAR PTR BIOSIN

          CMP AL,'P'-'@'

          JZ PRINTON

          IF NOT TOGLPRN

          CMP AL,'N'-'@'

          JZ PRINTOFF

          ENDIF

          CMP AL,'C'-'@'

          JNZ RET18

          ; Ctrl-C handler.

          ; "^C" and CR/LF is printed. Then the user registers are restored and the

          ; user CTRL-C handler is executed. At this point the top of the stack has

          ; 1) the interrupt return address should the user CTRL-C handler wish to

          ; allow processing to continue; 2) the original interrupt return address

          ; to the code that performed the function call in the first place. If the

          ; user CTRL-C handler wishes to continue, it must leave all registers

          ; unchanged and IRET. The function that was interrupted will simply be

          ; repeated.

          MOV AL,3 ;Display "^C"

          CALL BUFOUT

          CALL CRLF

          CLI ;Prepare to play with stack

          MOV SS,CS:[SSSAVE]

          MOV SP,CS:[SPSAVE] ;User stack now restored

          POP AX

          POP BX

          POP CX

          POP DX

          POP SI

          POP DI

          POP BP

          POP DS

          POP ES ;User registers now restored

          INT CONTC ;Execute user Ctrl-C handler

          JMP COMMAND ;Repeat command otherwise

          PRINTON:

          IF TOGLPRN

          NOT CS:BYTE PTR [PFLAG]

          RET

          ENDIF

          IF NOT TOGLPRN

          MOV CS:BYTE PTR [PFLAG],1

          RET

          PRINTOFF:

          MOV CS:BYTE PTR [PFLAG],0

          RET

          ENDIF

          CTRLOUT:

          CMP AL,13

          JZ ZERPOS

          CMP AL,8

          JZ BACKPOS

          CMP AL,9

          JNZ OUTCHJ

          MOV AL,CS:[CARPOS]

          OR AL,0F8H

          NEG AL

          TAB:

          PUSH CX

          MOV CL,AL

          MOV CH,0

          JCXZ POPTAB

          TABLP:

          MOV AL," "

          CALL OUT

          LOOP TABLP

          POPTAB:

          POP CX

          RET19: RET

          ZERPOS:

          MOV CS:BYTE PTR [CARPOS],0

          OUTCHJ: JMP OUTCH

          BACKPOS:

          DEC CS:BYTE PTR [CARPOS]

          JMP OUTCH

          CONSTAT: ;System call 11

          CALL STATCHK

          MOV AL,0

          JZ RET19

          OR AL,-1

          RET

          CONIN: ;System call 1

          CALL IN

          PUSH AX

          CALL OUT

          POP AX

          RET

          IN: ;System call 8

          CALL INCHK

          JZ IN

          RET29: RET

          RAWIO: ;System call 6

          MOV AL,DL

          CMP AL,-1

          JNZ RAWOUT

          LDS SI,DWORD PTR CS:[SPSAVE] ;Get pointer to register save area

          CALL FAR PTR BIOSSTAT

          JNZ RESFLG

          OR BYTE PTR [SI.FSAVE],40H ;Set user's zero flag

          XOR AL,AL

          RET

          RESFLG:

          AND BYTE PTR [SI.FSAVE],0FFH-40H ;Reset user's zero flag

          RAWINP: ;System call 7

          CALL FAR PTR BIOSIN

          RET

          RAWOUT:

          CALL FAR PTR BIOSOUT

          RET

          LIST: ;System call 5

          MOV AL,DL

          LISTOUT:

          PUSH AX

          CALL STATCHK

          POP AX

          CALL FAR PTR BIOSPRINT

          RET20: RET

          PRTBUF: ;System call 9

          MOV SI,DX

          OUTSTR:

          LODSB

          CMP AL,"$"

          JZ RET20

          CALL OUT

          JMP SHORT OUTSTR

          OUTMES: ;String output for internal messages

          LODS CS:BYTE PTR [SI]

          CMP AL,"$"

          JZ RET20

          CALL OUT

          JMP SHORT OUTMES

          MAKEFCB: ;Interrupt call 41

          DRVBIT EQU 2

          NAMBIT EQU 4

          EXTBIT EQU 8

          MOV DL,0 ;Flag--not ambiguous file name

          TEST AL,DRVBIT ;Use current drive field if default?

          JNZ DEFDRV

          MOV BYTE PTR ES:[DI],0 ;No - use default drive

          DEFDRV:

          INC DI

          MOV CX,8

          TEST AL,NAMBIT ;Use current name fiels as defualt?

          XCHG AX,BX ;Save bits in BX

          MOV AL," "

          JZ FILLB ;If not, go fill with blanks

          ADD DI,CX

          XOR CX,CX ;Don't fill any

          FILLB:

          REP STOSB

          MOV CL,3

          TEST BL,EXTBIT ;Use current extension as default

          JZ FILLB2

          ADD DI,CX

          XOR CX,CX

          FILLB2:

          REP STOSB

          XCHG AX,CX ;Put zero in AX

          STOSW

          STOSW ;Initialize two words after to zero

          SUB DI,16 ;Point back at start

          TEST BL,1 ;Scan off separators if not zero

          JZ SKPSPC

          CALL SCANB ;Peel off blanks and tabs

          CALL DELIM ;Is it a one-time-only delimiter?

          JNZ NOSCAN

          INC SI ;Skip over the delimiter

          SKPSPC:

          CALL SCANB ;Always kill preceding blanks and tabs

          NOSCAN:

          CALL GETLET

          JBE NODRV ;Quit if termination character

          CMP BYTE PTR[SI],":" ;Check for potential drive specifier

          JNZ NODRV

          INC SI ;Skip over colon

          SUB AL,"@" ;Convert drive letter to binary drive number

          JBE BADDRV ;Valid drive numbers are 1-15

          CMP AL,CS:[NUMDRV]

          JBE HAVDRV

          BADDRV:

          MOV DL,-1

          HAVDRV:

          STOSB ;Put drive specifier in first byte

          INC SI

          DEC DI ;Counteract next two instructions

          NODRV:

          DEC SI ;Back up

          INC DI ;Skip drive byte

          MOV CX,8

          CALL GETWORD ;Get 8-letter file name

          CMP BYTE PTR [SI],"."

          JNZ NODOT

          INC SI ;Skip over dot if present

          MOV CX,3 ;Get 3-letter extension

          CALL MUSTGETWORD

          NODOT:

          LDS BX,CS:DWORD PTR [SPSAVE]

          MOV [BX.SISAVE],SI

          MOV AL,DL

          RET

          NONAM:

          ADD DI,CX

          DEC SI

          RET

          GETWORD:

          CALL GETLET

          JBE NONAM ;Exit if invalid character

          DEC SI

          MUSTGETWORD:

          CALL GETLET

          JBE FILLNAM

          JCXZ MUSTGETWORD

          DEC CX

          CMP AL,"*" ;Check for ambiguous file specifier

          JNZ NOSTAR

          MOV AL,"?"

          REP STOSB

          NOSTAR:

          STOSB

          CMP AL,"?"

          JNZ MUSTGETWORD

          OR DL,1 ;Flag ambiguous file name

          JMP MUSTGETWORD

          FILLNAM:

          MOV AL," "

          REP STOSB

          DEC SI

          RET21: RET

          SCANB:

          LODSB

          CALL SPCHK

          JZ SCANB

          DEC SI

          RET

          GETLET:

          ;Get a byte from [SI], convert it to upper case, and compare for delimiter.

          ;ZF set if a delimiter, CY set if a control character (other than TAB).

          LODSB

          AND AL,7FH

          CMP AL,"a"

          JB CHK

          CMP AL,"z"

          JA CHK

          SUB AL,20H ;Convert to upper case

          CHK:

          CMP AL,"."

          JZ RET21

          CMP AL,'"'

          JZ RET21

          CMP AL,"/"

          JZ RET21

          CMP AL,"["

          JZ RET21

          CMP AL,"]"

          JZ RET21

          IF IBM

          DELIM:

          ENDIF

          CMP AL,":" ;Allow ":" as separator in IBM version

          JZ RET21

          IF NOT IBM

          DELIM:

          ENDIF

          CMP AL,"+"

          JZ RET101

          CMP AL,"="

          JZ RET101

          CMP AL,";"

          JZ RET101

          CMP AL,","

          JZ RET101

          SPCHK:

          CMP AL,9 ;Filter out tabs too

          JZ RET101

          ;WARNING! " " MUST be the last compare

          CMP AL," "

          RET101: RET

          SETVECT: ; Interrupt call 37

          XOR BX,BX

          MOV ES,BX

          MOV BL,AL

          SHL BX,1

          SHL BX,1

          MOV ES:[BX],DX

          MOV ES:[BX+2],DS

          RET

          NEWBASE: ; Interrupt call 38

          MOV ES,DX

          LDS SI,CS:DWORD PTR [SPSAVE]

          MOV DS,[SI.CSSAVE]

          XOR SI,SI

          MOV DI,SI

          MOV AX,DS:[2]

          MOV CX,80H

          REP MOVSW

          SETMEM:

          ; Inputs:

          ; AX = Size of memory in paragraphs

          ; 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)

          ; [18] to [21] have fatal error address (from INT 24H)

          ; DX,BP unchanged. All other registers destroyed.

          XOR CX,CX

          MOV DS,CX

          MOV ES,DX

          MOV SI,EXIT

          MOV DI,SAVEXIT

          MOVSW

          MOVSW

          MOVSW

          MOVSW

          MOVSW

          MOVSW

          MOV ES:[2],AX

          SUB AX,DX

          CMP AX,MAXDIF

          JBE HAVDIF

          MOV AX,MAXDIF

          HAVDIF:

          MOV BX,ENTRYPOINTSEG

          SUB BX,AX

          SHL AX,1

          SHL AX,1

          SHL AX,1

          SHL AX,1

          MOV DS,DX

          MOV DS:[6],AX

          MOV DS:[8],BX

          MOV DS:[0],20CDH ;"INT INTTAB"

          MOV DS:(BYTE PTR [5]),LONGCALL

          RET

          DATE16:

          PUSH CX

          CALL READTIME

          SHL CL,1 ;Minutes to left part of byte

          SHL CL,1

          SHL CX,1 ;Push hours and minutes to left end

          SHL CX,1

          SHL CX,1

          SHR DH,1 ;Count every two seconds

          OR CL,DH ;Combine seconds with hours and minutes

          MOV DX,CX

          POP CX

          MOV AX,WORD PTR [MONTH] ;Fetch month and year

          SHL AL,1 ;Push month to left to make room for day

          SHL AL,1

          SHL AL,1

          SHL AL,1

          SHL AX,1

          OR AL,[DAY]

          RET22: RET

          FOURYEARS EQU 3*365+366

          READTIME:

          ;Gets time in CX:DX. Figures new date if it has changed.

          ;Uses AX, CX, DX.

          CALL FAR PTR BIOSGETTIME

          CMP AX,[DAYCNT] ;See if day count is the same

          JZ RET22

          CMP AX,FOURYEARS*30 ;Number of days in 120 years

          JAE RET22 ;Ignore if too large

          MOV [DAYCNT],AX

          PUSH SI

          PUSH CX

          PUSH DX ;Save time

          XOR DX,DX

          MOV CX,FOURYEARS ;Number of days in 4 years

          DIV CX ;Compute number of 4-year units

          SHL AX,1

          SHL AX,1

          SHL AX,1 ;Multiply by 8 (no. of half-years)

          MOV CX,AX ;<240 implies AH=0

          MOV SI,OFFSET DOSGROUP:YRTAB ;Table of days in each year

          CALL DSLIDE ;Find out which of four years we're in

          SHR CX,1 ;Convert half-years to whole years

          JNC SK ;Extra half-year?

          ADD DX,200

          SK:

          CALL SETYEAR

          MOV CL,1 ;At least at first month in year

          MOV SI,OFFSET DOSGROUP:MONTAB ;Table of days in each month

          CALL DSLIDE ;Find out which month we're in

          MOV [MONTH],CL

          INC DX ;Remainder is day of month (start with one)

          MOV [DAY],DL

          CALL WKDAY ;Set day of week

          POP DX

          POP CX

          POP SI

          RET23: RET

          DSLIDE:

          MOV AH,0

          DSLIDE1:

          LODSB ;Get count of days

          CMP DX,AX ;See if it will fit

          JB RET23 ;If not, done

          SUB DX,AX

          INC CX ;Count one more month/year

          JMP SHORT DSLIDE1

          SETYEAR:

          ;Set year with value in CX. Adjust length of February for this year.

          MOV BYTE PTR [YEAR],CL

          CHKYR:

          TEST CL,3 ;Check for leap year

          MOV AL,28

          JNZ SAVFEB ;28 days if no leap year

          INC AL ;Add leap day

          SAVFEB:

          MOV [MONTAB+1],AL ;Store for February

          RET

          ;Days in year

          YRTAB DB 200,166 ;Leap year

          DB 200,165

          DB 200,165

          DB 200,165

          ;Days of each month

          MONTAB DB 31 ;January

          DB 28 ;February--reset each time year changes

          DB 31 ;March

          DB 30 ;April

          DB 31 ;May

          DB 30 ;June

          DB 31 ;July

          DB 31 ;August

          DB 30 ;September

          DB 31 ;October

          DB 30 ;November

          DB 31 ;December

          GETDATE: ;Function call 42

          PUSH CS

          POP DS

          CALL READTIME ;Check for rollover to next day

          MOV AX,[YEAR]

          MOV BX,WORD PTR [DAY]

          LDS SI,DWORD PTR [SPSAVE] ;Get pointer to user registers

          MOV [SI.DXSAVE],BX ;DH=month, DL=day

          ADD AX,1980 ;Put bias back

          MOV [SI.CXSAVE],AX ;CX=year

          MOV AL,CS:[WEEKDAY]

          RET24: RET

          SETDATE: ;Function call 43

          MOV AL,-1 ;Be ready to flag error

          SUB CX,1980 ;Fix bias in year

          JC RET24 ;Error if not big enough

          CMP CX,119 ;Year must be less than 2100

          JA RET24

          OR DH,DH

          JZ RET24

          OR DL,DL

          JZ RET24 ;Error if either month or day is 0

          CMP DH,12 ;Check against max. month

          JA RET24

          PUSH CS

          POP DS

          CALL CHKYR ;Set Feb. up for new year

          MOV AL,DH

          MOV BX,OFFSET DOSGROUP:MONTAB-1

          XLAT ;Look up days in month

          CMP AL,DL

          MOV AL,-1 ;Restore error flag, just in case

          JB RET24 ;Error if too many days

          CALL SETYEAR

          MOV WORD PTR [DAY],DX ;Set both day and month

          SHR CX,1

          SHR CX,1

          MOV AX,FOURYEARS

          MOV BX,DX

          MUL CX

          MOV CL,BYTE PTR [YEAR]

          AND CL,3

          MOV SI,OFFSET DOSGROUP:YRTAB

          MOV DX,AX

          SHL CX,1 ;Two entries per year, so double count

          CALL DSUM ;Add up the days in each year

          MOV CL,BH ;Month of year

          MOV SI,OFFSET DOSGROUP:MONTAB

          DEC CX ;Account for months starting with one

          CALL DSUM ;Add up days in each month

          MOV CL,BL ;Day of month

          DEC CX ;Account for days starting with one

          ADD DX,CX ;Add in to day total

          XCHG AX,DX ;Get day count in AX

          MOV [DAYCNT],AX

          CALL FAR PTR BIOSSETDATE

          WKDAY:

          MOV AX,[DAYCNT]

          XOR DX,DX

          MOV CX,7

          INC AX

          INC AX ;First day was Tuesday

          DIV CX ;Compute day of week

          MOV [WEEKDAY],DL

          XOR AL,AL ;Flag OK

          RET25: RET

          DSUM:

          MOV AH,0

          JCXZ RET25

          DSUM1:

          LODSB

          ADD DX,AX

          LOOP DSUM1

          RET

          GETTIME: ;Function call 44

          PUSH CS

          POP DS

          CALL READTIME

          LDS SI,DWORD PTR [SPSAVE] ;Get pointer to user registers

          MOV [SI.DXSAVE],DX

          MOV [SI.CXSAVE],CX

          XOR AL,AL

          RET26: RET

          SETTIME: ;Function call 45

          ;Time is in CX:DX in hours, minutes, seconds, 1/100 sec.

          MOV AL,-1 ;Flag in case of error

          CMP CH,24 ;Check hours

          JAE RET26

          CMP CL,60 ;Check minutes

          JAE RET26

          CMP DH,60 ;Check seconds

          JAE RET26

          CMP DL,100 ;Check 1/100's

          JAE RET26

          CALL FAR PTR BIOSSETTIME

          XOR AL,AL

          RET

          ; Default handler for division overflow trap

          DIVOV:

          PUSH SI

          PUSH AX

          MOV SI,OFFSET DOSGROUP:DIVMES

          CALL OUTMES

          POP AX

          POP SI

          INT 23H ;Use Ctrl-C abort on divide overflow

          IRET

          CODSIZ EQU $-CODSTRT ;Size of code segment

          CODE ENDS

          ;***** DATA AREA *****

          CONSTANTS SEGMENT BYTE

          ORG 0

          CONSTRT EQU $ ;Start of constants segment

          IONAME:

          IF NOT IBM

          DB "PRN ","LST ","NUL ","AUX ","CON "

          ENDIF

          IF IBM

          DB "COM1","PRN ","LPT1","NUL ","AUX ","CON "

          ENDIF

          DIVMES DB 13,10,"Divide overflow",13,10,"$"

          CARPOS DB 0

          STARTPOS DB 0

          PFLAG DB 0

          DIRTYDIR DB 0 ;Dirty buffer flag

          NUMDRV DB 0 ;Number of drives

          NUMIO DB ? ;Number of disk tables

          VERFLG DB 0 ;Initialize with verify off

          CONTPOS DW 0

          DMAADD DW 80H ;User's disk transfer address (disp/seg)

          DW ?

          ENDMEM DW ?

          MAXSEC DW 0

          BUFFER DW ?

          BUFSECNO DW 0

          BUFDRVNO DB -1

          DIRTYBUF DB 0

          BUFDRVBP DW ?

          DIRBUFID DW -1

          DAY DB 0

          MONTH DB 0

          YEAR DW 0

          DAYCNT DW -1

          WEEKDAY DB 0

          CURDRV DB 0 ;Default to drive A

          DRVTAB DW 0 ;Address of start of DPBs

          DOSLEN EQU CODSIZ+($-CONSTRT) ;Size of CODE + CONSTANTS segments

          CONSTANTS ENDS

          DATA SEGMENT WORD

          ; Init code overlaps with data area below

          ORG 0

          INBUF DB 128 DUP (?)

          CONBUF DB 131 DUP (?) ;The rest of INBUF and console buffer

          LASTENT DW ?

          EXITHOLD DB 4 DUP (?)

          FATBASE DW ?

          NAME1 DB 11 DUP (?) ;File name buffer

          ATTRIB DB ?

          NAME2 DB 11 DUP (?)

          NAME3 DB 12 DUP (?)

          EXTFCB DB ?

          ;WARNING - the following two items are accessed as a word

          CREATING DB ?

          DELALL DB ?

          TEMP LABEL WORD

          SPSAVE DW ?

          SSSAVE DW ?

          CONTSTK DW ?

          SECCLUSPOS DB ? ;Position of first sector within cluster

          DSKERR DB ?

          TRANS DB ?

          PREREAD DB ? ;0 means preread; 1 means optional

          READOP DB ?

          THISDRV DB ?

          EVEN

          FCB DW ? ;Address of user FCB

          NEXTADD DW ?

          RECPOS DB 4 DUP (?)

          RECCNT DW ?

          LASTPOS DW ?

          CLUSNUM DW ?

          SECPOS DW ? ;Position of first sector accessed

          VALSEC DW ? ;Number of valid (previously written) sectors

          BYTSECPOS DW ? ;Position of first byte within sector

          BYTPOS DB 4 DUP (?) ;Byte position in file of access

          BYTCNT1 DW ? ;No. of bytes in first sector

          BYTCNT2 DW ? ;No. of bytes in last sector

          SECCNT DW ? ;No. of whole sectors

          ENTFREE DW ?

          DB 80H DUP (?) ;Stack space

          IOSTACK LABEL BYTE

          DB 80H DUP (?)

          DSKSTACK LABEL BYTE

          IF DSKTEST

          NSS DW ?

          NSP DW ?

          ENDIF

          DIRBUF LABEL WORD

          ;Init code below overlaps with data area above

          ORG 0

          MOVFAT:

          ;This section of code is safe from being overwritten by block move

          REP MOVS BYTE PTR [DI],[SI]

          CLD

          MOV ES:[DMAADD+2],DX

          MOV SI,[DRVTAB] ;Address of first DPB

          MOV AL,-1

          MOV CL,[NUMIO] ;Number of DPBs

          FLGFAT:

          MOV DI,ES:[SI.FAT] ;get pointer to FAT

          DEC DI ;Point to dirty byte

          STOSB ;Flag as unused

          ADD SI,DPBSIZ ;Point to next DPB

          LOOP FLGFAT

          MOV AX,[ENDMEM]

          CALL SETMEM ;Set up segment

          XXX PROC FAR

          RET

          XXX ENDP

          DOSINIT:

          CLI

          CLD

          PUSH CS

          POP ES

          MOV ES:[ENDMEM],DX

          LODSB ;Get no. of drives & no. of I/O drivers

          MOV ES:[NUMIO],AL

          MOV DI,OFFSET DOSGROUP:MEMSTRT

          PERDRV:

          MOV BP,DI

          MOV AL,ES:[DRVCNT]

          STOSB ;DEVNUM

          LODSB ;Physical unit no.

          STOSB ;DRVNUM

          CMP AL,15

          JA BADINIT

          CBW ;Index into FAT size table

          SHL AX,1

          ADD AX,OFFSET DOSGROUP:FATSIZTAB

          XCHG BX,AX

          LODSW ;Pointer to DPT

          PUSH SI

          MOV SI,AX

          LODSW

          STOSW ;SECSIZ

          MOV DX,AX

          CMP AX,ES:[MAXSEC]

          JBE NOTMAX

          MOV ES:[MAXSEC],AX

          NOTMAX:

          LODSB

          DEC AL

          STOSB ;CLUSMSK

          JZ HAVSHFT

          CBW

          FIGSHFT:

          INC AH

          SAR AL,1

          JNZ FIGSHFT

          MOV AL,AH

          HAVSHFT:

          STOSB ;CLUSSHFT

          MOVSW ;FIRFAT (= number of reserved sectors)

          MOVSB ;FATCNT

          MOVSW ;MAXENT

          MOV AX,DX ;SECSIZ again

          MOV CL,5

          SHR AX,CL

          MOV CX,AX ;Directory entries per sector

          DEC AX

          ADD AX,ES:[BP.MAXENT]

          XOR DX,DX

          DIV CX

          STOSW ;DIRSEC (temporarily)

          MOVSW ;DSKSIZ (temporarily)

          FNDFATSIZ:

          MOV AL,1

          MOV DX,1

          GETFATSIZ:

          PUSH DX

          CALL FIGFATSIZ

          POP DX

          CMP AL,DL ;Compare newly computed FAT size with trial

          JZ HAVFATSIZ ;Has sequence converged?

          CMP AL,DH ;Compare with previous trial

          MOV DH,DL

          MOV DL,AL ;Shuffle trials

          JNZ GETFATSIZ ;Continue iterations if not oscillating

          DEC WORD PTR ES:[BP.DSKSIZ] ;Damp those oscillations

          JMP SHORT FNDFATSIZ ;Try again

          BADINIT:

          MOV SI,OFFSET DOSGROUP:BADMES

          CALL OUTMES

          STI

          HLT

          HAVFATSIZ:

          STOSB ;FATSIZ

          MUL ES:BYTE PTR[BP.FATCNT] ;Space occupied by all FATs

          ADD AX,ES:[BP.FIRFAT]

          STOSW ;FIRDIR

          ADD AX,ES:[BP.DIRSEC]

          MOV ES:[BP.FIRREC],AX ;Destroys DIRSEC

          CALL FIGMAX

          MOV ES:[BP.MAXCLUS],CX

          MOV AX,BX ;Pointer into FAT size table

          STOSW ;Allocate space for FAT pointer

          MOV AL,ES:[BP.FATSIZ]

          XOR AH,AH

          MUL ES:[BP.SECSIZ]

          CMP AX,ES:[BX] ;Bigger than already allocated

          JBE SMFAT

          MOV ES:[BX],AX

          SMFAT:

          POP SI ;Restore pointer to init. table

          MOV AL,ES:[DRVCNT]

          INC AL

          MOV ES:[DRVCNT],AL

          CMP AL,ES:[NUMIO]

          JAE CONTINIT

          JMP PERDRV

          BADINITJ:

          JMP BADINIT

          CONTINIT:

          PUSH CS

          POP DS

          ;Calculate true address of buffers, FATs, free space

          MOV BP,[MAXSEC]

          MOV AX,OFFSET DOSGROUP:DIRBUF

          ADD AX,BP

          MOV [BUFFER],AX ;Start of buffer

          ADD AX,BP

          MOV [DRVTAB],AX ;Start of DPBs

          SHL BP,1 ;Two sectors - directory and buffer

          ADD BP,DI ;Allocate buffer space

          ADD BP,ADJFAC ;True address of FATs

          PUSH BP

          MOV SI,OFFSET DOSGROUP:FATSIZTAB

          MOV DI,SI

          MOV CX,16

          TOTFATSIZ:

          INC BP ;Add one for Dirty byte

          INC BP ;Add one for I/O device number

          LODSW ;Get size of this FAT

          XCHG AX,BP

          STOSW ;Save address of this FAT

          ADD BP,AX ;Compute size of next FAT

          CMP AX,BP ;If size was zero done

          LOOPNZ TOTFATSIZ

          MOV AL,15

          SUB AL,CL ;Compute number of FATs used

          MOV [NUMDRV],AL

          XOR AX,AX ;Set zero flag

          REPZ SCASW ;Make sure all other entries are zero

          JNZ BADINITJ

          ADD BP,15 ;True start of free space

          MOV CL,4

          SHR BP,CL ;First free segment

          MOV DX,CS

          ADD DX,BP

          MOV BX,0FH

          MOV CX,[ENDMEM]

          CMP CX,1 ;Use memory scan?

          JNZ SETEND

          MOV CX,DX ;Start scanning just after DOS

          MEMSCAN:

          INC CX

          JZ SETEND

          MOV DS,CX

          MOV AL,[BX]

          NOT AL

          MOV [BX],AL

          CMP AL,[BX]

          NOT AL

          MOV [BX],AL

          JZ MEMSCAN

          SETEND:

          IF HIGHMEM

          SUB CX,BP

          MOV BP,CX ;Segment of DOS

          MOV DX,CS ;Program segment

          ENDIF

          IF NOT HIGHMEM

          MOV BP,CS

          ENDIF

          ; BP has segment of DOS (whether to load high or run in place)

          ; DX has program segment (whether after DOS or overlaying DOS)

          ; CX has size of memory in paragraphs (reduced by DOS size if HIGHMEM)

          MOV CS:[ENDMEM],CX

          IF HIGHMEM

          MOV ES,BP

          XOR SI,SI

          MOV DI,SI

          MOV CX,(DOSLEN+1)/2

          PUSH CS

          POP DS

          REP MOVSW ;Move DOS to high memory

          ENDIF

          XOR AX,AX

          MOV DS,AX

          MOV ES,AX

          MOV DI,INTBASE

          MOV AX,OFFSET DOSGROUP:QUIT

          STOSW ;Set abort address--displacement

          MOV AX,BP

          MOV BYTE PTR DS:[ENTRYPOINT],LONGJUMP

          MOV WORD PTR DS:[ENTRYPOINT+1],OFFSET DOSGROUP:ENTRY

          MOV WORD PTR DS:[ENTRYPOINT+3],AX

          MOV WORD PTR DS:[0],OFFSET DOSGROUP:DIVOV ;Set default divide trap address

          MOV DS:[2],AX

          MOV CX,9

          REP STOSW ;Set 5 segments (skip 2 between each)

          MOV WORD PTR DS:[INTBASE+4],OFFSET DOSGROUP:COMMAND

          MOV WORD PTR DS:[INTBASE+12],OFFSET DOSGROUP:IRET ;Ctrl-C exit

          MOV WORD PTR DS:[INTBASE+16],OFFSET DOSGROUP:IRET ;Fatal error exit

          MOV AX,OFFSET BIOSREAD

          STOSW

          MOV AX,BIOSSEG

          STOSW

          STOSW ;Add 2 to DI

          STOSW

          MOV WORD PTR DS:[INTBASE+18H],OFFSET BIOSWRITE

          MOV WORD PTR DS:[EXIT],100H

          MOV WORD PTR DS:[EXIT+2],DX

          IF NOT IBM

          MOV SI,OFFSET DOSGROUP:HEADER

          CALL OUTMES

          ENDIF

          PUSH CS

          POP DS

          PUSH CS

          POP ES

          ;Move the FATs into position

          MOV AL,[NUMIO]

          CBW

          XCHG AX,CX

          MOV DI,OFFSET DOSGROUP:MEMSTRT.FAT

          FATPOINT:

          MOV SI,WORD PTR [DI] ;Get address within FAT address table

          MOVSW ;Set address of this FAT

          ADD DI,DPBSIZ-2 ;Point to next DPB

          LOOP FATPOINT

          POP CX ;True address of first FAT

          MOV SI,OFFSET DOSGROUP:MEMSTRT ;Place to move DPBs from

          MOV DI,[DRVTAB] ;Place to move DPBs to

          SUB CX,DI ;Total length of DPBs

          CMP DI,SI

          JBE MOVJMP ;Are we moving to higher or lower memory?

          DEC CX ;Move backwards to higher memory

          ADD DI,CX

          ADD SI,CX

          INC CX

          STD

          MOVJMP:

          MOV ES,BP

          JMP MOVFAT

          FIGFATSIZ:

          MUL ES:BYTE PTR[BP.FATCNT]

          ADD AX,ES:[BP.FIRFAT]

          ADD AX,ES:[BP.DIRSEC]

          FIGMAX:

          ;AX has equivalent of FIRREC

          SUB AX,ES:[BP.DSKSIZ]

          NEG AX

          MOV CL,ES:[BP.CLUSSHFT]

          SHR AX,CL

          INC AX

          MOV CX,AX ;MAXCLUS

          INC AX

          MOV DX,AX

          SHR DX,1

          ADC AX,DX ;Size of FAT in bytes

          MOV SI,ES:[BP.SECSIZ]

          ADD AX,SI

          DEC AX

          XOR DX,DX

          DIV SI

          RET

          BADMES:

          DB 13,10,"INIT TABLE BAD",13,10,"$"

          FATSIZTAB:

          DW 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

          DRVCNT DB 0

          MEMSTRT LABEL WORD

          ADJFAC EQU DIRBUF-MEMSTRT

          DATA ENDS

          END

          

        看了“DOS操作系統(tǒng)源碼相關(guān)資料知識”還想看:

        1.計算機的DOS操作系統(tǒng)詳解

        2.dos操作系統(tǒng)介紹

        3.DOS操作系統(tǒng)歷史知識

        4.電腦操作系統(tǒng)介紹與發(fā)展歷程

        5.操作系統(tǒng)發(fā)展簡史

        2779956 主站蜘蛛池模板: 亚洲熟女精品中文字幕| AV最新高清无码专区| 国产福利2021最新在线观看| 国产乱码精品一区二区三上 | 热久久99精品这里有精品| 日本一卡二卡3卡四卡网站精品| 欧美交性一级视频免费| 欧美成人h精品网站| 亚洲成av人最新无码不卡短片| 黑森林福利视频导航| 国产欧美丝袜在线二区| 国产精品视频全国免费观看| 国产亚洲情侣一区二区无| 国精品91人妻无码一区二区三区 | 亚洲成人动漫在线| 综合区一区二区三区狠狠| 国内精品一区二区不卡| 国产区二区三区在线观看| 亚洲中文字幕无码av| 国产精品亚洲精品爽爽| 国产成人高清亚洲一区二区| 欧美怡春院一区二区三区| 亚洲欧洲日产国码久在线| 国内不卡不区二区三区| 亚洲天堂男人天堂女人天堂| 亚洲熟妇自偷自拍另欧美| 亚洲永久一区二区三区在线| 一区二区三区一级黄色片| 午夜性爽视频男人的天堂| 狠狠躁夜夜躁无码中文字幕| 亚洲va欧美va国产综合| 国产无码高清视频不卡| 蜜臀精品视频一区二区三区 | 久久精品熟女亚洲av艳妇| 久久国产热精品波多野结衣av| 天堂视频一区二区免费在线观看| 亚洲精品一二三四区| 色综合中文字幕色综合激情| 亚洲精品无码久久一线| 亚洲国产精品成人一区二区在线 | 天堂v亚洲国产v第一次|