summaryrefslogtreecommitdiff
path: root/v1.25/source/MSDOS.ASM
diff options
context:
space:
mode:
Diffstat (limited to 'v1.25/source/MSDOS.ASM')
-rw-r--r--v1.25/source/MSDOS.ASM4031
1 files changed, 4031 insertions, 0 deletions
diff --git a/v1.25/source/MSDOS.ASM b/v1.25/source/MSDOS.ASM
new file mode 100644
index 0000000..8538b76
--- /dev/null
+++ b/v1.25/source/MSDOS.ASM
@@ -0,0 +1,4031 @@
1; 86-DOS High-performance operating system for the 8086 version 1.25
2; by Tim Paterson
3
4
5; ****************** Revision History *************************
6; >> EVERY change must noted below!! <<
7;
8; 0.34 12/29/80 General release, updating all past customers
9; 0.42 02/25/81 32-byte directory entries added
10; 0.56 03/23/81 Variable record and sector sizes
11; 0.60 03/27/81 Ctrl-C exit changes, including register save on user stack
12; 0.74 04/15/81 Recognize I/O devices with file names
13; 0.75 04/17/81 Improve and correct buffer handling
14; 0.76 04/23/81 Correct directory size when not 2^N entries
15; 0.80 04/27/81 Add console input without echo, Functions 7 & 8
16; 1.00 04/28/81 Renumber for general release
17; 1.01 05/12/81 Fix bug in `STORE'
18; 1.10 07/21/81 Fatal error trapping, NUL device, hidden files, date & time,
19; RENAME fix, general cleanup
20; 1.11 09/03/81 Don't set CURRENT BLOCK to 0 on open; fix SET FILE SIZE
21; 1.12 10/09/81 Zero high half of CURRENT BLOCK after all (CP/M programs don't)
22; 1.13 10/29/81 Fix classic "no write-through" error in buffer handling
23; 1.20 12/31/81 Add time to FCB; separate FAT from DPT; Kill SMALLDIR;
24; Add FLUSH and MAPDEV calls; allow disk mapping in DSKCHG;
25; Lots of smaller improvements
26; 1.21 01/06/82 HIGHMEM switch to run DOS in high memory
27; 1.22 01/12/82 Add VERIFY system call to enable/disable verify after write
28; 1.23 02/11/82 Add defaulting to parser; use variable escape character
29; Don't zero extent field in IBM version (back to 1.01!)
30; 1.24 03/01/82 Restore fcn. 27 to 1.0 level; add fcn. 28
31; 1.25 03/03/82 Put marker (00) at end of directory to speed searches
32;
33; *************************************************************
34
35
36; Interrupt Entry Points:
37
38; INTBASE: ABORT
39; INTBASE+4: COMMAND
40; INTBASE+8: BASE EXIT ADDRESS
41; INTBASE+C: CONTROL-C ABORT
42; INTBASE+10H: FATAL ERROR ABORT
43; INTBASE+14H: BIOS DISK READ
44; INTBASE+18H: BIOS DISK WRITE
45; INTBASE+40H: Long jump to CALL entry point
46
47 IF IBM
48ESCCH EQU 0
49CANCEL EQU 1BH ;Cancel with ESC
50TOGLINS EQU TRUE ;One key toggles insert mode
51TOGLPRN EQU TRUE ;One key toggles printer echo
52NUMDEV EQU 6 ;Include "COM1" as I/O device name
53ZEROEXT EQU TRUE
54 ELSE
55ESCCH EQU 1BH
56CANCEL EQU "X"-"@" ;Cancel with Ctrl-X
57TOGLINS EQU FALSE ;Separate keys for insert mode on and off
58TOGLPRN EQU FALSE ;Separate keys for printer echo on and off
59NUMDEV EQU 5 ;Number of I/O device names
60ZEROEXT EQU FALSE
61 ENDIF
62
63MAXCALL EQU 36
64MAXCOM EQU 46
65INTBASE EQU 80H
66INTTAB EQU 20H
67ENTRYPOINTSEG EQU 0CH
68ENTRYPOINT EQU INTBASE+40H
69CONTC EQU INTTAB+3
70EXIT EQU INTBASE+8
71LONGJUMP EQU 0EAH
72LONGCALL EQU 9AH
73MAXDIF EQU 0FFFH
74SAVEXIT EQU 10
75
76; Field definition for FCBs
77
78FCBLOCK STRUC
79 DB 12 DUP (?) ;Drive code and name
80EXTENT DW ?
81RECSIZ DW ? ;Size of record (user settable)
82FILSIZ DW ? ;Size of file in bytes
83DRVBP DW ? ;BP for SEARCH FIRST and SEARCH NEXT
84FDATE DW ? ;Date of last writing
85FTIME DW ? ;Time of last writing
86DEVID DB ? ;Device ID number, bits 0-5
87 ;bit 7=0 for file, bit 7=1 for I/O device
88 ;If file, bit 6=0 if dirty
89 ;If I/O device, bit 6=0 if EOF (input)
90FIRCLUS DW ? ;First cluster of file
91LSTCLUS DW ? ;Last cluster accessed
92CLUSPOS DW ? ;Position of last cluster accessed
93 DB ? ;Forces NR to offset 32
94NR DB ? ;Next record
95RR DB 3 DUP (?) ;Random record
96FCBLOCK ENDS
97FILDIRENT = FILSIZ ;Used only by SEARCH FIRST and SEARCH NEXT
98
99; Description of 32-byte directory entry (same as returned by SEARCH FIRST
100; and SEARCH NEXT, functions 17 and 18).
101;
102; Location bytes Description
103;
104; 0 11 File name and extension ( 0E5H if empty)
105; 11 1 Attributes. Bits 1 or 2 make file hidden
106; 12 10 Zero field (for expansion)
107; 22 2 Time. Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour
108; 24 2 Date. Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980
109; 26 2 First allocation unit ( < 4080 )
110; 28 4 File size, in bytes (LSB first, 30 bits max.)
111;
112; The File Allocation Table uses a 12-bit entry for each allocation unit on
113; the disk. These entries are packed, two for every three bytes. The contents
114; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result
115; to the base address of the Allocation Table; 3) fetching the 16-bit word at
116; this address; 4) If N was odd (so that N*1.5 was not an integer), shift the
117; word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry number
118; zero is used as an end-of-file trap in the OS and as a flag for directory
119; entry size (if SMALLDIR selected). Entry 1 is reserved for future use. The
120; first available allocation unit is assigned entry number two, and even
121; though it is the first, is called cluster 2. Entries greater than 0FF8H are
122; end of file marks; entries of zero are unallocated. Otherwise, the contents
123; of a FAT entry is the number of the next cluster in the file.
124
125
126; Field definition for Drive Parameter Block
127
128DPBLOCK STRUC
129DEVNUM DB ? ;I/O driver number
130DRVNUM DB ? ;Physical Unit number
131SECSIZ DW ? ;Size of physical sector in bytes
132CLUSMSK DB ? ;Sectors/cluster - 1
133CLUSSHFT DB ? ;Log2 of sectors/cluster
134FIRFAT DW ? ;Starting record of FATs
135FATCNT DB ? ;Number of FATs for this drive
136MAXENT DW ? ;Number of directory entries
137FIRREC DW ? ;First sector of first cluster
138MAXCLUS DW ? ;Number of clusters on drive + 1
139FATSIZ DB ? ;Number of records occupied by FAT
140FIRDIR DW ? ;Starting record of directory
141FAT DW ? ;Pointer to start of FAT
142DPBLOCK ENDS
143
144DPBSIZ EQU 20 ;Size of the structure in bytes
145DIRSEC = FIRREC ;Number of dir. sectors (init temporary)
146DSKSIZ = MAXCLUS ;Size of disk (temp used during init only)
147
148;The following are all of the segments used
149;They are declared in the order that they should be placed in the executable
150
151CODE SEGMENT
152CODE ENDS
153
154CONSTANTS SEGMENT BYTE
155CONSTANTS ENDS
156
157DATA SEGMENT WORD
158DATA ENDS
159
160DOSGROUP GROUP CODE,CONSTANTS,DATA
161
162SEGBIOS SEGMENT
163SEGBIOS ENDS
164
165
166; BOIS entry point definitions
167
168 IF IBM
169BIOSSEG EQU 60H
170 ENDIF
171 IF NOT IBM
172BIOSSEG EQU 40H
173 ENDIF
174
175SEGBIOS SEGMENT AT BIOSSEG
176 ORG 0
177 DB 3 DUP (?) ;Reserve room for jump to init code
178BIOSSTAT DB 3 DUP (?) ;Console input status check
179BIOSIN DB 3 DUP (?) ;Get console character
180BIOSOUT DB 3 DUP (?) ;Output console character
181BIOSPRINT DB 3 DUP (?) ;Output to printer
182BIOSAUXIN DB 3 DUP (?) ;Get byte from auxilliary
183BIOSAUXOUT DB 3 DUP (?) ;Output byte to auxilliary
184BIOSREAD DB 3 DUP (?) ;Disk read
185BIOSWRITE DB 3 DUP (?) ;Disk write
186BIOSDSKCHG DB 3 DUP (?) ;Dsik-change status
187BIOSSETDATE DB 3 DUP (?) ;Set date
188BIOSSETTIME DB 3 DUP (?) ;Set time
189BIOSGETTIME DB 3 DUP (?) ;Get time and date
190BIOSFLUSH DB 3 DUP (?) ;Clear console input buffer
191BIOSMAPDEV DB 3 DUP (?) ;Dynamic disk table mapper
192
193SEGBIOS ENDS
194; Location of user registers relative user stack pointer
195
196STKPTRS STRUC
197AXSAVE DW ?
198BXSAVE DW ?
199CXSAVE DW ?
200DXSAVE DW ?
201SISAVE DW ?
202DISAVE DW ?
203BPSAVE DW ?
204DSSAVE DW ?
205ESSAVE DW ?
206IPSAVE DW ?
207CSSAVE DW ?
208FSAVE DW ?
209STKPTRS ENDS
210
211; Start of code
212
213CODE SEGMENT
214ASSUME CS:DOSGROUP,DS:DOSGROUP,ES:DOSGROUP,SS:DOSGROUP
215
216 ORG 0
217CODSTRT EQU $
218 JMP DOSINIT
219
220ESCCHAR DB ESCCH ;Lead-in character for escape sequences
221ESCTAB:
222 IF NOT IBM
223 DB "S" ;Copy one char
224 DB "V" ;Skip one char
225 DB "T" ;Copy to char
226 DB "W" ;Skip to char
227 DB "U" ;Copy line
228 DB "E" ;Kill line (no change in template)
229 DB "J" ;Reedit line (new template)
230 DB "D" ;Backspace
231 DB "P" ;Enter insert mode
232 DB "Q" ;Exit insert mode
233 DB "R" ;Escape character
234 DB "R" ;End of table
235 ENDIF
236 IF IBM
237 DB 64 ;Crtl-Z - F6
238 DB 77 ;Copy one char - -->
239 DB 59 ;Copy one char - F1
240 DB 83 ;Skip one char - DEL
241 DB 60 ;Copy to char - F2
242 DB 62 ;Skip to char - F4
243 DB 61 ;Copy line - F3
244 DB 61 ;Kill line (no change to template ) - Not used
245 DB 63 ;Reedit line (new template) - F5
246 DB 75 ;Backspace - <--
247 DB 82 ;Enter insert mode - INS (toggle)
248 DB 65 ;Escape character - F7
249 DB 65 ;End of table
250 ENDIF
251
252ESCTABLEN EQU $-ESCTAB
253 IF NOT IBM
254HEADER DB 13,10,"MS-DOS version 1.25"
255 IF HIGHMEM
256 DB "H"
257 ENDIF
258 IF DSKTEST
259 DB "D"
260 ENDIF
261
262 DB 13,10
263 DB "Copyright 1981,82 Microsoft, Inc.",13,10,"$"
264 ENDIF
265
266QUIT:
267 MOV AH,0
268 JMP SHORT SAVREGS
269
270COMMAND: ;Interrupt call entry point
271 CMP AH,MAXCOM
272 JBE SAVREGS
273BADCALL:
274 MOV AL,0
275IRET: IRET
276
277ENTRY: ;System call entry point and dispatcher
278 POP AX ;IP from the long call at 5
279 POP AX ;Segment from the long call at 5
280 POP CS:[TEMP] ;IP from the CALL 5
281 PUSHF ;Start re-ordering the stack
282 CLI
283 PUSH AX ;Save segment
284 PUSH CS:[TEMP] ;Stack now ordered as if INT had been used
285 CMP CL,MAXCALL ;This entry point doesn't get as many calls
286 JA BADCALL
287 MOV AH,CL
288SAVREGS:
289 PUSH ES
290 PUSH DS
291 PUSH BP
292 PUSH DI
293 PUSH SI
294 PUSH DX
295 PUSH CX
296 PUSH BX
297 PUSH AX
298
299 IF DSKTEST
300 MOV AX,CS:[SPSAVE]
301 MOV CS:[NSP],AX
302 MOV AX,CS:[SSSAVE]
303 MOV CS:[NSS],AX
304 POP AX
305 PUSH AX
306 ENDIF
307
308 MOV CS:[SPSAVE],SP
309 MOV CS:[SSSAVE],SS
310 MOV SP,CS
311 MOV SS,SP
312REDISP:
313 MOV SP,OFFSET DOSGROUP:IOSTACK
314 STI ;Stack OK now
315 MOV BL,AH
316 MOV BH,0
317 SHL BX,1
318 CLD
319 CMP AH,12
320 JLE SAMSTK
321 MOV SP,OFFSET DOSGROUP:DSKSTACK
322SAMSTK:
323 CALL CS:[BX+DISPATCH]
324LEAVE:
325 CLI
326 MOV SP,CS:[SPSAVE]
327 MOV SS,CS:[SSSAVE]
328 MOV BP,SP
329 MOV BYTE PTR [BP.AXSAVE],AL
330
331 IF DSKTEST
332 MOV AX,CS:[NSP]
333 MOV CS:[SPSAVE],AX
334 MOV AX,CS:[NSS]
335 MOV CS:[SSSAVE],AX
336 ENDIF
337
338 POP AX
339 POP BX
340 POP CX
341 POP DX
342 POP SI
343 POP DI
344 POP BP
345 POP DS
346 POP ES
347 IRET
348; Standard Functions
349DISPATCH DW ABORT ;0
350 DW CONIN
351 DW CONOUT
352 DW READER
353 DW PUNCH
354 DW LIST ;5
355 DW RAWIO
356 DW RAWINP
357 DW IN
358 DW PRTBUF
359 DW BUFIN ;10
360 DW CONSTAT
361 DW FLUSHKB
362 DW DSKRESET
363 DW SELDSK
364 DW OPEN ;15
365 DW CLOSE
366 DW SRCHFRST
367 DW SRCHNXT
368 DW DELETE
369 DW SEQRD ;20
370 DW SEQWRT
371 DW CREATE
372 DW RENAME
373 DW INUSE
374 DW GETDRV ;25
375 DW SETDMA
376 DW GETFATPT
377 DW GETFATPTDL
378 DW GETRDONLY
379 DW SETATTRIB ;30
380 DW GETDSKPT
381 DW USERCODE
382 DW RNDRD
383 DW RNDWRT
384 DW FILESIZE ;35
385 DW SETRNDREC
386; Extended Functions
387 DW SETVECT
388 DW NEWBASE
389 DW BLKRD
390 DW BLKWRT ;40
391 DW MAKEFCB
392 DW GETDATE
393 DW SETDATE
394 DW GETTIME
395 DW SETTIME ;45
396 DW VERIFY
397
398INUSE:
399GETIO:
400SETIO:
401GETRDONLY:
402SETATTRIB:
403USERCODE:
404 MOV AL,0
405 RET
406
407VERIFY:
408 AND AL,1
409 MOV CS:VERFLG,AL
410 RET
411
412FLUSHKB:
413 PUSH AX
414 CALL FAR PTR BIOSFLUSH
415 POP AX
416 MOV AH,AL
417 CMP AL,1
418 JZ REDISPJ
419 CMP AL,6
420 JZ REDISPJ
421 CMP AL,7
422 JZ REDISPJ
423 CMP AL,8
424 JZ REDISPJ
425 CMP AL,10
426 JZ REDISPJ
427 MOV AL,0
428 RET
429
430REDISPJ:JMP REDISP
431
432READER:
433AUXIN:
434 CALL STATCHK
435 CALL FAR PTR BIOSAUXIN
436 RET
437
438PUNCH:
439 MOV AL,DL
440AUXOUT:
441 PUSH AX
442 CALL STATCHK
443 POP AX
444 CALL FAR PTR BIOSAUXOUT
445 RET
446
447
448UNPACK:
449
450; Inputs:
451; DS = CS
452; BX = Cluster number
453; BP = Base of drive parameters
454; SI = Pointer to drive FAT
455; Outputs:
456; DI = Contents of FAT for given cluster
457; Zero set means DI=0 (free cluster)
458; No other registers affected. Fatal error if cluster too big.
459
460 CMP BX,[BP.MAXCLUS]
461 JA HURTFAT
462 LEA DI,[SI+BX]
463 SHR BX,1
464 MOV DI,[DI+BX]
465 JNC HAVCLUS
466 SHR DI,1
467 SHR DI,1
468 SHR DI,1
469 SHR DI,1
470 STC
471HAVCLUS:
472 RCL BX,1
473 AND DI,0FFFH
474 RET
475HURTFAT:
476 PUSH AX
477 MOV AH,80H ;Signal Bad FAT to INT 24H handler
478 MOV DI,0FFFH ;In case INT 24H returns (it shouldn't)
479 CALL FATAL
480 POP AX ;Try to ignore bad FAT
481 RET
482
483
484PACK:
485
486; Inputs:
487; DS = CS
488; BX = Cluster number
489; DX = Data
490; SI = Pointer to drive FAT
491; Outputs:
492; The data is stored in the FAT at the given cluster.
493; BX,DX,DI all destroyed
494; No other registers affected
495
496 MOV DI,BX
497 SHR BX,1
498 ADD BX,SI
499 ADD BX,DI
500 SHR DI,1
501 MOV DI,[BX]
502 JNC ALIGNED
503 SHL DX,1
504 SHL DX,1
505 SHL DX,1
506 SHL DX,1
507 AND DI,0FH
508 JMP SHORT PACKIN
509ALIGNED:
510 AND DI,0F000H
511PACKIN:
512 OR DI,DX
513 MOV [BX],DI
514 RET
515
516DEVNAME:
517 MOV SI,OFFSET DOSGROUP:IONAME ;List of I/O devices with file names
518 MOV BH,NUMDEV ;BH = number of device names
519LOOKIO:
520 MOV DI,OFFSET DOSGROUP:NAME1
521 MOV CX,4 ;All devices are 4 letters
522 REPE CMPSB ;Check for name in list
523 JZ IOCHK ;If first 3 letters OK, check for the rest
524 ADD SI,CX ;Point to next device name
525 DEC BH
526 JNZ LOOKIO
527CRET:
528 STC ;Not found
529 RET
530
531IOCHK:
532 IF IBM
533 CMP BH,NUMDEV ;Is it the first device?
534 JNZ NOTCOM1
535 MOV BH,2 ;Make it the same as AUX
536NOTCOM1:
537 ENDIF
538 NEG BH
539 MOV CX,2 ;Check rest of name but not extension
540 MOV AX,2020H
541 REPE SCASW ;Make sure rest of name is blanks
542 JNZ CRET
543RET1: RET ;Zero set so CREATE works
544
545GETFILE:
546; Same as GETNAME except ES:DI points to FCB on successful return
547 CALL MOVNAME
548 JC RET1
549 PUSH DX
550 PUSH DS
551 CALL FINDNAME
552 POP ES
553 POP DI
554RET2: RET
555
556
557GETNAME:
558
559; Inputs:
560; DS,DX point to FCB
561; Function:
562; Find file name in disk directory. First byte is
563; drive number (0=current disk). "?" matches any
564; character.
565; Outputs:
566; Carry set if file not found
567; ELSE
568; Zero set if attributes match (always except when creating)
569; BP = Base of drive parameters
570; DS = CS
571; ES = CS
572; BX = Pointer into directory buffer
573; SI = Pointer to First Cluster field in directory entry
574; [DIRBUF] has directory record with match
575; [NAME1] has file name
576; All other registers destroyed.
577
578 CALL MOVNAME
579 JC RET2 ;Bad file name?
580FINDNAME:
581 MOV AX,CS
582 MOV DS,AX
583 CALL DEVNAME
584 JNC RET2
585 CALL STARTSRCH
586CONTSRCH:
587 CALL GETENTRY
588 JC RET2
589SRCH:
590 MOV AH,BYTE PTR [BX]
591 OR AH,AH ;End of directory?
592 JZ FREE
593 CMP AH,[DELALL] ;Free entry?
594 JZ FREE
595 MOV SI,BX
596 MOV DI,OFFSET DOSGROUP:NAME1
597 MOV CX,11
598WILDCRD:
599 REPE CMPSB
600 JZ FOUND
601 CMP BYTE PTR [DI-1],"?"
602 JZ WILDCRD
603NEXTENT:
604 CALL NEXTENTRY
605 JNC SRCH
606RET3: RET
607
608FREE:
609 CMP [ENTFREE],-1 ;Found a free entry before?
610 JNZ TSTALL ;If so, ignore this one
611 MOV CX,[LASTENT]
612 MOV [ENTFREE],CX
613TSTALL:
614 CMP AH,[DELALL] ;At end of directory?
615 JZ NEXTENT ;No - continue search
616 STC ;Report not found
617 RET
618
619FOUND:
620;Check if attributes allow finding it
621 MOV AH,[ATTRIB] ;Attributes of search
622 NOT AH
623 AND AH,[SI] ;Compare with attributes of file
624 ADD SI,15
625 AND AH,6 ;Only look at bits 1 and 2
626 JZ RET3
627 TEST BYTE PTR [CREATING],-1 ;Pass back mismatch if creating
628 JZ NEXTENT ;Otherwise continue searching
629 RET
630
631
632GETENTRY:
633
634; Inputs:
635; [LASTENT] has previously searched directory entry
636; Function:
637; Locates next sequential directory entry in preparation for search
638; Outputs:
639; Carry set if none
640; ELSE
641; AL = Current directory block
642; BX = Pointer to next directory entry in [DIRBUF]
643; DX = Pointer to first byte after end of DIRBUF
644; [LASTENT] = New directory entry number
645
646 MOV AX,[LASTENT]
647 INC AX ;Start with next entry
648 CMP AX,[BP.MAXENT]
649 JAE NONE
650GETENT:
651 MOV [LASTENT],AX
652 MOV CL,4
653 SHL AX,CL
654 XOR DX,DX
655 SHL AX,1
656 RCL DX,1 ;Account for overflow in last shift
657 MOV BX,[BP.SECSIZ]
658 AND BL,255-31 ;Must be multiple of 32
659 DIV BX
660 MOV BX,DX ;Position within sector
661 MOV AH,[BP.DEVNUM] ;AL=Directory sector no.
662 CMP AX,[DIRBUFID]
663 JZ HAVDIRBUF
664 PUSH BX
665 CALL DIRREAD
666 POP BX
667HAVDIRBUF:
668 MOV DX,OFFSET DOSGROUP:DIRBUF
669 ADD BX,DX
670 ADD DX,[BP.SECSIZ]
671 RET
672
673NEXTENTRY:
674
675; Inputs:
676; Same as outputs of GETENTRY, above
677; Function:
678; Update AL, BX, and [LASTENT] for next directory entry.
679; Carry set if no more.
680
681 MOV DI,[LASTENT]
682 INC DI
683 CMP DI,[BP.MAXENT]
684 JAE NONE
685 MOV [LASTENT],DI
686 ADD BX,32
687 CMP BX,DX
688 JB HAVIT
689 INC AL ;Next directory sector
690 PUSH DX ;Save limit
691 CALL DIRREAD
692 POP DX
693 MOV BX,OFFSET DOSGROUP:DIRBUF
694HAVIT:
695 CLC
696 RET
697
698NONE:
699 CALL CHKDIRWRITE
700 STC
701RET4: RET
702
703
704DELETE: ; System call 19
705 CALL MOVNAME
706 MOV AL,-1
707 JC RET4
708 MOV AL,CS:[ATTRIB]
709 AND AL,6 ;Look only at hidden bits
710 CMP AL,6 ;Both must be set
711 JNZ NOTALL
712 MOV CX,11
713 MOV AL,"?"
714 MOV DI,OFFSET DOSGROUP:NAME1
715 REPE SCASB ;See if name is *.*
716 JNZ NOTALL
717 MOV BYTE PTR CS:[DELALL],0 ;DEL *.* - flag deleting all
718NOTALL:
719 CALL FINDNAME
720 MOV AL,-1
721 JC RET4
722 OR BH,BH ;Check if device name
723 JS RET4 ;Can't delete I/O devices
724DELFILE:
725 MOV BYTE PTR [DIRTYDIR],-1
726 MOV AH,[DELALL]
727 MOV BYTE PTR [BX],AH
728 MOV BX,[SI]
729 MOV SI,[BP.FAT]
730 OR BX,BX
731 JZ DELNXT
732 CMP BX,[BP.MAXCLUS]
733 JA DELNXT
734 CALL RELEASE
735DELNXT:
736 CALL CONTSRCH
737 JNC DELFILE
738 CALL FATWRT
739 CALL CHKDIRWRITE
740 XOR AL,AL
741 RET
742
743
744RENAME: ;System call 23
745 CALL MOVNAME
746 JC ERRET
747 ADD SI,5
748 MOV DI,OFFSET DOSGROUP:NAME2
749 CALL LODNAME
750 JC ERRET ;Report error if second name invalid
751 CALL FINDNAME
752 JC ERRET
753 OR BH,BH ;Check if I/O device name
754 JS ERRET ;If so, can't rename it
755 MOV SI,OFFSET DOSGROUP:NAME1
756 MOV DI,OFFSET DOSGROUP:NAME3
757 MOV CX,6 ;6 words (12 bytes)--include attribute byte
758 REP MOVSW ;Copy name to search for
759RENFIL:
760 MOV DI,OFFSET DOSGROUP:NAME1
761 MOV SI,OFFSET DOSGROUP:NAME2
762 MOV CX,11
763NEWNAM:
764 LODSB
765 CMP AL,"?"
766 JNZ NOCHG
767 MOV AL,[BX]
768NOCHG:
769 STOSB
770 INC BX
771 LOOP NEWNAM
772 MOV BYTE PTR [DI],6 ;Stop duplicates with any attributes
773 CALL DEVNAME ;Check if giving it a device name
774 JNC RENERR
775 PUSH [LASTENT] ;Save position of match
776 MOV [LASTENT],-1 ;Search entire directory for duplicate
777 CALL CONTSRCH ;See if new name already exists
778 POP AX
779 JNC RENERR ;Error if found
780 CALL GETENT ;Re-read matching entry
781 MOV DI,BX
782 MOV SI,OFFSET DOSGROUP:NAME1
783 MOV CX,5
784 MOVSB
785 REP MOVSW ;Replace old name with new one
786 MOV BYTE PTR [DIRTYDIR],-1 ;Flag change in directory
787 MOV SI,OFFSET DOSGROUP:NAME3
788 MOV DI,OFFSET DOSGROUP:NAME1
789 MOV CX,6 ;Include attribute byte
790 REP MOVSW ;Copy name back into search buffer
791 CALL CONTSRCH
792 JNC RENFIL
793 CALL CHKDIRWRITE
794 XOR AL,AL
795 RET
796
797RENERR:
798 CALL CHKDIRWRITE
799ERRET:
800 MOV AL,-1
801RET5: RET
802
803
804MOVNAME:
805
806; Inputs:
807; DS, DX point to FCB or extended FCB
808; Outputs:
809; DS:DX point to normal FCB
810; ES = CS
811; If file name OK:
812; BP has base of driver parameters
813; [NAME1] has name in upper case
814; All registers except DX destroyed
815; Carry set if bad file name or drive
816
817 MOV CS:WORD PTR [CREATING],0E500H ;Not creating, not DEL *.*
818 MOV AX,CS
819 MOV ES,AX
820 MOV DI,OFFSET DOSGROUP:NAME1
821 MOV SI,DX
822 LODSB
823 MOV CS:[EXTFCB],AL ;Set flag if extended FCB in use
824 MOV AH,0 ;Set default attributes
825 CMP AL,-1 ;Is it an extended FCB?
826 JNZ HAVATTRB
827 ADD DX,7 ;Adjust to point to normal FCB
828 ADD SI,6 ;Point to drive select byte
829 MOV AH,[SI-1] ;Get attribute byte
830 LODSB ;Get drive select byte
831HAVATTRB:
832 MOV CS:[ATTRIB],AH ;Save attributes
833 CALL GETTHISDRV
834LODNAME:
835; This entry point copies a file name from DS,SI
836; to ES,DI converting to upper case.
837 CMP BYTE PTR [SI]," " ;Don't allow blank as first letter
838 STC ;In case of error
839 JZ RET5
840 MOV CX,11
841MOVCHK:
842 CALL GETLET
843 JB RET5
844 JNZ STOLET ;Is it a delimiter?
845 CMP AL," " ;This is the only delimiter allowed
846 STC ;In case of error
847 JNZ RET5
848STOLET:
849 STOSB
850 LOOP MOVCHK
851 CLC ;Got through whole name - no error
852RET6: RET
853
854GETTHISDRV:
855 CMP CS:[NUMDRV],AL
856 JC RET6
857 DEC AL
858 JNS PHYDRV
859 MOV AL,CS:[CURDRV]
860PHYDRV:
861 MOV CS:[THISDRV],AL
862 RET
863
864
865OPEN: ;System call 15
866 CALL GETFILE
867DOOPEN:
868; Enter here to perform OPEN on file already found
869; in directory. DS=CS, BX points to directory
870; entry in DIRBUF, SI points to First Cluster field, and
871; ES:DI point to the FCB to be opened. This entry point
872; is used by CREATE.
873 JC ERRET
874 OR BH,BH ;Check if file is I/O device
875 JS OPENDEV ;Special handler if so
876 MOV AL,[THISDRV]
877 INC AX
878 STOSB
879 XOR AX,AX
880 IF ZEROEXT
881 ADD DI,11
882 STOSW ;Zero low byte of extent field if IBM only
883 ENDIF
884 IF NOT ZEROEXT
885 ADD DI,12 ;Point to high half of CURRENT BLOCK field
886 STOSB ;Set it to zero (CP/M programs set low byte)
887 ENDIF
888 MOV AL,128 ;Default record size
889 STOSW ;Set record size
890 LODSW ;Get starting cluster
891 MOV DX,AX ;Save it for the moment
892 MOVSW ;Transfer size to FCB
893 MOVSW
894 MOV AX,[SI-8] ;Get date
895 STOSW ;Save date in FCB
896 MOV AX,[SI-10] ;Get time
897 STOSW ;Save it in FCB
898 MOV AL,[BP.DEVNUM]
899 OR AL,40H
900 STOSB
901 MOV AX,DX ;Restore starting cluster
902 STOSW ; first cluster
903 STOSW ; last cluster accessed
904 XOR AX,AX
905 STOSW ; position of last cluster
906 RET
907
908
909OPENDEV:
910 ADD DI,13 ;point to 2nd half of extent field
911 XOR AX,AX
912 STOSB ;Set it to zero
913 MOV AL,128
914 STOSW ;Set record size to 128
915 XOR AX,AX
916 STOSW
917 STOSW ;Set current size to zero
918 CALL DATE16
919 STOSW ;Date is todays
920 XCHG AX,DX
921 STOSW ;Use current time
922 MOV AL,BH ;Get device number
923 STOSB
924 XOR AL,AL ;No error
925 RET
926FATERR:
927 XCHG AX,DI ;Put error code in DI
928 MOV AH,2 ;While trying to read FAT
929 MOV AL,[THISDRV] ;Tell which drive
930 CALL FATAL1
931 JMP SHORT FATREAD
932STARTSRCH:
933 MOV AX,-1
934 MOV [LASTENT],AX
935 MOV [ENTFREE],AX
936FATREAD:
937
938; Inputs:
939; DS = CS
940; Function:
941; If disk may have been changed, FAT is read in and buffers are
942; flagged invalid. If not, no action is taken.
943; Outputs:
944; BP = Base of drive parameters
945; Carry set if invalid drive returned by MAPDEV
946; All other registers destroyed
947
948 MOV AL,[THISDRV]
949 XOR AH,AH ;Set default response to zero & clear carry
950 CALL FAR PTR BIOSDSKCHG ;See what BIOS has to say
951 JC FATERR
952 CALL GETBP
953 MOV AL,[THISDRV] ;Use physical unit number
954 MOV SI,[BP.FAT]
955 OR AH,[SI-1] ;Dirty byte for FAT
956 JS NEWDSK ;If either say new disk, then it's so
957 JNZ MAPDRV
958 MOV AH,1
959 CMP AX,WORD PTR [BUFDRVNO] ;Does buffer have dirty sector of this drive?
960 JZ MAPDRV
961NEWDSK:
962 CMP AL,[BUFDRVNO] ;See if buffer is for this drive
963 JNZ BUFOK ;If not, don't touch it
964 MOV [BUFSECNO],0 ;Flag buffers invalid
965 MOV WORD PTR [BUFDRVNO],00FFH
966BUFOK:
967 MOV [DIRBUFID],-1
968 CALL FIGFAT
969NEXTFAT:
970 PUSH AX
971 CALL DSKREAD
972 POP AX
973 JC BADFAT
974 SUB AL,[BP.FATCNT]
975 JZ NEWFAT
976 CALL FATWRT
977NEWFAT:
978 MOV SI,[BP.FAT]
979 MOV AL,[BP.DEVNUM]
980 MOV AH,[SI] ;Get first byte of FAT
981 OR AH,0F8H ;Put in range
982 CALL FAR PTR BIOSMAPDEV
983 MOV AH,0
984 MOV [SI-2],AX ;Set device no. and reset dirty bit
985MAPDRV:
986 MOV AL,[SI-2] ;Get device number
987GETBP:
988 MOV BP,[DRVTAB] ;Just in case drive isn't valid
989 AND AL,3FH ;Mask out dirty bit
990 CMP AL,[NUMIO]
991 CMC
992 JC RET7
993 PUSH AX
994 MOV AH,DPBSIZ
995 MUL AH
996 ADD BP,AX
997 POP AX
998RET7: RET
999
1000BADFAT:
1001 MOV CX,DI
1002 ADD DX,CX
1003 DEC AL
1004 JNZ NEXTFAT
1005 CALL FIGFAT ;Reset registers
1006 CALL DREAD ;Try first FAT once more
1007 JMP SHORT NEWFAT
1008
1009OKRET1:
1010 MOV AL,0
1011 RET
1012
1013CLOSE: ;System call 16
1014 MOV DI,DX
1015 CMP BYTE PTR [DI],-1 ;Check for extended FCB
1016 JNZ NORMFCB3
1017 ADD DI,7
1018NORMFCB3:
1019 TEST BYTE PTR [DI.DEVID],0C0H ;Allow only dirty files
1020 JNZ OKRET1 ;can't close if I/O device, or not writen
1021 MOV AL,[DI] ;Get physical unit number
1022 DEC AL ;Make zero = drive A
1023 MOV AH,1 ;Look for dirty buffer
1024 CMP AX,CS:WORD PTR [BUFDRVNO]
1025 JNZ FNDDIR
1026;Write back dirty buffer if on same drive
1027 PUSH DX
1028 PUSH DS
1029 PUSH CS
1030 POP DS
1031 MOV BYTE PTR [DIRTYBUF],0
1032 MOV BX,[BUFFER]
1033 MOV CX,1
1034 MOV DX,[BUFSECNO]
1035 MOV BP,[BUFDRVBP]
1036 CALL DWRITE
1037 POP DS
1038 POP DX
1039FNDDIR:
1040 CALL GETFILE
1041BADCLOSEJ:
1042 JC BADCLOSE
1043 MOV CX,ES:[DI.FIRCLUS]
1044 MOV [SI],CX
1045 MOV DX,ES:WORD PTR [DI.FILSIZ]
1046 MOV [SI+2],DX
1047 MOV DX,ES:WORD PTR [DI.FILSIZ+2]
1048 MOV [SI+4],DX
1049 MOV DX,ES:[DI.FDATE]
1050 MOV [SI-2],DX
1051 MOV DX,ES:[DI.FTIME]
1052 MOV [SI-4],DX
1053 CALL DIRWRITE
1054
1055CHKFATWRT:
1056; Do FATWRT only if FAT is dirty and uses same I/O driver
1057 MOV SI,[BP.FAT]
1058 MOV AL,[BP.DEVNUM]
1059 MOV AH,1
1060 CMP [SI-2],AX ;See if FAT dirty and uses same driver
1061 JNZ OKRET
1062
1063FATWRT:
1064
1065; Inputs:
1066; DS = CS
1067; BP = Base of drive parameter table
1068; Function:
1069; Write the FAT back to disk and reset FAT
1070; dirty bit.
1071; Outputs:
1072; AL = 0
1073; BP unchanged
1074; All other registers destroyed
1075
1076 CALL FIGFAT
1077 MOV BYTE PTR [BX-1],0
1078EACHFAT:
1079 PUSH DX
1080 PUSH CX
1081 PUSH BX
1082 PUSH AX
1083 CALL DWRITE
1084 POP AX
1085 POP BX
1086 POP CX
1087 POP DX
1088 ADD DX,CX
1089 DEC AL
1090 JNZ EACHFAT
1091OKRET:
1092 MOV AL,0
1093 RET
1094
1095BADCLOSE:
1096 MOV SI,[BP.FAT]
1097 MOV BYTE PTR [SI-1],0
1098 MOV AL,-1
1099 RET
1100
1101
1102FIGFAT:
1103; Loads registers with values needed to read or
1104; write a FAT.
1105 MOV AL,[BP.FATCNT]
1106 MOV BX,[BP.FAT]
1107 MOV CL,[BP.FATSIZ] ;No. of records occupied by FAT
1108 MOV CH,0
1109 MOV DX,[BP.FIRFAT] ;Record number of start of FATs
1110 RET
1111
1112
1113DIRCOMP:
1114; Prepare registers for directory read or write
1115 CBW
1116 ADD AX,[BP.FIRDIR]
1117 MOV DX,AX
1118 MOV BX,OFFSET DOSGROUP:DIRBUF
1119 MOV CX,1
1120 RET
1121
1122
1123CREATE: ;System call 22
1124 CALL MOVNAME
1125 JC ERRET3
1126 MOV DI,OFFSET DOSGROUP:NAME1
1127 MOV CX,11
1128 MOV AL,"?"
1129 REPNE SCASB
1130 JZ ERRET3
1131 MOV CS:BYTE PTR [CREATING],-1
1132 PUSH DX
1133 PUSH DS
1134 CALL FINDNAME
1135 JNC EXISTENT
1136 MOV AX,[ENTFREE] ;First free entry found in FINDNAME
1137 CMP AX,-1
1138 JZ ERRPOP
1139 CALL GETENT ;Point at that free entry
1140 JMP SHORT FREESPOT
1141ERRPOP:
1142 POP DS
1143 POP DX
1144ERRET3:
1145 MOV AL,-1
1146 RET
1147
1148EXISTENT:
1149 JNZ ERRPOP ;Error if attributes don't match
1150 OR BH,BH ;Check if file is I/O device
1151 JS OPENJMP ;If so, no action
1152 MOV CX,[SI] ;Get pointer to clusters
1153 JCXZ FREESPOT
1154 CMP CX,[BP.MAXCLUS]
1155 JA FREESPOT
1156 PUSH BX
1157 MOV BX,CX
1158 MOV SI,[BP.FAT]
1159 CALL RELEASE ;Free any data already allocated
1160 CALL FATWRT
1161 POP BX
1162FREESPOT:
1163 MOV DI,BX
1164 MOV SI,OFFSET DOSGROUP:NAME1
1165 MOV CX,5
1166 MOVSB
1167 REP MOVSW
1168 MOV AL,[ATTRIB]
1169 STOSB
1170 XOR AX,AX
1171 MOV CL,5
1172 REP STOSW
1173 CALL DATE16
1174 XCHG AX,DX
1175 STOSW
1176 XCHG AX,DX
1177 STOSW
1178 XOR AX,AX
1179 PUSH DI
1180 MOV CL,6
1181SMALLENT:
1182 REP STOSB
1183 PUSH BX
1184 CALL DIRWRITE
1185 POP BX
1186 POP SI
1187OPENJMP:
1188 CLC ;Clear carry so OPEN won't fail
1189 POP ES
1190 POP DI
1191 JMP DOOPEN
1192
1193
1194DIRREAD:
1195
1196; Inputs:
1197; DS = CS
1198; AL = Directory block number
1199; BP = Base of drive parameters
1200; Function:
1201; Read the directory block into DIRBUF.
1202; Outputs:
1203; AX,BP unchanged
1204; All other registers destroyed.
1205
1206 PUSH AX
1207 CALL CHKDIRWRITE
1208 POP AX
1209 PUSH AX
1210 MOV AH,[BP.DEVNUM]
1211 MOV [DIRBUFID],AX
1212 CALL DIRCOMP
1213 CALL DREAD
1214 POP AX
1215RET8: RET
1216
1217
1218DREAD:
1219
1220; Inputs:
1221; BX,DS = Transfer address
1222; CX = Number of sectors
1223; DX = Absolute record number
1224; BP = Base of drive parameters
1225; Function:
1226; Calls BIOS to perform disk read. If BIOS reports
1227; errors, will call HARDERR for further action.
1228; BP preserved. All other registers destroyed.
1229
1230 CALL DSKREAD
1231 JNC RET8
1232 MOV CS:BYTE PTR [READOP],0
1233 CALL HARDERR
1234 CMP AL,1 ;Check for retry
1235 JZ DREAD
1236 RET ;Ignore otherwise
1237
1238
1239HARDERR:
1240
1241;Hard disk error handler. Entry conditions:
1242; DS:BX = Original disk transfer address
1243; DX = Original logical sector number
1244; CX = Number of sectors to go (first one gave the error)
1245; AX = Hardware error code
1246; DI = Original sector transfer count
1247; BP = Base of drive parameters
1248; [READOP] = 0 for read, 1 for write
1249
1250 XCHG AX,DI ;Error code in DI, count in AX
1251 SUB AX,CX ;Number of sectors successfully transferred
1252 ADD DX,AX ;First sector number to retry
1253 PUSH DX
1254 MUL [BP.SECSIZ] ;Number of bytes transferred
1255 POP DX
1256 ADD BX,AX ;First address for retry
1257 MOV AH,0 ;Flag disk section in error
1258 CMP DX,[BP.FIRFAT] ;In reserved area?
1259 JB ERRINT
1260 INC AH ;Flag for FAT
1261 CMP DX,[BP.FIRDIR] ;In FAT?
1262 JB ERRINT
1263 INC AH
1264 CMP DX,[BP.FIRREC] ;In directory?
1265 JB ERRINT
1266 INC AH ;Must be in data area
1267ERRINT:
1268 SHL AH,1 ;Make room for read/write bit
1269 OR AH,CS:[READOP]
1270FATAL:
1271 MOV AL,[BP.DRVNUM] ;Get drive number
1272FATAL1:
1273 PUSH BP ;The only thing we preserve
1274 MOV CS:[CONTSTK],SP
1275 CLI ;Prepare to play with stack
1276 MOV SS,CS:[SSSAVE]
1277 MOV SP,CS:[SPSAVE] ;User stack pointer restored
1278 INT 24H ;Fatal error interrupt vector
1279 MOV CS:[SPSAVE],SP
1280 MOV CS:[SSSAVE],SS
1281 MOV SP,CS
1282 MOV SS,SP
1283 MOV SP,CS:[CONTSTK]
1284 STI
1285 POP BP
1286 CMP AL,2
1287 JZ ERROR
1288 RET
1289
1290DSKREAD:
1291 MOV AL,[BP.DEVNUM]
1292 PUSH BP
1293 PUSH BX
1294 PUSH CX
1295 PUSH DX
1296 CALL FAR PTR BIOSREAD
1297 POP DX
1298 POP DI
1299 POP BX
1300 POP BP
1301RET9: RET
1302
1303
1304CHKDIRWRITE:
1305 TEST BYTE PTR [DIRTYDIR],-1
1306 JZ RET9
1307
1308DIRWRITE:
1309
1310; Inputs:
1311; DS = CS
1312; AL = Directory block number
1313; BP = Base of drive parameters
1314; Function:
1315; Write the directory block into DIRBUF.
1316; Outputs:
1317; BP unchanged
1318; All other registers destroyed.
1319
1320 MOV BYTE PTR [DIRTYDIR],0
1321 MOV AL,BYTE PTR [DIRBUFID]
1322 CALL DIRCOMP
1323
1324
1325DWRITE:
1326
1327; Inputs:
1328; BX,DS = Transfer address
1329; CX = Number of sectors
1330; DX = Absolute record number
1331; BP = Base of drive parameters
1332; Function:
1333; Calls BIOS to perform disk write. If BIOS reports
1334; errors, will call HARDERR for further action.
1335; BP preserved. All other registers destroyed.
1336
1337 MOV AL,[BP.DEVNUM]
1338 MOV AH,CS:VERFLG
1339 PUSH BP
1340 PUSH BX
1341 PUSH CX
1342 PUSH DX
1343 CALL FAR PTR BIOSWRITE
1344 POP DX
1345 POP DI
1346 POP BX
1347 POP BP
1348 JNC RET9
1349 MOV CS:BYTE PTR [READOP],1
1350 CALL HARDERR
1351 CMP AL,1 ;Check for retry
1352 JZ DWRITE
1353 RET
1354
1355
1356ABORT:
1357 LDS SI,CS:DWORD PTR [SPSAVE]
1358 MOV DS,[SI.CSSAVE]
1359 XOR AX,AX
1360 MOV ES,AX
1361 MOV SI,SAVEXIT
1362 MOV DI,EXIT
1363 MOVSW
1364 MOVSW
1365 MOVSW
1366 MOVSW
1367 MOVSW
1368 MOVSW
1369ERROR:
1370 MOV AX,CS
1371 MOV DS,AX
1372 MOV ES,AX
1373 CALL WRTFATS
1374 XOR AX,AX
1375 CLI
1376 MOV SS,[SSSAVE]
1377 MOV SP,[SPSAVE]
1378 MOV DS,AX
1379 MOV SI,EXIT
1380 MOV DI,OFFSET DOSGROUP:EXITHOLD
1381 MOVSW
1382 MOVSW
1383 POP AX
1384 POP BX
1385 POP CX
1386 POP DX
1387 POP SI
1388 POP DI
1389 POP BP
1390 POP DS
1391 POP ES
1392 STI ;Stack OK now
1393 JMP CS:DWORD PTR [EXITHOLD]
1394
1395
1396SEQRD: ;System call 20
1397 CALL GETREC
1398 CALL LOAD
1399 JMP SHORT FINSEQ
1400
1401SEQWRT: ;System call 21
1402 CALL GETREC
1403 CALL STORE
1404FINSEQ:
1405 JCXZ SETNREX
1406 ADD AX,1
1407 ADC DX,0
1408 JMP SHORT SETNREX
1409
1410RNDRD: ;System call 33
1411 CALL GETRRPOS1
1412 CALL LOAD
1413 JMP SHORT FINRND
1414
1415RNDWRT: ;System call 34
1416 CALL GETRRPOS1
1417 CALL STORE
1418 JMP SHORT FINRND
1419
1420BLKRD: ;System call 39
1421 CALL GETRRPOS
1422 CALL LOAD
1423 JMP SHORT FINBLK
1424
1425BLKWRT: ;System call 40
1426 CALL GETRRPOS
1427 CALL STORE
1428FINBLK:
1429 LDS SI,DWORD PTR [SPSAVE]
1430 MOV [SI.CXSAVE],CX
1431 JCXZ FINRND
1432 ADD AX,1
1433 ADC DX,0
1434FINRND:
1435 MOV ES:WORD PTR [DI.RR],AX
1436 MOV ES:[DI.RR+2],DL
1437 OR DH,DH
1438 JZ SETNREX
1439 MOV ES:[DI.RR+3],DH ;Save 4 byte of RECPOS only if significant
1440SETNREX:
1441 MOV CX,AX
1442 AND AL,7FH
1443 MOV ES:[DI.NR],AL
1444 AND CL,80H
1445 SHL CX,1
1446 RCL DX,1
1447 MOV AL,CH
1448 MOV AH,DL
1449 MOV ES:[DI.EXTENT],AX
1450 MOV AL,CS:[DSKERR]
1451 RET
1452
1453GETRRPOS1:
1454 MOV CX,1
1455GETRRPOS:
1456 MOV DI,DX
1457 CMP BYTE PTR [DI],-1
1458 JNZ NORMFCB1
1459 ADD DI,7
1460NORMFCB1:
1461 MOV AX,WORD PTR [DI.RR]
1462 MOV DX,WORD PTR [DI.RR+2]
1463 RET
1464
1465NOFILERR:
1466 XOR CX,CX
1467 MOV BYTE PTR [DSKERR],4
1468 POP BX
1469 RET
1470
1471SETUP:
1472
1473; Inputs:
1474; DS:DI point to FCB
1475; DX:AX = Record position in file of disk transfer
1476; CX = Record count
1477; Outputs:
1478; DS = CS
1479; ES:DI point to FCB
1480; BL = DEVID from FCB
1481; CX = No. of bytes to transfer
1482; BP = Base of drive parameters
1483; SI = FAT pointer
1484; [RECCNT] = Record count
1485; [RECPOS] = Record position in file
1486; [FCB] = DI
1487; [NEXTADD] = Displacement of disk transfer within segment
1488; [SECPOS] = Position of first sector
1489; [BYTPOS] = Byte position in file
1490; [BYTSECPOS] = Byte position in first sector
1491; [CLUSNUM] = First cluster
1492; [SECCLUSPOS] = Sector within first cluster
1493; [DSKERR] = 0 (no errors yet)
1494; [TRANS] = 0 (No transfers yet)
1495; [THISDRV] = Physical drive unit number
1496; If SETUP detects no records will be transfered, it returns 1 level up
1497; with CX = 0.
1498
1499 PUSH AX
1500 MOV AL,[DI]
1501 DEC AL
1502 MOV CS:[THISDRV],AL
1503 MOV AL,[DI.DEVID]
1504 MOV SI,[DI.RECSIZ]
1505 OR SI,SI
1506 JNZ HAVRECSIZ
1507 MOV SI,128
1508 MOV [DI.RECSIZ],SI
1509HAVRECSIZ:
1510 PUSH DS
1511 POP ES ;Set ES to DS
1512 PUSH CS
1513 POP DS ;Set DS to CS
1514 OR AL,AL ;Is it a device?
1515 JNS NOTDEVICE
1516 MOV AL,0 ;Fake in drive 0 so we can get SP
1517NOTDEVICE:
1518 CALL GETBP
1519 POP AX
1520 JC NOFILERR
1521 CMP SI,64 ;Check if highest byte of RECPOS is significant
1522 JB SMALREC
1523 MOV DH,0 ;Ignore MSB if record >= 64 bytes
1524SMALREC:
1525 MOV [RECCNT],CX
1526 MOV WORD PTR [RECPOS],AX
1527 MOV WORD PTR [RECPOS+2],DX
1528 MOV [FCB],DI
1529 MOV BX,[DMAADD]
1530 MOV [NEXTADD],BX
1531 MOV BYTE PTR [DSKERR],0
1532 MOV BYTE PTR [TRANS],0
1533 MOV BX,DX
1534 MUL SI
1535 MOV WORD PTR [BYTPOS],AX
1536 PUSH DX
1537 MOV AX,BX
1538 MUL SI
1539 POP BX
1540 ADD AX,BX
1541 ADC DX,0 ;Ripple carry
1542 JNZ EOFERR
1543 MOV WORD PTR [BYTPOS+2],AX
1544 MOV DX,AX
1545 MOV AX,WORD PTR [BYTPOS]
1546 MOV BX,[BP.SECSIZ]
1547 CMP DX,BX ;See if divide will overflow
1548 JNC EOFERR
1549 DIV BX
1550 MOV [SECPOS],AX
1551 MOV [BYTSECPOS],DX
1552 MOV DX,AX
1553 AND AL,[BP.CLUSMSK]
1554 MOV [SECCLUSPOS],AL
1555 MOV AX,CX ;Record count
1556 MOV CL,[BP.CLUSSHFT]
1557 SHR DX,CL
1558 MOV [CLUSNUM],DX
1559 MUL SI ;Multiply by bytes per record
1560 MOV CX,AX
1561 ADD AX,[DMAADD] ;See if it will fit in one segment
1562 ADC DX,0
1563 JZ OK ;Must be less than 64K
1564 MOV AX,[DMAADD]
1565 NEG AX ;Amount of room left in segment
1566 JNZ PARTSEG ;All 64K available?
1567 DEC AX ;If so, reduce by one
1568PARTSEG:
1569 XOR DX,DX
1570 DIV SI ;How many records will fit?
1571 MOV [RECCNT],AX
1572 MUL SI ;Translate that back into bytes
1573 MOV BYTE PTR [DSKERR],2 ;Flag that trimming took place
1574 MOV CX,AX
1575 JCXZ NOROOM
1576OK:
1577 MOV BL,ES:[DI.DEVID]
1578 MOV SI,[BP.FAT]
1579 RET
1580
1581EOFERR:
1582 MOV BYTE PTR [DSKERR],1
1583 XOR CX,CX
1584NOROOM:
1585 POP BX ;Kill return address
1586 RET
1587
1588BREAKDOWN:
1589
1590;Inputs:
1591; DS = CS
1592; CX = Length of disk transfer in bytes
1593; BP = Base of drive parameters
1594; [BYTSECPOS] = Byte position witin first sector
1595;Outputs:
1596; [BYTCNT1] = Bytes to transfer in first sector
1597; [SECCNT] = No. of whole sectors to transfer
1598; [BYTCNT2] = Bytes to transfer in last sector
1599;AX, BX, DX destroyed. No other registers affected.
1600
1601 MOV AX,[BYTSECPOS]
1602 MOV BX,CX
1603 OR AX,AX
1604 JZ SAVFIR ;Partial first sector?
1605 SUB AX,[BP.SECSIZ]
1606 NEG AX ;Max number of bytes left in first sector
1607 SUB BX,AX ;Subtract from total length
1608 JAE SAVFIR
1609 ADD AX,BX ;Don't use all of the rest of the sector
1610 XOR BX,BX ;And no bytes are left
1611SAVFIR:
1612 MOV [BYTCNT1],AX
1613 MOV AX,BX
1614 XOR DX,DX
1615 DIV [BP.SECSIZ] ;How many whole sectors?
1616 MOV [SECCNT],AX
1617 MOV [BYTCNT2],DX ;Bytes remaining for last sector
1618RET10: RET
1619
1620
1621FNDCLUS:
1622
1623; Inputs:
1624; DS = CS
1625; CX = No. of clusters to skip
1626; BP = Base of drive parameters
1627; SI = FAT pointer
1628; ES:DI point to FCB
1629; Outputs:
1630; BX = Last cluster skipped to
1631; CX = No. of clusters remaining (0 unless EOF)
1632; DX = Position of last cluster
1633; DI destroyed. No other registers affected.
1634
1635 MOV BX,ES:[DI.LSTCLUS]
1636 MOV DX,ES:[DI.CLUSPOS]
1637 OR BX,BX
1638 JZ NOCLUS
1639 SUB CX,DX
1640 JNB FINDIT
1641 ADD CX,DX
1642 XOR DX,DX
1643 MOV BX,ES:[DI.FIRCLUS]
1644FINDIT:
1645 JCXZ RET10
1646SKPCLP:
1647 CALL UNPACK
1648 CMP DI,0FF8H
1649 JAE RET10
1650 XCHG BX,DI
1651 INC DX
1652 LOOP SKPCLP
1653 RET
1654NOCLUS:
1655 INC CX
1656 DEC DX
1657 RET
1658
1659
1660BUFSEC:
1661; Inputs:
1662; AL = 0 if buffer must be read, 1 if no pre-read needed
1663; BP = Base of drive parameters
1664; [CLUSNUM] = Physical cluster number
1665; [SECCLUSPOS] = Sector position of transfer within cluster
1666; [BYTCNT1] = Size of transfer
1667; Function:
1668; Insure specified sector is in buffer, flushing buffer before
1669; read if necessary.
1670; Outputs:
1671; SI = Pointer to buffer
1672; DI = Pointer to transfer address
1673; CX = Number of bytes
1674; [NEXTADD] updated
1675; [TRANS] set to indicate a transfer will occur
1676
1677 MOV DX,[CLUSNUM]
1678 MOV BL,[SECCLUSPOS]
1679 CALL FIGREC
1680 MOV [PREREAD],AL
1681 CMP DX,[BUFSECNO]
1682 JNZ GETSEC
1683 MOV AL,[BUFDRVNO]
1684 CMP AL,[THISDRV]
1685 JZ FINBUF ;Already have it?
1686GETSEC:
1687 XOR AL,AL
1688 XCHG [DIRTYBUF],AL ;Read dirty flag and reset it
1689 OR AL,AL
1690 JZ RDSEC
1691 PUSH DX
1692 PUSH BP
1693 MOV BP,[BUFDRVBP]
1694 MOV BX,[BUFFER]
1695 MOV CX,1
1696 MOV DX,[BUFSECNO]
1697 CALL DWRITE
1698 POP BP
1699 POP DX
1700RDSEC:
1701 TEST BYTE PTR [PREREAD],-1
1702 JNZ SETBUF
1703 XOR AX,AX
1704 MOV [BUFSECNO],AX ;Set buffer valid in case of disk error
1705 DEC AX
1706 MOV [BUFDRVNO],AL
1707 MOV BX,[BUFFER]
1708 MOV CX,1
1709 PUSH DX
1710 CALL DREAD
1711 POP DX
1712SETBUF:
1713 MOV [BUFSECNO],DX
1714 MOV AL,[THISDRV]
1715 MOV [BUFDRVNO],AL
1716 MOV [BUFDRVBP],BP
1717FINBUF:
1718 MOV BYTE PTR [TRANS],1 ;A transfer is taking place
1719 MOV DI,[NEXTADD]
1720 MOV SI,DI
1721 MOV CX,[BYTCNT1]
1722 ADD SI,CX
1723 MOV [NEXTADD],SI
1724 MOV SI,[BUFFER]
1725 ADD SI,[BYTSECPOS]
1726 RET
1727
1728BUFRD:
1729 XOR AL,AL ;Pre-read necessary
1730 CALL BUFSEC
1731 PUSH ES
1732 MOV ES,[DMAADD+2]
1733 SHR CX,1
1734 JNC EVENRD
1735 MOVSB
1736EVENRD:
1737 REP MOVSW
1738 POP ES
1739 RET
1740
1741BUFWRT:
1742 MOV AX,[SECPOS]
1743 INC AX ;Set for next sector
1744 MOV [SECPOS],AX
1745 CMP AX,[VALSEC] ;Has sector been written before?
1746 MOV AL,1
1747 JA NOREAD ;Skip preread if SECPOS>VALSEC
1748 MOV AL,0
1749NOREAD:
1750 CALL BUFSEC
1751 XCHG DI,SI
1752 PUSH DS
1753 PUSH ES
1754 PUSH CS
1755 POP ES
1756 MOV DS,[DMAADD+2]
1757 SHR CX,1
1758 JNC EVENWRT
1759 MOVSB
1760EVENWRT:
1761 REP MOVSW
1762 POP ES
1763 POP DS
1764 MOV BYTE PTR [DIRTYBUF],1
1765 RET
1766
1767NEXTSEC:
1768 TEST BYTE PTR [TRANS],-1
1769 JZ CLRET
1770 MOV AL,[SECCLUSPOS]
1771 INC AL
1772 CMP AL,[BP.CLUSMSK]
1773 JBE SAVPOS
1774 MOV BX,[CLUSNUM]
1775 CMP BX,0FF8H
1776 JAE NONEXT
1777 MOV SI,[BP.FAT]
1778 CALL UNPACK
1779 MOV [CLUSNUM],DI
1780 INC [LASTPOS]
1781 MOV AL,0
1782SAVPOS:
1783 MOV [SECCLUSPOS],AL
1784CLRET:
1785 CLC
1786 RET
1787NONEXT:
1788 STC
1789 RET
1790
1791TRANBUF:
1792 LODSB
1793 STOSB
1794 CMP AL,13 ;Check for carriage return
1795 JNZ NORMCH
1796 MOV BYTE PTR [SI],10
1797NORMCH:
1798 CMP AL,10
1799 LOOPNZ TRANBUF
1800 JNZ ENDRDCON
1801 CALL OUT ;Transmit linefeed
1802 XOR SI,SI
1803 OR CX,CX
1804 JNZ GETBUF
1805 OR AL,1 ;Clear zero flag--not end of file
1806ENDRDCON:
1807 MOV [CONTPOS],SI
1808ENDRDDEV:
1809 MOV [NEXTADD],DI
1810 POP ES
1811 JNZ SETFCBJ ;Zero set if Ctrl-Z found in input
1812 MOV DI,[FCB]
1813 AND ES:BYTE PTR [DI.DEVID],0FFH-40H ;Mark as no more data available
1814SETFCBJ:
1815 JMP SETFCB
1816
1817READDEV:
1818 PUSH ES
1819 LES DI,DWORD PTR [DMAADD]
1820 INC BL
1821 JZ READCON
1822 INC BL
1823 JNZ ENDRDDEV
1824READAUX:
1825 CALL AUXIN
1826 STOSB
1827 CMP AL,1AH
1828 LOOPNZ READAUX
1829 JMP SHORT ENDRDDEV
1830
1831READCON:
1832 PUSH CS
1833 POP DS
1834 MOV SI,[CONTPOS]
1835 OR SI,SI
1836 JNZ TRANBUF
1837 CMP BYTE PTR [CONBUF],128
1838 JZ GETBUF
1839 MOV WORD PTR [CONBUF],0FF80H ;Set up 128-byte buffer with no template
1840GETBUF:
1841 PUSH CX
1842 PUSH ES
1843 PUSH DI
1844 MOV DX,OFFSET DOSGROUP:CONBUF
1845 CALL BUFIN ;Get input buffer
1846 POP DI
1847 POP ES
1848 POP CX
1849 MOV SI,2 + OFFSET DOSGROUP:CONBUF
1850 CMP BYTE PTR [SI],1AH ;Check for Ctrl-Z in first character
1851 JNZ TRANBUF
1852 MOV AL,1AH
1853 STOSB
1854 MOV AL,10
1855 CALL OUT ;Send linefeed
1856 XOR SI,SI
1857 JMP SHORT ENDRDCON
1858
1859RDERR:
1860 XOR CX,CX
1861 JMP WRTERR
1862
1863RDLASTJ:JMP RDLAST
1864
1865LOAD:
1866
1867; Inputs:
1868; DS:DI point to FCB
1869; DX:AX = Position in file to read
1870; CX = No. of records to read
1871; Outputs:
1872; DX:AX = Position of last record read
1873; CX = No. of bytes read
1874; ES:DI point to FCB
1875; LSTCLUS, CLUSPOS fields in FCB set
1876
1877 CALL SETUP
1878 OR BL,BL ;Check for named device I/O
1879 JS READDEV
1880 MOV AX,ES:WORD PTR [DI.FILSIZ]
1881 MOV BX,ES:WORD PTR [DI.FILSIZ+2]
1882 SUB AX,WORD PTR [BYTPOS]
1883 SBB BX,WORD PTR [BYTPOS+2]
1884 JB RDERR
1885 JNZ ENUF
1886 OR AX,AX
1887 JZ RDERR
1888 CMP AX,CX
1889 JAE ENUF
1890 MOV CX,AX
1891ENUF:
1892 CALL BREAKDOWN
1893 MOV CX,[CLUSNUM]
1894 CALL FNDCLUS
1895 OR CX,CX
1896 JNZ RDERR
1897 MOV [LASTPOS],DX
1898 MOV [CLUSNUM],BX
1899 CMP [BYTCNT1],0
1900 JZ RDMID
1901 CALL BUFRD
1902RDMID:
1903 CMP [SECCNT],0
1904 JZ RDLASTJ
1905 CALL NEXTSEC
1906 JC SETFCB
1907 MOV BYTE PTR [TRANS],1 ;A transfer is taking place
1908ONSEC:
1909 MOV DL,[SECCLUSPOS]
1910 MOV CX,[SECCNT]
1911 MOV BX,[CLUSNUM]
1912RDLP:
1913 CALL OPTIMIZE
1914 PUSH DI
1915 PUSH AX
1916 PUSH DS
1917 MOV DS,[DMAADD+2]
1918 PUSH DX
1919 PUSH BX
1920 PUSHF ;Save carry flag
1921 CALL DREAD
1922 POPF ;Restore carry flag
1923 POP DI ;Initial transfer address
1924 POP AX ;First sector transfered
1925 POP DS
1926 JC NOTBUFFED ;Was one of those sectors in the buffer?
1927 CMP BYTE PTR [DIRTYBUF],0 ;Is buffer dirty?
1928 JZ NOTBUFFED ;If not no problem
1929;We have transfered in a sector from disk when a dirty copy of it is in the buffer.
1930;We must transfer the sector from the buffer to correct memory address
1931 SUB AX,[BUFSECNO] ;How many sectors into the transfer?
1932 NEG AX
1933 MOV CX,[BP.SECSIZ]
1934 MUL CX ;How many bytes into the transfer?
1935 ADD DI,AX
1936 MOV SI,[BUFFER]
1937 PUSH ES
1938 MOV ES,[DMAADD+2] ;Get disk transfer segment
1939 SHR CX,1
1940 REP MOVSW
1941 JNC EVENMOV
1942 MOVSB
1943EVENMOV:
1944 POP ES
1945NOTBUFFED:
1946 POP CX
1947 POP BX
1948 JCXZ RDLAST
1949 CMP BX,0FF8H
1950 JAE SETFCB
1951 MOV DL,0
1952 INC [LASTPOS] ;We'll be using next cluster
1953 JMP SHORT RDLP
1954
1955SETFCB:
1956 MOV SI,[FCB]
1957 MOV AX,[NEXTADD]
1958 MOV DI,AX
1959 SUB AX,[DMAADD] ;Number of bytes transfered
1960 XOR DX,DX
1961 MOV CX,ES:[SI.RECSIZ]
1962 DIV CX ;Number of records
1963 CMP AX,[RECCNT] ;Check if all records transferred
1964 JZ FULLREC
1965 MOV BYTE PTR [DSKERR],1
1966 OR DX,DX
1967 JZ FULLREC ;If remainder 0, then full record transfered
1968 MOV BYTE PTR [DSKERR],3 ;Flag partial last record
1969 SUB CX,DX ;Bytes left in last record
1970 PUSH ES
1971 MOV ES,[DMAADD+2]
1972 XCHG AX,BX ;Save the record count temporarily
1973 XOR AX,AX ;Fill with zeros
1974 SHR CX,1
1975 JNC EVENFIL
1976 STOSB
1977EVENFIL:
1978 REP STOSW
1979 XCHG AX,BX ;Restore record count to AX
1980 POP ES
1981 INC AX ;Add last (partial) record to total
1982FULLREC:
1983 MOV CX,AX
1984 MOV DI,SI ;ES:DI point to FCB
1985SETCLUS:
1986 MOV AX,[CLUSNUM]
1987 MOV ES:[DI.LSTCLUS],AX
1988 MOV AX,[LASTPOS]
1989 MOV ES:[DI.CLUSPOS],AX
1990ADDREC:
1991 MOV AX,WORD PTR [RECPOS]
1992 MOV DX,WORD PTR [RECPOS+2]
1993 JCXZ RET28 ;If no records read, don't change position
1994 DEC CX
1995 ADD AX,CX ;Update current record position
1996 ADC DX,0
1997 INC CX
1998RET28: RET
1999
2000RDLAST:
2001 MOV AX,[BYTCNT2]
2002 OR AX,AX
2003 JZ SETFCB
2004 MOV [BYTCNT1],AX
2005 CALL NEXTSEC
2006 JC SETFCB
2007 MOV [BYTSECPOS],0
2008 CALL BUFRD
2009 JMP SHORT SETFCB
2010
2011WRTDEV:
2012 PUSH DS
2013 LDS SI,DWORD PTR [DMAADD]
2014 OR BL,40H
2015 INC BL
2016 JZ WRTCON
2017 INC BL
2018 JZ WRTAUX
2019 INC BL
2020 JZ ENDWRDEV ;Done if device is NUL
2021WRTLST:
2022 LODSB
2023 CMP AL,1AH
2024 JZ ENDWRDEV
2025 CALL LISTOUT
2026 LOOP WRTLST
2027 JMP SHORT ENDWRDEV
2028
2029WRTAUX:
2030 LODSB
2031 CALL AUXOUT
2032 CMP AL,1AH
2033 LOOPNZ WRTAUX
2034 JMP SHORT ENDWRDEV
2035
2036WRTCON:
2037 LODSB
2038 CMP AL,1AH
2039 JZ ENDWRDEV
2040 CALL OUT
2041 LOOP WRTCON
2042ENDWRDEV:
2043 POP DS
2044 MOV CX,[RECCNT]
2045 MOV DI,[FCB]
2046 JMP SHORT ADDREC
2047
2048HAVSTART:
2049 MOV CX,AX
2050 CALL SKPCLP
2051 JCXZ DOWRTJ
2052 CALL ALLOCATE
2053 JNC DOWRTJ
2054WRTERR:
2055 MOV BYTE PTR [DSKERR],1
2056LVDSK:
2057 MOV AX,WORD PTR [RECPOS]
2058 MOV DX,WORD PTR [RECPOS+2]
2059 MOV DI,[FCB]
2060 RET
2061
2062DOWRTJ: JMP DOWRT
2063
2064WRTEOFJ:
2065 JMP WRTEOF
2066
2067STORE:
2068
2069; Inputs:
2070; DS:DI point to FCB
2071; DX:AX = Position in file of disk transfer
2072; CX = Record count
2073; Outputs:
2074; DX:AX = Position of last record written
2075; CX = No. of records written
2076; ES:DI point to FCB
2077; LSTCLUS, CLUSPOS fields in FCB set
2078
2079 CALL SETUP
2080 CALL DATE16
2081 MOV ES:[DI.FDATE],AX
2082 MOV ES:[DI.FTIME],DX
2083 OR BL,BL
2084 JS WRTDEV
2085 AND BL,3FH ;Mark file as dirty
2086 MOV ES:[DI.DEVID],BL
2087 CALL BREAKDOWN
2088 MOV AX,WORD PTR [BYTPOS]
2089 MOV DX,WORD PTR [BYTPOS+2]
2090 JCXZ WRTEOFJ
2091 DEC CX
2092 ADD AX,CX
2093 ADC DX,0 ;AX:DX=last byte accessed
2094 DIV [BP.SECSIZ] ;AX=last sector accessed
2095 MOV CL,[BP.CLUSSHFT]
2096 SHR AX,CL ;Last cluster to be accessed
2097 PUSH AX
2098 MOV AX,ES:WORD PTR [DI.FILSIZ]
2099 MOV DX,ES:WORD PTR [DI.FILSIZ+2]
2100 DIV [BP.SECSIZ]
2101 OR DX,DX
2102 JZ NORNDUP
2103 INC AX ;Round up if any remainder
2104NORNDUP:
2105 MOV [VALSEC],AX ;Number of sectors that have been written
2106 POP AX
2107 MOV CX,[CLUSNUM] ;First cluster accessed
2108 CALL FNDCLUS
2109 MOV [CLUSNUM],BX
2110 MOV [LASTPOS],DX
2111 SUB AX,DX ;Last cluster minus current cluster
2112 JZ DOWRT ;If we have last clus, we must have first
2113 JCXZ HAVSTART ;See if no more data
2114 PUSH CX ;No. of clusters short of first
2115 MOV CX,AX
2116 CALL ALLOCATE
2117 POP AX
2118 JC WRTERR
2119 MOV CX,AX
2120 MOV DX,[LASTPOS]
2121 INC DX
2122 DEC CX
2123 JZ NOSKIP
2124 CALL SKPCLP
2125NOSKIP:
2126 MOV [CLUSNUM],BX
2127 MOV [LASTPOS],DX
2128DOWRT:
2129 CMP [BYTCNT1],0
2130 JZ WRTMID
2131 MOV BX,[CLUSNUM]
2132 CALL BUFWRT
2133WRTMID:
2134 MOV AX,[SECCNT]
2135 OR AX,AX
2136 JZ WRTLAST
2137 ADD [SECPOS],AX
2138 CALL NEXTSEC
2139 MOV BYTE PTR [TRANS],1 ;A transfer is taking place
2140 MOV DL,[SECCLUSPOS]
2141 MOV BX,[CLUSNUM]
2142 MOV CX,[SECCNT]
2143WRTLP:
2144 CALL OPTIMIZE
2145 JC NOTINBUF ;Is one of the sectors buffered?
2146 MOV [BUFSECNO],0 ;If so, invalidate the buffer since we're
2147 MOV WORD PTR [BUFDRVNO],0FFH ; completely rewritting it
2148NOTINBUF:
2149 PUSH DI
2150 PUSH AX
2151 PUSH DS
2152 MOV DS,[DMAADD+2]
2153 CALL DWRITE
2154 POP DS
2155 POP CX
2156 POP BX
2157 JCXZ WRTLAST
2158 MOV DL,0
2159 INC [LASTPOS] ;We'll be using next cluster
2160 JMP SHORT WRTLP
2161WRTLAST:
2162 MOV AX,[BYTCNT2]
2163 OR AX,AX
2164 JZ FINWRT
2165 MOV [BYTCNT1],AX
2166 CALL NEXTSEC
2167 MOV [BYTSECPOS],0
2168 CALL BUFWRT
2169FINWRT:
2170 MOV AX,[NEXTADD]
2171 SUB AX,[DMAADD]
2172 ADD AX,WORD PTR [BYTPOS]
2173 MOV DX,WORD PTR [BYTPOS+2]
2174 ADC DX,0
2175 MOV CX,DX
2176 MOV DI,[FCB]
2177 CMP AX,ES:WORD PTR [DI.FILSIZ]
2178 SBB CX,ES:WORD PTR [DI.FILSIZ+2]
2179 JB SAMSIZ
2180 MOV ES:WORD PTR [DI.FILSIZ],AX
2181 MOV ES:WORD PTR [DI.FILSIZ+2],DX
2182SAMSIZ:
2183 MOV CX,[RECCNT]
2184 JMP SETCLUS
2185
2186
2187WRTERRJ:JMP WRTERR
2188
2189WRTEOF:
2190 MOV CX,AX
2191 OR CX,DX
2192 JZ KILLFIL
2193 SUB AX,1
2194 SBB DX,0
2195 DIV [BP.SECSIZ]
2196 MOV CL,[BP.CLUSSHFT]
2197 SHR AX,CL
2198 MOV CX,AX
2199 CALL FNDCLUS
2200 JCXZ RELFILE
2201 CALL ALLOCATE
2202 JC WRTERRJ
2203UPDATE:
2204 MOV DI,[FCB]
2205 MOV AX,WORD PTR [BYTPOS]
2206 MOV ES:WORD PTR [DI.FILSIZ],AX
2207 MOV AX,WORD PTR [BYTPOS+2]
2208 MOV ES:WORD PTR [DI.FILSIZ+2],AX
2209 XOR CX,CX
2210 JMP ADDREC
2211
2212RELFILE:
2213 MOV DX,0FFFH
2214 CALL RELBLKS
2215SETDIRT:
2216 MOV BYTE PTR [SI-1],1
2217 JMP SHORT UPDATE
2218
2219KILLFIL:
2220 XOR BX,BX
2221 XCHG BX,ES:[DI.FIRCLUS]
2222 OR BX,BX
2223 JZ UPDATE
2224 CALL RELEASE
2225 JMP SHORT SETDIRT
2226
2227
2228OPTIMIZE:
2229
2230; Inputs:
2231; DS = CS
2232; BX = Physical cluster
2233; CX = No. of records
2234; DL = sector within cluster
2235; BP = Base of drives parameters
2236; [NEXTADD] = transfer address
2237; Outputs:
2238; AX = No. of records remaining
2239; BX = Transfer address
2240; CX = No. or records to be transferred
2241; DX = Physical sector address
2242; DI = Next cluster
2243; Carry clear if a sector to transfer is in the buffer
2244; Carry set otherwise
2245; [CLUSNUM] = Last cluster accessed
2246; [NEXTADD] updated
2247; BP unchanged. Note that segment of transfer not set.
2248
2249 PUSH DX
2250 PUSH BX
2251 MOV AL,[BP.CLUSMSK]
2252 INC AL ;Number of sectors per cluster
2253 MOV AH,AL
2254 SUB AL,DL ;AL = Number of sectors left in first cluster
2255 MOV DX,CX
2256 MOV SI,[BP.FAT]
2257 MOV CX,0
2258OPTCLUS:
2259;AL has number of sectors available in current cluster
2260;AH has number of sectors available in next cluster
2261;BX has current physical cluster
2262;CX has number of sequential sectors found so far
2263;DX has number of sectors left to transfer
2264;SI has FAT pointer
2265 CALL UNPACK
2266 ADD CL,AL
2267 ADC CH,0
2268 CMP CX,DX
2269 JAE BLKDON
2270 MOV AL,AH
2271 INC BX
2272 CMP DI,BX
2273 JZ OPTCLUS
2274 DEC BX
2275FINCLUS:
2276 MOV [CLUSNUM],BX ;Last cluster accessed
2277 SUB DX,CX ;Number of sectors still needed
2278 PUSH DX
2279 MOV AX,CX
2280 MUL [BP.SECSIZ] ;Number of sectors times sector size
2281 MOV SI,[NEXTADD]
2282 ADD AX,SI ;Adjust by size of transfer
2283 MOV [NEXTADD],AX
2284 POP AX ;Number of sectors still needed
2285 POP DX ;Starting cluster
2286 SUB BX,DX ;Number of new clusters accessed
2287 ADD [LASTPOS],BX
2288 POP BX ;BL = sector postion within cluster
2289 CALL FIGREC
2290 MOV BX,SI
2291;Now let's see if any of these sectors are already in the buffer
2292 CMP [BUFSECNO],DX
2293 JC RET100 ;If DX > [BUFSECNO] then not in buffer
2294 MOV SI,DX
2295 ADD SI,CX ;Last sector + 1
2296 CMP [BUFSECNO],SI
2297 CMC
2298 JC RET100 ;If SI <= [BUFSECNO] then not in buffer
2299 PUSH AX
2300 MOV AL,[BP.DEVNUM]
2301 CMP AL,[BUFDRVNO] ;Is buffer for this drive?
2302 POP AX
2303 JZ RET100 ;If so, then we match
2304 STC ;No match
2305RET100: RET
2306BLKDON:
2307 SUB CX,DX ;Number of sectors in cluster we don't want
2308 SUB AH,CL ;Number of sectors in cluster we accepted
2309 DEC AH ;Adjust to mean position within cluster
2310 MOV [SECCLUSPOS],AH
2311 MOV CX,DX ;Anyway, make the total equal to the request
2312 JMP SHORT FINCLUS
2313
2314
2315FIGREC:
2316
2317;Inputs:
2318; DX = Physical cluster number
2319; BL = Sector postion within cluster
2320; BP = Base of drive parameters
2321;Outputs:
2322; DX = physical sector number
2323;No other registers affected.
2324
2325 PUSH CX
2326 MOV CL,[BP.CLUSSHFT]
2327 DEC DX
2328 DEC DX
2329 SHL DX,CL
2330 OR DL,BL
2331 ADD DX,[BP.FIRREC]
2332 POP CX
2333 RET
2334
2335GETREC:
2336
2337; Inputs:
2338; DS:DX point to FCB
2339; Outputs:
2340; CX = 1
2341; DX:AX = Record number determined by EXTENT and NR fields
2342; DS:DI point to FCB
2343; No other registers affected.
2344
2345 MOV DI,DX
2346 CMP BYTE PTR [DI],-1 ;Check for extended FCB
2347 JNZ NORMFCB2
2348 ADD DI,7
2349NORMFCB2:
2350 MOV CX,1
2351 MOV AL,[DI.NR]
2352 MOV DX,[DI.EXTENT]
2353 SHL AL,1
2354 SHR DX,1
2355 RCR AL,1
2356 MOV AH,DL
2357 MOV DL,DH
2358 MOV DH,0
2359 RET
2360
2361
2362ALLOCATE:
2363
2364; Inputs:
2365; DS = CS
2366; ES = Segment of FCB
2367; BX = Last cluster of file (0 if null file)
2368; CX = No. of clusters to allocate
2369; DX = Position of cluster BX
2370; BP = Base of drive parameters
2371; SI = FAT pointer
2372; [FCB] = Displacement of FCB within segment
2373; Outputs:
2374; IF insufficient space
2375; THEN
2376; Carry set
2377; CX = max. no. of records that could be added to file
2378; ELSE
2379; Carry clear
2380; BX = First cluster allocated
2381; FAT is fully updated including dirty bit
2382; FIRCLUS field of FCB set if file was null
2383; SI,BP unchanged. All other registers destroyed.
2384
2385 PUSH [SI]
2386 PUSH DX
2387 PUSH CX
2388 PUSH BX
2389 MOV AX,BX
2390ALLOC:
2391 MOV DX,BX
2392FINDFRE:
2393 INC BX
2394 CMP BX,[BP.MAXCLUS]
2395 JLE TRYOUT
2396 CMP AX,1
2397 JG TRYIN
2398 POP BX
2399 MOV DX,0FFFH
2400 CALL RELBLKS
2401 POP AX ;No. of clusters requested
2402 SUB AX,CX ;AX=No. of clusters allocated
2403 POP DX
2404 POP [SI]
2405 INC DX ;Position of first cluster allocated
2406 ADD AX,DX ;AX=max no. of cluster in file
2407 MOV DL,[BP.CLUSMSK]
2408 MOV DH,0
2409 INC DX ;DX=records/cluster
2410 MUL DX ;AX=max no. of records in file
2411 MOV CX,AX
2412 SUB CX,WORD PTR [RECPOS] ;CX=max no. of records that could be written
2413 JA MAXREC
2414 XOR CX,CX ;If CX was negative, zero it
2415MAXREC:
2416 STC
2417RET11: RET
2418
2419TRYOUT:
2420 CALL UNPACK
2421 JZ HAVFRE
2422TRYIN:
2423 DEC AX
2424 JLE FINDFRE
2425 XCHG AX,BX
2426 CALL UNPACK
2427 JZ HAVFRE
2428 XCHG AX,BX
2429 JMP SHORT FINDFRE
2430HAVFRE:
2431 XCHG BX,DX
2432 MOV AX,DX
2433 CALL PACK
2434 MOV BX,AX
2435 LOOP ALLOC
2436 MOV DX,0FFFH
2437 CALL PACK
2438 MOV BYTE PTR [SI-1],1
2439 POP BX
2440 POP CX ;Don't need this stuff since we're successful
2441 POP DX
2442 CALL UNPACK
2443 POP [SI]
2444 XCHG BX,DI
2445 OR DI,DI
2446 JNZ RET11
2447 MOV DI,[FCB]
2448 MOV ES:[DI.FIRCLUS],BX
2449RET12: RET
2450
2451
2452RELEASE:
2453
2454; Inputs:
2455; DS = CS
2456; BX = Cluster in file
2457; SI = FAT pointer
2458; BP = Base of drive parameters
2459; Function:
2460; Frees cluster chain starting with [BX]
2461; AX,BX,DX,DI all destroyed. Other registers unchanged.
2462
2463 XOR DX,DX
2464RELBLKS:
2465; Enter here with DX=0FFFH to put an end-of-file mark
2466; in the first cluster and free the rest in the chain.
2467 CALL UNPACK
2468 JZ RET12
2469 MOV AX,DI
2470 CALL PACK
2471 CMP AX,0FF8H
2472 MOV BX,AX
2473 JB RELEASE
2474RET13: RET
2475
2476
2477GETEOF:
2478
2479; Inputs:
2480; BX = Cluster in a file
2481; SI = Base of drive FAT
2482; DS = CS
2483; Outputs:
2484; BX = Last cluster in the file
2485; DI destroyed. No other registers affected.
2486
2487 CALL UNPACK
2488 CMP DI,0FF8H
2489 JAE RET13
2490 MOV BX,DI
2491 JMP SHORT GETEOF
2492
2493
2494SRCHFRST: ;System call 17
2495 CALL GETFILE
2496SAVPLCE:
2497; Search-for-next enters here to save place and report
2498; findings.
2499 JC KILLSRCH
2500 OR BH,BH
2501 JS SRCHDEV
2502 MOV AX,[LASTENT]
2503 MOV ES:[DI.FILDIRENT],AX
2504 MOV ES:[DI.DRVBP],BP
2505;Information in directory entry must be copied into the first
2506; 33 bytes starting at the disk transfer address.
2507 MOV SI,BX
2508 LES DI,DWORD PTR [DMAADD]
2509 MOV AX,00FFH
2510 CMP AL,[EXTFCB]
2511 JNZ NORMFCB
2512 STOSW
2513 INC AL
2514 STOSW
2515 STOSW
2516 MOV AL,[ATTRIB]
2517 STOSB
2518NORMFCB:
2519 MOV AL,[THISDRV]
2520 INC AL
2521 STOSB ;Set drive number
2522 MOV CX,16
2523 REP MOVSW ;Copy remaining 10 characters of name
2524 XOR AL,AL
2525 RET
2526
2527KILLSRCH:
2528KILLSRCH1 EQU KILLSRCH+1
2529;The purpose of the KILLSRCH1 label is to provide a jump label to the following
2530; instruction which leaves out the segment override.
2531 MOV WORD PTR ES:[DI.FILDIRENT],-1
2532 MOV AL,-1
2533 RET
2534
2535SRCHDEV:
2536 MOV ES:[DI.FILDIRENT],BX
2537 LES DI,DWORD PTR [DMAADD]
2538 XOR AX,AX
2539 STOSB ;Zero drive byte
2540 SUB SI,4 ;Point to device name
2541 MOVSW
2542 MOVSW
2543 MOV AX,2020H
2544 STOSB
2545 STOSW
2546 STOSW
2547 STOSW ;Fill with 8 blanks
2548 XOR AX,AX
2549 MOV CX,10
2550 REP STOSW
2551 STOSB
2552RET14: RET
2553
2554SRCHNXT: ;System call 18
2555 CALL MOVNAME
2556 MOV DI,DX
2557 JC NEAR PTR KILLSRCH1
2558 MOV BP,[DI.DRVBP]
2559 MOV AX,[DI.FILDIRENT]
2560 OR AX,AX
2561 JS NEAR PTR KILLSRCH1
2562 PUSH DX
2563 PUSH DS
2564 PUSH CS
2565 POP DS
2566 MOV [LASTENT],AX
2567 CALL CONTSRCH
2568 POP ES
2569 POP DI
2570 JMP SAVPLCE
2571
2572
2573FILESIZE: ;System call 35
2574 CALL GETFILE
2575 MOV AL,-1
2576 JC RET14
2577 ADD DI,33 ;Write size in RR field
2578 MOV CX,ES:[DI.RECSIZ-33]
2579 OR CX,CX
2580 JNZ RECOK
2581 MOV CX,128
2582RECOK:
2583 XOR AX,AX
2584 XOR DX,DX ;Intialize size to zero
2585 OR BH,BH ;Check for named I/O device
2586 JS DEVSIZ
2587 INC SI
2588 INC SI ;Point to length field
2589 MOV AX,[SI+2] ;Get high word of size
2590 DIV CX
2591 PUSH AX ;Save high part of result
2592 LODSW ;Get low word of size
2593 DIV CX
2594 OR DX,DX ;Check for zero remainder
2595 POP DX
2596 JZ DEVSIZ
2597 INC AX ;Round up for partial record
2598 JNZ DEVSIZ ;Propagate carry?
2599 INC DX
2600DEVSIZ:
2601 STOSW
2602 MOV AX,DX
2603 STOSB
2604 MOV AL,0
2605 CMP CX,64
2606 JAE RET14 ;Only 3-byte field if RECSIZ >= 64
2607 MOV ES:[DI],AH
2608 RET
2609
2610
2611SETDMA: ;System call 26
2612 MOV CS:[DMAADD],DX
2613 MOV CS:[DMAADD+2],DS
2614 RET
2615
2616NOSUCHDRV:
2617 MOV AL,-1
2618 RET
2619
2620GETFATPT: ;System call 27
2621 MOV DL,0 ;Use default drive
2622
2623GETFATPTDL: ;System call 28
2624 PUSH CS
2625 POP DS
2626 MOV AL,DL
2627 CALL GETTHISDRV
2628 JC NOSUCHDRV
2629 CALL FATREAD
2630 MOV BX,[BP.FAT]
2631 MOV AL,[BP.CLUSMSK]
2632 INC AL
2633 MOV DX,[BP.MAXCLUS]
2634 DEC DX
2635 MOV CX,[BP.SECSIZ]
2636 LDS SI,DWORD PTR [SPSAVE]
2637 MOV [SI.BXSAVE],BX
2638 MOV [SI.DXSAVE],DX
2639 MOV [SI.CXSAVE],CX
2640 MOV [SI.DSSAVE],CS
2641 RET
2642
2643
2644GETDSKPT: ;System call 31
2645 PUSH CS
2646 POP DS
2647 MOV AL,[CURDRV]
2648 MOV [THISDRV],AL
2649 CALL FATREAD
2650 LDS SI,DWORD PTR [SPSAVE]
2651 MOV [SI.BXSAVE],BP
2652 MOV [SI.DSSAVE],CS
2653 RET
2654
2655
2656DSKRESET: ;System call 13
2657 PUSH CS
2658 POP DS
2659WRTFATS:
2660; DS=CS. Writes back all dirty FATs. All registers destroyed.
2661 XOR AL,AL
2662 XCHG AL,[DIRTYBUF]
2663 OR AL,AL
2664 JZ NOBUF
2665 MOV BP,[BUFDRVBP]
2666 MOV DX,[BUFSECNO]
2667 MOV BX,[BUFFER]
2668 MOV CX,1
2669 CALL DWRITE
2670NOBUF:
2671 MOV CL,[NUMIO]
2672 MOV CH,0
2673 MOV BP,[DRVTAB]
2674WRTFAT:
2675 PUSH CX
2676 CALL CHKFATWRT
2677 POP CX
2678 ADD BP,DPBSIZ
2679 LOOP WRTFAT
2680 RET
2681
2682
2683GETDRV: ;System call 25
2684 MOV AL,CS:[CURDRV]
2685RET15: RET
2686
2687
2688SETRNDREC: ;System call 36
2689 CALL GETREC
2690 MOV [DI+33],AX
2691 MOV [DI+35],DL
2692 CMP [DI.RECSIZ],64
2693 JAE RET15
2694 MOV [DI+36],DH ;Set 4th byte only if record size < 64
2695RET16: RET
2696
2697
2698SELDSK: ;System call 14
2699 MOV AL,CS:[NUMDRV]
2700 CMP DL,AL
2701 JNB RET17
2702 MOV CS:[CURDRV],DL
2703RET17: RET
2704
2705BUFIN: ;System call 10
2706 MOV AX,CS
2707 MOV ES,AX
2708 MOV SI,DX
2709 MOV CH,0
2710 LODSW
2711 OR AL,AL
2712 JZ RET17
2713 MOV BL,AH
2714 MOV BH,CH
2715 CMP AL,BL
2716 JBE NOEDIT
2717 CMP BYTE PTR [BX+SI],0DH
2718 JZ EDITON
2719NOEDIT:
2720 MOV BL,CH
2721EDITON:
2722 MOV DL,AL
2723 DEC DX
2724NEWLIN:
2725 MOV AL,CS:[CARPOS]
2726 MOV CS:[STARTPOS],AL
2727 PUSH SI
2728 MOV DI,OFFSET DOSGROUP:INBUF
2729 MOV AH,CH
2730 MOV BH,CH
2731 MOV DH,CH
2732GETCH:
2733 CALL IN
2734 CMP AL,"F"-"@" ;Ignore ^F
2735 JZ GETCH
2736 CMP AL,CS:ESCCHAR
2737 JZ ESC
2738 CMP AL,7FH
2739 JZ BACKSP
2740 CMP AL,8
2741 JZ BACKSP
2742 CMP AL,13
2743 JZ ENDLIN
2744 CMP AL,10
2745 JZ PHYCRLF
2746 CMP AL,CANCEL
2747 JZ KILNEW
2748SAVCH:
2749 CMP DH,DL
2750 JAE BUFFUL
2751 STOSB
2752 INC DH
2753 CALL BUFOUT
2754 OR AH,AH
2755 JNZ GETCH
2756 CMP BH,BL
2757 JAE GETCH
2758 INC SI
2759 INC BH
2760 JMP SHORT GETCH
2761
2762BUFFUL:
2763 MOV AL,7
2764 CALL OUT
2765 JMP SHORT GETCH
2766
2767ESC:
2768 CALL IN
2769 MOV CL,ESCTABLEN
2770 PUSH DI
2771 MOV DI,OFFSET DOSGROUP:ESCTAB
2772 REPNE SCASB
2773 POP DI
2774 SHL CX,1
2775 MOV BP,CX
2776 JMP [BP+OFFSET DOSGROUP:ESCFUNC]
2777
2778ENDLIN:
2779 STOSB
2780 CALL OUT
2781 POP DI
2782 MOV [DI-1],DH
2783 INC DH
2784COPYNEW:
2785 MOV BP,ES
2786 MOV BX,DS
2787 MOV ES,BX
2788 MOV DS,BP
2789 MOV SI,OFFSET DOSGROUP:INBUF
2790 MOV CL,DH
2791 REP MOVSB
2792 RET
2793CRLF:
2794 MOV AL,13
2795 CALL OUT
2796 MOV AL,10
2797 JMP OUT
2798
2799PHYCRLF:
2800 CALL CRLF
2801 JMP SHORT GETCH
2802
2803KILNEW:
2804 MOV AL,"\"
2805 CALL OUT
2806 POP SI
2807PUTNEW:
2808 CALL CRLF
2809 MOV AL,CS:[STARTPOS]
2810 CALL TAB
2811 JMP NEWLIN
2812
2813BACKSP:
2814 OR DH,DH
2815 JZ OLDBAK
2816 CALL BACKUP
2817 MOV AL,ES:[DI]
2818 CMP AL," "
2819 JAE OLDBAK
2820 CMP AL,9
2821 JZ BAKTAB
2822 CALL BACKMES
2823OLDBAK:
2824 OR AH,AH
2825 JNZ GETCH1
2826 OR BH,BH
2827 JZ GETCH1
2828 DEC BH
2829 DEC SI
2830GETCH1:
2831 JMP GETCH
2832BAKTAB:
2833 PUSH DI
2834 DEC DI
2835 STD
2836 MOV CL,DH
2837 MOV AL," "
2838 PUSH BX
2839 MOV BL,7
2840 JCXZ FIGTAB
2841FNDPOS:
2842 SCASB
2843 JNA CHKCNT
2844 CMP ES:BYTE PTR [DI+1],9
2845 JZ HAVTAB
2846 DEC BL
2847CHKCNT:
2848 LOOP FNDPOS
2849FIGTAB:
2850 SUB BL,CS:[STARTPOS]
2851HAVTAB:
2852 SUB BL,DH
2853 ADD CL,BL
2854 AND CL,7
2855 CLD
2856 POP BX
2857 POP DI
2858 JZ OLDBAK
2859TABBAK:
2860 CALL BACKMES
2861 LOOP TABBAK
2862 JMP SHORT OLDBAK
2863BACKUP:
2864 DEC DH
2865 DEC DI
2866BACKMES:
2867 MOV AL,8
2868 CALL OUT
2869 MOV AL," "
2870 CALL OUT
2871 MOV AL,8
2872 JMP OUT
2873
2874TWOESC:
2875 MOV AL,ESCCH
2876 JMP SAVCH
2877
2878COPYLIN:
2879 MOV CL,BL
2880 SUB CL,BH
2881 JMP SHORT COPYEACH
2882
2883COPYSTR:
2884 CALL FINDOLD
2885 JMP SHORT COPYEACH
2886
2887COPYONE:
2888 MOV CL,1
2889COPYEACH:
2890 MOV AH,0
2891 CMP DH,DL
2892 JZ GETCH2
2893 CMP BH,BL
2894 JZ GETCH2
2895 LODSB
2896 STOSB
2897 CALL BUFOUT
2898 INC BH
2899 INC DH
2900 LOOP COPYEACH
2901GETCH2:
2902 JMP GETCH
2903
2904SKIPONE:
2905 CMP BH,BL
2906 JZ GETCH2
2907 INC BH
2908 INC SI
2909 JMP GETCH
2910
2911SKIPSTR:
2912 CALL FINDOLD
2913 ADD SI,CX
2914 ADD BH,CL
2915 JMP GETCH
2916
2917FINDOLD:
2918 CALL IN
2919 MOV CL,BL
2920 SUB CL,BH
2921 JZ NOTFND
2922 DEC CX
2923 JZ NOTFND
2924 PUSH ES
2925 PUSH DS
2926 POP ES
2927 PUSH DI
2928 MOV DI,SI
2929 INC DI
2930 REPNE SCASB
2931 POP DI
2932 POP ES
2933 JNZ NOTFND
2934 NOT CL
2935 ADD CL,BL
2936 SUB CL,BH
2937RET30: RET
2938NOTFND:
2939 POP BP
2940 JMP GETCH
2941
2942REEDIT:
2943 MOV AL,"@"
2944 CALL OUT
2945 POP DI
2946 PUSH DI
2947 PUSH ES
2948 PUSH DS
2949 CALL COPYNEW
2950 POP DS
2951 POP ES
2952 POP SI
2953 MOV BL,DH
2954 JMP PUTNEW
2955
2956ENTERINS:
2957 IF TOGLINS
2958 NOT AH
2959 JMP GETCH
2960 ENDIF
2961 IF NOT TOGLINS
2962 MOV AH,-1
2963 JMP GETCH
2964
2965EXITINS:
2966 MOV AH,0
2967 JMP GETCH
2968 ENDIF
2969
2970ESCFUNC DW GETCH
2971 DW TWOESC
2972 IF NOT TOGLINS
2973 DW EXITINS
2974 ENDIF
2975 DW ENTERINS
2976 DW BACKSP
2977 DW REEDIT
2978 DW KILNEW
2979 DW COPYLIN
2980 DW SKIPSTR
2981 DW COPYSTR
2982 DW SKIPONE
2983 DW COPYONE
2984
2985 IF IBM
2986 DW COPYONE
2987 DW CTRLZ
2988CTRLZ:
2989 MOV AL,"Z"-"@"
2990 JMP SAVCH
2991 ENDIF
2992BUFOUT:
2993 CMP AL," "
2994 JAE OUT
2995 CMP AL,9
2996 JZ OUT
2997 PUSH AX
2998 MOV AL,"^"
2999 CALL OUT
3000 POP AX
3001 OR AL,40H
3002 JMP SHORT OUT
3003
3004NOSTOP:
3005 CMP AL,"P"-"@"
3006 JZ INCHK
3007 IF NOT TOGLPRN
3008 CMP AL,"N"-"@"
3009 JZ INCHK
3010 ENDIF
3011 CMP AL,"C"-"@"
3012 JZ INCHK
3013 RET
3014
3015CONOUT: ;System call 2
3016 MOV AL,DL
3017OUT:
3018 CMP AL,20H
3019 JB CTRLOUT
3020 CMP AL,7FH
3021 JZ OUTCH
3022 INC CS:BYTE PTR [CARPOS]
3023OUTCH:
3024 PUSH AX
3025 CALL STATCHK
3026 POP AX
3027 CALL FAR PTR BIOSOUT
3028 TEST CS:BYTE PTR [PFLAG],-1
3029 JZ RET18
3030 CALL FAR PTR BIOSPRINT
3031RET18: RET
3032
3033STATCHK:
3034 CALL FAR PTR BIOSSTAT
3035 JZ RET18
3036 CMP AL,'S'-'@'
3037 JNZ NOSTOP
3038 CALL FAR PTR BIOSIN ;Eat Cntrl-S
3039INCHK:
3040 CALL FAR PTR BIOSIN
3041 CMP AL,'P'-'@'
3042 JZ PRINTON
3043 IF NOT TOGLPRN
3044 CMP AL,'N'-'@'
3045 JZ PRINTOFF
3046 ENDIF
3047 CMP AL,'C'-'@'
3048 JNZ RET18
3049; Ctrl-C handler.
3050; "^C" and CR/LF is printed. Then the user registers are restored and the
3051; user CTRL-C handler is executed. At this point the top of the stack has
3052; 1) the interrupt return address should the user CTRL-C handler wish to
3053; allow processing to continue; 2) the original interrupt return address
3054; to the code that performed the function call in the first place. If the
3055; user CTRL-C handler wishes to continue, it must leave all registers
3056; unchanged and IRET. The function that was interrupted will simply be
3057; repeated.
3058 MOV AL,3 ;Display "^C"
3059 CALL BUFOUT
3060 CALL CRLF
3061 CLI ;Prepare to play with stack
3062 MOV SS,CS:[SSSAVE]
3063 MOV SP,CS:[SPSAVE] ;User stack now restored
3064 POP AX
3065 POP BX
3066 POP CX
3067 POP DX
3068 POP SI
3069 POP DI
3070 POP BP
3071 POP DS
3072 POP ES ;User registers now restored
3073 INT CONTC ;Execute user Ctrl-C handler
3074 JMP COMMAND ;Repeat command otherwise
3075
3076PRINTON:
3077 IF TOGLPRN
3078 NOT CS:BYTE PTR [PFLAG]
3079 RET
3080 ENDIF
3081 IF NOT TOGLPRN
3082 MOV CS:BYTE PTR [PFLAG],1
3083 RET
3084
3085PRINTOFF:
3086 MOV CS:BYTE PTR [PFLAG],0
3087 RET
3088 ENDIF
3089
3090CTRLOUT:
3091 CMP AL,13
3092 JZ ZERPOS
3093 CMP AL,8
3094 JZ BACKPOS
3095 CMP AL,9
3096 JNZ OUTCHJ
3097 MOV AL,CS:[CARPOS]
3098 OR AL,0F8H
3099 NEG AL
3100TAB:
3101 PUSH CX
3102 MOV CL,AL
3103 MOV CH,0
3104 JCXZ POPTAB
3105TABLP:
3106 MOV AL," "
3107 CALL OUT
3108 LOOP TABLP
3109POPTAB:
3110 POP CX
3111RET19: RET
3112
3113ZERPOS:
3114 MOV CS:BYTE PTR [CARPOS],0
3115OUTCHJ: JMP OUTCH
3116
3117BACKPOS:
3118 DEC CS:BYTE PTR [CARPOS]
3119 JMP OUTCH
3120
3121
3122CONSTAT: ;System call 11
3123 CALL STATCHK
3124 MOV AL,0
3125 JZ RET19
3126 OR AL,-1
3127 RET
3128
3129
3130CONIN: ;System call 1
3131 CALL IN
3132 PUSH AX
3133 CALL OUT
3134 POP AX
3135 RET
3136
3137
3138IN: ;System call 8
3139 CALL INCHK
3140 JZ IN
3141RET29: RET
3142
3143RAWIO: ;System call 6
3144 MOV AL,DL
3145 CMP AL,-1
3146 JNZ RAWOUT
3147 LDS SI,DWORD PTR CS:[SPSAVE] ;Get pointer to register save area
3148 CALL FAR PTR BIOSSTAT
3149 JNZ RESFLG
3150 OR BYTE PTR [SI.FSAVE],40H ;Set user's zero flag
3151 XOR AL,AL
3152 RET
3153
3154RESFLG:
3155 AND BYTE PTR [SI.FSAVE],0FFH-40H ;Reset user's zero flag
3156RAWINP: ;System call 7
3157 CALL FAR PTR BIOSIN
3158 RET
3159RAWOUT:
3160 CALL FAR PTR BIOSOUT
3161 RET
3162
3163LIST: ;System call 5
3164 MOV AL,DL
3165LISTOUT:
3166 PUSH AX
3167 CALL STATCHK
3168 POP AX
3169 CALL FAR PTR BIOSPRINT
3170RET20: RET
3171
3172PRTBUF: ;System call 9
3173 MOV SI,DX
3174OUTSTR:
3175 LODSB
3176 CMP AL,"$"
3177 JZ RET20
3178 CALL OUT
3179 JMP SHORT OUTSTR
3180
3181OUTMES: ;String output for internal messages
3182 LODS CS:BYTE PTR [SI]
3183 CMP AL,"$"
3184 JZ RET20
3185 CALL OUT
3186 JMP SHORT OUTMES
3187
3188
3189MAKEFCB: ;Interrupt call 41
3190DRVBIT EQU 2
3191NAMBIT EQU 4
3192EXTBIT EQU 8
3193 MOV DL,0 ;Flag--not ambiguous file name
3194 TEST AL,DRVBIT ;Use current drive field if default?
3195 JNZ DEFDRV
3196 MOV BYTE PTR ES:[DI],0 ;No - use default drive
3197DEFDRV:
3198 INC DI
3199 MOV CX,8
3200 TEST AL,NAMBIT ;Use current name fiels as defualt?
3201 XCHG AX,BX ;Save bits in BX
3202 MOV AL," "
3203 JZ FILLB ;If not, go fill with blanks
3204 ADD DI,CX
3205 XOR CX,CX ;Don't fill any
3206FILLB:
3207 REP STOSB
3208 MOV CL,3
3209 TEST BL,EXTBIT ;Use current extension as default
3210 JZ FILLB2
3211 ADD DI,CX
3212 XOR CX,CX
3213FILLB2:
3214 REP STOSB
3215 XCHG AX,CX ;Put zero in AX
3216 STOSW
3217 STOSW ;Initialize two words after to zero
3218 SUB DI,16 ;Point back at start
3219 TEST BL,1 ;Scan off separators if not zero
3220 JZ SKPSPC
3221 CALL SCANB ;Peel off blanks and tabs
3222 CALL DELIM ;Is it a one-time-only delimiter?
3223 JNZ NOSCAN
3224 INC SI ;Skip over the delimiter
3225SKPSPC:
3226 CALL SCANB ;Always kill preceding blanks and tabs
3227NOSCAN:
3228 CALL GETLET
3229 JBE NODRV ;Quit if termination character
3230 CMP BYTE PTR[SI],":" ;Check for potential drive specifier
3231 JNZ NODRV
3232 INC SI ;Skip over colon
3233 SUB AL,"@" ;Convert drive letter to binary drive number
3234 JBE BADDRV ;Valid drive numbers are 1-15
3235 CMP AL,CS:[NUMDRV]
3236 JBE HAVDRV
3237BADDRV:
3238 MOV DL,-1
3239HAVDRV:
3240 STOSB ;Put drive specifier in first byte
3241 INC SI
3242 DEC DI ;Counteract next two instructions
3243NODRV:
3244 DEC SI ;Back up
3245 INC DI ;Skip drive byte
3246 MOV CX,8
3247 CALL GETWORD ;Get 8-letter file name
3248 CMP BYTE PTR [SI],"."
3249 JNZ NODOT
3250 INC SI ;Skip over dot if present
3251 MOV CX,3 ;Get 3-letter extension
3252 CALL MUSTGETWORD
3253NODOT:
3254 LDS BX,CS:DWORD PTR [SPSAVE]
3255 MOV [BX.SISAVE],SI
3256 MOV AL,DL
3257 RET
3258
3259NONAM:
3260 ADD DI,CX
3261 DEC SI
3262 RET
3263
3264GETWORD:
3265 CALL GETLET
3266 JBE NONAM ;Exit if invalid character
3267 DEC SI
3268MUSTGETWORD:
3269 CALL GETLET
3270 JBE FILLNAM
3271 JCXZ MUSTGETWORD
3272 DEC CX
3273 CMP AL,"*" ;Check for ambiguous file specifier
3274 JNZ NOSTAR
3275 MOV AL,"?"
3276 REP STOSB
3277NOSTAR:
3278 STOSB
3279 CMP AL,"?"
3280 JNZ MUSTGETWORD
3281 OR DL,1 ;Flag ambiguous file name
3282 JMP MUSTGETWORD
3283FILLNAM:
3284 MOV AL," "
3285 REP STOSB
3286 DEC SI
3287RET21: RET
3288
3289SCANB:
3290 LODSB
3291 CALL SPCHK
3292 JZ SCANB
3293 DEC SI
3294 RET
3295
3296GETLET:
3297;Get a byte from [SI], convert it to upper case, and compare for delimiter.
3298;ZF set if a delimiter, CY set if a control character (other than TAB).
3299 LODSB
3300 AND AL,7FH
3301 CMP AL,"a"
3302 JB CHK
3303 CMP AL,"z"
3304 JA CHK
3305 SUB AL,20H ;Convert to upper case
3306CHK:
3307 CMP AL,"."
3308 JZ RET21
3309 CMP AL,'"'
3310 JZ RET21
3311 CMP AL,"/"
3312 JZ RET21
3313 CMP AL,"["
3314 JZ RET21
3315 CMP AL,"]"
3316 JZ RET21
3317
3318 IF IBM
3319DELIM:
3320 ENDIF
3321 CMP AL,":" ;Allow ":" as separator in IBM version
3322 JZ RET21
3323 IF NOT IBM
3324DELIM:
3325 ENDIF
3326
3327 CMP AL,"+"
3328 JZ RET101
3329 CMP AL,"="
3330 JZ RET101
3331 CMP AL,";"
3332 JZ RET101
3333 CMP AL,","
3334 JZ RET101
3335SPCHK:
3336 CMP AL,9 ;Filter out tabs too
3337 JZ RET101
3338;WARNING! " " MUST be the last compare
3339 CMP AL," "
3340RET101: RET
3341
3342SETVECT: ; Interrupt call 37
3343 XOR BX,BX
3344 MOV ES,BX
3345 MOV BL,AL
3346 SHL BX,1
3347 SHL BX,1
3348 MOV ES:[BX],DX
3349 MOV ES:[BX+2],DS
3350 RET
3351
3352
3353NEWBASE: ; Interrupt call 38
3354 MOV ES,DX
3355 LDS SI,CS:DWORD PTR [SPSAVE]
3356 MOV DS,[SI.CSSAVE]
3357 XOR SI,SI
3358 MOV DI,SI
3359 MOV AX,DS:[2]
3360 MOV CX,80H
3361 REP MOVSW
3362
3363SETMEM:
3364
3365; Inputs:
3366; AX = Size of memory in paragraphs
3367; DX = Segment
3368; Function:
3369; Completely prepares a program base at the
3370; specified segment.
3371; Outputs:
3372; DS = DX
3373; ES = DX
3374; [0] has INT 20H
3375; [2] = First unavailable segment ([ENDMEM])
3376; [5] to [9] form a long call to the entry point
3377; [10] to [13] have exit address (from INT 22H)
3378; [14] to [17] have ctrl-C exit address (from INT 23H)
3379; [18] to [21] have fatal error address (from INT 24H)
3380; DX,BP unchanged. All other registers destroyed.
3381
3382 XOR CX,CX
3383 MOV DS,CX
3384 MOV ES,DX
3385 MOV SI,EXIT
3386 MOV DI,SAVEXIT
3387 MOVSW
3388 MOVSW
3389 MOVSW
3390 MOVSW
3391 MOVSW
3392 MOVSW
3393 MOV ES:[2],AX
3394 SUB AX,DX
3395 CMP AX,MAXDIF
3396 JBE HAVDIF
3397 MOV AX,MAXDIF
3398HAVDIF:
3399 MOV BX,ENTRYPOINTSEG
3400 SUB BX,AX
3401 SHL AX,1
3402 SHL AX,1
3403 SHL AX,1
3404 SHL AX,1
3405 MOV DS,DX
3406 MOV DS:[6],AX
3407 MOV DS:[8],BX
3408 MOV DS:[0],20CDH ;"INT INTTAB"
3409 MOV DS:(BYTE PTR [5]),LONGCALL
3410 RET
3411
3412DATE16:
3413 PUSH CX
3414 CALL READTIME
3415 SHL CL,1 ;Minutes to left part of byte
3416 SHL CL,1
3417 SHL CX,1 ;Push hours and minutes to left end
3418 SHL CX,1
3419 SHL CX,1
3420 SHR DH,1 ;Count every two seconds
3421 OR CL,DH ;Combine seconds with hours and minutes
3422 MOV DX,CX
3423 POP CX
3424 MOV AX,WORD PTR [MONTH] ;Fetch month and year
3425 SHL AL,1 ;Push month to left to make room for day
3426 SHL AL,1
3427 SHL AL,1
3428 SHL AL,1
3429 SHL AX,1
3430 OR AL,[DAY]
3431RET22: RET
3432
3433FOURYEARS EQU 3*365+366
3434
3435READTIME:
3436;Gets time in CX:DX. Figures new date if it has changed.
3437;Uses AX, CX, DX.
3438 CALL FAR PTR BIOSGETTIME
3439 CMP AX,[DAYCNT] ;See if day count is the same
3440 JZ RET22
3441 CMP AX,FOURYEARS*30 ;Number of days in 120 years
3442 JAE RET22 ;Ignore if too large
3443 MOV [DAYCNT],AX
3444 PUSH SI
3445 PUSH CX
3446 PUSH DX ;Save time
3447 XOR DX,DX
3448 MOV CX,FOURYEARS ;Number of days in 4 years
3449 DIV CX ;Compute number of 4-year units
3450 SHL AX,1
3451 SHL AX,1
3452 SHL AX,1 ;Multiply by 8 (no. of half-years)
3453 MOV CX,AX ;<240 implies AH=0
3454 MOV SI,OFFSET DOSGROUP:YRTAB ;Table of days in each year
3455 CALL DSLIDE ;Find out which of four years we're in
3456 SHR CX,1 ;Convert half-years to whole years
3457 JNC SK ;Extra half-year?
3458 ADD DX,200
3459SK:
3460 CALL SETYEAR
3461 MOV CL,1 ;At least at first month in year
3462 MOV SI,OFFSET DOSGROUP:MONTAB ;Table of days in each month
3463 CALL DSLIDE ;Find out which month we're in
3464 MOV [MONTH],CL
3465 INC DX ;Remainder is day of month (start with one)
3466 MOV [DAY],DL
3467 CALL WKDAY ;Set day of week
3468 POP DX
3469 POP CX
3470 POP SI
3471RET23: RET
3472
3473DSLIDE:
3474 MOV AH,0
3475DSLIDE1:
3476 LODSB ;Get count of days
3477 CMP DX,AX ;See if it will fit
3478 JB RET23 ;If not, done
3479 SUB DX,AX
3480 INC CX ;Count one more month/year
3481 JMP SHORT DSLIDE1
3482
3483SETYEAR:
3484;Set year with value in CX. Adjust length of February for this year.
3485 MOV BYTE PTR [YEAR],CL
3486CHKYR:
3487 TEST CL,3 ;Check for leap year
3488 MOV AL,28
3489 JNZ SAVFEB ;28 days if no leap year
3490 INC AL ;Add leap day
3491SAVFEB:
3492 MOV [MONTAB+1],AL ;Store for February
3493 RET
3494
3495;Days in year
3496YRTAB DB 200,166 ;Leap year
3497 DB 200,165
3498 DB 200,165
3499 DB 200,165
3500
3501;Days of each month
3502MONTAB DB 31 ;January
3503 DB 28 ;February--reset each time year changes
3504 DB 31 ;March
3505 DB 30 ;April
3506 DB 31 ;May
3507 DB 30 ;June
3508 DB 31 ;July
3509 DB 31 ;August
3510 DB 30 ;September
3511 DB 31 ;October
3512 DB 30 ;November
3513 DB 31 ;December
3514
3515GETDATE: ;Function call 42
3516 PUSH CS
3517 POP DS
3518 CALL READTIME ;Check for rollover to next day
3519 MOV AX,[YEAR]
3520 MOV BX,WORD PTR [DAY]
3521 LDS SI,DWORD PTR [SPSAVE] ;Get pointer to user registers
3522 MOV [SI.DXSAVE],BX ;DH=month, DL=day
3523 ADD AX,1980 ;Put bias back
3524 MOV [SI.CXSAVE],AX ;CX=year
3525 MOV AL,CS:[WEEKDAY]
3526RET24: RET
3527
3528SETDATE: ;Function call 43
3529 MOV AL,-1 ;Be ready to flag error
3530 SUB CX,1980 ;Fix bias in year
3531 JC RET24 ;Error if not big enough
3532 CMP CX,119 ;Year must be less than 2100
3533 JA RET24
3534 OR DH,DH
3535 JZ RET24
3536 OR DL,DL
3537 JZ RET24 ;Error if either month or day is 0
3538 CMP DH,12 ;Check against max. month
3539 JA RET24
3540 PUSH CS
3541 POP DS
3542 CALL CHKYR ;Set Feb. up for new year
3543 MOV AL,DH
3544 MOV BX,OFFSET DOSGROUP:MONTAB-1
3545 XLAT ;Look up days in month
3546 CMP AL,DL
3547 MOV AL,-1 ;Restore error flag, just in case
3548 JB RET24 ;Error if too many days
3549 CALL SETYEAR
3550 MOV WORD PTR [DAY],DX ;Set both day and month
3551 SHR CX,1
3552 SHR CX,1
3553 MOV AX,FOURYEARS
3554 MOV BX,DX
3555 MUL CX
3556 MOV CL,BYTE PTR [YEAR]
3557 AND CL,3
3558 MOV SI,OFFSET DOSGROUP:YRTAB
3559 MOV DX,AX
3560 SHL CX,1 ;Two entries per year, so double count
3561 CALL DSUM ;Add up the days in each year
3562 MOV CL,BH ;Month of year
3563 MOV SI,OFFSET DOSGROUP:MONTAB
3564 DEC CX ;Account for months starting with one
3565 CALL DSUM ;Add up days in each month
3566 MOV CL,BL ;Day of month
3567 DEC CX ;Account for days starting with one
3568 ADD DX,CX ;Add in to day total
3569 XCHG AX,DX ;Get day count in AX
3570 MOV [DAYCNT],AX
3571 CALL FAR PTR BIOSSETDATE
3572WKDAY:
3573 MOV AX,[DAYCNT]
3574 XOR DX,DX
3575 MOV CX,7
3576 INC AX
3577 INC AX ;First day was Tuesday
3578 DIV CX ;Compute day of week
3579 MOV [WEEKDAY],DL
3580 XOR AL,AL ;Flag OK
3581RET25: RET
3582
3583DSUM:
3584 MOV AH,0
3585 JCXZ RET25
3586DSUM1:
3587 LODSB
3588 ADD DX,AX
3589 LOOP DSUM1
3590 RET
3591
3592GETTIME: ;Function call 44
3593 PUSH CS
3594 POP DS
3595 CALL READTIME
3596 LDS SI,DWORD PTR [SPSAVE] ;Get pointer to user registers
3597 MOV [SI.DXSAVE],DX
3598 MOV [SI.CXSAVE],CX
3599 XOR AL,AL
3600RET26: RET
3601
3602SETTIME: ;Function call 45
3603;Time is in CX:DX in hours, minutes, seconds, 1/100 sec.
3604 MOV AL,-1 ;Flag in case of error
3605 CMP CH,24 ;Check hours
3606 JAE RET26
3607 CMP CL,60 ;Check minutes
3608 JAE RET26
3609 CMP DH,60 ;Check seconds
3610 JAE RET26
3611 CMP DL,100 ;Check 1/100's
3612 JAE RET26
3613 CALL FAR PTR BIOSSETTIME
3614 XOR AL,AL
3615 RET
3616
3617
3618; Default handler for division overflow trap
3619DIVOV:
3620 PUSH SI
3621 PUSH AX
3622 MOV SI,OFFSET DOSGROUP:DIVMES
3623 CALL OUTMES
3624 POP AX
3625 POP SI
3626 INT 23H ;Use Ctrl-C abort on divide overflow
3627 IRET
3628
3629CODSIZ EQU $-CODSTRT ;Size of code segment
3630CODE ENDS
3631
3632
3633;***** DATA AREA *****
3634CONSTANTS SEGMENT BYTE
3635 ORG 0
3636CONSTRT EQU $ ;Start of constants segment
3637
3638IONAME:
3639 IF NOT IBM
3640 DB "PRN ","LST ","NUL ","AUX ","CON "
3641 ENDIF
3642 IF IBM
3643 DB "COM1","PRN ","LPT1","NUL ","AUX ","CON "
3644 ENDIF
3645DIVMES DB 13,10,"Divide overflow",13,10,"$"
3646CARPOS DB 0
3647STARTPOS DB 0
3648PFLAG DB 0
3649DIRTYDIR DB 0 ;Dirty buffer flag
3650NUMDRV DB 0 ;Number of drives
3651NUMIO DB ? ;Number of disk tables
3652VERFLG DB 0 ;Initialize with verify off
3653CONTPOS DW 0
3654DMAADD DW 80H ;User's disk transfer address (disp/seg)
3655 DW ?
3656ENDMEM DW ?
3657MAXSEC DW 0
3658BUFFER DW ?
3659BUFSECNO DW 0
3660BUFDRVNO DB -1
3661DIRTYBUF DB 0
3662BUFDRVBP DW ?
3663DIRBUFID DW -1
3664DAY DB 0
3665MONTH DB 0
3666YEAR DW 0
3667DAYCNT DW -1
3668WEEKDAY DB 0
3669CURDRV DB 0 ;Default to drive A
3670DRVTAB DW 0 ;Address of start of DPBs
3671DOSLEN EQU CODSIZ+($-CONSTRT) ;Size of CODE + CONSTANTS segments
3672CONSTANTS ENDS
3673
3674DATA SEGMENT WORD
3675; Init code overlaps with data area below
3676
3677 ORG 0
3678INBUF DB 128 DUP (?)
3679CONBUF DB 131 DUP (?) ;The rest of INBUF and console buffer
3680LASTENT DW ?
3681EXITHOLD DB 4 DUP (?)
3682FATBASE DW ?
3683NAME1 DB 11 DUP (?) ;File name buffer
3684ATTRIB DB ?
3685NAME2 DB 11 DUP (?)
3686NAME3 DB 12 DUP (?)
3687EXTFCB DB ?
3688;WARNING - the following two items are accessed as a word
3689CREATING DB ?
3690DELALL DB ?
3691TEMP LABEL WORD
3692SPSAVE DW ?
3693SSSAVE DW ?
3694CONTSTK DW ?
3695SECCLUSPOS DB ? ;Position of first sector within cluster
3696DSKERR DB ?
3697TRANS DB ?
3698PREREAD DB ? ;0 means preread; 1 means optional
3699READOP DB ?
3700THISDRV DB ?
3701
3702 EVEN
3703FCB DW ? ;Address of user FCB
3704NEXTADD DW ?
3705RECPOS DB 4 DUP (?)
3706RECCNT DW ?
3707LASTPOS DW ?
3708CLUSNUM DW ?
3709SECPOS DW ? ;Position of first sector accessed
3710VALSEC DW ? ;Number of valid (previously written) sectors
3711BYTSECPOS DW ? ;Position of first byte within sector
3712BYTPOS DB 4 DUP (?) ;Byte position in file of access
3713BYTCNT1 DW ? ;No. of bytes in first sector
3714BYTCNT2 DW ? ;No. of bytes in last sector
3715SECCNT DW ? ;No. of whole sectors
3716ENTFREE DW ?
3717
3718 DB 80H DUP (?) ;Stack space
3719IOSTACK LABEL BYTE
3720 DB 80H DUP (?)
3721DSKSTACK LABEL BYTE
3722
3723 IF DSKTEST
3724NSS DW ?
3725NSP DW ?
3726 ENDIF
3727
3728DIRBUF LABEL WORD
3729
3730;Init code below overlaps with data area above
3731
3732 ORG 0
3733
3734MOVFAT:
3735;This section of code is safe from being overwritten by block move
3736 REP MOVS BYTE PTR [DI],[SI]
3737 CLD
3738 MOV ES:[DMAADD+2],DX
3739 MOV SI,[DRVTAB] ;Address of first DPB
3740 MOV AL,-1
3741 MOV CL,[NUMIO] ;Number of DPBs
3742FLGFAT:
3743 MOV DI,ES:[SI.FAT] ;get pointer to FAT
3744 DEC DI ;Point to dirty byte
3745 STOSB ;Flag as unused
3746 ADD SI,DPBSIZ ;Point to next DPB
3747 LOOP FLGFAT
3748 MOV AX,[ENDMEM]
3749 CALL SETMEM ;Set up segment
3750
3751XXX PROC FAR
3752 RET
3753XXX ENDP
3754
3755DOSINIT:
3756 CLI
3757 CLD
3758 PUSH CS
3759 POP ES
3760 MOV ES:[ENDMEM],DX
3761 LODSB ;Get no. of drives & no. of I/O drivers
3762 MOV ES:[NUMIO],AL
3763 MOV DI,OFFSET DOSGROUP:MEMSTRT
3764PERDRV:
3765 MOV BP,DI
3766 MOV AL,ES:[DRVCNT]
3767 STOSB ;DEVNUM
3768 LODSB ;Physical unit no.
3769 STOSB ;DRVNUM
3770 CMP AL,15
3771 JA BADINIT
3772 CBW ;Index into FAT size table
3773 SHL AX,1
3774 ADD AX,OFFSET DOSGROUP:FATSIZTAB
3775 XCHG BX,AX
3776 LODSW ;Pointer to DPT
3777 PUSH SI
3778 MOV SI,AX
3779 LODSW
3780 STOSW ;SECSIZ
3781 MOV DX,AX
3782 CMP AX,ES:[MAXSEC]
3783 JBE NOTMAX
3784 MOV ES:[MAXSEC],AX
3785NOTMAX:
3786 LODSB
3787 DEC AL
3788 STOSB ;CLUSMSK
3789 JZ HAVSHFT
3790 CBW
3791FIGSHFT:
3792 INC AH
3793 SAR AL,1
3794 JNZ FIGSHFT
3795 MOV AL,AH
3796HAVSHFT:
3797 STOSB ;CLUSSHFT
3798 MOVSW ;FIRFAT (= number of reserved sectors)
3799 MOVSB ;FATCNT
3800 MOVSW ;MAXENT
3801 MOV AX,DX ;SECSIZ again
3802 MOV CL,5
3803 SHR AX,CL
3804 MOV CX,AX ;Directory entries per sector
3805 DEC AX
3806 ADD AX,ES:[BP.MAXENT]
3807 XOR DX,DX
3808 DIV CX
3809 STOSW ;DIRSEC (temporarily)
3810 MOVSW ;DSKSIZ (temporarily)
3811FNDFATSIZ:
3812 MOV AL,1
3813 MOV DX,1
3814GETFATSIZ:
3815 PUSH DX
3816 CALL FIGFATSIZ
3817 POP DX
3818 CMP AL,DL ;Compare newly computed FAT size with trial
3819 JZ HAVFATSIZ ;Has sequence converged?
3820 CMP AL,DH ;Compare with previous trial
3821 MOV DH,DL
3822 MOV DL,AL ;Shuffle trials
3823 JNZ GETFATSIZ ;Continue iterations if not oscillating
3824 DEC WORD PTR ES:[BP.DSKSIZ] ;Damp those oscillations
3825 JMP SHORT FNDFATSIZ ;Try again
3826
3827BADINIT:
3828 MOV SI,OFFSET DOSGROUP:BADMES
3829 CALL OUTMES
3830 STI
3831 HLT
3832
3833HAVFATSIZ:
3834 STOSB ;FATSIZ
3835 MUL ES:BYTE PTR[BP.FATCNT] ;Space occupied by all FATs
3836 ADD AX,ES:[BP.FIRFAT]
3837 STOSW ;FIRDIR
3838 ADD AX,ES:[BP.DIRSEC]
3839 MOV ES:[BP.FIRREC],AX ;Destroys DIRSEC
3840 CALL FIGMAX
3841 MOV ES:[BP.MAXCLUS],CX
3842 MOV AX,BX ;Pointer into FAT size table
3843 STOSW ;Allocate space for FAT pointer
3844 MOV AL,ES:[BP.FATSIZ]
3845 XOR AH,AH
3846 MUL ES:[BP.SECSIZ]
3847 CMP AX,ES:[BX] ;Bigger than already allocated
3848 JBE SMFAT
3849 MOV ES:[BX],AX
3850SMFAT:
3851 POP SI ;Restore pointer to init. table
3852 MOV AL,ES:[DRVCNT]
3853 INC AL
3854 MOV ES:[DRVCNT],AL
3855 CMP AL,ES:[NUMIO]
3856 JAE CONTINIT
3857 JMP PERDRV
3858
3859BADINITJ:
3860 JMP BADINIT
3861
3862CONTINIT:
3863 PUSH CS
3864 POP DS
3865;Calculate true address of buffers, FATs, free space
3866 MOV BP,[MAXSEC]
3867 MOV AX,OFFSET DOSGROUP:DIRBUF
3868 ADD AX,BP
3869 MOV [BUFFER],AX ;Start of buffer
3870 ADD AX,BP
3871 MOV [DRVTAB],AX ;Start of DPBs
3872 SHL BP,1 ;Two sectors - directory and buffer
3873 ADD BP,DI ;Allocate buffer space
3874 ADD BP,ADJFAC ;True address of FATs
3875 PUSH BP
3876 MOV SI,OFFSET DOSGROUP:FATSIZTAB
3877 MOV DI,SI
3878 MOV CX,16
3879TOTFATSIZ:
3880 INC BP ;Add one for Dirty byte
3881 INC BP ;Add one for I/O device number
3882 LODSW ;Get size of this FAT
3883 XCHG AX,BP
3884 STOSW ;Save address of this FAT
3885 ADD BP,AX ;Compute size of next FAT
3886 CMP AX,BP ;If size was zero done
3887 LOOPNZ TOTFATSIZ
3888 MOV AL,15
3889 SUB AL,CL ;Compute number of FATs used
3890 MOV [NUMDRV],AL
3891 XOR AX,AX ;Set zero flag
3892 REPZ SCASW ;Make sure all other entries are zero
3893 JNZ BADINITJ
3894 ADD BP,15 ;True start of free space
3895 MOV CL,4
3896 SHR BP,CL ;First free segment
3897 MOV DX,CS
3898 ADD DX,BP
3899 MOV BX,0FH
3900 MOV CX,[ENDMEM]
3901 CMP CX,1 ;Use memory scan?
3902 JNZ SETEND
3903 MOV CX,DX ;Start scanning just after DOS
3904MEMSCAN:
3905 INC CX
3906 JZ SETEND
3907 MOV DS,CX
3908 MOV AL,[BX]
3909 NOT AL
3910 MOV [BX],AL
3911 CMP AL,[BX]
3912 NOT AL
3913 MOV [BX],AL
3914 JZ MEMSCAN
3915SETEND:
3916 IF HIGHMEM
3917 SUB CX,BP
3918 MOV BP,CX ;Segment of DOS
3919 MOV DX,CS ;Program segment
3920 ENDIF
3921 IF NOT HIGHMEM
3922 MOV BP,CS
3923 ENDIF
3924; BP has segment of DOS (whether to load high or run in place)
3925; DX has program segment (whether after DOS or overlaying DOS)
3926; CX has size of memory in paragraphs (reduced by DOS size if HIGHMEM)
3927 MOV CS:[ENDMEM],CX
3928 IF HIGHMEM
3929 MOV ES,BP
3930 XOR SI,SI
3931 MOV DI,SI
3932 MOV CX,(DOSLEN+1)/2
3933 PUSH CS
3934 POP DS
3935 REP MOVSW ;Move DOS to high memory
3936 ENDIF
3937 XOR AX,AX
3938 MOV DS,AX
3939 MOV ES,AX
3940 MOV DI,INTBASE
3941 MOV AX,OFFSET DOSGROUP:QUIT
3942 STOSW ;Set abort address--displacement
3943 MOV AX,BP
3944 MOV BYTE PTR DS:[ENTRYPOINT],LONGJUMP
3945 MOV WORD PTR DS:[ENTRYPOINT+1],OFFSET DOSGROUP:ENTRY
3946 MOV WORD PTR DS:[ENTRYPOINT+3],AX
3947 MOV WORD PTR DS:[0],OFFSET DOSGROUP:DIVOV ;Set default divide trap address
3948 MOV DS:[2],AX
3949 MOV CX,9
3950 REP STOSW ;Set 5 segments (skip 2 between each)
3951 MOV WORD PTR DS:[INTBASE+4],OFFSET DOSGROUP:COMMAND
3952 MOV WORD PTR DS:[INTBASE+12],OFFSET DOSGROUP:IRET ;Ctrl-C exit
3953 MOV WORD PTR DS:[INTBASE+16],OFFSET DOSGROUP:IRET ;Fatal error exit
3954 MOV AX,OFFSET BIOSREAD
3955 STOSW
3956 MOV AX,BIOSSEG
3957 STOSW
3958 STOSW ;Add 2 to DI
3959 STOSW
3960 MOV WORD PTR DS:[INTBASE+18H],OFFSET BIOSWRITE
3961 MOV WORD PTR DS:[EXIT],100H
3962 MOV WORD PTR DS:[EXIT+2],DX
3963 IF NOT IBM
3964 MOV SI,OFFSET DOSGROUP:HEADER
3965 CALL OUTMES
3966 ENDIF
3967 PUSH CS
3968 POP DS
3969 PUSH CS
3970 POP ES
3971;Move the FATs into position
3972 MOV AL,[NUMIO]
3973 CBW
3974 XCHG AX,CX
3975 MOV DI,OFFSET DOSGROUP:MEMSTRT.FAT
3976FATPOINT:
3977 MOV SI,WORD PTR [DI] ;Get address within FAT address table
3978 MOVSW ;Set address of this FAT
3979 ADD DI,DPBSIZ-2 ;Point to next DPB
3980 LOOP FATPOINT
3981 POP CX ;True address of first FAT
3982 MOV SI,OFFSET DOSGROUP:MEMSTRT ;Place to move DPBs from
3983 MOV DI,[DRVTAB] ;Place to move DPBs to
3984 SUB CX,DI ;Total length of DPBs
3985 CMP DI,SI
3986 JBE MOVJMP ;Are we moving to higher or lower memory?
3987 DEC CX ;Move backwards to higher memory
3988 ADD DI,CX
3989 ADD SI,CX
3990 INC CX
3991 STD
3992MOVJMP:
3993 MOV ES,BP
3994 JMP MOVFAT
3995
3996FIGFATSIZ:
3997 MUL ES:BYTE PTR[BP.FATCNT]
3998 ADD AX,ES:[BP.FIRFAT]
3999 ADD AX,ES:[BP.DIRSEC]
4000FIGMAX:
4001;AX has equivalent of FIRREC
4002 SUB AX,ES:[BP.DSKSIZ]
4003 NEG AX
4004 MOV CL,ES:[BP.CLUSSHFT]
4005 SHR AX,CL
4006 INC AX
4007 MOV CX,AX ;MAXCLUS
4008 INC AX
4009 MOV DX,AX
4010 SHR DX,1
4011 ADC AX,DX ;Size of FAT in bytes
4012 MOV SI,ES:[BP.SECSIZ]
4013 ADD AX,SI
4014 DEC AX
4015 XOR DX,DX
4016 DIV SI
4017 RET
4018
4019BADMES:
4020 DB 13,10,"INIT TABLE BAD",13,10,"$"
4021
4022FATSIZTAB:
4023 DW 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
4024
4025DRVCNT DB 0
4026
4027MEMSTRT LABEL WORD
4028ADJFAC EQU DIRBUF-MEMSTRT
4029DATA ENDS
4030 END
4031 \ No newline at end of file