Fixed up memlib.c65 and added errors to POKEW and PEEKW if using the same variable for pointer and value.
This commit is contained in:
parent
4971da9978
commit
23a721217d
3 changed files with 121 additions and 248 deletions
|
|
@ -197,6 +197,11 @@ func (c *PeekWCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContex
|
||||||
}
|
}
|
||||||
c.destVarName = destSym.FullName()
|
c.destVarName = destSym.FullName()
|
||||||
|
|
||||||
|
// Check for self-referential PEEKW (reading through a pointer into itself)
|
||||||
|
if c.isZPPointer && c.addrVarName == c.destVarName {
|
||||||
|
return fmt.Errorf("PEEKW: cannot read through pointer %q into itself (would corrupt pointer during read)", c.destVarName)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,10 @@ func (c *PokeWCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContex
|
||||||
c.isValueVar = false
|
c.isValueVar = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for self-referential POKEW (writing pointer through itself)
|
||||||
|
if c.isZPPointer && c.isValueVar && c.addrVarName == c.valueVarName {
|
||||||
|
return fmt.Errorf("POKEW: writing pointer %q through itself - pointer is both address and value", c.valueVarName)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
360
lib/memlib.c65
360
lib/memlib.c65
|
|
@ -4,48 +4,34 @@
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Author: Mattias Hansson
|
// Author: Mattias Hansson
|
||||||
// Copyright (c) : 2000-2005 Mattias Hansson
|
// Copyright (c) : 2000-2025 Mattias Hansson
|
||||||
// License: GNU LGPL 2
|
// License: GNU LGPL 2
|
||||||
// Language: 65CM v0.4+
|
// Language: 65CM v0.4+
|
||||||
// Dependencies:
|
// Dependencies:
|
||||||
// Target: generic 6502
|
// Target: generic 6502
|
||||||
//
|
//
|
||||||
// Purpose: Provide some functions the help to create, update and access
|
// Purpose: Dynamic memory allocation using free list
|
||||||
// a linked list of strings.
|
//
|
||||||
|
// Modernized with:
|
||||||
|
// - Free list algorithm
|
||||||
|
// - ZP pointer for array-style access
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
// Internals:
|
// Internals:
|
||||||
//
|
//
|
||||||
// Makes heap-handling in a defined part of the memory.
|
// Free list memory allocator.
|
||||||
//
|
//
|
||||||
// Requested memory is placed "from bottom upwards".
|
// Block structure:
|
||||||
// Allocation entries are written from the top downwards.
|
// - Free blocks: [size:WORD][next:WORD][...free space...]
|
||||||
|
// - Allocated blocks: [size:WORD][...user data...]
|
||||||
//
|
//
|
||||||
// layout:
|
// User receives pointer to data area (block + 2).
|
||||||
|
// Size field includes 2-byte header.
|
||||||
//
|
//
|
||||||
// Bottom ( e.g. $2000-$2fff )
|
// ZP usage (can be overridden):
|
||||||
// --------------
|
// - $fa-$fb: current block pointer
|
||||||
// $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
|
#IFNDEF __LIB_MEM
|
||||||
#DEFINE __LIB_MEM = 1
|
#DEFINE __LIB_MEM = 1
|
||||||
|
|
@ -60,246 +46,124 @@
|
||||||
#DEFINE __LIB_MEM_END = $$9fff
|
#DEFINE __LIB_MEM_END = $$9fff
|
||||||
#IFEND
|
#IFEND
|
||||||
|
|
||||||
|
#IFNDEF __LIB_MEM_ZP_CURRENT
|
||||||
|
#DEFINE __LIB_MEM_ZP_CURRENT = $$fa
|
||||||
|
#IFEND
|
||||||
|
|
||||||
#IFNDEF NULL
|
#IFNDEF NULL
|
||||||
#DEFINE NULL = 0
|
#DEFINE NULL = 0
|
||||||
#IFEND
|
#IFEND
|
||||||
|
|
||||||
GOTO lib_memlib_skip
|
GOTO lib_memlib_skip
|
||||||
|
|
||||||
WORD CONST lib_memstart = __LIB_MEM_START
|
|
||||||
WORD CONST lib_memend = __LIB_MEM_END
|
|
||||||
|
|
||||||
WORD lib_alloctable_end
|
WORD lib_memlib_current
|
||||||
|
WORD lib_memlib_free_head
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
// Init: sets upp things for the lib in mem before start
|
// Init: Initialize heap with one large free block
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
FUNC lib_mem_init
|
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
|
||||||
|
|
||||||
//set allocation table end start value
|
POKEW current[0] , total_size
|
||||||
LET lib_alloctable_end GET lib_memend
|
POKEW current[2] , NULL
|
||||||
INC lib_alloctable_end
|
|
||||||
|
|
||||||
FEND
|
FEND
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
// Malloc: alloc memory of size size_t
|
// Malloc: Allocate memory block
|
||||||
// Address to allocated space is returned in result
|
// Returns pointer to user data area or NULL if no space
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
|
FUNC lib_mem_malloc({WORD size_t} out:{WORD result})
|
||||||
FUNC lib_mem_malloc ( {WORD size_t} out:{WORD result} )
|
WORD current @ __LIB_MEM_ZP_CURRENT
|
||||||
WORD maxsize //max possible size now in heap
|
WORD prev
|
||||||
WORD newspaceb
|
WORD block_size
|
||||||
WORD newspacee
|
WORD needed_size
|
||||||
WORD newtableend
|
WORD remaining
|
||||||
|
WORD next_free
|
||||||
DEC size_t // 1 = e.g. $2001-$2001 ( $2001 - $2001 = 0 )
|
WORD split_addr
|
||||||
|
WORD alloc_addr
|
||||||
LET newtableend GET lib_alloctable_end
|
|
||||||
SUBT newtableend - 4 -> newtableend
|
result = NULL
|
||||||
|
|
||||||
IF lib_alloctable_end > lib_memend THEN // only when first item!
|
IF size_t = 0
|
||||||
|
EXIT
|
||||||
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
|
|
||||||
POKEW lib_alloctable_end , newspaceb
|
|
||||||
DEC lib_alloctable_end
|
|
||||||
DEC lib_alloctable_end
|
|
||||||
POKEW lib_alloctable_end , newspacee
|
|
||||||
|
|
||||||
LET result GET newspaceb
|
|
||||||
|
|
||||||
GOTO lib_malloc_exit;
|
|
||||||
|
|
||||||
ENDIF
|
ENDIF
|
||||||
//else if this is not the first item then:
|
|
||||||
|
needed_size = size_t + 2
|
||||||
WORD lib_malloc_ptr
|
|
||||||
WORD lib_malloc_spaceend
|
current = lib_memlib_free_head
|
||||||
WORD lib_malloc_spacestart
|
prev = NULL
|
||||||
|
|
||||||
//LET lib_malloc_ptr GET lib_memend
|
WHILE current != NULL
|
||||||
//SUBT lib_malloc_ptr - 3 -> lib_malloc_ptr
|
block_size = PEEKW current[0]
|
||||||
LET lib_malloc_ptr GET lib_alloctable_end
|
|
||||||
|
IF block_size >= needed_size
|
||||||
lib_malloc_spaceend = PEEKW lib_malloc_ptr
|
next_free = PEEKW current[2]
|
||||||
|
alloc_addr = current
|
||||||
LET newspaceb GET NULL //if not found afterwards
|
|
||||||
|
remaining = block_size - needed_size
|
||||||
WHILE 1
|
|
||||||
|
IF remaining >= 6
|
||||||
//if we reached the last record in the alloc-table
|
POKEW current[0] , needed_size
|
||||||
IF lib_malloc_ptr = lib_alloctable_end THEN
|
|
||||||
//is there sufficient space left @ top of heap?
|
split_addr = current + needed_size
|
||||||
INC lib_malloc_spaceend
|
current = split_addr
|
||||||
SUBT newtableend - lib_malloc_spaceend -> maxsize
|
POKEW current[0] , remaining
|
||||||
|
POKEW current[2] , next_free
|
||||||
IF maxsize > size_t THEN
|
|
||||||
LET newspaceb GET lib_malloc_spaceend
|
IF prev = NULL
|
||||||
ADD size_t + newspaceb -> newspacee
|
lib_memlib_free_head = split_addr
|
||||||
ENDIF
|
ELSE
|
||||||
|
current = prev
|
||||||
BREAK
|
POKEW current[2] , split_addr
|
||||||
ENDIF
|
|
||||||
|
|
||||||
DEC lib_malloc_ptr
|
|
||||||
DEC lib_malloc_ptr
|
|
||||||
lib_malloc_spacestart = PEEKW lib_malloc_ptr
|
|
||||||
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
|
|
||||||
lib_malloc_spaceend = PEEKW lib_malloc_ptr
|
|
||||||
|
|
||||||
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
|
|
||||||
POKEW lib_alloctable_end , newspaceb
|
|
||||||
DEC lib_alloctable_end
|
|
||||||
DEC lib_alloctable_end
|
|
||||||
POKEW lib_alloctable_end , 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
|
|
||||||
POKEW lib_malloc_ptr , newspaceb
|
|
||||||
DEC lib_malloc_ptr
|
|
||||||
DEC lib_malloc_ptr
|
|
||||||
POKEW lib_malloc_ptr , 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
|
|
||||||
startaddr = PEEKW ptr
|
|
||||||
|
|
||||||
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
|
ENDIF
|
||||||
DEC from
|
ELSE
|
||||||
DEC to
|
IF prev = NULL
|
||||||
WEND
|
lib_memlib_free_head = next_free
|
||||||
|
ELSE
|
||||||
ADD 4 + lib_alloctable_end -> lib_alloctable_end
|
current = prev
|
||||||
|
POKEW current[2] , next_free
|
||||||
BREAK
|
ENDIF
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
result = alloc_addr + 2
|
||||||
|
EXIT
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
DEC ptr
|
prev = current
|
||||||
DEC ptr
|
WORD temp
|
||||||
|
temp = PEEKW current[2]
|
||||||
IF ptr = lib_alloctable_end THEN
|
current = temp
|
||||||
BREAK
|
|
||||||
ENDIF
|
|
||||||
|
|
||||||
DEC ptr
|
|
||||||
DEC ptr
|
|
||||||
|
|
||||||
WEND
|
WEND
|
||||||
|
|
||||||
|
FEND
|
||||||
|
|
||||||
LABEL lib_free_exit
|
//-----------------------------------------------------------
|
||||||
|
// 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
|
FEND
|
||||||
|
|
||||||
LABEL lib_memlib_skip
|
LABEL lib_memlib_skip
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue