📄 buffers.a86
字号:
test es:BCB_FLAGS[si],BF_DIRTY
jz locate5 ; skip if buffer not dirty
mov al,es:BCB_DRV[si] ; get the buffer's drive
mov ah,es:BCB_FLAGS[si] ; flush all buffers of same type
and ah,BF_ISFAT+BF_ISDIR+BF_ISDAT
push ss ! pop ds
call flush_drive ; gives us burst mode behaviour
; but might re-arrange buffers
call find_prev ; find preceding BCB for re-link
; so DS:BX -> BCB_LINK == ES:SI
locate5:
pop dx ! pop cx ! pop ax ; restore all registers
mov es:BCB_DRV[si],al ; fill in the BCB: drive
mov es:BCB_REC[si],dx ; record low,middle
mov es:BCB_REC2[si],ah ; record high
mov es:BCB_FLAGS[si],cl ; mark as clean, ISFAT,ISDIR or ISDAT
test ch,ch ; is preread required?
jz locate6 ; skip if it isn't
push es ! push si
push ds ! push bx ; save the previous buffer segment
push ss ! pop ds ; for unlinking our buffer
call fill_buffer ; read it from disk, don't return
; on physical errors
pop bx ! pop ds
pop si ! pop es
locate6:
cmp bx,0FFFFh ; are we the MRU buffer
jz locate9 ; yes, leave it at the head
locate8: ; arrive here if found as not 1st
mov ax,es:BCB_LINK_OFF[si]
mov BCB_LINK_OFF[bx],ax
mov ax,es:BCB_LINK_SEG[si]
mov BCB_LINK_SEG[bx],ax ; unlink this buffer
; we now want to attach the
push ss ! pop ds ; BCB at ES:BX to the root
mov ax,ds:word ptr bcb_root
mov es:BCB_LINK_OFF[si],ax
mov ax,ds:word ptr bcb_root+2
mov es:BCB_LINK_SEG[si],ax
mov ds:word ptr bcb_root,si ; insert the new entry
mov ds:word ptr bcb_root+2,es
locate9:
push ss ! pop ds ; DS back to normal
ret
pick_cheapest: ; find cheapest replacement sector
;-------------
; entry: ES:SI = least recently used BCB
; DS:BX = previous buffer
; exit: ES, BX unmodified if LRU buffer marked as cheap
; or no other cheap buffer found
; -or-
; ES:SI, DS:BX modified to cheapest buffer and previous buffer
test es:BCB_FLAGS[si],BF_DIRTY
; is this buffer very expensive?
jz pck_chp5 ; return if it is cheapest "cheap" buffer
; else is cheapest "expensive" buffer
; find the cheapest "cheap" buffer
les si,ss:bcb_root ; as we start at the root with
mov ax,0FFFFh ; no previous buffer
pck_chp1: ; check if buffer at DS is cheap
test es:BCB_FLAGS[si],BF_ISFAT+BF_ISDIR+BF_DIRTY
; check the "not cheap" flag
jnz pck_chp2 ; skip if expensive buffer
mov ds,dx
mov bx,ax ; remember previous buffer
pck_chp2:
mov dx,es ; remember this buffer
mov ax,si ; when we move onto next one
les si,es:BCB_NEXT[si] ; get next buffer
cmp si,0FFFFh ; end of the line ?
jne pck_chp1 ; go again if still buffers
pck_chp3: ; done all buffers
cmp bx,0FFFFh ; did we find the root ?
jne pck_chp4
les si,ss:bcb_root ; return ES:SI -> root
ret
pck_chp4:
les si,ds:BCB_NEXT[bx] ; ES:SI = cheapest buffer
pck_chp5: ; ES:SI = cheapest buffer
ret ; DS:BX = previous
find_prev:
;---------
; entry: ES:SI = BCB to find previous buffer for
; exit: DS:BX = predecessor, BX = FFFF if first
;
mov ax,es
mov dx,si ; AX:DX -> buffer we want to find link for
mov bx,0FFFFh ; assume it's the first buffer
les si,ss:bcb_root ; we start at the root with
find_prv1:
mov cx,es
cmp dx,si ; does offset match ?
jne find_prv2
cmp ax,cx ; does segment match ?
je find_prv3 ; yes, return this one then
find_prv2:
mov ds,cx ; remember previous link
mov bx,si
les si,es:BCB_NEXT[si] ; else have a go at the next one
jmps find_prv1 ; and repeat until match
find_prv3:
ret
; Flush all dirty FAT buffers for drive AL
; entry: AL = drive to flush (0-15)
; exit: CY = 0 if no error
; ax,bx,cx,dx,es preserved
flush_fat:
;---------
; entry: AL = drive for FAT flush
mov ah,BF_ISFAT ; flush all dirty FAT buffers
jmps flush_drive ; shared code for all flushes
;----------
update_dir:
;----------
call flush_dirbuf ; flush local dirbuf to buffers
;---------
flush_dir:
;---------
mov ah,BF_ISDIR ; write out dirty directories
jmps flush_adrive ; update the disk
;----------
update_dat:
;----------
mov ah,BF_ISDAT ; write out dirty data
jmps flush_adrive ; update the disk
;----------
update_fat: ;write out modified FAT buffers
;----------
mov ah,BF_ISFAT ; flush all dirty FAT buffers
; jmp flush_adrive ; update the disk if dirty
flush_adrive:
;------------
mov al,adrive ; AL = currently selected drive
; jmp flush_drive
; Write out all dirty data buffers for a given drive
; entry: AL = drive to be flushed
; AH = mask of buffer types to be flushed
; exit: AX,DX preserved
; Note: sector buffers will be written in the
; sequence in which they appear on disk (low to high)
flush_drive:
;-----------
push ds
push es
push bx ; save registers
push si
flush_dr0:
les si,ss:bcb_root ; start with the first buffer
mov bx,0FFFFh ; assume no buffer found
flush_dr1:
test es:BCB_FLAGS[si],BF_DIRTY
; has buffer been written to?
jz flush_dr3 ; no, do the next one
test es:BCB_FLAGS[si],ah ; is it one of these buffers?
jz flush_dr3 ; no, do the next one
cmp al,es:BCB_DRV[si] ; does the drive match?
jne flush_dr3 ; skip if wrong drive
; we've found a buffer to flush
cmp bx,0FFFFh ; first buffer ever found in list?
jz flush_dr2 ; yes, save as new best candidate
; else check if < previous lowest addr
mov dl,es:BCB_REC2[si] ; compare the disk addresss
sub dl,ds:BCB_REC2[bx]
mov dx,es:BCB_REC[si]
sbb dx,ds:BCB_REC[bx]
jnb flush_dr3 ; CY = 0 if old BCB lower
flush_dr2: ; else ES = best BCB so far
push es
pop ds
mov bx,si ; save it for later
flush_dr3:
les si,es:BCB_NEXT[si] ; get next buffer address
cmp si,0ffffh
jne flush_dr1
flush_dr4: ; DS:BX = best BCB
cmp bx,0FFFFh ; did we find a dirty buffer?
jz flush_dr5 ; no, all buffers cleaned
mov si,bx ; ES:SI -> BCB to flush
push ds ! pop es
push ss ! pop ds
call flush_buffer ; write sector to disk
jmps flush_dr0 ; check if more dirty buffers
flush_dr5:
pop si
pop bx
pop es
pop ds ; restore registers
ret
endif
flush_buffer:
;------------
; entry: ES:SI = address of BCB
; exit: buffer flushed if BCB_FLAGS & BF_DIRTY
; note: preserves AX,BX,CX,DX,ES
test es:BCB_FLAGS[si],BF_DIRTY
; is the buffer dirty?
jz flush_buf9 ; skip update if not modified
flush_buf1:
push es ! push si
push ax ! push bx ; else save all registers
push cx ! push dx
mov al,es:BCB_DRV[si] ; get the buffer drive
cmp al,adrive ; same as the selected drive?
je flush_buf2 ; skip if already selected
push es ; save the BCB
push si
push ds ! pop es ; ES = SYSDAT
call select_adrive ; select drive AL, ZF = 1 if logged in
pop si
pop es ; recover BCB
jc flush_buf5 ; don't flush to bad drive
flush_buf2:
mov cx,nfats ; else FAT sectors written CX times
mov al,0000$0011b ; mark as FAT write
test es:BCB_FLAGS[si],BF_ISFAT
jnz flush_buf3 ; go ahead
mov cx,1 ; directory/data written once only
mov al,0000$0101b ; mark as directory write
test es:BCB_FLAGS[si],BF_ISDIR
jnz flush_buf3 ; if not dir, must be data
mov al,0000$0111b ; mark as data buffer write
flush_buf3: ; CX = # of times to write sector
mov rwmode,al
sub ax,ax ; offset for write = 0
flush_buf4: ; loop back to here for other copies
push ax
push cx ; save loop variables
call setup_rwx ; compute disk address
call write_buff ; write the sector
pop cx
pop ax
add ax,nfatrecs ; move to next FAT copy
loop flush_buf4 ; repeat for all FAT copies
flush_buf5:
and es:BCB_FLAGS[si],not BF_DIRTY
; mark it as no longer dirty
mov al,physical_drv ; work drive for BDOS function
cmp al,adrive ; drive from last IO_SELDSK
je flush_buf6 ; skip if flush to work drive
; else reselect BDOS drive after flush
push ds ! pop es ; ES = SYSDAT
call select_adrive ; reselect the work drive
flush_buf6:
pop dx ! pop cx ; restore all registers
pop bx ! pop ax
pop si ! pop es
flush_buf9: ; all done, CY = 0 if O.K.
ret
;-------
zeroblk: ; AX = blk
;-------
xor bx,bx ; Start at begining of cluster
call clus2sec ; translate to sector address
xchg ax,dx ; DX = low 16 bits of address
mov ah,al ; AH:DX = 24 bit sector address
mov cx,secperclu ; CX == sectors/cluster
zeroblk10: ; repeat for all sectors in cluster
push ax
push cx
push dx
mov cx,BF_ISDIR ; locate directory sector w/o preread
call locate_buffer ; this will find the cheapest buffer
or es:BCB_FLAGS[si],BF_DIRTY
lea di,BCB_DATA[si] ; ES:DI -> disk buffer
mov cx,psecsiz ; CX = byte count for REP STOSB
xor ax,ax
rep stosb ; zero the whole data buffer
pop dx
pop cx
pop ax
add dx,1 ; onto the next block
adc ah,0
loop zeroblk10 ; repeat for all sectors in cluster
jmp flush_dir
fill_buffer:
;-----------
; On Entry:
; ES:SI = address of BCB to be filled
; On Exit:
; ES:SI preserved
; data read into buffer
;
test es:BCB_FLAGS[si],BF_ISFAT
; are we reading a FAT sector?
jz fill_buf1 ; skip if directory/data
mov al,es:BCB_DRV[si] ; get the drive
call flush_fat ; write out all dirty buffers
mov al,0000$0010b ; reading from FAT area
jmps fill_buf3 ; go ahead
fill_buf1:
mov al,0000$0100b ; else mark as directory
test es:BCB_FLAGS[si],BF_ISDIR; test if directory read
jnz fill_buf3 ; go ahead
fill_buf2: ; neither FAT nor directory => data
mov al,0000$0110b ; mark read as data buffer read
fill_buf3:
mov rwmode,al
push cx
xor cx,cx
cmp al,0000$0010b
jne fill_buf4
mov cx,nfats
dec cx
fill_buf4:
mov es:BCB_DRV[si],0FFh ; discard in case of error
sub ax,ax ; no offset for 2nd copy yet
fill_buf5:
push ax
call setup_rwx ; compute disk address
call read_buff ; read the sector
pop ax
jns fill_buf6
; we can end here only if CX was non-zero above and we failed to read a
; FAT copy while there is still another one we could use
add ax,nfatrecs
dec cx
jmps fill_buf5
fill_buf6:
pop cx
mov al,adrive ; restore the drive
mov es:BCB_DRV[si],al ; set the drive #
ret
read_buff:
;---------
push es
push si ; save BCB_
push cur_dma_seg
push cur_dma ; save DMA address
push cx
mov cx,ss:deblock_seg
jcxz read_buff10
mov cur_dma_seg,cx
mov cur_dma,0 ; xfer via deblocking buffer
read_buff10:
pop cx
call read_block
pop cur_dma ; restore DMA address
pop cur_dma_seg
js read_buff20 ; can happen only on FAT read
mov cx,ss:deblock_seg ; if deblocked, copy data
jcxz read_buff20
les di,dword ptr cur_dma ; point to destination
mov cx,psecsiz ; CX = sector size
shr cx,1 ; CX = words per sector
push ds
mov ds,ss:deblock_seg
xor si,si ; DS:SI = source
rep movsw ; copy the data
pop ds
read_buff20: ; SF still indicating error here
pop si ; recover BCB_
pop es
ret
write_buff:
;----------
push es
push si
push cur_dma_seg
push cur_dma
mov cx,ss:deblock_seg ; if deblocking we have to
jcxz write_buff10 ; copy the data first
push ds ; save SYSDAT
les si,dword ptr cur_dma ; ES:SI -> source
push es ; save source seg
mov es,cx
xor di,di ; ES:DI -> deblocking buffer
mov cur_dma_seg,es
mov cur_dma,di ; do xfer via deblocking buffer
mov cx,psecsiz ; CX = sector size
shr cx,1 ; CX = words per sector
pop ds ; DS:SI -> source
rep movsw ; copy to deblocking buffer
pop ds ; restore SYSDAT
write_buff10:
call write_block
pop cur_dma
pop cur_dma_seg
pop si
pop es
ret
setup_rwx:
;---------
; entry: AX = sector offset (multiple FAT writes)
; ES:SI = BCB, BCB_REC filled in
; exit: all values set up for RWXIOSIF
mov cur_dma_seg,es ; segment = BCB_SEGMENT
lea dx,BCB_DATA[si]
mov cur_dma,dx ; offset
xor dx,dx
add ax,es:BCB_REC[si]
adc dl,es:BCB_REC2[si]
mov word ptr pblock,ax ; xfer starts at this block
mov word ptr pblock+WORD,dx
mov mult_sec,1 ; single sector transfer
ret
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -