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

📄 gcompact.asm

📁 dos 1.0 其中包含quick basic源代码、内存管理himem emm386 发展历史
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;	destination = b
;
; Free and busy block NOT adjacent
;     0000:0	|	    |		    |		|
;		|-----------|		    |-----------|
;		|   busy    |		    |	free	|
;		|-----------|		    |-----------|
;		|	    |		    |		|
;		|-----------|	     a ->   |-----------|
;		|   free    |		    |	free  ? |
;		|	    |	     b ->   |-----------|
;		|	    |		    | ? busy  ? |
;		|-----------|	     c ->   |-----------|
;     FFFF:0	|	    |		    | ? 	|
;
;
;	a = free
;	b = free.ga_next - busy.ga_size - 1
;	c = free.ga_next
;	destination = b
;
gslideup:
	mov	ax,es:[di].ga_next
	push	ax			; Save c
	sub	ax,dx
	push	ax			; Save b
	cmp	es:[bx],si		; Are blocks adjacent?
	je	gslideup1
	push	es			; No, a = free
	jmp	short gslideup2
gslideup1:
	push	si			; Yes, a = busy
gslideup2:
	mov	es,ax			; Destination is b
	xor	ax,ax			; a.ga_prev will remain valid
	jmp	short gslidemove

; Here to slide moveable block down to low end of free block.
;
; Free and busy block adjacent
;     0000:0	|	    |		    |		|
;		|-----------|	     a ->   |-----------|
;		|   free    |		    | ? busy  ? |
;		|	    |	     b ->   |-----------|
;		|-----------|		    | ? free  ? |
;		|   busy    |		    |		|
;		|-----------|	     c ->   |-----------|
;     FFFF:0	|	    |		    | ? 	|
;
;	a = free
;	b = free + busy.ga_size + 1
;	c = busy.ga_next
;	destination = free
;
; Free and busy block NOT adjacent
;     0000:0	|	    |		    |		|
;		|-----------|	     a ->   |-----------|
;		|   free    |		    | ? busy  ? |
;		|	    |	     b ->   |-----------|
;		|	    |		    | ? free  ? |
;		|-----------|	     c ->   |-----------|
;		|	    |		    | ? 	|
;		|-----------|		    |-----------|
;		|   busy    |		    |	free	|
;		|-----------|		    |-----------|
;     FFFF:0	|	    |		    |		|
;
;
;	a = free
;	b = free + busy.ga_size + 1
;	c = free.ga_next
;	destination = free
;

gslidedown:
	cmp	es:[bx],si		; Are blocks adjacent?
	je	gslidedn1
	push	es:[di].ga_next 	; No, c = free.ga_next
	jmp	short gslidedn2
gslidedn1:
	add	ax,dx			; Yes, c = busy.ga_next
	push	ax
gslidedn2:
	mov	ax,es
	add	ax,dx
	push	ax			; Save b
	push	es			; Save a
	mov	ax,es:[di].ga_prev	; a.ga_prev must be restored after move
gslidemove:
	call	gmove
	mov	si,es			; Save new busy block location
	pop	es			; ES = a
	or	ax,ax			; Does a.prev need to be restored?
	jz	gslide1 		; No, continue
	mov	es:[di].ga_prev,ax	; Yes, do it
gslide1:
	pop	ax
	mov	es:[di].ga_next,ax	; a.ga_next = b
	mov	dx,es
	mov	es,ax
	mov	es:[di].ga_prev,dx	; b.ga_prev = a
	pop	ax
	mov	es:[di].ga_next,ax	; b.ga_next = c
	mov	dx,es
	mov	es,ax
	mov	es:[di].ga_prev,dx	; c.ga_prev = b
	mov	es,si			; ES = new busy block
	mov	si,es:[di].ga_handle	; SI = handle
	or	si,si
	jz	gslide2
	mov	ax,es
	inc	ax
	mov	ds:[si].he_address,ax	; Update client address
gslide2:
	mov	es,es:[bx]		; Move to new free block
	mov	ax,es:[di].ga_next	; Set size and signature
	mov	si,es			; byte fields of new free block
	sub	ax,si
	dec	ax
	mov	es:[di].ga_size,ax
	mov	es:[di].ga_sig,GA_SIGNATURE
	mov	es:[di].ga_flags,0
	mov	es:[di].ga_handle,di
	call	gmarkfree		; Coelesce new free block
	or	ax,ax
	ret


