Tvůrce webu je i pro tebe! Postav třeba web. Bez grafika. Bez kodéra. Hned.
wz

DOS_BUF.ASM

Obsluha diskových bufferů


; ============================================================================
;
;                       LT-DOS - Int 21h buffers
;
; ============================================================================

; ------------- Disk Buffer, BUF

struc		BUF

BUF_Next:	resd	1		; 0: pointer to next disk buffer
					;	offset 0ffffh = last
BUF_DiskFlags:
BUF_Disk:	resb	1		; 4: drive (0=A:, ..., 0ffh=unused)
BUF_Flags:	resb	1		; 5: flags (see Buffer flags)
BUF_Sector:
BUF_SectorH:	resw	1		; 6: logical sector number HIGH
BUF_SectorL:	resw	1		; 8: logical sector number LOW
BUF_CopyOffset:
BUF_Copies:	resb	1		; 0Ah: number of copies to write
					;	(1 for non-FAT sectors)
BUF_Offset:	resb	1		; 0Bh: sector offset between copies
BUF_DDPB:	resd	1		; 0Ch: pointer to DDPB (drive)
BUF_Data:				; 10h: buffered data
endstruc

BUF_SIZE	EQU	BUF_size	; 10h = 16 bytes

; ------------- Buffer flags

BUFFLAG_MODI	EQU	B0		; buffer is modified
;BUFFLAG_MARK	EQU	B1		; buffer is marked as processed
BUFFLAG_DATA	EQU	B2		; buffer contains data

; ----------------------------------------------------------------------------
;                     Mark all disk buffers as free
; ----------------------------------------------------------------------------
; OUTPUT:	DS:SI = first disk buffer
; ----------------------------------------------------------------------------

; ------------- First disk buffer

MarkFreeAll:	lds	si,[cs:FirstDiskBuff] ; DS:SI <- first disk buffer
		push	si		; push SI
		push	ds		; push DS

; ------------- Mark disk buffer as free

MarkFreeAll2:	and	byte [si+BUF_Flags],~BUFFLAG_DATA ; mark buffer as free

; ------------- Next disk buffer

		lds	si,[si+BUF_Next]; DS:SI <- next disk buffer
		cmp	si,byte -1	; check if it is was buffer
		jne	MarkFreeAll2	; next buffer

; ------------- Pop address of first disk buffer

		pop	ds		; pop DS
		pop	si		; pop SI
		ret

; ----------------------------------------------------------------------------
;                     Find next free buffer (without data)
; ----------------------------------------------------------------------------
; INPUT:	DS:SI = disk buffer (-1=invalid)
; OUTPUT:	ZY = there is no next free buffer
; NOTES:	- Entry point is FindFreeBuf
; ----------------------------------------------------------------------------

; ------------- Check if it is unmarked buffer

FindFreeBuf2:	test	byte [si+BUF_Flags],BUFFLAG_DATA ; contains any data?
		jz	FindFreeBuf4	; this buffer does not contain data

; ------------- Next disk buffer

		lds	si,[si+BUF_Next]; DS:SI <- next disk buffer

; ------------- Check if it was last buffer

FindFreeBuf:	cmp	si,byte -1	; was it last buffer?
		jne	FindFreeBuf2	; it was not last buffer
FindFreeBuf4:	ret

; ----------------------------------------------------------------------------
;                 Shift disk buffer to end of buffer chain
; ----------------------------------------------------------------------------
; INPUT:	DS:SI = disk buffer
; ----------------------------------------------------------------------------

; ------------- Push registers

ShiftEnd:	call	PushAll		; push all registers

; ------------- Check if shifted buffer is already last in chain

		mov	ax,[si+BUF_Next] ; offset of next disk buffer
		inc	ax		; is it last disk buffer (=-1)?
		je	ShiftStart8	; it is already last disk buffer
		dec	ax		; return offset of next disk buffer

; ------------- Check if shifted buffer is first disk buffer

		les	di,[cs:FirstDiskBuff] ; ES:DI <- first disk buffer
		call	CompAddr	; is it first disk buffer?
		jne	ShiftEnd2	; it is not first disk buffer

; ------------- Shifted buffer is first, set next buffer as first disk buffer

		les	di,[si+BUF_Next] ; ES:DI <- next disk buffer
		mov	[cs:FirstDiskBuff],di ; set offset of disk buffer
		mov	[cs:FirstDiskBuff+2],es ; set segment of disk buffer
		jmp	short ShiftEnd5	; move disk buffer to the end of chain

