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

📄 bambi.asm

📁 Dos6.0
💻 ASM
📖 第 1 页 / 共 5 页
字号:
	not     di      ;2,       2bytes   invert mask so we can get high bits for ax
	and     cx,di   ;2,       2bytes   mask just covers the high bits
	or      ax,cx   ;2        2bytes   or the high bits into ax--ax is done
			;= 21 clocks total (386),19 bytes

	mov     curblk_l,ax             ; store the cache block number of
	mov     curblk_h,dl             ;  the 1st sector in a temp. variable

	pop     ax                      ; get low bits (modulo)
	mov     ah,byte ptr cache_block_sectors
	dec     ah                      ; generate a mask for secs/blk
	and     al,ah                   ; extract the partial block size
	mov     byte ptr curblk_index,al ; save index within cache block

	cmp     es:[bx.reqfunc],devrd   ; reading?
	jnz     do_writes               ; assume all other functions are writes

	call    cache_reads             ; use a subroutine for the read loop
	jmp     short common_exit

do_writes:
	call    cache_write_data        ;  write it, cache if appropriate

common_exit:
go_back_to_dos:

	pop     si
	pop     di
	pop     bx
	pop     es
	pop     cx                      ; restore 1st tier of saved regs
	pop     dx
	pop     bp

	cmp     in_device_call,0
	jne     handle_reentrancy_exit_near

	mov     ss,save_stack_ss        ;restore stack
	mov     sp,save_stack_sp

dont_restore_stack:
	dec     in_bambi                ; free device_driver resource

	dec     in_device_call          ;keep track of reentrancy

	cmp     commit_all_when_ok,0    ;now is a good time to determine if
	jne     must_commit_all         ;some asynch event (ctrl+alt+delete)
					;requires us to commit all 
continue_returntodos:

	pop     ds                      ; restore caller's ds
	assume  ds:nothing

	ret                             ; back to DOS (or last hooker)
must_commit_all:
	call    write_behind_cache
	jmp     short continue_returntodos

handle_reentrancy_exit_near:
	jmp     handle_reentrancy_exit
our_int endp

;-----------------------------------------------------------------------
;
;       This routine is used when a media_change or an IOCTL forces
;       us to invalidate our information about a given drive so that
;       we are forced to re-read it.
;
reset_drive_stuff       proc    near
	assume  cs:zseg,ds:zseg,es:nothing

	mov     num_valid_buffers,0     ; invalidate supercache
	push    ax                      ;flush the cache and invalidate
	push    bx
	push    cx
	push    dx
	push    bp
	push    si
	push    di
	push    es

	call    commit_all_dirty
	call    flush_queue

	pop     es
	pop     di
	pop     si
	pop     bp
	pop     dx
	pop     cx
	pop     bx
	pop     ax

	ret

reset_drive_stuff       endp

;-----------------------------------------------------------------------
;
;       Come here when we have a read operation on a cached drive.
;       The block number and index within the first block have already
;       been setup by the common entry code.
;
;       The basic idea is that we break the read down into:
;
;          First partial (non-cache-block aligned sectors on front)
;          Full cache blocks
;          Last partial (cache-block aligned, but we don't need it all)

xno_partial_on_front: jmp no_partial_on_front   ; make short branch reach

cache_reads     proc    near
	assume  cs:zseg,ds:zseg,es:nothing

	cmp     byte ptr curblk_index,0 ; partial block at the front?
	jz      xno_partial_on_front    ;  skip if not

	call    check_supercache_match  ; if we're lucky, the data we want
					;  is already in our RAM buffer and
					;  we won't even have to hit XMS

	jnc     no_supercache_in_partial ; Skip if we weren't lucky

;       the block we need part of is already in the cache, copy to
;         user's buffer.  Note:  si has already been setup (pointing
;         to the target block in the supercache) and must not be trashed.

	call    first_partial_setup     ; get sector count, set es:di for move
	push    ax                      ; save # sectors
	mov     ax,curblk_index         ; get offset within block
	mul     sector_size_bytes
	add     si,ax                   ; point to correct source in supercache
	pop     ax
	mul     sector_size_bytes
	mov     cx,ax
	shr     cx,1                    ; convert to words

	mov     ds,lb_seg
	assume  ds:nothing

