⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 buffers.a86

📁 一个dos操作系统DRDOS的源码
💻 A86
📖 第 1 页 / 共 3 页
字号:
	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 + -