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
|
;
; buffer management for MSDOS
;
INCLUDE DOSSEG.ASM
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
i_need BuffHead,DWORD
i_need PreRead,WORD
i_need LastBuffer,DWORD
i_need CurBuf,DWORD
i_need WPErr,BYTE
SUBTTL SETVISIT,SKIPVISIT -- MANAGE BUFFER SCANS
PAGE
procedure SETVISIT,near
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; None
; Function:
; Set up a scan of I/O buffers
; Outputs:
; All visit flags = 0
; NOTE: This pre-scan is needed because a hard disk error
; may cause a scan to stop in the middle leaving some
; visit flags set, and some not set.
; DS:DI Points to [BUFFHEAD]
; No other registers altered
LDS DI,[BUFFHEAD]
PUSH AX
XOR AX,AX
SETLOOP:
MOV [DI.VISIT],AL
LDS DI,[DI.NEXTBUF]
CMP DI,-1
JNZ SETLOOP
LDS DI,[BUFFHEAD]
POP AX
return
entry SKIPVISIT
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DS:DI Points to a buffer
; Function:
; Skip visited buffers
; Outputs:
; DS:DI Points to next unvisited buffer
; Zero is set if skip to LAST buffer
; No other registers altered
CMP DI,-1
retz
CMP [DI.VISIT],1
retnz
LDS DI,[DI.NEXTBUF]
JMP SHORT SKIPVISIT
return
SetVisit ENDP
SUBTTL SCANPLACE, PLACEBUF -- PUT A BUFFER BACK IN THE POOL
PAGE
procedure ScanPlace,near
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; Same as PLACEBUF
; Function:
; Save scan location and call PLACEBUF
; Outputs:
; DS:DI Points to saved scan location
; SI destroyed, other registers unchanged
PUSH ES
LES SI,[DI.NEXTBUF] ; Save scan location
CALL PLACEBUF
PUSH ES
POP DS ; Restore scan location
MOV DI,SI
POP ES
return
ScanPlace ENDP
NRETJ: JMP SHORT NRET
procedure PLACEBUF,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Input:
; DS:DI points to buffer
; Function:
; Remove buffer from queue and re-insert it in proper place.
; If buffer doesn't go at end, and isn't free, decrement
; priorities.
; NO registers altered
;
; DS:SI -- Curbuf, current buffer in list
; ES:DI -- Buf, buffer passed as argument
; BP:CX -- Pointsave, saved Buf.nextbuf
; DX:BX -- Lastbuf, previous buffer in list
; AL -- Inserted, Buf has been inserted
; AH -- Removed, Buf has been removed
IF IBM
IF NOT IBM
invoke save_world
XOR AX,AX ; Inserted = Removed = FALSE
LES CX,[DI.NEXTBUF]
MOV BP,ES ; Pointsave = Buf.nextbuf
MOV SI,DS
MOV ES,SI ; Buf is ES:DI
LDS SI,[BUFFHEAD] ; Curbuf = HEAD
CALL POINTCOMP ; Buf == HEAD?
JNZ TNEWHEAD
CMP CX,-1 ; Buf is LAST?
JZ NRETJ ; Only one buffer, nothing to do
MOV WORD PTR [BUFFHEAD],CX
MOV WORD PTR [BUFFHEAD+2],BP ; HEAD = Pointsave
INC AH ; Removed = TRUE
MOV DS,BP
MOV SI,CX ; Curbuf = HEAD
TNEWHEAD:
MOV BL,ES:[DI.BUFPRI]
CMP BL,[SI.BUFPRI]
JGE BUFLOOP
NEWHEAD: ; If Buf.pri < HEAD.pri
MOV WORD PTR ES:[DI.NEXTBUF],SI
MOV WORD PTR ES:[DI.NEXTBUF+2],DS ; Buf.nextbuf = HEAD
MOV WORD PTR [BUFFHEAD],DI
MOV WORD PTR [BUFFHEAD+2],ES ; HEAD = Buf
INC AL ; Inserted = TRUE
OR AH,AH
JNZ NRET ; If Removed == TRUE
BUFLOOP:
PUSH DS
PUSH SI
LDS SI,[SI.NEXTBUF]
CALL POINTCOMP
POP SI
POP DS
JNZ TESTINS
MOV WORD PTR [SI.NEXTBUF],CX ; If Curbuf.nextbuf == buf
MOV WORD PTR [SI.NEXTBUF+2],BP ; Curbuf.nextbuf = Pointsave
INC AH ; Removed = TRUE
OR AL,AL
JNZ SHUFFLE ; If Inserted == TRUE
TESTINS:
OR AL,AL
JNZ LOOKBUF
PUSH CX ; If NOT Inserted
MOV CL,ES:[DI.BUFPRI]
CMP CL,[SI.BUFPRI]
POP CX
JGE LOOKBUF
PUSH DS ; If Buf.pri < Curbuf.pri
MOV DS,DX
MOV WORD PTR [BX.NEXTBUF],DI
MOV WORD PTR [BX.NEXTBUF+2],ES ; Lastbuf.nextbuf = Buf
POP DS
MOV WORD PTR ES:[DI.NEXTBUF],SI
MOV WORD PTR ES:[DI.NEXTBUF+2],DS ; Buf.nextbuf = Curbuf
INC AL ; Inserted = TRUE
OR AH,AH
JNZ SHUFFLE ; If Removed == TRUE
LOOKBUF:
MOV BX,SI
MOV DX,DS ; Lastbuf = Curbuf
CMP WORD PTR [SI.NEXTBUF],-1
JZ ISLAST
LDS SI,[SI.NEXTBUF] ; Curbuf = Curbuf.nextbuf
JMP SHORT BUFLOOP
ISLAST: ; If Curbuf is LAST
MOV WORD PTR [SI.NEXTBUF],DI
MOV WORD PTR [SI.NEXTBUF+2],ES ; Curbuf.nextbuf = Buf
MOV WORD PTR ES:[DI.NEXTBUF],-1
MOV WORD PTR ES:[DI.NEXTBUF+2],-1 ; Buf is LAST
NRET:
invoke restore_world
return
SHUFFLE:
LDS DI,[BUFFHEAD]
DECLOOP:
CMP [DI.BUFPRI],FREEPRI
JZ NODEC
DEC [DI.BUFPRI]
NODEC:
LDS DI,[DI.NEXTBUF]
CMP DI,-1
JNZ DECLOOP
JMP SHORT NRET
ENDIF
ENDIF
invoke save_world
LES CX,[DI.NEXTBUF]
CMP CX,-1 ; Buf is LAST?
JZ NRET ; Buffer already last
MOV BP,ES ; Pointsave = Buf.nextbuf
PUSH DS
POP ES ; Buf is ES:DI
LDS SI,[BUFFHEAD] ; Curbuf = HEAD
CALL POINTCOMP ; Buf == HEAD?
JNZ BUFLOOP
MOV WORD PTR [BUFFHEAD],CX
MOV WORD PTR [BUFFHEAD+2],BP ; HEAD = Pointsave
JMP SHORT LOOKEND
BUFLOOP:
PUSH DS
PUSH SI
LDS SI,[SI.NEXTBUF]
CALL POINTCOMP
JZ GOTTHEBUF
POP AX
POP AX
JMP SHORT BUFLOOP
GOTTHEBUF:
POP SI
POP DS
MOV WORD PTR [SI.NEXTBUF],CX ; If Curbuf.nextbuf == buf
MOV WORD PTR [SI.NEXTBUF+2],BP ; Curbuf.nextbuf = Pointsave
LOOKEND:
PUSH DS
PUSH SI
LDS SI,[SI.NEXTBUF]
CMP SI,-1
JZ GOTHEEND
POP AX
POP AX
JMP SHORT LOOKEND
GOTHEEND:
POP SI
POP DS
MOV WORD PTR [SI.NEXTBUF],DI
MOV WORD PTR [SI.NEXTBUF+2],ES ; Curbuf.nextbuf = Buf
MOV WORD PTR ES:[DI.NEXTBUF],-1
MOV WORD PTR ES:[DI.NEXTBUF+2],-1 ; Buf is LAST
NRET:
invoke restore_world
return
PLACEBUF ENDP
procedure PLACEHEAD,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; SAME AS PLACEBUF except places buffer at head
invoke save_world
PUSH DS
POP ES
LDS SI,[BUFFHEAD]
MOV WORD PTR [BUFFHEAD],DI
MOV WORD PTR [BUFFHEAD+2],ES
MOV WORD PTR ES:[DI.NEXTBUF],SI
MOV WORD PTR ES:[DI.NEXTBUF+2],DS
LOOKEND2:
PUSH DS
PUSH SI
LDS SI,[SI.NEXTBUF]
CALL POINTCOMP
JZ GOTHEEND2
POP AX
POP AX
JMP SHORT LOOKEND2
GOTHEEND2:
POP SI
POP DS
MOV WORD PTR [SI.NEXTBUF],-1
MOV WORD PTR [SI.NEXTBUF+2],-1 ; Buf is LAST
JMP SHORT NRET
PLACEHEAD ENDP
SUBTTL POINTCOMP -- 20 BIT POINTER COMPARE
PAGE
procedure PointComp,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Compare DS:SI to ES:DI (or DS:DI to ES:SI) for equality
; DO NOT USE FOR < or >
; No Registers altered
CMP SI,DI
retnz
PUSH CX
PUSH DX
MOV CX,DS
MOV DX,ES
CMP CX,DX
POP DX
POP CX
return
PointComp ENDP
SUBTTL GETBUFFR -- GET A SECTOR INTO A BUFFER
PAGE
procedure GETBUFFR,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Input:
; AH = Priority buffer is to have
; AL = 0 means sector must be pre-read
; ELSE no pre-read
; DX = Desired physical sector number
; ES:BP = Pointer to drive parameters
; Function:
; Get the specified sector into one of the I/O buffers
; And shuffle the queue
; Output:
; [CURBUF] Points to the Buffer for the sector
; DX,ES:BP unchanged, all other registers destroyed
XOR SI,SI
entry GETBUFFRB
MOV [PREREAD],AX
MOV AL,ES:[BP.dpb_drive]
LDS DI,[LASTBUFFER]
ASSUME DS:NOTHING
CMP DI,-1 ; Recency pointer valid?
JZ SKBUF ; No
CMP DX,[DI.BUFSECNO]
JNZ SKBUF ; Wrong sector
CMP AL,[DI.BUFDRV]
JNZ SKBUF ; Wrong Drive
JMP SHORT JUSTBUF ; Just asked for same buffer
SKBUF:
LDS DI,[BUFFHEAD]
NXTBFF:
CMP DX,[DI.BUFSECNO]
JNZ BUMP
CMP AL,[DI.BUFDRV]
JNZ BUMP
JMP SHORT SETINF
BUMP:
LDS DI,[DI.NEXTBUF]
CMP DI,-1
JNZ NXTBFF
LDS DI,[BUFFHEAD]
PUSH SI
PUSH DX
PUSH BP
PUSH ES
CALL BUFWRITE ; Write out the dirty buffer
POP ES
POP BP
POP DX
POP SI
RDSEC: ; Read in the new sector
TEST BYTE PTR [PREREAD],-1
JNZ SETBUF
LEA BX,[DI.BufInSiz] ; Point at buffer
MOV CX,1
PUSH SI
PUSH DI
PUSH DX
OR SI,SI
JZ NORMSEC
invoke FATSECRD
JMP SHORT GOTTHESEC ; Buffer is marked free if read barfs
NORMSEC:
invoke DREAD ; Buffer is marked free if read barfs
GOTTHESEC:
POP DX
POP DI
POP SI
SETBUF:
MOV [DI.BUFSECNO],DX
MOV WORD PTR [DI.BUFDRVDP],BP
MOV WORD PTR [DI.BUFDRVDP+2],ES
XOR AH,AH
MOV AL,ES:[BP.dpb_drive]
MOV WORD PTR [DI.BUFDRV],AX
SETINF:
MOV AX,1 ; Default to not a FAT sector
OR SI,SI
JZ SETSTUFFOK
MOV AL,ES:[BP.dpb_FAT_count]
MOV AH,ES:[BP.dpb_FAT_size]
SETSTUFFOK:
MOV WORD PTR [DI.BUFWRTCNT],AX
CALL PLACEBUF
JUSTBUF:
MOV WORD PTR [CURBUF+2],DS
MOV WORD PTR [LASTBUFFER+2],DS
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV WORD PTR [CURBUF],DI
MOV WORD PTR [LASTBUFFER],DI
return
GETBUFFR ENDP
SUBTTL FLUSHBUF -- WRITE OUT DIRTY BUFFERS
PAGE
procedure FlushBuf,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Input:
; DS = DOSGROUP
; AL = Physical unit number
; = -1 for all units
; Function:
; Write out all dirty buffers for unit, and flag them as clean
; DS Preserved, all others destroyed (ES too)
LDS DI,[BUFFHEAD]
ASSUME DS:NOTHING
MOV AH,-1
NXTBUFF:
CMP [DI.BUFDRV],AH
JZ SKIPBFF ; Skip free buffers
CMP AH,AL
JZ DOBUFFER ; Do all dirty buffers
CMP AL,[DI.BUFDRV]
JNZ SKIPBFF ; Buffer not for this unit
DOBUFFER:
CMP BYTE PTR [DI.BUFDIRTY],0
JZ SKIPBFF ; Buffer not dirty
PUSH AX
PUSH WORD PTR [DI.BUFDRV]
CALL BUFWRITE
POP AX
XOR AH,AH ; Buffer is clean
CMP AL,BYTE PTR [WPERR]
JNZ NOZAP
MOV AL,0FFH ; Invalidate buffer, it is inconsistent
NOZAP:
MOV WORD PTR [DI.BUFDRV],AX
POP AX ; Search info
SKIPBFF:
LDS DI,[DI.NEXTBUF]
CMP DI,-1
JNZ NXTBUFF
PUSH SS
POP DS
return
FlushBuf ENDP
SUBTTL BUFWRITE -- WRITE OUT A BUFFER IF DIRTY
PAGE
procedure BufWrite,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Input:
; DS:DI Points to the buffer
; Function:
; Write out all the buffer if dirty.
; Output:
; Buffer marked free
; DS:DI Preserved, ALL others destroyed (ES too)
MOV AX,00FFH
XCHG AX,WORD PTR [DI.BUFDRV] ; Free, in case write barfs
CMP AL,0FFH
retz ; Buffer is free.
OR AH,AH
retz ; Buffer is clean.
CMP AL,BYTE PTR [WPERR]
retz ; If in WP error zap buffer
LES BP,[DI.BUFDRVDP]
LEA BX,[DI.BufInSiz] ; Point at buffer
MOV DX,[DI.BUFSECNO]
MOV CX,WORD PTR [DI.BUFWRTCNT]
MOV AL,CH ; [DI.BUFWRTINC]
XOR CH,CH
MOV AH,CH
PUSH DI
WRTAGAIN:
PUSH CX
PUSH AX
MOV CX,1
PUSH BX
PUSH DX
invoke DWRITE ; Write out the dirty buffer
POP DX
POP BX
POP AX
POP CX
ADD DX,AX
LOOP WRTAGAIN
POP DI
return
BufWrite ENDP
do_ext
CODE ENDS
END
|