+/*-------------------------------------------------------------------------
+ malloc.c - allocate memory.
+
+ Copyright (C) 2004 - Maarten Brock, sourceforge.brock@dse.nl
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-------------------------------------------------------------------------*/
+
#include <sdcc-lib.h>
#include <malloc.h>
+#if defined(SDCC_STACK_AUTO) || defined(SDCC_z80) || defined(SDCC_gbz80)
+ #define CRITICAL __critical
+#else
+ #define CRITICAL
+#endif
+
#if _SDCC_MALLOC_TYPE_MLH
typedef struct _MEMHEADER MEMHEADER;
struct _MEMHEADER
{
- MEMHEADER * next;
- MEMHEADER * prev;
- unsigned int len;
- unsigned char mem;
+ MEMHEADER * next;
+ MEMHEADER * prev;
+ unsigned int len;
+ unsigned char mem;
};
#define HEADER_SIZE (sizeof(MEMHEADER)-sizeof(char))
-/* These veriables are defined through the crt0 functions. */
+/* These variables are defined through the crt0 functions. */
/* Base of this variable is the first byte of the heap. */
extern MEMHEADER _sdcc_heap_start;
/* Address of this variable is the last byte of the heap. */
void *
malloc (unsigned int size)
{
- MEMHEADER * current_header;
- MEMHEADER * new_header;
+ register MEMHEADER * current_header;
+ register MEMHEADER * new_header;
+ register void * ret;
if (size>(0xFFFF-HEADER_SIZE))
{
size += HEADER_SIZE; //We need a memory for header too
current_header = &_sdcc_heap_start;
- while (1)
- {
- // current
- // | len next
- // v v v
- //....*****.........******....
- // ^^^^^^^^^
- // spare
-
- if ((((unsigned int)current_header->next) -
- ((unsigned int)current_header) -
- current_header->len) >= size)
- {
- break; //if spare is more than need
- }
- current_header = current_header->next; //else try next
- if (!current_header->next)
- {
- return NULL; //if end_of_list reached
- }
- }
-
- if (!current_header->len)
- { //This code works only for first_header in the list and only
- current_header->len = size; //for first allocation
- return ¤t_header->mem;
- }
- else
+ CRITICAL
{
- //else create new header at the begin of spare
- new_header = (MEMHEADER * )((char *)current_header + current_header->len);
- new_header->next = current_header->next; //and plug it into the chain
- new_header->prev = current_header;
- current_header->next = new_header;
- if (new_header->next)
+ while (1)
{
- new_header->next->prev = new_header;
+ // current
+ // | len next
+ // v v v
+ //....*****.........******....
+ // ^^^^^^^^^
+ // spare
+
+ if ((((unsigned int)current_header->next) -
+ ((unsigned int)current_header) -
+ current_header->len) >= size)
+ { //if spare is more than needed
+ ret = ¤t_header->mem;
+ break;
+ }
+ current_header = current_header->next; //else try next
+ if (!current_header->next)
+ { //if end_of_list reached
+ ret = NULL;
+ break;
+ }
}
- new_header->len = size; //mark as used
- return &new_header->mem;
- }
-}
-
-void
-free (void *p)
-{
- MEMHEADER *prev_header, *pthis;
- if ( p ) //For allocated pointers only!
- {
- pthis = (MEMHEADER * )((char *) p - HEADER_SIZE); //to start of header
- if ( pthis->prev ) // For the regular header
+ if (ret)
{
- prev_header = pthis->prev;
- prev_header->next = pthis->next;
- if (pthis->next)
+ if (!current_header->len)
+ { //This code works only for first_header in the list and only
+ current_header->len = size; //for first allocation
+ }
+ else
{
- pthis->next->prev = prev_header;
+ //else create new header at the begin of spare
+ new_header = (MEMHEADER * )((char *)current_header + current_header->len);
+ new_header->next = current_header->next; //and plug it into the chain
+ new_header->prev = current_header;
+ current_header->next = new_header;
+ if (new_header->next)
+ {
+ new_header->next->prev = new_header;
+ }
+ new_header->len = size; //mark as used
+ ret = &new_header->mem;
}
}
- else
- {
- pthis->len = 0; //For the first header
- }
}
+ return ret;
}
#else
//--------------------------------------------------------------------
//malloc and free functions implementation for embedded system
//Non-ANSI keywords are C51 specific.
- // xdata - variable in external memory (just RAM)
+ // __xdata - variable in external memory (just RAM)
//--------------------------------------------------------------------
#define MEMHEADER struct MAH// Memory Allocation Header
MEMHEADER
{
- MEMHEADER xdata * next;
- MEMHEADER xdata * prev;
- unsigned int len;
- unsigned char mem;
+ MEMHEADER __xdata * next;
+ unsigned int len;
+ unsigned char mem[];
};
- #define HEADER_SIZE (sizeof(MEMHEADER)-1)
+ #define HEADER_SIZE sizeof(MEMHEADER)
+
+ MEMHEADER __xdata * _sdcc_first_memheader = NULL;
- //Static here means: can be accessed from this module only
- static MEMHEADER xdata * FIRST_MEMORY_HEADER_PTR;
- void init_dynamic_memory(MEMHEADER xdata * array, unsigned int size)
+ extern __xdata char _sdcc_heap[];
+ extern const unsigned int _sdcc_heap_size;
+
+ static void init_dynamic_memory(void)
{
+ char __xdata * heap = (char __xdata *)_sdcc_heap;
+ unsigned int size = _sdcc_heap_size;
- //This function MUST be called after the RESET.
- //Parameters: array - pointer to memory allocated by the linker
- // size - size of this memory pool
- //Example:
- // #define DYNAMIC_MEMORY_SIZE 0x2000
- // .....
- // unsigned char xdata dynamic_memory_pool[DYNAMIC_MEMORY_SIZE];
- // unsigned char xdata * current_buffer;
- // .....
- // void main(void)
- // {
- // ...
- // init_dynamic_memory(dynamic_memory_pool,DYNAMIC_MEMORY_SIZE);
- // Now it is possible to use malloc.
- // ...
- // current_buffer = malloc(0x100);
- //
- //
-
- if ( !array ) /*Reserved memory starts on 0x0000 but it's NULL...*/
+ if ( !heap ) //Reserved memory starts at 0x0000 but that's NULL...
{ //So, we lost one byte!
- array = (MEMHEADER xdata * )((char xdata * ) array + 1) ;
- size --;
+ heap++;
+ size--;
}
- FIRST_MEMORY_HEADER_PTR = array;
+ _sdcc_first_memheader = (MEMHEADER __xdata * ) heap;
//Reserve a mem for last header
- array->next = (MEMHEADER xdata * )(((char xdata * ) array) + size - HEADER_SIZE);
- array->next->next = (void xdata * ) NULL; //And mark it as last
- array->prev = (void xdata * ) NULL; //and mark first as first
- array->len = 0; //Empty and ready.
+ _sdcc_first_memheader->next = (MEMHEADER __xdata * )(heap + size - sizeof(MEMHEADER __xdata *));
+ _sdcc_first_memheader->next->next = (MEMHEADER __xdata * ) NULL; //And mark it as last
+ _sdcc_first_memheader->len = 0; //Empty and ready.
}
- void xdata * malloc (unsigned int size)
+ void __xdata * malloc (unsigned int size)
{
- register MEMHEADER xdata * current_header;
- register MEMHEADER xdata * new_header;
+ register MEMHEADER __xdata * current_header;
+ register MEMHEADER __xdata * new_header;
+ register void __xdata * ret;
- if (size>(0xFFFF-HEADER_SIZE)) return (void xdata *) NULL; //To prevent overflow in next line
+ if (size>(0xFFFF-HEADER_SIZE))
+ return (void __xdata *) NULL; //To prevent overflow in next line
size += HEADER_SIZE; //We need a memory for header too
- current_header = FIRST_MEMORY_HEADER_PTR;
- while (1)
- {
- // current
- // | len next
- // v v v
- //....*****.........******....
- // ^^^^^^^^^
- // spare
-
- if ((((unsigned int)current_header->next) -
- ((unsigned int)current_header) -
- current_header->len) >= size) break; //if spare is more than need
- current_header = current_header->next; //else try next
- if (!current_header->next) return (void xdata *) NULL; //if end_of_list reached
- }
- if (!current_header->len)
- { //This code works only for first_header in the list and only
- current_header->len = size; //for first allocation
- return ((xdata *)&(current_header->mem));
- } //else create new header at the begin of spare
- new_header = (MEMHEADER xdata * )((char xdata *)current_header + current_header->len);
- new_header->next = current_header->next; //and plug it into the chain
- new_header->prev = current_header;
- current_header->next = new_header;
- if (new_header->next) new_header->next->prev = new_header;
- new_header->len = size; //mark as used
- return ((xdata *)&(new_header->mem));
- }
+ if (!_sdcc_first_memheader)
+ init_dynamic_memory();
- void free (void xdata * p)
- {
- register MEMHEADER xdata * prev_header;
- if ( p ) //For allocated pointers only!
+ current_header = _sdcc_first_memheader;
+ CRITICAL
{
- p = (MEMHEADER xdata * )((char xdata *) p - HEADER_SIZE); //to start of header
- if ( ((MEMHEADER xdata * ) p)->prev ) // For the regular header
- {
- prev_header = ((MEMHEADER xdata * ) p)->prev;
- prev_header->next = ((MEMHEADER xdata * ) p)->next;
- if (((MEMHEADER xdata * ) p)->next)
- ((MEMHEADER xdata * ) p)->next->prev = prev_header;
+ while (1)
+ {
+
+ // current
+ // | len next
+ // v v v
+ //....*****.........******....
+ // ^^^^^^^^^
+ // spare
+
+ if ((((unsigned int)current_header->next) -
+ ((unsigned int)current_header) -
+ current_header->len) >= size)
+ { //if spare is more than needed
+ ret = current_header->mem;
+ break;
+ }
+ current_header = current_header->next; //else try next
+ if (!current_header->next)
+ { //if end_of_list reached
+ ret = (void __xdata *) NULL;
+ break;
+ }
+ }
+ if (ret)
+ {
+ if (!current_header->len)
+ { //This code works only for first_header in the list and only
+ current_header->len = size; //for first allocation
}
- else ((MEMHEADER xdata * ) p)->len = 0; //For the first header
+ else
+ { //else create new header at the begin of spare
+ new_header = (MEMHEADER __xdata * )((char __xdata *)current_header + current_header->len);
+ new_header->next = current_header->next; //and plug it into the chain
+ current_header->next = new_header;
+ new_header->len = size; //mark as used
+ ret = new_header->mem;
+ }
+ }
}
+ return ret;
}
+
//END OF MODULE
#endif