pcs/block.asm

352 lines
11 KiB
NASM
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; =====> BASICIO.ASM
;********************************************************
;* Scheme Runtime Support *
;* Memory Allocation Routines *
;* for Variable Length Objects *
;* *
;* (C) Copyright 1985 by Texas *
;* Instruments Incorporated. *
;* All rights reserved. *
;* *
;* Date Written: 31 December 1987 *
;* Last Modification: *
;********************************************************
page 60,132
include memtype.equ
include scheme.equ
SMALL_SIZE equ 1024 ;space in page not worth searching
DGROUP group data
data segment word public 'DATA'
assume DS:DGROUP
data ends
PGROUP group prog
prog segment byte public 'PROG'
assume CS:PGROUP
extrn alloc_bi:near,alloc_pa:near,garbage:near,gcsquish:near
extrn out_of_m:near
;;;ALLOC_BLOCK
;;;
;;; calling sequence: alloc_block(reg, type, size)
;;;
;;; local storage: int temp_ret,*last_page,page,str_size
;;;
al_args struc
temp_ret dw ? ;return address from srch_block
last_page dw ? ;address of pagelink chain
page dw ? ;page # of candidate
str_size dw ? ;actual size of object
al_bp dw ? ;callers bp
dw ? ;callers es
dw ? ;return address
ret_reg dw ? ;register for return value
ob_typ dw ? ;type of object to find
ob_siz dw ? ;size of object to find
al_args ends
public alloc_bl
alloc_bl proc near
push es
push bp
sub sp,al_bp
mov bp,sp
;if object is string, check for small string and adjust size appropriately
mov ax,[bp].ob_siz ;get object size
mov [bp].str_size,ax ;and save for later
cmp [BP].ob_typ,STRTYPE ;is it a string?
jnz al005 ; no, jump
cmp ax,PTRSIZE ;is it a small string?
jge al005 ; no, jump
mov [bp].ob_siz,PTRSIZE ;size = PTRSIZE
al005:
add [bp].ob_siz,BLK_OVHD ;size += BLK_OVHD
;search page type chain for block
call srch_block
jc al050 ;jump if block found
; Didn't find a block, test for a large block
mov ax,[BP].ob_siz
cmp ax,pagesize ;requested size > pagesize?
jb al010 ; no, jump
public try_big
try_big:
;try to allocate a big block
mov si,[bp].ret_reg
mov word ptr [si+02],NIL_PAGE*2 ;clear ret reg in case of GC
push ax ;size
push [BP].ob_typ ;type
push si ;return reg
call alloc_bi ;Allocate Big Block
mov sp,bp
jmp al050 ;return to caller
;block not found in allocated pages, try to allocate a new page
al010:
push [bp].ob_typ ;type
call alloc_pa ;Allocate new page
mov sp,bp
mov [bp].page,ax ;update page
cmp ax,END_LIST ;did we succeed?
jnz al040 ; yes, jump
;no more pages, try a garbage collection, then search the pages again
;for a free block
mov si,[bp].ret_reg
mov word ptr [si+02],NIL_PAGE*2 ;clear reg before GC
call garbage ;do garbage collection
call srch_block ;search for block again
jc al050 ;return on success
;
; Still couldn't find a block large enough, try to allocate a new page once
; again (since we just did a garbage collection).
;
push [BP].ob_typ ;type
call alloc_pa ;Allocate a new page
mov sp,bp
mov [bp].page,AX ;save page number
cmp ax,END_LIST ;did we succeed?
jnz al040 ; yes, jump
; We're getting desperate now. Try a collection with compaction, then try to
; allocate a new page for the object
mov si,[bp].ret_reg
mov word ptr [si+02],0 ;clear for possible GC
call gcsquish ;Compact memory
push [bp].ob_typ ;type
call alloc_pa ;Allocate a new page
mov sp,bp
mov [bp].page,ax
cmp ax,END_LIST ;Did we succeed?
jz alloc_err ; no, out of memory
;at this point, a new page has been allocated; get a block from it
al040:
push [bp].page ;page
push [bp].ob_siz ;size
push [bp].ob_typ ;type
push [bp].ret_reg ;return reg
call find_block ;Allocate a Block
mov sp,bp
jnc alloc_err
;
; We have found a block, set up the header and return
;
al050:
cmp [bp].ob_typ,STRTYPE
jnz alloc_ret
cmp [bp].str_size,PTRSIZE
jge alloc_ret
;for small strings, put the negative value for object length
push es
mov si,[bp].ret_reg
mov bx,[si+02] ;bx = page
mov si,[si] ;si = displacement
LoadPage es,bx
mov cx,[bp].str_size
sub cx,PTRSIZE ;cx = size - PTRSIZE
mov word ptr es:[si+1],cx ;replace object length
pop es ;restore extra segment
alloc_ret:
add sp,al_bp ;remove local data
pop bp ;restore base pointer
pop es ;restore extra segment
ret ;return to caller
public alloc_err
alloc_err:
call out_of_m ;out of memory
jmp alloc_ret ;control will not return here
; SRCH_BLOCK - Search through all the pages of a given type looking for a
; block large enough to fill the size request.
;
; Upon Entry: All local storage and args to ALLOC_BLOCK are used. Do
; not modify BP.
;
; Upon Exit: Carry Flag set, ret_reg will contain the page:disp of the block.
; Carry Flag clear, ret_reg will contain page of -1
;
public srch_block
srch_block label near
pop [bp].temp_ret ;save return value
mov bx,[bp].ob_typ ;bx = object type
shl bx,1 ;make into table index
mov si,bx
add bx,offset pagelist ;bx = address of pagelist[type]
mov [bp].last_page,bx ;save in last_page
mov ax,pagelist[si] ;ax = page number for this type
cmp ax,END_LIST ;any pages to search?
clc ;carry clear = failure
jz srch_end ; no, skip loop
srch_loop:
mov [bp].page,ax ;save page number for later
push ax ;page number
push [bp].ob_siz ;size of object
push [bp].ob_typ ;type of object
push [bp].ret_reg ;register to return value in
call find_block ;look for free space in page
mov sp,bp ;dump args off stack
jc srch_end ;carry set = success
;
; Block not found within current page.
;
mov si,[bp].page ;get page number
shl si,1 ; and make into index
cmp [bp].ob_siz,SMALL_SiZE ;size <= SMALL_SIZE?
jg sr10 ; no, jump
; less than small_size space is left within the page; this isn't worth searching
; again, so update the last position in the chain (last_page) to point to the
; next page in the chain.
mov ax,pagelink[si] ;get next page link
mov di,[bp].last_page
mov [di],ax ;*last_page = pagelink[page]
sr10:
; update last_page to contain the address of the next position in the chain,
; and get the next page from pagelink[page].
mov bx,offset pagelink ;bx = address of pagelink table
add bx,si ;bx = address of pagelink[page]
mov [bp].last_page,bx ;save in last_page
mov ax,pagelink[si] ;get next page number
cmp ax,END_LIST ;reached end of chain?
jne srch_loop ; no, continue search for block
clc ;carry clear = failure
srch_end:
jmp [bp].temp_ret ;return to caller
alloc_bl endp
;;;FIND_BLOCK
;;;
;;; calling sequence: find_block(reg, type, size, page)
;;;
;;; Upon Exit: carry flag set: reg contains page:displ of new block
;;; carry flag clr: reg contains page of -1
;;;
fb_args struc
dw ? ;callers bp
dw ? ;return address
r_reg dw ? ;register for return value
bl_typ dw ? ;block type
bl_siz dw ? ;block size
bl_pag dw ? ;page number
fb_args ends
public find_block
find_block proc near
push bp
mov bp,sp
mov si,[bp].r_reg ;get return register
mov Word Ptr [si+02],-1 ;default to block not found
mov si,[bp].bl_pag ;get page number
shl si,1 ;si = page index
LoadPage es,si ;es => page
; lets see if there's space in the free pool of this block
mov bx,nextcell[si] ;bx = next cell in page
cmp bx,END_LIST ;if no more space
jz fb015 ; then jump
mov ax,es:[bx+1] ;ax = free pool size
mov dx,[bp].bl_siz ;get size required
cmp ax,dx ;if not enough space in pool
jl fb015 ; then jump
; allocate a block from the free pool.
; ax = free pool size, bx = displacement, dx = object size
mov cx,[bp].bl_typ ;cx = type of object
mov byte ptr es:[bx],cl ;store type of new object
mov word ptr es:[bx+1],dx ;store size of new object
mov di,bx ;cx = displacement
add di,dx ;di = new displacement
mov cx,psize[si] ;get page size
sub cx,BLK_OVHD ; and subtract block overhead
cmp cx,di ;next displ still in page?
jb fb010 ; no, jump
mov byte ptr es:[di],FREETYPE ;mark next area as free
sub ax,dx ;ax = pool size - object size
mov word ptr es:[di+1],ax ;update free pool size
mov nextcell[si],di ;update nextcell chain
jmp fb045 ;return to caller
fb010:
mov nextcell[si],END_LIST ;nextcell[page] = END_LIST
jmp fb045 ;return to caller
; A block was not found in the free pool. Search the entire block for a fragment
; to satisfy the request.
fb015:
xor bx,bx ;bx = displacement
mov cx,psize[si]
sub cx,[bp].bl_siz ;cx = displacement threshold
cmp cx,bx ;threshhold >= displacement?
clc ;zero flag not set = failure
jl fb050 ;return with no block found
;the following loop requires bx=displacement, cx=threshold, dx=free size
fb020:
mov dx,word ptr es:[bx+1] ;dx = size of object
cmp byte ptr es:[bx],FREETYPE ;is next area free?
jz fb035 ; yes, jump
fb025: mov ax,BLK_OVHD+PTRSIZE ;ax = ovhd for small string
test dx,dx ;if size negative
js fb030 ; then jump
mov ax,dx ; else ax = size of object
fb030: add bx,ax ;displacement += size
cmp cx,bx ;if disp <= threshhold
jge fb020 ; then go look at next object
clc ;zero flag not set = failure
jmp fb050 ;return with no block found
;we have found a free space in the block; if not big enough then jump back
;into loop above, otherwise allocate the new storage
fb035:
mov ax,[bp].bl_siz
cmp ax,dx ;compare size to free size
jl fb025 ;if less, return to loop
jnz fb040 ;if not equal, jump
; we found an exact match
mov ax,[bp].bl_typ
mov byte ptr es:[bx],al ;just update the type field
jmp fb045 ;and return to caller
fb040:
mov di,dx
sub di,BLK_OVHD ;di = free size - block overhead
cmp di,ax ;can object fit into free space?
jle fb025 ; no, return to loop
; we can fit into a larger block, split block to allocate storage
mov cx,[bp].bl_typ ;cx = type of object
mov byte ptr es:[bx],cl ;store type of new object
mov word ptr es:[bx+1],ax ;store size of new object
;ax=new object size, bx=disp, dx= free size
mov di,bx
add di,ax ;di = new displacement
mov cx,dx
sub cx,ax ;cx = free size - new size
mov byte ptr es:[di],FREETYPE ;mark next area as free
mov word ptr es:[di+1],cx ;update next area free size
;
; block found; return page,disp in return register.
; si = page index, bx = displacement
fb045:
mov ax,si ;ax = page index
mov si,[bp].r_reg ;si = address of return reg
mov [si+02],ax ;put page index in register
mov [si],bx ;put diplacement in register
stc ;carry set = success
fb050:
pop bp ;restore base pointer
ret ;return to caller
find_block endp
prog ends
END