; ------------- Find previous disk buffer

ShiftEnd2:	push	di		; push DI (buffer offset)
		push	es		; push ES (buffer segment)

; ------------- Address of next disk buffer (-> ES:DI)

		les	di,[es:di+BUF_Next] ; ES:DI <- next disk buffer

; ------------- Check if it is shifted buffer

		call	CompAddr	; is it shifted buffer?
		je	ShiftEnd4	; it is shifted buffer

; ------------- Destroy disk buffer address in stack

		pop	bx		; destroy ES
		pop	bx		; destroy DI
		jmp	short ShiftEnd2 ; next disk buffer

; ------------- Return address of previous buffer (-> ES:DI)

ShiftEnd4:	pop	es		; pop ES
		pop	di		; pop DI

; ------------- Skip shifted buffer (here is AX = offset of next disk buffer)

		mov	[es:di+BUF_Next],ax ; set offset of next buffer
		mov	ax,[si+BUF_Next+2] ; segment of next disk buffer
		mov	[es:di+BUF_Next+2],ax ; set segment of next buffer

; ------------- Find last disk buffer

ShiftEnd5:	cmp	word [es:di+BUF_Next],byte -1 ; is it last disk buffer?
		je	ShiftEnd6	; it is last disk buffer
		les	di,[es:di+BUF_Next] ; ES:DI <- next disk buffer
		jmp	short ShiftEnd5

; ------------- Set shifted buffer as last

ShiftEnd6:	mov	[es:di+BUF_Next],si ; link to shifted buffer - offset
		mov	[es:di+BUF_Next+2],ds ; link to shifted buffer - segment
		jmp	short ShiftStart6

; ----------------------------------------------------------------------------
;                  Shift last disk buffer to start of buffer chain
; ----------------------------------------------------------------------------
; INPUT:	DS:SI = last disk buffer
; ----------------------------------------------------------------------------

; ------------- Push registers

ShiftStart:	call	PushAll		; push all registers

; ------------- First disk buffer (-> ES:DI)

		les	di,[cs:FirstDiskBuff] ; ES:DI <- first disk buffer

; ------------- Set shifted buffer DS:SI as first disk buffer

		mov	[cs:FirstDiskBuff],si ; set offset of buffer
		mov	[cs:FirstDiskBuff+2],ds ; set segment of buffer

; ------------- Link first disk buffer to shifted buffer

		mov	[si+BUF_Next],di ; offset of first buffer
		mov	[si+BUF_Next+2],es ; segment of first buffer

; ------------- Push disk buffer address

ShiftStart2:	push	di		; push DI (buffer offset)
		push	es		; push ES (buffer segment)

; ------------- Address of next disk buffer (-> ES:DI)

		les	di,[es:di+BUF_Next] ; ES:DI <- next disk buffer

; ------------- Check if it is shifted buffer

		call	CompAddr	; is it shifted buffer?
		je	ShiftStart4	; it is shifted buffer

; ------------- Destroy disk buffer address in stack

		pop	ax		; destroy ES
		pop	ax		; destroy DI
		jmp	short ShiftStart2 ; next disk buffer

; ------------- Return address of buffer (-> DS:SI)

ShiftStart4:	pop	ds		; pop DS
		pop	si		; pop SI

; ------------- Mark buffer as end of chain

ShiftStart6:	mov	word [si+BUF_Next],-1 ; set end mark to offset

; ------------- Pop registers

ShiftStart8:	call	PopAll		; pop all registers
		ret

; ----------------------------------------------------------------------------
;          Shift disk buffer to end of buffer chain and get next buffer
; ----------------------------------------------------------------------------
; INPUT:	DS:SI = disk buffer
; OUTPUT:	DS:SI = next disk buffer in chain
; ----------------------------------------------------------------------------

