📄 mem.asm
字号:
mb_scan proc
; LoadVMTSeg es,bx
@@check:
call ds:[si] method memory_block:IsFree
; cmp word ptr ds:[si.next],FREE_BLOCK ; See if this block is free
jz @@found
; It's not free. So go to the next block.
call ds:[si] method memory_block:GetNext
IsZero ax ; Check for the last block in the chain (next=0?)
jz @@done
mov ds,ax
jmp @@check
@@found:
; Load the size of the current block into AX
; Size in paragraphs is (seg of next block) - (seg of this block)
mov ax,ds
neg ax
add ax,word ptr ds:[si.next2]
dec ax ; Adjust for block bookkeeping information
; mov ax,ds:[si.blksize] ; This should produce the same
; value for free blocks.
@@done:
ret
mb_scan endp
mb_rawblocksize proc
; LoadVMTSeg es,bx
call ds:[si] method memory_block:GetNext
mov bx,ds
sub ax,bx
ret
mb_rawblocksize endp
mb_breakblock proc uses ds si
local desiredsize:word,currentnext:word,newnext:word,currblock:word,\
newblocksize:word
mov [desiredsize],ax
mov ax,ds
mov [currblock],ax
mov [newnext],ax ; We'll use newnext as the address to return in
; AX.
; This routine is only valid for free memory blocks
; LoadVMTSeg es,bx
ifdef _DO_ISFREE_
call ds:[si] method memory_block:IsFree
jnz @@done
endif
call ds:[si] method memory_block:RawBlockSize
mov bx,ax
sub bx,[desiredsize]
dec bx ; Represent bookkeeping information of current block
dec bx ; For bookkeeping information of the new block
mov [newblocksize],bx
cmp bx,2 ; If less than four paragraphs left over, don't
; do the breakdown.
jbe @@done
; Get the current next block
call ds:[si] method memory_block:GetNext
mov [currentnext],ax
; Calculate the segment of the new block
mov ax,ds
add ax,[desiredsize]
inc ax ; For the size of our bookkeeping info
mov [newnext],ax
; Set our next pointer to new block
call ds:[si] method memory_block:SetNext
; Set our size
mov ax,[desiredsize]
call ds:[si] method memory_block:SetSize
; Set the new block to point to its neighbors
mov ds,[newnext]
call ds:[si] method memory_block:init pascal,[currblock],[currentnext],[newblocksize]
ifdef _DO_SETPREV_
; Set the old next block to point to the new block created just
; before it.
mov ds,[currentnext]
call ds:[si] method memory_block:setprev
endif
@@done:
mov ax,[newnext]
ret
mb_breakblock endp
memory_block_markfree proc
ifdef _DO_ISFREE_
local previous:word
mov [previous],ax
call ds:[si] method memory_block:IsFree
jz @@block_is_free_skip
; Get the pointer to the next block
call ds:[si] method memory_block:GetNext
; Calculate the size of this block
push ax
mov bx,ax
mov ax,ds
sub bx,ax
dec bx ; For the bookkeeping area
pop ax
call ds:[si] method memory_block:init pascal,[previous],ax,bx
@@block_is_free_skip:
endif
ret
memory_block_markfree endp
memory_block_markused proc
ifdef _DO_ISFREE_
call ds:[si] method memory_block:IsFree
jnz @@done
endif
mov ax,word ptr ds:[si.next2]
mov word ptr ds:[si.next],ax
mov ax,word ptr ds:[si.next2+2]
mov word ptr ds:[si.next+2],ax
; Change the block type to be a used block.
; Do this by changing the VMT!
mov ds:[si.@Mptr_memory_block],offset @TableAddr_memory_usedblock
;if @CodeSize eq 1
; mov word ptr ds:[si.@Mptr_memory_block+2],seg @TableAddr_memory_usedblock
;endif
@@done:
ret
memory_block_markused endp
memory_block_lock proc
ret
memory_block_lock endp
memory_block_unlock proc
ret
memory_block_unlock endp
memory_block_allocfail proc
ret
memory_block_allocfail endp
page
;***** Routines for MEMORY_USEDBLOCK
memory_usedblock_markfree proc
local previous:word
mov [previous],ax
ifdef _DO_ISFREE_
call ds:[si] method memory_block:IsFree
jz @@block_is_free_skip
endif
; Get the pointer to the next block
call ds:[si] method memory_block:GetNext
; Calculate the size of this block
push ax
mov bx,ax
mov ax,ds
sub bx,ax
dec bx ; For the bookkeeping area
pop ax
call ds:[si] method memory_block:init pascal,[previous],ax,bx
@@block_is_free_skip:
ret
memory_usedblock_markfree endp
memory_usedblock_combine proc
ret ;Can't do a combine with a used block. So ignore it!
memory_usedblock_combine endp
memory_usedblock_setnext proc
mov word ptr ds:[si.next],ax
ret
memory_usedblock_setnext endp
memory_usedblock_invalid proc
ret
memory_usedblock_invalid endp
memory_usedblock_isfree proc uses ax
mov ax,1 ; Set the Z flag to zero!
IsZero ax
ret
memory_usedblock_isfree endp
memory_usedblock_scan proc
; This block is not free, so quickly pass the call
; along to the next object in this chain!
mov ax,word ptr ds:[si.next]
mov ds,ax
IsZero ax ; Check for zero, meaning end of the line!
jz @@done
; Use a jump, instead of
; call ds:[si] method memory_usedblock:ScanFree
; so that we eliminate overflowing the stack during this routine.
MOV BX,ds:[([ SI ]).@Mptr_memory_block]
;if @CodeSize eq 1
; MOV ES,word ptr [([DS :SI ]).@Mptr_memory_block+2]
;endif
jmp es:[(@Table_memory_usedblock PTR BX).ScanFree]
@@done:
ret
memory_usedblock_scan endp
memory_usedblock_getnext proc
mov ax,word ptr ds:[si.next]
ret
memory_usedblock_getnext endp
memory_usedblock_init proc
; Set the VMT PTR within this block!
mov ds:[si.@Mptr_memory_block],offset @TableAddr_memory_usedblock
ret
memory_usedblock_init endp
memory_usedblock_show proc uses ds es dx ax
.data
@@type db "USED$"
@@next db " Next:$"
.code
call Show_Bracket
push ds
pop es
mov ax,@data
mov ds,ax
mov dx,offset @@type
mov ah,DOSPRINTSTRING
int DOSINT
mov ah,DOSPRINTSTRING
mov dx,offset @@next
int DOSINT
mov ax,word ptr es:[si.next]
call ShowHexWord
call Show_Endbracket
ret
memory_usedblock_show endp
memory_usedblock_lock proc
ret
memory_usedblock_lock endp
memory_usedblock_unlock proc
ret
memory_usedblock_unlock endp
page
;***** Routines for MEMORY_ENDBLOCK
memory_endblock_ignore proc
ret
memory_endblock_ignore endp
memory_endblock_getnext proc
xor ax,ax
ret
memory_endblock_getnext endp
memory_endblock_init proc
; Set the VMT PTR within this block!
mov ds:[si.@Mptr_memory_block],offset @TableAddr_memory_endblock
;if @CodeSize eq 1
; mov word ptr ds:[si.@Mptr_memory_block],seg @TableAddr_memory_endblock
;endif
xor ax,ax
mov word ptr ds:[si.next],ax
mov word ptr ds:[si.next+2],ax
ret
memory_endblock_init endp
memory_endblock_show proc uses ds dx ax
.data
@@end db "END$"
.code
call Show_Bracket
mov ax,@data
mov ds,ax
mov dx,offset @@end
mov ah,DOSPRINTSTRING
int DOSINT
call Show_Endbracket
ret
memory_endblock_show endp
page
;***** Routines for MEMORY_SYSTEM
memory_system_init proc uses es ds si bx
local endblockseg:word
; Fill in the VMT for the memory system
mov ds:[si.@Mptr_memory_system],offset @TableAddr_memory_system
; Get a block of memory.
mov bx,ax ; Get the desired size, unless it is zero,
; then get the largest possible block.
or bx,bx
jnz @Memory_system_init_Alloc
dec bx ;mov bx,0FFFFh ; Go for largest possible
@Memory_system_init_Alloc:
mov ds:[si.blocksize],bx
mov ah,DOSGETMEMBLOCK
int DOSINT
; Need to handle fail here! (Carryflag set, and BX with size of
; largest block available. )
jnc AllocSuccess
; Check the high bit of blocksize to see
; if we can get a different size.
; Note that if we come here a second time, it is because DOS
; said a certain size was available, and then it wouldn't give
; it when requested. The high bit wont be set on the second call.
TESTFLAG ds:[si.blocksize],8000h
jz AllocFailed
; BX has size of largest block available. Go get it if it is NZ.
or bx,bx
jnz @Memory_system_init_Alloc ; Jump back and get it if there
; is some available.
AllocFailed:
mov ds:[si.blocksize],0
jmp @Memory_system_init_done
AllocSuccess:
; Success: Carryflag clear, and AX initial segment of allocated block
mov [si.root],ax ; Segment of start of block still in AX!
mov [si.rover],ax
; Load the size of the block into BX
mov bx,ds:[si.blocksize]
dec bx ; For bookkeeping
dec bx ; For the endblock
; Calculate in CX the segment of the endblock
mov cx,bx
inc cx ; For bookkeeping for first block
add cx,ax ; To get segment
mov [endblockseg],cx
mov [si.last],cx
; Save the address of the memory system, so we
; can call constructor for the memory block.
push ds
push si
; Load the pointer to the block into DS:SI
mov ds,ax
xor si,si
xor ax,ax ; For pushing zeros for prev & next blocks
; ; Need to set the VMT for the memory block before calling init!
; ; This is only needed if INIT routine is in the VMT!
; mov ds:[si.@Mptr_memory_block],offset @TableAddr_memory_block
LoadVMTSeg ES
call ds:[si] method memory_block:init pascal, ax,cx,bx
; Now make an endblock
mov ds,[endblockseg]
call ds:[si] method memory_endblock:init
; Restore pointre to the memory system
pop si
pop ds
@Memory_system_init_done:
mov ds:[si.usedspace],0
mov ax,ds:[si.blocksize]
dec ax ; Bookkeeping for the first block
dec ax ; Bookkeeping for the end block
mov ds:[si.freespace],ax
dec ds:[si.freespace]
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -