pcs/block.asm

352 lines
11 KiB
NASM
Raw Normal View History

2023-05-20 05:57:05 -04:00
; =====> 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