ShiftNext:	push	word [si+BUF_Next] ; push offset of next buffer
		push	word [si+BUF_Next+2] ; push segment of next buffer
		call	ShiftEnd	; shift buffer to end of chain
		pop	ds		; pop DS (segment of buffer)
		pop	si		; pop SI (offset of buffer
		ret

; ----------------------------------------------------------------------------
;                            Compare addresses
; ----------------------------------------------------------------------------
; INPUT:	DS:SI = first address
;		ES:DI = second address
; OUTPUT:	ZY = addresses are equal
; ----------------------------------------------------------------------------

; ------------- Compare offsets

CompAddr:	cmp	si,di		; are offsets equal?
		jne	CompAddr2	; offsets are not equal

; ------------- Push registers

		push	ax		; push AX
		push	bx		; push BX

; ------------- Compare segments

		mov	ax,ds		; AX <- DS
		mov	bx,es		; BX <- ES
		cmp	ax,bx		; compare segments

; ------------- Pop registers

		pop	bx		; pop BX
		pop	ax		; pop AX
CompAddr2:	ret

; ----------------------------------------------------------------------------
;                         Flush all disk buffers
; ----------------------------------------------------------------------------
; INPUT:	AL = disk (0ffh = all disks)
; ----------------------------------------------------------------------------

; ------------- Push registers

FlushAll:	push	bx		; push BX
		push	si		; push SI
		push	ds		; push DS

; ------------- First disk buffer (-> DS:SI)

		lds	si,[cs:FirstDiskBuff] ; DS:SI <- first disk buffer

; ------------- Check if this buffer is modified

FlushAll2:	mov	bx,[si+BUF_DiskFlags] ; BL <- disk, BH <- flags
		test	bh,BUFFLAG_MODI	; is this buffer modified?
		jz	FlushAll6	; this buffer is not modified

; ------------- Check if it is correct disk

		cmp	bl,0ffh		; is it valid disk?
		je	FlushAll6	; it is not valid disk
		cmp	al,0ffh		; flush all disks?
		je	FlushAll4	; flush all disks	
		cmp	al,bl		; is it required disk?
		jne	FlushAll6	; it is not required disk

; ------------- Flush buffer

FlushAll4:	call	FlushBuff	; flush buffer

; ------------- Return disk (to reuse buffer)

		cmp	bl,[cs:LastDiskError] ; is it last disk with error?
		je	FlushAll6	; it is last disk with error
		mov	[si+BUF_Disk],bl ; return disk to reuse data

; ------------- Next disk buffer (-> DS:SI)

FlushAll6:	lds	si,[si+BUF_Next] ; DS:SI <- next disk buffer
		cmp	si,byte -1	; is it last disk buffer?
		jne	FlushAll2	; there is no next disk buffer

; ------------- Pop registers

		pop	ds		; pop DS
		pop	si		; pop SI
		pop	bx		; pop BX
		ret

; ----------------------------------------------------------------------------
;                              Flush disk buffer
; ----------------------------------------------------------------------------
; INPUT:	DS:SI = disk buffer
; ----------------------------------------------------------------------------

; ------------- Push registers

FlushBuff:	call	PushAll		; push all registers

; ------------- Check if buffer is used

		mov	ax,[si+BUF_DiskFlags] ; AL <- disk, AH <- flags
		cmp	al,0ffh		; is this buffer used?
		je	FlushBuff8	; this buffer is not used
		mov	byte [si+BUF_Disk],0ffh ; buffer si unused

; ------------- Check if buffer is modified

		test	ah,BUFFLAG_MODI	; is this buffer modified?
		jz	FlushBuff8	; buffer is not modified
		and	byte [si+BUF_Flags],~BUFFLAG_MODI ; clear modified flag

; ------------- Check if it is last disk with error

		cmp	al,[cs:LastDiskError] ; is it last disk with error?
		je	FlushBuff8	; it is last disk with error

; ------------- Prepare parameters

		les	bp,[si+BUF_DDPB] ; ES:BP <- pointer to DDPB
		lea	bx,[si+BUF_Data] ; BX <- data buffer
		mov	dx,[si+BUF_SectorL] ; DX <- sector LOW
		mov	di,[si+BUF_SectorH] ; DI <- sector HIGH
		xor	cx,cx		; CX <- 0
		mov	cl,[si+BUF_Copies] ; CX <- number of copies

; ------------- Write sector

FlushBuff4:	push	cx		; push CX
		mov	cl,1		; write 1 sector
		call	DOS24Write	; write sector to disk with Int 24h
		pop	cx		; pop CX

; ------------- Next sector

		xor	ax,ax		; AX <- 0
		mov	al,[si+BUF_Offset] ; AX <- offset of copies
		add	dx,ax		; shift sector number LOW
		adc	di,byte 0	; shift sector number HIGH
		loop	FlushBuff4	; write next sector

; ------------- Pop registers

FlushBuff8:	call	PopAll		; pop all registers
		ret

; ----------------------------------------------------------------------------
;                           Test one buffer
; ----------------------------------------------------------------------------
; INPUT:	AL = disk number
;		DI:DX = sector number
;		ES:BP = DOS Drive Parameter Block (DDPB)
; 		DS:SI = disk buffer
; OUTPUT:	ZY = disk buffer does correspond
; ----------------------------------------------------------------------------

GetSectorTest:	cmp	al,[si+BUF_Disk] ; does disk number correspond?
		jne	GetSectorTest2	; disk sector does not correspond
		cmp	dx,[si+BUF_SectorL] ; does disk sector LOW correspond?
		jne	GetSectorTest2	; disk sector does not correspond
		cmp	di,[si+BUF_SectorH] ; does disk sector HIGH correspond?
GetSectorTest2:	ret

; ----------------------------------------------------------------------------
;                         Get sector using disk buffer
; ----------------------------------------------------------------------------
; INPUT:	AH = flags
;			bit 0: don't read sector (else don't read, it is created)
;			bit 1: it is FAT sector, use multiple write
;		DI:DX = sector number
;		ES:BP = DOS Drive Parameter Block (DDPB)
; OUTPUT:	DS:SI = disk buffer
; DESTROYS:	AX
; ----------------------------------------------------------------------------

