dos_compilers/Zortech C++ v206/SOURCE/CLIB/PAGE.ASM

360 lines
8.3 KiB
NASM
Raw Normal View History

2024-07-02 16:30:38 +02:00
;_ page.asm Wed May 24 1989 Modified by: Walter Bright */
; Copyright (C) 1989 by Walter Bright
; All rights reserved
; Written by Walter Bright
include macros.asm
; Storage allocator
begcode page
c_public page_malloc,page_calloc,page_realloc,page_free
; The start of each page (set by page_initialize()) looks like:
pagesize equ 0 ;total size of this page
maxsize equ 2 ;max size of a free block in free list
allocp equ 4 ;roving pointer for allocator
bassize equ 6 ;size of first block (0 so it
; is never allocated)
baslnk equ 8 ;offset of next free block
pageoverhead equ 10 ;# of bytes of bookkeeping
; A block in the free list consists of:
; dw size of block in bytes (must be even) (including both words)
; dw pointer to next block in list
; When it's allocated,
; dw # of bytes in this block including this word
; db... the bytes allocated
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Allocate a block of data and clear it.
; Use:
; unsigned page_calloc(void far *baseptr,unsigned size);
; Returns:
; offset of allocated data else 0
func page_calloc
push BP
mov BP,SP
push P+4[BP]
push P+2[BP]
push P[BP]
callm page_malloc ;allocate a chunk
mov SP,BP
tst AX ;out of memory?
jz C2 ;yes
.save <DI>
les DI,P[BP] ;ES:DI = baseptr
add DI,AX ;offset to start of allocated memory
mov DX,AX ;save offset of result
mov CX,ES:-2[DI] ;# of bytes
shr CX,1 ;# of words (including byte count)
dec CX ;skip byte count
clr AX
rep stosw ;clear the memory
mov AX,DX ;restore offset of result
.restore <DI>
C2:
pop BP
ret
c_endp page_calloc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Allocate a block of data.
; unsigned page_malloc(void far *baseptr,unsigned size);
; Returns:
; offset of allocated data else 0
func page_malloc
push BP
mov BP,SP
.save <SI,DI>
push DS
lds BX,P[BP] ;DS:BX = baseptr
mov AX,P+4[BP] ;get size
add AX,3 ;need another word for length info
and AL,0FEh ;round up to nearest word
.if AX b 4, allocerr ;can't allocate 0 bytes
; mov SI,allocp[BX] ;last item
mov SI,baslnk[BX] ;last item
mov CX,SI ;CX to save bytes
jmps A2
A1: mov SI,DI
.if SI e CX, allocerr ;wrapped around, didn't find any
A2: mov DI,2[BX+SI] ;next item in list
.if AX a [BX+DI], A1 ;not big enough
je A3 ;exactly big enough
add AX,2 ;we'll need another 2 bytes
.if AX e [BX+DI],A3 ;have to allocate an entire block
sub AX,2
;Allocate from bottom of free block.
; DI -> free block
; SI -> previous free block
; AX = # of bytes in allocated block
add 2[BX+SI],AX ;link to new free block
mov SI,2[BX+SI] ;pointer to new free block
mov CX,[BX+DI] ;number of bytes in block we're splitting
sub CX,AX ;CX = remaining bytes
mov [BX+SI],CX ;# of bytes in this block
mov [BX+DI],AX ;[DI] = # of bytes
A3: mov AX,2[BX+DI] ;AX = next free block
mov 2[BX+SI],AX ;skip the DI entry in list
mov allocp[BX],SI
mov AX,DI
add AX,2 ;pointer to area allocated (DI + 2)
A6: mov word ptr maxsize[BX],0 ;recalculate size of largest available block
pop DS
.restore <DI,SI>
pop BP
ret
allocerr:
clr AX ;NULL
jmp A6
c_endp page_malloc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Reallocate memory that was allocated by page_malloc() or page_calloc().
; Use:
; unsigned page_realloc(void far *baseptr,unsigned p, unsigned nbytes)
; Returns:
; 0 error
; else offset of reallocated memory
func page_realloc
push BP
mov BP,SP
mov AX,P+4+2[BP] ;AX = nbytes
tst AX ;trying to realloc() to 0 size?
jnz R6 ;no
pop BP
jmp near ptr page_free ;page_free(baseptr,p)
R6: ;If p is 0, this is just a page_malloc()
mov BX,P+4[BP] ;BX = p
tst BX ;is p NULL?
jnz R5 ;no
;function just like page_malloc(baseptr,nbytes)
push AX
push P+2[BP]
push P[BP]
callm page_malloc
mov SP,BP
pop BP
ret
;if realloced size is smaller, attempt to just shrink current block
R5: push SI
les SI,P[BP] ;ES:SI = baseptr
sub BX,2
mov CX,ES:[SI+BX] ;CX = # of bytes in this block
add AX,3
and AL,0FEh ;AX = real new size
sub CX,AX
jb R3 ;if allocating more bytes
.if CX b 4, R4 ;size of free list entry
mov ES:[SI+BX],AX ;realloced size of p
add BX,AX ;BX -> new fragment
mov ES:[SI+BX],CX ;size of new fragment
add BX,2
push BX
push P+2[BP]
push P[BP]
callm page_free
add SP,6
R4:
mov AX,P+4[BP]
jmps R1 ;no change, return p
;we'll have to allocate a new block, copy the data over,
;and free the old one
R3:
push P+6[BP]
push P+2[BP]
push P[BP]
callm page_malloc ;page_malloc(baseptr,nbytes)
add SP,6
tst AX
jz rallocerr ;error
push AX ;save pointer to new memory
.save <DI>
push DS
mov DI,AX
add DI,SI ;ES:DI -> new item
add SI,P+4[BP] ;DS:SI -> original
mov CX,ES
mov DS,CX
mov CX,-2[SI]
.if CX be -2[DI], R2
mov CX,-2[DI] ;CX = smaller of two size
R2: shr CX,1 ;# of words
dec CX ;compensate for extra word in beginning
rep movsw ;transfer the words
pop DS
push P+4[BP]
push P+2[BP]
push P[BP]
callm page_free ;free the old one
add SP,6
.restore <DI>
tst AX
pop AX ;restore pointer to new memory
jz R1
rallocerr:
clr AX
R1: pop SI
pop BP
ret
c_endp page_realloc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Free memory that was allocated by page_malloc() or page_calloc().
; Use:
; int page_free(void far *baseptr,unsigned p);
; Returns:
; 0 success
; -1 error
func page_free
push BP
mov BP,SP
.save <SI,DI>
push DS
mov DX,P+4[BP] ;get p
tst DX ;pass a NULL pointer?
jz F5 ;yes, return 0
lds BX,P[BP] ;DS:BX = baseptr
.if DX be baslnk+1, freeerr ;if below bottom of pool
.if DX ae pagesize[BX], freeerr ;if above top of pool
test DL,1 ;odd?
jne freeerr
sub DX,2 ;point to start of block
mov SI,DX
mov AX,[BX+SI] ;# of bytes in block to be freed
; Try to find SI and DI such that SI < DX < DI
mov SI,allocp[BX] ;try our roving pointer
.if SI b DX, F1 ;a good starting point
mov SI, bassize
jmps F1
F6: mov SI,DI
F1: mov DI,2[BX+SI] ;the next in the list
.if SI ae DX, freeerr
.if DI a DX, F2 ;got it
.if DI a SI, F6 ;no wrap around (SI < DI < DX)
; We have SI < DX < DI (relative position in list)
F2: mov CX,[BX+SI] ;# of bytes in previous block
add CX,SI ;+ link
.if CX ne DX, F3 ;if can't collapse with prev block
add [BX+SI],AX
jmps F4
F3: mov 2[BX+SI],DX ;link to DX
mov SI,DX
mov 2[BX+SI],DI ;link to block after DX
; See if we can collapse SI with DI
; SI -> block just before DI
; DI -> block just after SI
F4: mov allocp[BX],SI ;for next time
mov AX,[BX+SI]
add AX,SI
.if AX ne DI, F5 ;nope
mov AX,2[DI+BX] ;link after DI
mov 2[SI+BX],AX ;becomes link after SI
mov AX,[BX+DI] ;# of bytes in DI
add [BX+SI],AX ;add to # of bytes in SI
F5: clr AX ;success
F7: mov word ptr maxsize[BX],0 ;recalc max size
pop DS
.restore <DI,SI>
pop BP
ret
freeerr:
mov AX,-1 ;error
jmp F7
c_endp page_free
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Determine size of largest free block in page.
; unsigned page_maxfree(void far *baseptr);
c_public page_maxfree
func page_maxfree
push BP
mov BP,SP
push SI
push DS
lds SI,P[BP] ;DS:SI = baseptr
mov AX,maxsize[SI]
tst AX
jnz M3 ;does not need recalculation
clr AX
mov BX,baslnk[SI] ;offset to first free block
M1: mov CX,[SI+BX] ;size of free block
.if CX b AX, M2
mov AX,CX
M2: mov CX,2[SI+BX] ;offset to next link
xchg CX,BX
.if BX a CX, M1
sub AX,2
jc M4
mov maxsize[SI],AX
M3: pop DS
pop SI
pop BP
ret
M4: clr AX
jmp M3
c_endp page_maxfree
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Initialize memory allocation system in a page.
; unsigned page_initialize(void far *baseptr,unsigned pagesize);
; Returns:
; size of largest allocatable block
c_public page_initialize
func page_initialize
push BP
mov BP,SP
push DS
lds BX,P[BP] ;DS:BX = baseptr
mov AX,P+4[BP] ;AX = pagesize
mov pagesize[BX],AX
sub AX,pageoverhead
mov word ptr allocp[BX],bassize
mov word ptr bassize[BX],0
mov word ptr baslnk[BX],pageoverhead
;Construct one big free block of the remainder
mov pageoverhead[BX],AX ;size of that block
mov word ptr pageoverhead+2[BX],bassize
sub AX,2 ;overhead per allocated block
mov maxsize[BX],AX
pop DS
pop BP
ret
c_endp page_initialize
endcode page
end