c65gm/lib/memlib.c65

304 lines
6.8 KiB
Text

//-----------------------------------------------------------
//
// Memory library ( Malloc, Free )
//
//
// Author: Mattias Hansson
// Copyright (c) : 2000-2005 Mattias Hansson
// License: GNU LGPL 2
// Language: 65CM v0.4+
// Dependencies:
// Target: generic 6502
//
// Purpose: Provide some functions the help to create, update and access
// a linked list of strings.
//-----------------------------------------------------------
//-----------------------------------------------------------
// Internals:
//
// Makes heap-handling in a defined part of the memory.
//
// Requested memory is placed "from bottom upwards".
// Allocation entries are written from the top downwards.
//
// layout:
//
// Bottom ( e.g. $2000-$2fff )
// --------------
// $2000
// .
// . area 1 allocated by application
// .
// $2020
// $2021
// .
// . area 2 allocated by application
// .
// $2025
//
// .
// .
// .
//
// $2ff8 + $2ff9 = $2025 end of area 2
// $2ffa + $2ffb = $2021 start of area 2
// $2ffc + $2ffd = $2020 end of area 1
// $2ffe + $2fff = $2000 start of area 1
#IFNDEF __LIB_MEM
#DEFINE __LIB_MEM = 1
#IFNDEF __LIB_MEM_START
#DEFINE __LIB_MEM_START = $$5000
#IFEND
#IFNDEF __LIB_MEM_END
#DEFINE __LIB_MEM_END = $$9fff
#IFEND
#IFNDEF NULL
#DEFINE NULL = 0
#IFEND
GOTO lib_memlib_skip
WORD CONST lib_memstart = __LIB_MEM_START
WORD CONST lib_memend = __LIB_MEM_END
WORD lib_alloctable_end
//-----------------------------------------------------------
// Init: sets upp things for the lib in mem before start
//-----------------------------------------------------------
FUNC lib_mem_init
//set allocation table end start value
LET lib_alloctable_end GET lib_memend
INC lib_alloctable_end
FEND
//-----------------------------------------------------------
// Malloc: alloc memory of size size_t
// Address to allocated space is returned in result
//-----------------------------------------------------------
FUNC lib_mem_malloc ( {WORD size_t} out:{WORD result} )
WORD maxsize //max possible size now in heap
WORD newspaceb
WORD newspacee
WORD newtableend
DEC size_t // 1 = e.g. $2001-$2001 ( $2001 - $2001 = 0 )
LET newtableend GET lib_alloctable_end
SUBT newtableend - 4 -> newtableend
IF lib_alloctable_end > lib_memend THEN // only when first item!
SUBT newtableend - lib_memstart -> maxsize
IF maxsize < size_t THEN
//error handling: return NULL pointer!
LET result GET NULL
GOTO lib_malloc_exit
ENDIF
LET newspaceb GET lib_memstart
ADD newspaceb + size_t -> newspacee
//insert first record and recalc lib_alloctable_end
DEC lib_alloctable_end
DEC lib_alloctable_end
PUTASWORD@ lib_alloctable_end VALUE newspaceb
DEC lib_alloctable_end
DEC lib_alloctable_end
PUTASWORD@ lib_alloctable_end VALUE newspacee
LET result GET newspaceb
GOTO lib_malloc_exit;
ENDIF
//else if this is not the first item then:
WORD lib_malloc_ptr
WORD lib_malloc_spaceend
WORD lib_malloc_spacestart
LET lib_malloc_ptr GET lib_memend
SUBT lib_malloc_ptr - 3 -> lib_malloc_ptr
GETASWORD@ lib_malloc_ptr -> lib_malloc_spaceend
LET newspaceb GET NULL //if not found afterwards
WHILE 1
//if we reached the last record in the alloc-table
IF lib_malloc_ptr = lib_alloctable_end THEN
//is there sufficient space left @ top of heap?
INC lib_malloc_spaceend
SUBT newtableend - lib_malloc_spaceend -> maxsize
IF maxsize > size_t THEN
LET newspaceb GET lib_malloc_spaceend
ADD size_t + newspaceb -> newspacee
ENDIF
BREAK
ENDIF
DEC lib_malloc_ptr
DEC lib_malloc_ptr
GETASWORD@ lib_malloc_ptr -> lib_malloc_spacestart
SUBT lib_malloc_spacestart - lib_malloc_spaceend -> maxsize
DEC maxsize
//if we found a space big enough for the allocation
IF maxsize > size_t THEN
//Save the pointer to the new space end the pointer in the alloctable
LET newspaceb GET lib_malloc_spaceend
INC newspaceb // must start @ the next byte
ADD size_t + newspaceb -> newspacee
INC lib_malloc_ptr // set it to start of record! ( for move )
// INC lib_malloc_ptr
BREAK
ENDIF
DEC lib_malloc_ptr
DEC lib_malloc_ptr
GETASWORD@ lib_malloc_ptr -> lib_malloc_spaceend
WEND
IF newspaceb <> NULL THEN // allocate @ found space
IF lib_malloc_ptr = lib_alloctable_end THEN //allocate @ end of table
//insert record and recalc lib_alloctable_end
DEC lib_alloctable_end
DEC lib_alloctable_end
PUTASWORD@ lib_alloctable_end VALUE newspaceb
DEC lib_alloctable_end
DEC lib_alloctable_end
PUTASWORD@ lib_alloctable_end VALUE newspacee
//return new pointer
LET result GET newspaceb
GOTO lib_malloc_exit
ENDIF
//else = insert into alloctable
WORD lib_malloc_from
WORD lib_malloc_to
BYTE lib_malloc_byte
// move the rest of the stack
LET lib_malloc_from GET lib_alloctable_end
LET lib_malloc_to GET newtableend
WHILE 1
PEEK lib_malloc_from -> lib_malloc_byte
POKE lib_malloc_to WITH lib_malloc_byte
IF lib_malloc_from = lib_malloc_ptr THEN
BREAK
ENDIF
INC lib_malloc_from
INC lib_malloc_to
WEND
//insert record and recalc lib_alloctable_end
DEC lib_malloc_ptr
PUTASWORD@ lib_malloc_ptr VALUE newspaceb
DEC lib_malloc_ptr
DEC lib_malloc_ptr
PUTASWORD@ lib_malloc_ptr VALUE newspacee
LET lib_alloctable_end GET newtableend
//return new pointer
LET result GET newspaceb
ENDIF
IF newspaceb = NULL THEN // return null pointer
LET result GET NULL
GOTO lib_malloc_exit
ENDIF
LABEL lib_malloc_exit
INC size_t
FEND
//-----------------------------------------------------------
// Free: free alloced memory at m_ptr
//-----------------------------------------------------------
FUNC lib_mem_free ( {WORD m_ptr} )
WORD ptr
WORD startaddr
WORD lastrecfirst
WORD from
WORD to
BYTE tempb
IF lib_alloctable_end > lib_memend THEN // no entries
GOTO lib_free_exit
ENDIF
LET ptr GET lib_memend
DEC ptr
ADD 2 + lib_alloctable_end -> lastrecfirst
WHILE 1
GETASWORD@ ptr -> startaddr
IF startaddr = m_ptr THEN //found allocation!
//remove it!
IF ptr = lastrecfirst THEN
ADD 4 + lib_alloctable_end -> lib_alloctable_end
BREAK
ENDIF
LET to GET ptr
INC to
SUBT to - 4 -> from
WHILE 1
PEEK from -> tempb
POKE to WITH tempb
IF from = lib_alloctable_end THEN
BREAK
ENDIF
DEC from
DEC to
WEND
ADD 4 + lib_alloctable_end -> lib_alloctable_end
BREAK
ENDIF
DEC ptr
DEC ptr
IF ptr = lib_alloctable_end THEN
BREAK
ENDIF
DEC ptr
DEC ptr
WEND
LABEL lib_free_exit
FEND
LABEL lib_memlib_skip
#IFEND