; ------------- Push registers

GetSector:	push	bx		; push BX
		push	cx		; push CX

; ------------- Prepare disk number (-> AL)

		mov	al,[es:bp+DDPB_disk] ; AL <- disk number

; ------------- Check last used disk buffer

		lds	si,[cs:LastBuffer] ; DS:SI <- last used disk buffer
		inc	si		; is it valid buffer?
		jz	GetSector2	; it is not valid buffer
		dec	si		; return offset of disk buffer
		call	GetSectorTest	; test sector
		je	GetSector9	; sector does correspond

; ------------- Find corresponding disk buffer

GetSector2:	lds	si,[cs:FirstDiskBuff] ; DS:SI <- first disk buffer
GetSector3:	call	GetSectorTest	; test sector
		je	GetSector7	; disk buffer does correspond
		lds	si,[si+BUF_Next] ; DS:SI <- next buffer
		cmp	si,byte -1	; is it valid buffer?
		jne	GetSector3	; it is valid buffer

; ------------- Buffer not found, flush first disk buffer (=oldest)

                lds	si,[cs:FirstDiskBuff] ; DS:SI <- first disk buffer
		call	FlushBuff	; flush disk buffer

; ------------- Read sector into disk buffer

		lea	bx,[si+BUF_Data] ; BX <- data buffer
		mov	cx,1		; read 1 sector
		test	ah,B0		; don't read sector?
		jnz	GetSector6	; don't read sector
		test	ah,B1		; is it FAT sector?
		jz	GetSector5	; it is not FAT sector
		call	DOS24ReadFAT	; read FAT into buffer
		jmp	short GetSector6

GetSector5:	call	DOS24Read	; read sector into buffer

; ------------- Store parameters into disk buffer

GetSector6:	mov	[si+BUF_Disk],al ; disk number
		and	byte [si+BUF_Flags],~BUFFLAG_DATA ; unmark buffer
		mov	[si+BUF_SectorH],di ; disk sector HIGH
		mov	[si+BUF_SectorL],dx ; disk sector LOW
		mov	[si+BUF_DDPB],bp ; offset of DDPB
		mov	[si+BUF_DDPB+2],es ; segment of DDPB

; ------------- Set number of copies

GetSector7:	test	ah,B1		; is it FAT sector?
		mov	ax,1		; number of copies for non-FAT
		jz	GetSector8	; it is non-FAT sector
		mov	al,[es:bp+DDPB_fat] ; AL <- number of FATs
		mov	ah,[es:bp+DDPB_fatsec] ; AH <- sector per FAT
GetSector8:	mov	[si+BUF_CopyOffset],ax ; set number of copies + offset

; ------------- Shift buffer to end of buffer chain

		call	ShiftEnd	; shift buffer to end of buffer chain

; ------------- Store last used disk buffer

GetSector9:	mov	[cs:LastBuffer],si ; store offset of last disk buffer
		mov	[cs:LastBuffer+2],ds ; store segment of last disk buffer

; ------------- Pop registers

		pop	cx		; pop CX
		pop	bx		; pop BX
		ret

; ----------------------------------------------------------------------------
;                                    Data
; ----------------------------------------------------------------------------

LastBuffer:	dd	-1		; pointer to last used disk buffer

Zpět na stránku systému LT-DOS