📄 mem.asm
字号:
ret
memory_system_init endp
memory_system_deinit proc
; Return the memory to DOS.
mov es,ds:[si.root]
mov ah,DOSRELEASEBLOCK
int DOSINT
ret
memory_system_deinit endp
memory_system_resetrover proc
mov bx,ds:[si.root]
mov ds:[si.rover],root
ret
memory_system_resetrover endp
.data
mss_initial db "Memory System Show:",CR,LF
db "System at:$"
mss_root db " Root block at:$"
mss_last db " Last block at:$"
mss_rover db " Rover block at:$"
mss_free db " Freespace:$"
mss_used db " Usedspace:$"
mss_blocks db "Blocks at:$"
mss_no_blks db "No blocks in heap.$"
.code
memory_system_show proc uses ax dx es ds
; Move pointer to the memory system from DS:SI, to ES:SI
push ds
pop es
; Now load pointer to our messages
mov dx,@data
mov ds,dx
; Show the location of the memory system
mov dx,offset mss_initial
mov ah,DOSPRINTSTRING
int DOSINT
mov ax,es
call ShowHexWord
mov dl,':'
mov al,DOSPRINTCHAR
int DOSINT
mov ax,si
call ShowHexWord
call CRLF
; Show the internal variables of the memory system
mov dx,offset mss_root
mov ah,DOSPRINTSTRING
int DOSINT
mov ax,es:[si.root]
call ShowHexWord
call CRLF
mov dx,offset mss_last
mov ah,DOSPRINTSTRING
int DOSINT
mov ax,es:[si.last]
call ShowHexWord
call CRLF
mov dx,offset mss_rover
mov ah,DOSPRINTSTRING
int DOSINT
mov ax,es:[si.rover]
call ShowHexWord
call CRLF
mov dx,offset mss_free
mov ah,DOSPRINTSTRING
int DOSINT
mov ax,es:[si.freespace]
call ShowHexWord
call CRLF
mov dx,offset mss_used
mov ah,DOSPRINTSTRING
int DOSINT
mov ax,es:[si.usedspace]
call ShowHexWord
call CRLF
; Save pointer to the memory system
push es
push si
mov ax,es:[si.root]
xor si,si
; Check for empty chain
cmp ax,0
jz mss_no_blocks
push ax
; Now we need to walk the chain
mov dx,offset mss_blocks
mov ah,DOSPRINTSTRING
int DOSINT
pop ax
mss_show_block:
mov ds,ax
call ShowHexWord
LoadVMTSeg ES,AX
call ds:[si] method memory_block:show
call ds:[si] method memory_block:GetNext
; See if it is the last block
IsZero ax
jz mss_show_block_done
push ax
mov ah,DOSPRINTCHAR
mov dl,','
int DOSINT
pop ax
jmp mss_show_block
; Branch here if this heap system is still empty
mss_no_blocks:
mov dx,offset mss_no_blks
mov ah,DOSPRINTSTRING
int DOSINT
mss_show_block_done:
pop si
pop es
call CRLF
ret
memory_system_show endp
memory_system_freeall proc
mov ax,[si.root]
@@free_another:
; If it is the end block, dont try to free it.
cmp ax,ds:[si.last]
jz @@done
push ax
call ds:[si] method memory_system:free
pop ax
push ds
push si
mov ds,ax
xor si,si
call ds:[si] method memory_block:GetNext
IsZero ax
pop si
pop ds
jnz @@free_another
@@done:
ret
memory_system_freeall endp
memory_system_findprev proc uses ds si
; local systemseg:word,systemofs:word,findprevfor:word
; mov [systemseg],ds
; mov [systemofs],si
; mov [findprevfor],ax
; Check if this block is the root block
cmp ax,[si.root]
jz @memory_system_findprev_atroot
; Make pointer to first block in memory system
mov ds,[si.root]
xor si,si
call [si] method memory_block:MatchNext
cmp ax,0
jne @memory_system_findprev_done
; The block wasn't found!
@memory_system_findprev_atroot:
@memory_system_findprev_done:
; mov ds,[systemseg]
; mov si,[systemofs]
ret
memory_system_findprev endp
memory_system_blockofs proc uses ds si
cmp ax,0
jne @memory_system_blockofs_getit
mov ax,ds:[si.root] ; Get the root and use it's offset since
; no segment was passed in
@memory_system_blockofs_getit:
mov ds,ax
xor si,si
call ds:[si] method memory_block:memstart
ret
memory_system_blockofs endp
memory_system_alloc proc uses ds si
local allocsize:word,\
allocblock:word,\
largest:word,\ ; The size of the largest block encountered
largestseg:word,\
newfree:word,\
rootscan:word,\
memsysaddr:dword
mov [largest],0
mov [rootscan],0
mov word ptr [memsysaddr],si
mov word ptr [memsysaddr+2],ds
mov [allocsize],ax
ifdef _USE_ROVER_
mov ax,ds:[si.rover]
else
mov ax,ds:[si.root]
endif
mov ds,ax
@@scan:
xor si,si
call ds:[si] method memory_block:ScanFree
; Check if there is enough room in this free block
cmp ax,[largest]
jbe @@scan_2
mov [largest],ax
mov [largestseg],ds
@@scan_2:
cmp ax,[allocsize]
ja @@found
mov ax,ds
IsZero ax
je @@no_more_blocks
call ds:[si] method memory_block:GetNext
IsZero ax
je @@no_more_blocks
; The following block may also be free. Try to combine them.
; Swap DS and AX
mov bx,ds ; DS has the previous block!
mov ds,ax
mov ax,bx ; Make sure AX has the previous block
call ds:[si] method memory_block:Combine
jmp @@scan
; No more blocks to scan!
@@no_more_blocks:
ifdef _USE_ROVER_
; Scan again from the root, because a big enough
; block could be prior to rover.
cmp [rootscan],0
jne @@scan_root
inc [rootscan]
lds si,dword ptr [memsysaddr]
mov ax,ds:[si.root]
; Check to see that rover wasn't already pointing at the root
cmp ax,ds:[si.rover]
je @@scan_root
mov ds,ax
jmp @@scan
@@scan_root:
endif
; Set rover to point to this new largest memory block,
; because combines might have invalidated the rover pointer.
lds si,dword ptr [memsysaddr]
mov ax,[largestseg]
mov ds:[si.rover],ax
xor ax,ax
mov bx,[largest]
jmp @@done
@@found:
mov [allocblock],ds
; See how much is leftover in the block after the memory needed
; for this alloc call is taken out
mov ax,[allocsize]
call ds:[si] method memory_block:BreakBlock
ifdef _USE_ROVER_
mov [newfree],ax
endif
; Mark the block as used!
call ds:[si] method memory_block:MarkUsed
call ds:[si] method memory_block:LockBlock
call ds:[si] method memory_block:memstart
push bx
; If enough area was leftover, the extra area has been
; broken off to make a separate block.
lds si,dword ptr [memsysaddr]
ifdef _USE_ROVER_
; Update rover
mov ax,[newfree]
mov ds:[si.rover],ax
endif
mov ax,[allocblock]
pop bx
; call ds:[si] method memory_block:memstart
@@done:
ret
memory_system_alloc endp
memory_system_free proc uses ds si bx
local prevblock:word,\ ; Address of the block previous to this one
freeblock:word,\ ; Address of block that is being freed
systemaddr:dword
mov word ptr [systemaddr],si
mov word ptr [systemaddr+2],ds
mov [freeblock],ax
cmp ax,0
jz @@done
; Check the block to make sure that it is not already free
; Note that an invalid block address here will likely hang the
; memory manager, since the VMT will not be valid.
mov ds,ax
xor si,si
ifdef _DO_ISFREE_
call ds:[si] method memory_block:IsFree
jz @@done
endif
call ds:[si] method memory_block:UnLockBlock
lds si,dword ptr [systemaddr]
mov ax,[freeblock]
cmp ax,ds:[si.root]
je @@free_root ; Special routine to free the root block
ifdef _COMBINE_PREVIOUS_
; Prior to freeing the block, get the address of
; the previous block. If no previous block is found,
; then this is a bogus FREE request and will be ignored.
call ds:[si] method memory_system:findprev
IsZero ax ; Check for zero.
jz @@done
; There is a previous block
mov [prevblock],ax
endif
; Mark the current block as free.
mov ds,[freeblock]
xor si,si
call ds:[si] method memory_block:MarkFree
ifdef _COMBINE_PREVIOUS_
mov ds,[prevblock]
xor si,si
call ds:[si] method memory_block:IsFree
mov ds,[freeblock]
jnz @@try_combine_next
else
jmp @@try_combine_next
endif
@@combine_previous:
; The previous block is free, therefore it can be combined with
; this one. Set the previous block to point to our next block.
call ds:[si] method memory_block:GetNext
mov ds,[prevblock]
call ds:[si] method memory_block:SetNext
; Also, need to update size of previous block
; AX still contains seg of block after one being freed.
mov bx,ds
sub ax,bx
dec ax
call ds:[si] method memory_block:SetSize
mov [freeblock],ds
jmp @@try_combine_next
@@free_root:
; At this point we only have to worry is if the block following
; a free block so it can be combined with this one.
; AX is the block to free.
mov ds,ax
xor si,si
xor ax,ax ; Because there is not previous block
call ds:[si] method memory_block:MarkFree
@@try_combine_next:
call ds:[si] method memory_block:GetNext
mov ds,ax
call ds:[si] method memory_block:IsFree
jnz @@No_more_combine
mov ax,[freeblock]
mov [prevblock],ax
jmp @@combine_previous
@@No_more_combine:
ifdef _USE_ROVER_
; Just in case the rover might have pointed to a block that was
; combined with another, set rover to the start of the new
; free block that was created.
lds si,dword ptr [systemaddr]
mov bx,[freeblock]
mov ds:[si.rover],bx
endif
@@done:
ret
memory_system_free endp
.data
LastSeg dw seg zzlastseg
.code
shrink_memory proc
; Have to give up extra memory that we don't need
; so the memory system objects can get blocks of memory.
mov bx,[LastSeg]
mov ax,es
sub bx,ax ; Size of program as a number of segments is in BX
mov ah,DOSRESIZEBLOCK
int DOSINT
ret
shrink_memory endp
zzlastseg segment
zzlastseg ends
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -