1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
|
;
; Disk utilities of MSDOS
;
INCLUDE DOSSEG.ASM
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.XLIST
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
TITLE ROM - miscellaneous routines
NAME ROM
i_need CLUSNUM,WORD
i_need NEXTADD,WORD
i_need LASTPOS,WORD
i_need SECCLUSPOS,BYTE
i_need FATBYT,WORD
i_need RECPOS,4
i_need THISFCB,DWORD
i_need TRANS,BYTE
i_need BYTCNT1,WORD
i_need CURBUF,DWORD
i_need BYTSECPOS,WORD
i_need DMAADD,WORD
i_need SECPOS,WORD
i_need VALSEC,WORD
procedure GET_random_record,NEAR
entry GETRRPOS1
MOV CX,1
entry GetRRPos
MOV DI,DX
CMP BYTE PTR [DI],-1
JNZ NORMFCB1
ADD DI,7
NORMFCB1:
MOV AX,WORD PTR [DI.fcb_RR]
MOV DX,WORD PTR [DI.fcb_RR+2]
return
GET_random_record ENDP
SUBTTL FNDCLUS -- Skip over allocation units
PAGE
procedure FNDCLUS,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; CX = No. of clusters to skip
; ES:BP = Base of drive parameters
; [THISFCB] 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.
PUSH ES
LES DI,[THISFCB]
MOV BX,ES:[DI.fcb_LSTCLUS] ; fcb_lstclus is packed with dir clus
AND BX,0FFFh ; get rid of dir nibble
MOV DX,ES:[DI.fcb_CLUSPOS]
OR BX,BX
JZ NOCLUS
SUB CX,DX
JNB FINDIT
ADD CX,DX
XOR DX,DX
MOV BX,ES:[DI.fcb_FIRCLUS]
FINDIT:
POP ES
JCXZ RET10
entry SKPCLP
invoke UNPACK
CMP DI,0FF8H
JAE RET10
XCHG BX,DI
INC DX
LOOP SKPCLP
RET10: return
NOCLUS:
POP ES
INC CX
DEC DX
return
FNDCLUS ENDP
SUBTTL BUFSEC -- BUFFER A SECTOR AND SET UP A TRANSFER
PAGE
procedure BUFSEC,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; AH = priority of buffer
; AL = 0 if buffer must be read, 1 if no pre-read needed
; ES: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:
; ES:DI = Pointer to buffer
; SI = 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
invoke GETBUFFR
MOV BYTE PTR [TRANS],1 ; A transfer is taking place
MOV SI,[NEXTADD]
MOV DI,SI
MOV CX,[BYTCNT1]
ADD DI,CX
MOV [NEXTADD],DI
LES DI,[CURBUF]
ADD DI,BUFINSIZ ; Point to buffer
ADD DI,[BYTSECPOS]
return
BUFSEC ENDP
SUBTTL BUFRD, BUFWRT -- PERFORM BUFFERED READ AND WRITE
PAGE
procedure BUFRD,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Do a partial sector read via one of the system buffers
; ES:BP Points to DPB
PUSH ES
MOV AX,LBRPRI SHL 8 ; Assume last byte read
CALL BUFSEC
MOV BX,ES
MOV ES,[DMAADD+2]
MOV DS,BX
ASSUME DS:NOTHING
XCHG DI,SI
SHR CX,1
JNC EVENRD
MOVSB
EVENRD:
REP MOVSW
POP ES
LDS DI,[CURBUF]
LEA BX,[DI.BufInSiz]
SUB SI,BX ; Position in buffer
invoke PLACEBUF
CMP SI,ES:[BP.dpb_sector_size]
JB RBUFPLACED
invoke PLACEHEAD
RBUFPLACED:
PUSH SS
POP DS
return
BUFRD ENDP
procedure BUFWRT,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Do a partial sector write via one of the system buffers
; ES:BP Points to DPB
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
XOR AL,AL
NOREAD:
PUSH ES
CALL BUFSEC
MOV DS,[DMAADD+2]
ASSUME DS:NOTHING
SHR CX,1
JNC EVENWRT
MOVSB
EVENWRT:
REP MOVSW
POP ES
LDS BX,[CURBUF]
MOV BYTE PTR [BX.BUFDIRTY],1
LEA SI,[BX.BufInSiz]
SUB DI,SI ; Position in buffer
MOV SI,DI
MOV DI,BX
invoke PLACEBUF
CMP SI,ES:[BP.dpb_sector_size]
JB WBUFPLACED
invoke PLACEHEAD
WBUFPLACED:
PUSH SS
POP DS
return
BUFWRT ENDP
SUBTTL NEXTSEC -- Compute next sector to read or write
PAGE
procedure NEXTSEC,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Compute the next sector to read or write
; ES:BP Points to DPB
TEST BYTE PTR [TRANS],-1
JZ CLRET
MOV AL,[SECCLUSPOS]
INC AL
CMP AL,ES:[BP.dpb_cluster_mask]
JBE SAVPOS
MOV BX,[CLUSNUM]
CMP BX,0FF8H
JAE NONEXT
invoke UNPACK
MOV [CLUSNUM],DI
INC [LASTPOS]
MOV AL,0
SAVPOS:
MOV [SECCLUSPOS],AL
CLRET:
CLC
return
NONEXT:
STC
return
NEXTSEC ENDP
SUBTTL OPTIMIZE -- DO A USER DISK REQUEST WELL
PAGE
procedure OPTIMIZE,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; BX = Physical cluster
; CX = No. of records
; DL = sector within cluster
; ES: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
; [CLUSNUM] = Last cluster accessed
; [NEXTADD] updated
; ES:BP unchanged. Note that segment of transfer not set.
PUSH DX
PUSH BX
MOV AL,ES:[BP.dpb_cluster_mask]
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 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
; ES:BP Points to DPB
; ES:SI has FAT pointer
invoke 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 ES:[BP.dpb_sector_size] ; 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
invoke FIGREC
MOV BX,SI
return
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
OPTIMIZE ENDP
SUBTTL FIGREC -- Figure sector in allocation unit
PAGE
procedure FIGREC,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DX = Physical cluster number
; BL = Sector postion within cluster
; ES:BP = Base of drive parameters
; Outputs:
; DX = physical sector number
; No other registers affected.
PUSH CX
MOV CL,ES:[BP.dpb_cluster_shift]
DEC DX
DEC DX
SHL DX,CL
OR DL,BL
ADD DX,ES:[BP.dpb_first_sector]
POP CX
return
FIGREC ENDP
SUBTTL GETREC -- Figure record in file from fcb
PAGE
procedure GETREC,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DS:DX point to FCB
; Outputs:
; CX = 1
; DX:AX = Record number determined by fcb_EXTENT and fcb_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.fcb_NR]
MOV DX,[DI.fcb_EXTENT]
SHL AL,1
SHR DX,1
RCR AL,1
MOV AH,DL
MOV DL,DH
MOV DH,0
return
GETREC ENDP
SUBTTL ALLOCATE -- Assign disk space
PAGE
procedure ALLOCATE,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; BX = Last cluster of file (0 if null file)
; CX = No. of clusters to allocate
; DX = Position of cluster BX
; ES:BP = Base of drive parameters
; [THISFCB] = Points to FCB
; 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
; fcb_FIRCLUS field of FCB set if file was null
; SI,BP unchanged. All other registers destroyed.
PUSH BX ; save the fat byte
XOR BX,BX
invoke UNPACK
MOV [FATBYT],DI
POP BX
PUSH DX
PUSH CX
PUSH BX
MOV AX,BX
CLUSALLOC:
MOV DX,BX
FINDFRE:
INC BX
CMP BX,ES:[BP.dpb_max_cluster]
JLE TRYOUT
CMP AX,1
JG TRYIN
POP BX
MOV DX,0FFFH
invoke RELBLKS
POP AX ; No. of clusters requested
SUB AX,CX ; AX=No. of clusters allocated
POP DX
invoke RESTFATBYT
INC DX ; Position of first cluster allocated
ADD AX,DX ; AX=max no. of cluster in file
MOV DL,ES:[BP.dpb_cluster_mask]
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
return
TRYOUT:
invoke UNPACK
JZ HAVFRE
TRYIN:
DEC AX
JLE FINDFRE
XCHG AX,BX
invoke UNPACK
JZ HAVFRE
XCHG AX,BX
JMP SHORT FINDFRE
HAVFRE:
XCHG BX,DX
MOV AX,DX
invoke PACK
MOV BX,AX
LOOP CLUSALLOC
MOV DX,0FFFH
invoke PACK
POP BX
POP CX ; Don't need this stuff since we're successful
POP DX
invoke UNPACK
invoke RESTFATBYT
XCHG BX,DI
OR DI,DI
retnz
PUSH ES
LES DI,[THISFCB]
AND BX,0FFFh
MOV ES:[DI.fcb_FIRCLUS],BX
AND ES:[DI.fcb_LSTCLUS],0F000h ; clear out old lstclus
OR ES:[DI.fcb_LSTCLUS],BX ; or the new guy in...
POP ES
return
ALLOCATE ENDP
procedure RESTFATBYT,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
PUSH BX
PUSH DX
PUSH DI
XOR BX,BX
MOV DX,[FATBYT]
invoke PACK
POP DI
POP DX
POP BX
return
RESTFATBYT ENDP
SUBTTL RELEASE -- DEASSIGN DISK SPACE
PAGE
procedure RELEASE,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; BX = Cluster in file
; ES:BP = Base of drive parameters
; Function:
; Frees cluster chain starting with [BX]
; AX,BX,DX,DI all destroyed. Other registers unchanged.
XOR DX,DX
entry RELBLKS
; Enter here with DX=0FFFH to put an end-of-file mark
; in the first cluster and free the rest in the chain.
invoke UNPACK
retz
MOV AX,DI
invoke PACK
CMP AX,0FF8H
MOV BX,AX
JB RELEASE
RET12: return
RELEASE ENDP
SUBTTL GETEOF -- Find the end of a file
PAGE
procedure GETEOF,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; ES:BP Points to DPB
; BX = Cluster in a file
; DS = CS
; Outputs:
; BX = Last cluster in the file
; DI destroyed. No other registers affected.
invoke UNPACK
CMP DI,0FF8H
JAE RET12
MOV BX,DI
JMP SHORT GETEOF
GETEOF ENDP
do_ext
CODE ENDS
END
|