173 lines
3.8 KiB
Text
173 lines
3.8 KiB
Text
//-----------------------------------------------------------
|
|
//
|
|
// Memory library ( Malloc, Free )
|
|
//
|
|
//
|
|
// Author: Mattias Hansson
|
|
// Copyright (c) : 2000-2025 Mattias Hansson
|
|
// License: GNU LGPL 2
|
|
// Language: 65CM v0.4+
|
|
// Dependencies:
|
|
// Target: generic 6502
|
|
//
|
|
// Purpose: Dynamic memory allocation using free list
|
|
//
|
|
// Modernized with:
|
|
// - Free list algorithm
|
|
// - ZP pointer for array-style access
|
|
//-----------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------
|
|
// Internals:
|
|
//
|
|
// Free list memory allocator.
|
|
//
|
|
// Block structure:
|
|
// - Free blocks: [size:WORD][next:WORD][...free space...]
|
|
// - Allocated blocks: [size:WORD][...user data...]
|
|
//
|
|
// User receives pointer to data area (block + 2).
|
|
// Size field includes 2-byte header.
|
|
//
|
|
// ZP usage (can be overridden):
|
|
// - $fa-$fb: current block pointer
|
|
//-----------------------------------------------------------
|
|
|
|
#IFNDEF __LIB_MEM
|
|
#DEFINE __LIB_MEM = 1
|
|
|
|
#PRAGMA _P_USE_LONG_JUMP 1
|
|
|
|
#IFNDEF __LIB_MEM_START
|
|
#DEFINE __LIB_MEM_START = $$5000
|
|
#IFEND
|
|
|
|
#IFNDEF __LIB_MEM_END
|
|
#DEFINE __LIB_MEM_END = $$9fff
|
|
#IFEND
|
|
|
|
#IFNDEF __LIB_MEM_ZP_CURRENT
|
|
#DEFINE __LIB_MEM_ZP_CURRENT = $$fa
|
|
#IFEND
|
|
|
|
#IFNDEF NULL
|
|
#DEFINE NULL = 0
|
|
#IFEND
|
|
|
|
GOTO lib_memlib_skip
|
|
|
|
|
|
WORD lib_memlib_current
|
|
WORD lib_memlib_free_head
|
|
|
|
//-----------------------------------------------------------
|
|
// Init: Initialize heap with one large free block
|
|
//-----------------------------------------------------------
|
|
FUNC lib_mem_init
|
|
WORD current @ __LIB_MEM_ZP_CURRENT
|
|
WORD CONST memstart = __LIB_MEM_START
|
|
WORD CONST memend = __LIB_MEM_END
|
|
|
|
lib_memlib_free_head = memstart
|
|
lib_memlib_current = memstart
|
|
current = lib_memlib_current
|
|
|
|
WORD CONST total_size = memend-memstart+1
|
|
|
|
POKEW current[0] , total_size
|
|
POKEW current[2] , NULL
|
|
FEND
|
|
|
|
//-----------------------------------------------------------
|
|
// Malloc: Allocate memory block
|
|
// Returns pointer to user data area or NULL if no space
|
|
//-----------------------------------------------------------
|
|
FUNC lib_mem_malloc({WORD size_t} out:{WORD result})
|
|
WORD current @ __LIB_MEM_ZP_CURRENT
|
|
WORD prev
|
|
WORD block_size
|
|
WORD needed_size
|
|
WORD remaining
|
|
WORD next_free
|
|
WORD split_addr
|
|
WORD alloc_addr
|
|
|
|
result = NULL
|
|
|
|
IF size_t = 0
|
|
EXIT
|
|
ENDIF
|
|
|
|
needed_size = size_t + 2
|
|
|
|
current = lib_memlib_free_head
|
|
prev = NULL
|
|
|
|
WHILE current != NULL
|
|
block_size = PEEKW current[0]
|
|
|
|
IF block_size >= needed_size
|
|
next_free = PEEKW current[2]
|
|
alloc_addr = current
|
|
|
|
remaining = block_size - needed_size
|
|
|
|
IF remaining >= 6
|
|
POKEW current[0] , needed_size
|
|
|
|
split_addr = current + needed_size
|
|
current = split_addr
|
|
POKEW current[0] , remaining
|
|
POKEW current[2] , next_free
|
|
|
|
IF prev = NULL
|
|
lib_memlib_free_head = split_addr
|
|
ELSE
|
|
current = prev
|
|
POKEW current[2] , split_addr
|
|
ENDIF
|
|
ELSE
|
|
IF prev = NULL
|
|
lib_memlib_free_head = next_free
|
|
ELSE
|
|
current = prev
|
|
POKEW current[2] , next_free
|
|
ENDIF
|
|
ENDIF
|
|
|
|
result = alloc_addr + 2
|
|
EXIT
|
|
ENDIF
|
|
|
|
prev = current
|
|
WORD temp
|
|
temp = PEEKW current[2]
|
|
current = temp
|
|
WEND
|
|
|
|
FEND
|
|
|
|
//-----------------------------------------------------------
|
|
// Free: Release allocated memory block
|
|
//-----------------------------------------------------------
|
|
FUNC lib_mem_free({WORD m_ptr})
|
|
WORD current @ __LIB_MEM_ZP_CURRENT
|
|
WORD block_start
|
|
|
|
IF m_ptr = NULL
|
|
EXIT
|
|
ENDIF
|
|
|
|
block_start = m_ptr - 2
|
|
|
|
current = block_start
|
|
POKEW current[2] , lib_memlib_free_head
|
|
lib_memlib_free_head = block_start
|
|
|
|
FEND
|
|
|
|
LABEL lib_memlib_skip
|
|
|
|
#PRAGMA _P_USE_LONG_JUMP 0
|
|
|
|
#IFEND
|