summaryrefslogtreecommitdiff
path: root/v2.0/source/ROM.ASM
blob: f66898645e362de72f6bb02313c049960daed7c5 (plain) (blame)
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