; Subroutine to search for the largest moveable block that
; will fit in the passed free block.
;
;   Inputs:	ES:DI = free block
;		DS:DI = address of global heap information
;		CX = #arena entries left to examine
;		BX = ga_next or ga_prev
;
;   Outputs:	Z flag set if block found and moved into passed free
;		block with no extra room.
;		ES:DI = busy block before/after new busy block.
;
;		Z flag clear if ES:DI points to a free block, either the
;		original one or what is left over after moving a block
;		into it.
;
;   Destroys:	DX,SI
;

gbestfit:
	push	es
	push	cx
	xor	si,si		    ; Have not found anything yet
	mov	dx,ES:[di].ga_size  ; Compute max size to look for
gbfloop:
	cmp	ES:[di].ga_owner,di ; Is this block busy?
	je	gbfnext 	    ; No, continue
	push	si
	call	gmoveable	    ; Yes, is it moveable
	pop	si
	jz	gbfnext 	    ; No, continue
	cmp	ES:[di].ga_size,dx  ; Yes, is block bigger than max size?
	ja	gbfnext 	    ; Yes, continue
	or	si,si		    ; First block we have found?
	jz	gbf1st		    ; Yes, special case
	push	es
	mov	es,si
	mov	ax,ES:[di].ga_size  ; No, get size of largest block so far
	pop	es		    ; Compare with this block
	cmp	ES:[di].ga_size,ax  ; Is it bigger than the largest so far?
	jbe	gbfnext 	    ; No, continue
gbf1st:
	mov	si,es		    ; Yes, remember biggest block
	mov	ax,ES:[di].ga_size  ; ...and size
gbfnext:
	mov	es,ES:[bx]	    ; Skip past this block
	loop	gbfloop
	pop	cx		    ; All done looking
	pop	es
	or	si,si		    ; Did we find a block?
	jz	gbestfit1	    ; No, return with Z flag
	call	gmovebusy	    ; Yes, move it into free block
gbestfit1:
	ret

; Subroutine to move a busy block to a free block of the same size,
; preserving the appropriate arena header fields, freeing the old
; busy block and updating the handle table entry to point to the
; new location of the block
;
;   Inputs:	SI = old busy block location
;		ES:DI = new busy block location
;		DS:DI = address of global heap information
;
;   Outputs:	ES:DI = points to new busy block arena header
;
;   Destroys:	AX,SI
;

gmovebusy:
	push	cx
	push	dx
	mov	ax,es
	mov	cx,es:[di].ga_size  ; CX = size of destination
	cmp	es:[di].ga_owner,di ; Is destination busy?
	mov	es,si
	mov	dx,es:[di].ga_size  ; DX = size of source
	jne	gmbexactfit	    ; Yes, then dont create extra block
	cmp	cx,dx		    ; No, are source and destination same size?
	je	gmbexactfit	    ; Yes, then dont create extra block

	mov	es,ax		    ; ES = destination
	mov	ax,si		    ; AX = source
	push	si		    ; Save busy block address
	call	gslidecommon	    ; Call common code to do the move
	inc	[di].hi_count	    ; Just created a new arena entry
	mov	ax,es		    ; Save new free block address
	pop	es		    ; Get old busy block address
	call	gmarkfree	    ; Mark as free and coalesce
	mov	es,ax		    ; Restore new free block address
	or	ax,ax		    ; Return with Z flag clear.
	jmp	gmbexit

gmbexactfit:
	inc	si			; SI = old client data address
	mov	cl,ES:[di].ga_flags
	push	ES:[di].ga_owner
	mov	es,ax
	pop	ES:[di].ga_owner	; Copy client words to new header
	mov	ES:[di].ga_flags,cl
	inc	ax
	mov	es,ax			; ES = new client data address
	call	gmove			; Move the client data
	dec	si
	mov	es,si			; ES:DI = old arena header
	call	gmarkfree		; Free old block
	dec	ax
	mov	es,ax			; ES:DI = new arena header
	inc	ax
	or	si,si
	jz	gmb1
	mov	[si].he_address,ax	; Set new client data address
	mov	ES:[di].ga_handle,si	; Set back link to handle in new block
	xor	si,si			; Set Z flag
gmb1:
gmbexit:
	pop	dx
	pop	cx
	ret

; Subroutine to walk segment list, discarding objects until the #paras
; discarded, plus the biggest free block is greater than the #paras
; we are looking for.
;
;   Inputs:	ES:DI = largest free block
;		AX = size of largest free block
;		DX = minimum #paras needed
;		DS:DI = address of global heap information
;
;   Outputs:	Z flag clear if one or more objects discarded.
;
;		Z flag set if no objects discarded.
;
;   Destroys:	BX,CX,SI
;