;       ds:si -> desired sector in supercache (our local RAM buffer)
;       es:di -> user's transfer address
;       cx    =  length of this transfer in words
;       ax    =  length of this transfer in bytes

	rep     movsw                   ; move to user's buffer
	push    cs
	pop     ds
	assume  ds:zseg                 ; restore addressability

	jmp     short next_read_block   ; update transfer, curblk, and continue

;       We're still trying to satisfy our first partial, but it wasn't
;       in the supercache.  Our next best bet is our REAL cache.

no_supercache_in_partial:

	call    check_hit               ; see if we hit on curblk
	jnz     partial_was_a_hit       ;  skip if that block is present

;       the block we need isn't in cache!  We've got to hit the disk,
;         and while we're at it, we'll stick it into the cache for
;         future use.

	mov     cx,1                    ; just get one block
	call    get_curblks_into_cache  ; get the curblk into local buf
;                                       ;  and cache it!
	jnc     frst_prt_rdok           ; done if no disk read error

;       we couldn't read the whole block.  Now we'd better try to
;         read just the part the user wanted directly into his buffer
;         before we decide to bomb out and report an error.

	call    first_partial_setup     ; get es:di -> dma addr, ax=count

	push    ax                      ; save count
	mov     ah,al                   ; get count into ah
	mov     al,byte ptr curblk_index ; get sector within block
	call    read_part_curblk_from_disk
	pop     dx                      ; restore count into dx to preserve
					; error code in ax

	jc      xgot_fatal_error        ; bomb out if fatal disk error

;       lucky us!  the read error was in another part of the
;       block, or, the retry was sufficient to get the data.

	mov     ax,dx                   ; get count just xferred
	mul     sector_size_bytes       ; get amount to bump xfer addr by
	jmp     short next_read_block

xgot_fatal_pop2:                        ; BUG1 - adjust stack & exit if error
	add     sp,4                    ; BUG1 - pop 2 entries off stack
xgot_fatal_error:       jmp     got_fatal_error ; make short branch reach

;       We've got the first partial read and cached.  Now pass it
;       back to the caller.

frst_prt_rdok:

	call    first_partial_setup     ; setup for partial block

	mul     sector_size_bytes       ; get byte count for transfer
	mov     cx,ax
	shr     cx,1                    ; convert to words

	push    ax                      ; preserve the byte count in ax
	mov     ax,curblk_index         ; get starting index
	mul     sector_size_bytes
	lds     si,local_buf
	assume  ds:nothing
	add     si,ax
	rep     movsw                   ; move the sectors
	pop     ax

	push    cs
	pop     ds
	assume  ds:zseg                 ; restore addressability

	jmp     short next_read_block

x_do_last_partial:      jmp     do_last_partial ; bridge for short jumps

;       the block we need part of is already in the cache, copy to
;         user's buffer.

partial_was_a_hit:
	call    first_partial_setup

	push    ax                      ; save # sectors
	mov     ah,byte ptr curblk_index ; get al blocks, starting here

	ifdef   USE_VALID
	push    ax
	call    make_sure_sectors_are_valid     ; if valid_bits not set,
;                                               ;  this routine will read the
;                                               ;  whole block and make sure
;                                               ;  it's all valid.
	jc      xgot_fatal_pop2                 ; BUG1 exit if error reading
	pop     ax

	endif

	mov     bp,cache_element_index
	les     di,d_trans
	call    read_part_cache_block   ; read from cache into user buffer
	pop     ax                      ; restore sector count
	mul     sector_size_bytes

;//////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////////////

;       This is the main READ loop.  We come back here after successfully
;       completing the first partial or any full blocks.  AX has the number
;       of bytes just transferred, and will be added to the transfer address.
;       curblk is also incremented.

next_read_block:
	add     word ptr d_trans,ax     ; update transfer address
	add     curblk_l,1              ; move to next block
	adc     curblk_h,0

;       Now we're block aligned.  Complete any remaining full blocks first.

