* device/include/malloc.h: Added z80 and gbz80 support.
[fw/sdcc] / device / lib / malloc.c
1 #include <sdcc-lib.h>
2
3 #if _SDCC_MALLOC_TYPE_MLH
4 #include <malloc.h>
5
6 typedef struct _MEMHEADER MEMHEADER;
7
8 struct _MEMHEADER
9 {
10   MEMHEADER *  next;
11   MEMHEADER *  prev;
12   unsigned int       len;
13   unsigned char      mem;
14 };
15
16 #define HEADER_SIZE (sizeof(MEMHEADER)-sizeof(char))
17 #define NULL        0
18
19 /* These veriables are defined through the crt0 functions. */
20 /* Base of this variable is the first byte of the heap. */
21 extern MEMHEADER _sdcc_heap_start;
22 /* Address of this variable is the last byte of the heap. */
23 extern char _sdcc_heap_end;
24
25 void 
26 _sdcc_heap_init(void)
27 {
28   MEMHEADER *pbase = &_sdcc_heap_start;
29   unsigned int size = &_sdcc_heap_end - (char *)pbase;
30
31   pbase->next = (MEMHEADER *)((char *)pbase + size - HEADER_SIZE);
32   pbase->next->next = NULL; //And mark it as last
33   pbase->prev       = NULL; //and mark first as first
34   pbase->len        = 0;    //Empty and ready.
35 }
36
37 void *
38 malloc (unsigned int size)
39 {
40   MEMHEADER * current_header;
41   MEMHEADER * new_header;
42
43   if (size>(0xFFFF-HEADER_SIZE))
44     {
45       return NULL; //To prevent overflow in next line
46     }
47
48   size += HEADER_SIZE; //We need a memory for header too
49   current_header = &_sdcc_heap_start;
50
51   while (1)
52     {
53       //    current
54       //    |   len       next
55       //    v   v         v
56       //....*****.........******....
57       //         ^^^^^^^^^
58       //           spare
59
60       if ((((unsigned int)current_header->next) -
61            ((unsigned int)current_header) -
62            current_header->len) >= size) 
63         {
64           break; //if spare is more than need
65         }
66       current_header = current_header->next;    //else try next             
67       if (!current_header->next)  
68         {
69           return NULL;  //if end_of_list reached    
70         }
71     }
72
73   if (!current_header->len)
74     { //This code works only for first_header in the list and only
75       current_header->len = size; //for first allocation
76       return &current_header->mem;
77     } 
78   else
79     {
80       //else create new header at the begin of spare
81       new_header = (MEMHEADER * )((char *)current_header + current_header->len);
82       new_header->next = current_header->next; //and plug it into the chain
83       new_header->prev = current_header;
84       current_header->next  = new_header;
85       if (new_header->next)
86         {
87           new_header->next->prev = new_header;
88         }
89       new_header->len  = size; //mark as used
90       return &new_header->mem;
91     }
92 }
93
94 void 
95 free (void *p)
96 {
97   MEMHEADER *prev_header, *pthis;
98
99   if ( p ) //For allocated pointers only!
100     {
101       pthis = (MEMHEADER * )((char *)  p - HEADER_SIZE); //to start of header
102       if ( pthis->prev ) // For the regular header
103         {
104           prev_header = pthis->prev;
105           prev_header->next = pthis->next;
106           if (pthis->next)  
107             {
108               pthis->next->prev = prev_header;
109             }
110         }
111       else 
112         {
113           pthis->len = 0; //For the first header
114         }
115     }
116 }
117
118 #else
119
120             //--------------------------------------------------------------------
121             //Written by Dmitry S. Obukhov, 1997
122             //dso@usa.net
123             //--------------------------------------------------------------------
124             //Modified for SDCC by Sandeep Dutta, 1999
125             //sandeep.dutta@usa.net
126             //--------------------------------------------------------------------
127             //malloc and free functions implementation for embedded system
128             //Non-ANSI keywords are C51 specific.
129             // xdata - variable in external memory (just RAM)
130             //--------------------------------------------------------------------
131
132             #define MEMHEADER   struct MAH// Memory Allocation Header
133
134             MEMHEADER
135             {
136               MEMHEADER xdata *  next;
137               MEMHEADER xdata *  prev;
138               unsigned int       len;
139               unsigned char      mem;
140             };
141
142             #define HEADER_SIZE (sizeof(MEMHEADER)-1)
143             #define NULL        (void xdata * ) 0
144
145
146             //Static here means: can be accessed from this module only
147             static MEMHEADER xdata * FIRST_MEMORY_HEADER_PTR;
148             void init_dynamic_memory(MEMHEADER xdata * array, unsigned int size) 
149             {
150
151             //This function MUST be called after the RESET.
152             //Parameters: array - pointer to memory allocated by the linker
153             //            size  - size of this memory pool
154             //Example:
155             //     #define DYNAMIC_MEMORY_SIZE 0x2000
156             //     .....
157             //     unsigned char xdata dynamic_memory_pool[DYNAMIC_MEMORY_SIZE];
158             //     unsigned char xdata * current_buffer;
159             //     .....
160             //     void main(void)
161             //     {
162             //         ...
163             //         init_dynamic_memory(dynamic_memory_pool,DYNAMIC_MEMORY_SIZE);
164             //         Now it is possible to use malloc.
165             //         ...
166             //         current_buffer = malloc(0x100);
167             //
168             //
169
170               if ( !array ) /*Reserved memory starts on 0x0000 but it's NULL...*/
171               {             //So, we lost one byte!
172                  array = (MEMHEADER xdata * )((char xdata * ) array + 1) ;
173                  size --;
174               }
175               FIRST_MEMORY_HEADER_PTR = array;
176               //Reserve a mem for last header
177               array->next = (MEMHEADER xdata * )(((char xdata * ) array) + size - HEADER_SIZE);
178               array->next->next = NULL; //And mark it as last
179               array->prev       = NULL; //and mark first as first
180               array->len        = 0;    //Empty and ready.
181             }
182
183             void  xdata * malloc (unsigned int size)
184             {
185               register MEMHEADER xdata * current_header;
186               register MEMHEADER xdata * new_header;
187
188               if (size>(0xFFFF-HEADER_SIZE)) return NULL; //To prevent overflow in next line
189               size += HEADER_SIZE; //We need a memory for header too
190               current_header = FIRST_MEMORY_HEADER_PTR;
191               while (1)
192               {
193
194                 //    current
195                 //    |   len       next
196                 //    v   v         v
197                 //....*****.........******....
198                 //         ^^^^^^^^^
199                 //           spare
200
201                 if ((((unsigned int)current_header->next) -
202                      ((unsigned int)current_header) -
203                      current_header->len) >= size) break; //if spare is more than need
204                 current_header = current_header->next;    //else try next             
205                 if (!current_header->next)  return NULL;  //if end_of_list reached    
206               }
207               if (!current_header->len)
208               { //This code works only for first_header in the list and only
209                  current_header->len = size; //for first allocation
210                  return ((xdata *)&(current_header->mem));
211               } //else create new header at the begin of spare
212               new_header = (MEMHEADER xdata * )((char xdata *)current_header + current_header->len);
213               new_header->next = current_header->next; //and plug it into the chain
214               new_header->prev = current_header;
215               current_header->next  = new_header;
216               if (new_header->next)  new_header->next->prev = new_header;
217               new_header->len  = size; //mark as used
218               return ((xdata *)&(new_header->mem));
219             }
220
221             void free (MEMHEADER xdata * p)
222             {
223               register MEMHEADER xdata * prev_header;
224               if ( p ) //For allocated pointers only!
225               {
226                   p = (MEMHEADER xdata * )((char xdata *)  p - HEADER_SIZE); //to start of header
227                   if ( p->prev ) // For the regular header
228                   {
229                     prev_header = p->prev;
230                     prev_header->next = p->next;
231                     if (p->next)  p->next->prev = prev_header;
232                   }
233                   else p->len = 0; //For the first header
234               }
235             }
236             //END OF MODULE
237
238 #endif