📄 memory.asm
字号:
; |prevfree| |CurFreeBlk| |FollowingBlk| |NextFreeBlk|
;
; We want to wind up with:
;
;
; +------------------------------------------+ <-These are dbl links.
; | |
; |prevfree| |CurFreeBlk| |FollowingBlk| |NextFreeBlk|
;
;
; First, merge the current free block and the following block together.
;
mov ax, dsptr.blksize ;Get size of next block.
add esptr.blksize, ax ; Join the blocks together.
mov ax, dsptr.fwdptr
mov esptr.fwdptr, ax
or ax, ax
jz DontSetBwd
push ds
mov ds, ax
mov dsptr.bwdptr, es
pop ds
;
; Make sure that there is a |prevfree| block.
;
DontSetBwd: mov ax, dsptr.freebwdptr
or ax, ax
jz SetFreeSpcPtr
;
; prevfree.fwd := following.fwd;
;
mov es, dsptr.freebwdptr ;Point ES at previous guy.
mov ax, dsptr.freefwdptr
mov esptr.freefwdptr, ax ;Skip over current guy.
;
; If the fwd pointer is NIL, no need to continue.
;
or ax, ax ;See if end of list.
jz NextBlkNotFree
;
; nextfree.bwd := following.bwd (prevfree).
;
mov ax, es ;Save ptr to this guy.
mov es, dsptr.freefwdptr
mov esptr.freebwdptr, ax
jmp short NextBlkNotFree
;
; If FollowingBlk is the first free block in the free list, we have to
; execute the following code.
;
SetFreeSpcPtr: mov es, dsptr.freefwdptr
mov esptr.freebwdptr, NIL
mov StdGrp:FreeSpace, es
;
;
;
; After processing the block following this block, or if the next block
; was not free, come down here and check to see if the previous block
; was free.
;
NextBlkNotFree: pop es ;Restore pointer to current block.
push es
mov ax, esptr.bwdptr
or ax, ax ;Is it a NIL pointer
jz NoPrevBlock
mov ds, ax
cmp dsptr.refcnt, 0 ;Is that block free?
jnz NoPrevBlock
;
; Okay, the block in front is free. Merge the current block into that one.
;
mov ax, esptr.blksize
add dsptr.blksize, ax
mov ax, esptr.fwdptr
mov dsptr.fwdptr, ax
or ax, ax ;See if there is a next blk.
jz NoNextBlk
mov es, ax
mov esptr.bwdptr, ds
NoNextBlk: stc
pop es
pop ds
ret
;
NoPrevBlock: clc
pop es
pop ds
ret
Coalesce endp
;
;
;============================================================================
;
; ***** ******* * * * ***** *****
; * * * * * * * * * * *
; * * * * * * * * * *
; ***** ***** ***** * * * * *
; * * * * * * * * * *
; * * * * * * * * * * *
; * * ******* * * ***** ***** ***** *****
;
;============================================================================
;
;
; REALLOC - This routine expects a pointer in ES:DI and a new size in CX.
; If the specified block is larger than the value in CX then
; realloc shrinks the size of the block and returns the left over
; information to the system heap. If CX is larger than the speci-
; fied block then realloc allocates a new block and copies the
; data from the old block to the new block and then frees the
; old block. In any case, realloc returns a pointer to the
; (possibly new) block in ES:DI. Carry=0 on return if no error,
; carry=1 on return if there wasn't enough room on the heap to
; reallocate a larger block.
;
public sl_realloc
sl_realloc proc far
cmp di, 8 ;Is this a realistic pointer?
jz DoREALLOC
stc ;Return with error, if not.
ret
;
DoREALLOC: push ax
push cx
push ds
push si
;
;
; Convert byte count to paragraph count, since we always allocate whole
; paragraphs.
;
add cx, 8 ;We have eight bytes of overhead!
rcr cx, 1 ;Use rcr because of add above.
adc cx, 0
shr cx, 1
adc cx, 0
shr cx, 1
adc cx, 0
shr cx, 1
adc cx, 0
;
; See if the new block size is larger or smaller than the old block size.
;
cmp cx, esptr.BlkSize
ja MakeBigger
;
; New desired size is less than or equal to the current size. If no more
; than 32 bytes larger, don't even bother with the operation.
;
inc cx
inc cx
cmp cx, esptr.BlkSize
jae ReallocDone
dec cx
dec cx
;
; Okay, the new block size is seriously smaller here. Turn the last group
; of bytes into a free block.
;
mov ax, es ;Get ptr to block
add ax, cx ;Add in new length
mov ds, ax ;Point at new block.
mov ax, esptr.BlkSize ;Compute the size of the
sub ax, cx ; new block.
mov dsptr.BlkSize, ax ;Save away the link.
mov dsptr.bwdptr, es ;Set up back pointer.
mov ax, esptr.fwdptr ;Copy old fwd ptr to new
mov dsptr.fwdptr, ax ; fwd ptr.
mov dsptr.refcnt, 1 ;Init reference count to 1.
mov esptr.fwdptr, ds ;Set up new fwd ptr.
mov esptr.BlkSize, cx ;Set up new length.
push es
mov di, 8
mov ax, ds
mov es, ax
call sl_free ;Free the new block.
mov di, 8
pop es ;Get pointer to original blk
;
ReAllocDone: pop si
pop ds
pop cx
pop ax
clc
ret
;
;
;
; If they had the nerve to want this block larger, come down here and allocate
; a new block, copy the old data to the new block, and then free the old block.
;
;
MakeBigger: mov ax, es ;Preserve pointer to old blk.
mov ds, ax
mov si, di ;Contains "8".
call sl_malloc ;Allocate new block.
jc BadRealloc
;
; Okay, copy the old block to the new block. Note that both SI and DI
; contain 8 at this point. We can make this assumption here because,
; after all, this is the memory manager code and it knows the internal
; representation.
;
mov cx, dsptr.BlkSize ;Get original block size
shl cx, 1 ;Convert from paragraphs
shl cx, 1 ; to word count.
shl cx, 1
pushf
cld
rep movsw ;Note we're moving words!
popf
;
; Okay, free up the old block and we're done.
;
mov di, 8
push es ;Save ptr to new block.
mov ax, ds
mov es, ax
call sl_free
clc
mov di, 8 ;Restore new block ptr.
pop es
pop si
pop ds
pop cx
pop ax
ret
;
BadRealloc: stc
pop si
pop ds
pop cx
pop ax
ret
sl_realloc endp
;
;
;
;
;============================================================================
;
; ******** * * ******** ******** ******* *******
; * * * * * * * * * * *
; * * * * * * * * * * *
; * * * * ******** ******** * *******
; * * * * * * * * *
; * * * * * * * * *
; * * * * * * * * *
; ******** ******** * * * * *
;
;============================================================================
;
;
; Dupptr - Bumps up the reference count for a particular pointer by one.
; Returns carry = 1 if initial pointer is illegal, returns carry=0
; if no error. Returns pointer in ES:DI. You must pass the pointer
; to increment in ES:DI.
;
public sl_DupPtr
sl_DupPtr proc far
cmp di, 8 ;See if this is a valid ptr.
je GoodPtr
stc
ret
;
GoodPtr: inc esptr.refcnt ;Bump up the reference cnt.
clc
ret
sl_DupPtr endp
;
;
;============================================================================
;
; ***** ***** ***** * * * * ***** * *****
; * * * ** * * * * * * *
; * *** * * * * ***** *** ***** * *
; * * * * ** * * * * * *****
; * * * * * * * * * * *
; ***** ***** ***** * * * * ***** * * *
;
;============================================================================
;
; IsInHeap- Returns carry clear if the pointer passed in es:di is within
; the heap. Returns carry set if this pointer is outside the
; heap.
;
public sl_IsInHeap
sl_IsInHeap proc far
push ax
push bx
mov bx, es
mov ax, StdGrp:StartOfHeap
cmp bx, ax
jb Outside
add ax, StdGrp:SizeOfHeap
mov bx, es
cmp bx, ax
ja Outside
clc
pop bx
pop ax
ret
;
Outside: stc
pop bx
pop ax
ret
sl_IsInHeap endp
;
;
;
;
;============================================================================
;
; ***** ***** ***** ***** *****
; * * * * * * *
; * *** ***** * *****
; * * * * * *
; * * * * * *
; ***** ***** * * * *
;
;============================================================================
;
; IsPtr- Returns the carry flag clear if es:di points at the beginning
; of an allocated block in the heap. Returns with the carry
; flag clear if es:di points at a deallocated block.
;
public sl_IsPtr
sl_IsPtr proc far
cmp di, 8 ;All of our ptrs have an offset of 8.
jne NotPtr2
push ax
push bx
push es
mov ax, es
;
mov bx, StdGrp:StartOfHeap
CmpLoop: cmp bx, ax
je MightBe
ja NotPtr
mov es, bx
mov bx, esptr.fwdptr
or bx, bx ;See if NIL link.
jnz CmpLoop
;
NotPtr: pop es
pop bx
pop ax
NotPtr2: stc
ret
;
; Might be the pointer, let's see if this guy's allocation count is greater
; than zero.
;
MightBe: mov es, bx
cmp esptr.blksize, 0
je NotPtr
clc
pop es
pop bx
pop ax
ret
sl_IsPtr endp
;============================================================================
;
; * * ***** * **** **** ***** * **** *****
; * * * * * * * * * * * * * *
; * * * * * * * * * * * * * *
; ***** **** ***** **** *** * ***** **** *
; * * * * * * * * * * * * *
; * * * * * * * * * * * * *
; * * ***** * * * **** * * * * * *
;
;============================================================================
;
; sl_HeapStart- Returns a pointer to the start of the heap. Useful for various
; operations involving DOS memory management functions (like
; deallocating the heap).
public sl_HeapStart
sl_HeapStart proc far
push es
mov ax, StdGrp
mov es, ax
mov ax, StdGrp:StartOfHeap
pop es
ret
sl_HeapStart endp
;
;
;
;============================================================================
;
; sl_BlockSize- Returns the size of the block pointed at by ES:DI. If
; ES:DI is not in the heap, then it returns zero. Returns
; the size, in bytes, in the CX register.
public sl_BlockSize
sl_BlockSize proc far
assume es:nothing, ds:nothing
cmp di, 8 ;All ptrs have 8 as offset
jne BadBlkSize
mov cx, es
cmp cx, STDGRP:StartOfHeap
jb BadBlkSize
cmp cx, STDGRP:EndOfHeap
jae BadBlkSize
mov cx, esptr.BlkSize ;Get size of this block.
ret
BadBlkSize: xor cx, cx
ret
sl_BlockSize endp
;============================================================================
;
; sl_MemAvail- Returns the size of the largest free block available in
; the heap.
;
; On Entry- Nothing
; On Exit- CX contains the size of the largest free block (in paras).
public sl_MemAvail
sl_MemAvail proc far
assume ds:nothing, es:nothing
push es
push ax
xor cx, cx ;Assume no free space.
mov ax, StdGrp:FreeSpace
or ax, ax
je MADone
FreeSpaceLp: mov ax, esptr.blksize
cmp ax, cx
jb NextFree
mov cx, ax
NextFree: mov es, esptr.FreeFwdPtr
mov ax, es
or ax, ax ;Quit when Fwd ptr is NIL.
jnz FreeSpaceLp
MADone: pop ax
pop es
ret
sl_MemAvail endp
;============================================================================
;
; sl_MemFree- Returns the size of all the free blocks in the heap.
;
; On Entry- Nothing
; On Exit- CX contains the size of the free blocks (in paras).
public sl_MemFree
sl_MemFree proc far
assume ds:nothing, es:nothing
push es
push ax
xor cx, cx ;Assume no free space.
mov ax, StdGrp:FreeSpace
or ax, ax
je MFDone
FreeLp: add cx, esptr.blksize
mov ax, esptr.FreeFwdPtr
mov es, ax
or ax, ax
jnz FreeLp
MFDone: pop ax
pop es
ret
sl_MemFree endp
stdlib ends
;
;
zzzzzzseg segment para public 'zzzzzz'
LastBytes db 16 dup (?)
zzzzzzseg ends
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -