dos_compilers/Zortech C++ v206/SOURCE/CLIB/PAGE.ASM
2024-07-02 07:30:38 -07:00

360 lines
8.3 KiB
NASM
Raw 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.

;_ 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