no_partial_on_front:
	mov     ax,cache_block_sectors
	cmp     ax,d_count              ; do we need a full block?
	ja      x_do_last_partial

	sub     d_count,ax              ; count it down

	call    check_supercache_match  ; did we match in supercache?
	jnc     no_full_block_supercache_hit

;       copy the block from supercache

	les     di,d_trans              ; get user buffer
	mov     cx,cache_block_words    ; move one full cache block
	mov     ds,lb_seg               ; si set by check_supercache_match
	assume  ds:nothing
	rep     movsw                   ; move from supercache
	push    cs
	pop     ds
	assume  ds:zseg                 ; restore addressability

	mov     ax,cache_block_bytes    ; size for updating pointer
	jmp     short next_read_block

no_full_block_supercache_hit:

;       No supercache match on full cache block.  Our next best bet
;       is the REAL cache.

	call    check_hit               ; is curblk in cache?
	jz      full_nohit              ; brif not

	ifdef   USE_VALID
	mov     ax,cache_mask           ; make sure it is valid
	call    make_sure_sectors_are_valid_mask
	jc      zgot_fatal_error        ; BUG1 -- exit if read error!
	endif

	les     di,d_trans              ; get user buffer
	mov     bp,cache_element_index
	call    read_full_cache_block   ;  read the whole cached block
	mov     ax,cache_block_bytes    ; size for updating pointer
	jmp     next_read_block

zgot_fatal_error:                       ; BUG1 -- error exit bridge
	jmp     got_fatal_error         ; BUG1

;       block not in cache.  Figure out how many contiguous nohits
;         there are in the data we need, and read them all, then
;         transfer them all into the cache at once.

full_nohit:
	mov     ax,curblk_l
	mov     dl,curblk_h             ; get last block number

	xor     cx,cx                   ; init block needed count
	mov     bx,d_count              ; we need this many more sectors

count_nohit_loop:
	inc     cx                      ; count blocks needed
	sub     bx,cache_block_sectors  ;  do we need another full block?
	jb      we_know_how_many_nohits

	add     ax,1                    ; point to next block
	adc     dl,0

	push    ax
	push    bx
	push    cx
	push    dx
	call    check_hit_in_regs       ; do we need to read next block?
	pop     dx
	pop     cx
	pop     bx
	pop     ax
	jz      count_nohit_loop        ; just keep looping while no hits


we_know_how_many_nohits:

;       now cx tells us how many blocks we need to read from disk
;           bx is the number of remaining sectors after the contig nohits

;       Okay, then.  Let's jam directly on the user's buffer.

cant_fit_more_in_localbuf:
	les     di,d_trans              ; get user buffer
	push    cx                      ; save number of blks for caching loop
	mov     ax,cx                   ; get count of blocks
	call    read_curblks_from_disk  ; read that sucker
	pop     cx
	jc      got_fatal_error         ; error out!  We NEED those blocks
;                                       ;  to succeed this call!

;       adjust d_count to reflect multiple blocks transferred

	mov     ax,cx                   ; we know this is at least one
	dec     ax
	mul     cache_block_sectors
	sub     d_count,ax

;       Now we've got to copy all of that shit into the cache

	les     di,d_trans              ; point to buffer

	push    es                              ;check if this is a 
	les     si,accessing_swap_file_ptr      ;swapfile access, if so
	cmp     byte ptr es:[si],0              ;dont cache it
	pop     es
	jne     skip_cache_em

cache_em:
	push    cx
	push    di
	xor     cx,cx                   ; none of it is dirty!!!
	ifdef   USE_VALID
	mov     bx,cache_mask           ; all valid
	endif
	call    create_cache_block      ; **** create the block^
	pop     di
	push    di
	call    write_full_cache_block
	add     curblk_l,1
	adc     curblk_h,0
	pop     di
	pop     cx
	add     di,cache_block_bytes
	loop    cache_em

done_cache_em:
	mov     word ptr d_trans,di     ; update d_trans

;       **** Note:  We're branching all of the way back here so
;            we can test for the case where we've done with all
;            of the full blocks.  A potential speed optimization
;            would be to duplicate the test here, and not bother
;            looking up the next block if there is another one.
;            In that case, we already know it is a hit.  The
;            block number would have to be saved above in this

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -