; ============================================================================
;
; LT-DOS - Int 21h memory
;
; ============================================================================
; ------------- Memory Control Block, MCB
struc MCB
MCB_Type: resb 1 ; 0: block type (see below)
MCB_Owner: resw 1 ; 1: PSP segment of owner or flag (see below)
MCB_Size: resw 1 ; 3: size of block in paragraphs
MCB_Res: resb 3 ; 5: ...reserved
MCB_Name: resb 8 ; 8: ASCII program name (nul terminated if < 8)
endstruc
MCB_SIZE EQU MCB_size ; 10h (=16) bytes
; ------------- MCB block type
MCBTypeLast EQU 5Ah ; last block in chain (="Z")
MCBTypeMid EQU 4Dh ; middle block in chain ("M")
; ------------- MCB owner flag (in MCB_PSP)
MCBOwnerFree EQU 0 ; free block
MCBOwnerSys EQU 8 ; system
; ------------- Allocation strategy
MEMFIRSTFIT EQU 0 ; memory first fit
MEMBESTFIT EQU 1 ; memory best fit
MEMLASTFIT EQU 2 ; memory last fit
; ----------------------------------------------------------------------------
; Find next MCB
; ----------------------------------------------------------------------------
; INPUT: SI = 0 (to optimize program)
; DS = segment of MCB header
; OUTPUT: CF = (NC) clear if valid MCB
; DS = segment of next MCB
; CF = (CY) set on error, MCB is invalid
; DESTROYS: AX
; ----------------------------------------------------------------------------
NextMCB: mov ax,ds ; AX <- segment of MCB
inc ax ; skip MCB header
add ax,[si+MCB_Size]; skip MCB size
mov ds,ax ; DS <- segment of next MCB
jc TestMCB2 ; error, overflow 1 MB boundary
; --- TestMCB function must follow!
; ----------------------------------------------------------------------------
; Test validity of MCB (Memory Control Block)
; ----------------------------------------------------------------------------
; INPUT: SI = 0 (to optimize program)
; DS = segment of MCB header
; OUTPUT: CF = (NC) clear if valid MCB
; CF = (CY) set on error, MCB is invalid
; ----------------------------------------------------------------------------
TestMCB: cmp byte [si+MCB_Type],MCBTypeMid ; is it middle MCB?
je TestMCB2 ; it is middle MCB
cmp byte [si+MCB_Type],MCBTypeLast ; is it last MCB?
je TestMCB2 ; it is last MCB
stc ; set error flag
TestMCB2: ret
; ----------------------------------------------------------------------------
; Coalesce free MCBs
; ----------------------------------------------------------------------------
; INPUT: SI = 0 (to optimize program)
; DS = segment of first free MCB header
; OUTPUT: CF = (NC) clear if valid MCB
; CF = (CY) set on error, MCB is invalid
; DESTROYS: AX, ES
; ----------------------------------------------------------------------------
; ------------- Check if it is last MCB
CoalesceMCB: cmp byte [si+MCB_Type],MCBTypeLast ; is it last MCB?
je TestMCB2 ; it is last MCB (here is NC)
; ------------- Find next MCB (-> ES)
push ds ; push DS
call NextMCB ; find next MCB
push ds ; push DS
pop es ; ES <- segment of next MCB
pop ds ; pop DS
jc TestMCB2 ; error
; ------------- Check if it is free MCB (else return with NC)
cmp [es:si+MCB_Owner],si ; free MCB?
jne TestMCB2 ; it is not free MCB (here is NC)
; ------------- Coalesce MCBs
mov ax,[es:si+MCB_Size]; AX <- size of coalesced MCB
inc ax ; add size of MCB header
add [si+MCB_Size],ax ; increase size of this MCB
; ------------- Transfer type of MCB
mov al,[es:si+MCB_Type]; AL <- type of coalesced MCB
mov [si+MCB_Type],al ; transfer type of MCB
jmp short CoalesceMCB ; coalesce next MCB
; ----------------------------------------------------------------------------
; Free memory blocks of one owner
; ----------------------------------------------------------------------------
; INPUT: AX = owner
; DESTROYS: SI
; ----------------------------------------------------------------------------
; ------------- Test first allocated block
FreeOwner: xor si,si ; SI <- 0 (to optimize program)
mov ds,[FirstAlloc] ; DS <- first allocated block
call TestMCB ; test first MCB
FreeOwner2: jc TestMCB2 ; invalid MCB
; ------------- Check if it is this owner
cmp [si+MCB_Owner],ax ; is it this owner?
jne FreeOwner4 ; it is not this owner
mov [si+MCB_Owner],si ; mark this MCB as free
; ------------- Find next MCB
FreeOwner4: cmp byte [si+MCB_Type],MCBTypeLast ; is it last MCB?
je TestMCB2 ; it is last MCB
call NextMCB ; find next MCB
jmp short FreeOwner2
; ----------------------------------------------------------------------------
; Int 21h, function 48h - Allocate memory
; ----------------------------------------------------------------------------
; INT21 INPUT: AH = 48h (function code)
; BX = number of paragraphs to allocate
; INT21 OUTPUT: CF = (NC) clear if successful
; AX = segment of allocated block
; CF = (CY) set on error
; AX = error code
; 7: memory control block damaged
; 8: insufficient memory
; BX = size of largest available block
; ----------------------------------------------------------------------------
; ------------- Init pointers
Int2148: xor si,si ; SI <- 0 (to optimize program)
push cs ; push CS
pop ds ; DS <- CS
xor ax,ax ; AX <- 0
mov [FirstMem],ax ; reset first found block
mov [SmallMem],ax ; reset smallest suitable block
mov [LastMem],ax ; reset last found block
xchg ax,di ; DI <- 0 max. size of block
; ------------- Test first allocated block
mov ds,[FirstAlloc] ; DS <- first allocated block
call TestMCB ; test first MCB
jc Int2148MCBErr ; invalid first MCB
; ------------- Check if it is free MCB
Int21481: cmp [si+MCB_Owner],si ; free MCB?
jne Int21486 ; it is not free MCB
; ------------- Found free block, coalesce following free MCBs
call CoalesceMCB ; coalesce free MCBs
jc Int2148MCBErr ; error, damaged MCB
; ------------- Check if it is bigger block
mov ax,[si+MCB_Size]; AX <- size of this MCB
cmp ax,di ; is it bigger block?
jbe Int21482 ; it is not bigger block
mov di,ax ; DI <- size of largest block
; ------------- Check if this block satisfies
Int21482: cmp ax,bx ; is this block big enough?
jb Int21486 ; this block is not big enough
; ------------- Store first found block
cmp [cs:FirstMem],si ; is it first block?
jne Int21483 ; first block was already found
mov [cs:FirstMem],ds ; store first found block
; ------------- Store smallest suitable block
Int21483: cmp [cs:SmallMem],si ; smallest block found?
je Int21484 ; smallest block not found
mov es,[cs:SmallMem] ; ES <- smallest block
cmp ax,[es:si+MCB_Size] ; found smaller block?
jae Int21485 ; it is not smaller block
Int21484: mov [cs:SmallMem],ds ; store smallest suitable block
; ------------- Store last found allocated block
Int21485: mov [cs:LastMem],ds ; store last found allocated block
; ------------- Check, if it is last MCB
Int21486: cmp byte [si+MCB_Type],MCBTypeLast ; is it last MCB?
je Int21487 ; it is last MCB
; ------------- Find next MCB
call NextMCB ; find next MCB
jnc Int21481 ; test next MCB
; ------------- Invalid MCB
Int2148MCBErr: mov al,DOSERR_MCBERR ; AL <- 7 error, damaged MCB
Int2148Err: jmp DOSError ; set DOS error
; ------------- End of memory reached, test if any MCB was found
Int21487: mov ax,[cs:FirstMem] ; AX <- first found block
or ax,ax ; any MCB found?
xchg ax,di ; AX <- max. size, DI <- first block
je Int214A2 ; error, insufficient memory
; ------------- Prepare address of found MCB (-> DS, SI)
cmp byte [cs:MemStrategy],1 ; use best fit block?
ja Int2148A ; use last found block
jb Int21488 ; use first found block
mov di,[cs:SmallMem] ; DS <- smallest block
Int21488: mov ds,di ; DS <- segment of found block
; ------------- Size of rest of block
Int214882: mov ax,[si+MCB_Size]; AX <- size of block
sub ax,bx ; AX <- rest of block size
jz Int21489 ; no block lefts
dec ax ; without header
; ------------- Split block into two parts
mov dx,ds ; DX <- segment of block
inc dx ; skip header of block
add dx,bx ; skip data of block
mov es,dx ; ES <- segment of next block
Int214884: mov [es:si+MCB_Size],ax ; size of second block
mov [si+MCB_Size],bx ; set new size of first block
; ------------- Mark blocks
mov al,MCBTypeMid ; AL <- mark of middle block
xchg al,[si+MCB_Type] ; mark this block as middle
mov [es:si+MCB_Type],al ; transfer mark to next block
mov ax,es ; AX <- second block
cmp ax,di ; is it new block?
je Int21489 ; it is new block
mov [es:si+MCB_Owner],si ; mark block as free
mov [es:si+MCB_Name],si ; no valid name of block
; ------------- Set owner of new MCB
Int21489: mov ds,di ; DS <- segment of MCB
mov ax,[cs:CurrentPSP] ; AX <- current PSP
mov [si+MCB_Owner],ax; owner of this MCB
; ------------- Segment of new MCB
xchg ax,di ; AX <- segment of found block
inc ax ; skip header of MCB
jmp DOSOK ; clear CF
; ------------- Use last found allocated block (use end of block)
Int2148A: mov ds,[cs:LastMem] ; DS <- last memory
mov di,ds ; DI <- segment of found block
mov ax,[si+MCB_Size]; AX <- size of block
sub ax,bx ; AX <- rest of block size
jz Int21489 ; no block lefts
add di,ax ; DI <- next block
mov es,di ; ES <- next block
dec ax ; size without header
xchg ax,bx ; AX <- MCB 2 size, BX <- MCB 1 size
jmp short Int214884
; ----------------------------------------------------------------------------
; Int 21h, function 4Ah - Resize memory
; ----------------------------------------------------------------------------
; INT21 INPUT: AH = 4Ah (function code)
; BX = new size of memory block
; ES = segment of block to resize
; INT21 OUTPUT: CF = (NC) clear if successful
; CF = (CY) set on error
; AX = error code
; 7: memory control block damaged
; 8: insufficient memory
; 9: memory block address invalid
; BX = maximum available size of block
; NOTES: If there is insufficient memory to expand the block, the block will
; be made as large as possible and BX returns new size of the block
; ----------------------------------------------------------------------------
; ------------- Prepare address of MCB
Int214A: xor si,si ; SI <- 0 (to optimize program)
mov ax,es ; AX <- segment of MCB
dec ax ; AX <- segment of MCB header
mov ds,ax ; DS <- segment of MCB
xchg ax,di ; DI <- segment of MCB
; ------------- Test MCB
call TestMCB ; test first MCB
jc Int21492 ; error, invalid address
; ------------- Coalesce following free MCBs
call CoalesceMCB ; coalesce free MCBs
jc Int21494 ; error, damaged MCB
; ------------- Check new size of MCB
mov ax,[si+MCB_Size]; AX <- size of MCB
cmp ax,bx ; check MCB size
jae Int214882 ; MCB size is OK
; ------------- Error, insufficient memory
Int214A2: xchg ax,bx ; BX <- new size of MCB
call SetRegBX ; set register BX (new size of MCB)
mov al,DOSERR_MEMORY ; AL <- error 8, insufficient memory
jmp short Int21581 ; error, insufficient memory
; ----------------------------------------------------------------------------
; Int 21h, function 49h - Free memory
; ----------------------------------------------------------------------------
; INT21 INPUT: AH = 49h (function code)
; ES = segment of block to free
; INT21 OUTPUT: CF = (NC) clear if successful
; CF = (CY) set on error
; AX = error code
; 7: memory control block damaged
; 9: memory block address invalid
; ----------------------------------------------------------------------------
; ------------- Prepare address of MCB
Int2149: xor si,si ; SI <- 0 (to optimize program)
mov ax,es ; AX <- segment of MCB
dec ax ; AX <- segment of MCB header
mov ds,ax ; DS <- segment of MCB
; ------------- Test MCB
call TestMCB ; test first MCB
Int21492: mov al,DOSERR_ADDRESS ; AL <- error 9, invalid address
jc Int21581 ; error, invalid address
; ------------- Mark MCB as free
mov word [si+MCB_Owner],si ; mark MCB as free
; ------------- Coalesce following free MCBs
call CoalesceMCB ; coalesce free MCBs
Int21494: mov al,DOSERR_MCBERR ; AL <- error 7, MCB damaged
jc Int21581 ; error, damaged MCB
jmp short Int21586 ; return OK
; ----------------------------------------------------------------------------
; Int 21h, function 58h - Get or set allocation strategy
; ----------------------------------------------------------------------------
; INT21 INPUT: AH = 58h (function code)
; AL = subfunction
; 0 = get allocation strategy
; 1 = set allocation strategy
; if subfunction 1:
; BL = new allocation strategy (see Allocation strategy)
; INT21 OUTPUT: CF = (NC) clear if successful
; if subfunction 0:
; AX = current strategy (see Allocation strategy)
; CF = (CY) set on error
; AX = error code
; 1: function number invalid
; ----------------------------------------------------------------------------
; ------------- Test subfunction code
Int2158: cmp al,1 ; set allocation strategy?
je Int21584 ; set allocation strategy
jb Int21582 ; get allocation strategy
; ------------- Error - invalid subfunction code
mov al,DOSERR_INVFUNC ; AL <- error, invalid function
Int21581: jmp DOSError ; set CF
; ------------- Get allocation strategy
Int21582: mov ah,0 ; AH <- 0
mov al,[cs:MemStrategy] ; AL <- current strategy
jmp short Int21586 ; return OK
; ------------- Set allocation strategy
Int21584: mov [cs:MemStrategy],al ; set allocation strategy
Int21586: jmp DOSOK ; return OK
; ----------------------------------------------------------------------------
; Data
; ----------------------------------------------------------------------------
FirstMem: dw 0 ; first found allocated block
SmallMem: dw 0 ; smallest suitable allocated block
LastMem: dw 0 ; last found allocated block
TopMem: dw 0a000h ; top of usable memory
MemStrategy: db MEMFIRSTFIT ; allocation strategy
|