* device/lib/pic16/libdev/pic18f[24][45]j10.c: fixed svn atrributes
[fw/sdcc] / device / lib / malloc.c
index 00439285906a51957f92bb4f4851a88f8cc5da80..e52fa7fa72e8496cde163cb3aba27e0447e28554 100644 (file)
@@ -1,21 +1,47 @@
+/*-------------------------------------------------------------------------
+   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. */
@@ -36,8 +62,9 @@ _sdcc_heap_init(void)
 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))
     {
@@ -47,71 +74,55 @@ malloc (unsigned int 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 &current_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 = &current_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
@@ -125,111 +136,100 @@ free (void *p)
             //--------------------------------------------------------------------
             //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