gdiscard:
	push	es
	push	ax
	push	dx

	mov	[di].hi_ncompact,0	; Clear compaction flag
	sub	dx,ax			; How much to discard before
	mov	[di].hi_distotal,dx	; compacting again.
	mov	es,ds:[di].hi_last
	mov	cx,es			; Assume no discard fence
	cmp	ds:[di].gi_reserve,di	; True if no reserve area
	je	gdstart
	test	byte ptr ds:[di].gi_cmpflags,GA_DISCCODE    ; or code request
	jnz	gdstart
gdloop0:
	mov	es,es:[di].ga_prev
	cmp	es:[di].ga_owner,di
	je	gdfence
	test	es:[di].ga_flags,GA_DISCCODE
	jnz	gdloop0
gdfence:
	sub	cx,ds:[di].gi_reserve	; Compute beginning of reserve area
	cmp	cx,es:[di].ga_next	; Does all disc. code lie within it?
	jbe	gdstart 		; Yes, set discard fence
	mov	cx,ds:[di].hi_last	; No, then no discard fence
gdstart:
	mov	ds:[di].gi_disfence,cx	; Set the discard fence
gdloop:
	call	ggetlru 		;* get least recently used code handle
	jz	gdexit			; No, more see if we discarded anything
					;* ignore items below swap fence

IFDEF DEBUG
	cmp	[si].he_count,0 	; Is this handle locked?
	je	gd_not_locked
	cCall	CowAssertFailed 	;* we do not support code locking
gd_not_locked:
ENDIF ;DEBUG
	mov	bx,[si].he_address
	dec	bx
	mov	es,bx			;* es:0 => arena
	mov	bx,si			; BX = handle
	mov	al,GN_DISCARD		; AX = GN_DISCARD
	mov	dx,es:[di].ga_owner	;* set up owner for gnotify
	push	dx			;* save owner
	push	[si].he_address 	;* save original address
	call	gnotify

	pop	ax			;* original address
	dec	ax
	mov	es,ax			; ES:DI = address of block to free
	mov	dx,es:[di].ga_size	; Save size !!!
	call	gmarkfree		; Free the block associated with this handle
					;* DX not trashed !!
	pop	[si].he_address 	; Remember owner in handle table entry
	or	[si].he_flags,HE_DISCARDED  ; ...and mark discarded
	mov	[di].hi_ncompact,1	; Remember we discarded something
	sub	[di].hi_distotal,dx	; Have we discarded enough yet?
	ja	gdloop			; No, look at next handle
gdexit:
	cmp	[di].hi_ncompact,0	; Return with Z flag set or clear
	pop	dx
	pop	ax
	pop	es
	ret


;********** ggetlru **********
;*	entry : DI = 0
;*	* scan LRU table, return handle to code segment to discard
;*	* Note : this is a simple scan to find the maximum segref
;*	*  (later on make more efficient depending on code requirements needed).
;*	* NOTE : ignores items that are above swap fence
;*		(swap fence (gi_disfence) should not be set for GA_DISCCODE
;*		   allocations).
;*	exit : Z => no more left
;*		else SI = handle

ggetlru:
	push	bp
	mov	bp,ds:[di].gi_disfence		;* swap fence limit

	mov	es,psLom
	mov	cx,es:[neLom.ne_cseg]
	dec	cx				;* count of code segments
	mov	si,es:[neLom.ne_psegrefbytes]
	mov	di,es:[neLom.ne_segtab] 	;* point to segtab
;*	* note : DI != 0
	xor	dx,dx				;* null return (handle)
	xor	ah,ah				;* see if you can beat or match 0

gget_loop:
	lods	byte ptr es:[si]		;* al = segref
	cmp	al,ah
	jl	gget_next			;* too small
;*	* test to see if below swap fence
	mov	bx,es:[di].ns_handle		;* get handle
	cmp	[bx].he_address,bp		;* above swap fence ?
	jae	gget_next			;* above => don't discard.
;*	* the new maximum (so far)
	mov	dx,bx				;* new handle
	mov	ah,al				;* new maximum segref
gget_next:
	add	di,SIZE NEW_SEG1
	loop	gget_loop
;*	* dx = handle of discardable segment with largest seg-ref (lru)
	mov	si,dx
	xor	di,di				;* restore DI
	or	si,si				;* z=> none found
	pop	bp
	ret

SUBRS	ENDP


;*****************************************************************************


sEnd	KERNEL

	END

⌨️ 快捷键说明

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