blob: 75943c1acb052f29d48dd9190c52b810f18794cd [file] [log] [blame]
kthacker62e146c2006-04-17 15:11:35 +00001#include <sdcc-lib.h>
2#include <malloc.h>
3
4#if _SDCC_MALLOC_TYPE_MLH
5
6typedef struct _MEMHEADER MEMHEADER;
7
8struct _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
18/* These veriables are defined through the crt0 functions. */
19/* Base of this variable is the first byte of the heap. */
20//extern MEMHEADER _sdcc_heap_start;
21/* Address of this variable is the last byte of the heap. */
22//extern char _sdcc_heap_end;
23
kthacker62e146c2006-04-17 15:11:35 +000024extern char progend;
25
PulkoMandy8ecb97e2014-07-01 19:14:44 +020026unsigned int _heapmaxavail;
27
kthacker62e146c2006-04-17 15:11:35 +000028static MEMHEADER *firstheader;
29/* setup two headers. One at start of free ram, second at end of free ram.
PulkoMandy66b4e3c2014-06-28 17:12:39 +020030 *
31 * Free ram starts after the _BSS segment.
32 * Free RAM ends before the memory used by expansion ROMs. For now we only
33 * consider ROM 7 (AMSDOS), which must be initialized before calling
34 * _sdcc_heap_init - probably in crt0.s...
35 */
kthacker62e146c2006-04-17 15:11:35 +000036
37void
38_sdcc_heap_init(void)
39{
40 MEMHEADER *lastheader;
PulkoMandy66b4e3c2014-06-28 17:12:39 +020041 int ramend;
kthacker62e146c2006-04-17 15:11:35 +000042
PulkoMandy8ecb97e2014-07-01 19:14:44 +020043 /* this is our first mem header - right after the end of the code area */
PulkoMandy66b4e3c2014-06-28 17:12:39 +020044 firstheader = (MEMHEADER *)(&progend);
kthacker62e146c2006-04-17 15:11:35 +000045
PulkoMandy8ecb97e2014-07-01 19:14:44 +020046 /* this is the size of ram available - read from firmware */
PulkoMandy66b4e3c2014-06-28 17:12:39 +020047 ramend = *(int*)(0xb8e8);
kthacker62e146c2006-04-17 15:11:35 +000048
49 /* calc address of last header */
PulkoMandy66b4e3c2014-06-28 17:12:39 +020050 lastheader = (MEMHEADER *)(ramend - HEADER_SIZE);
kthacker62e146c2006-04-17 15:11:35 +000051
52 /* setup last header */
53 lastheader->next = NULL;
54 lastheader->prev = firstheader;
55 lastheader->len = 0;
56
57 /* setup first header */
58 firstheader->next = lastheader;
59 firstheader->prev = NULL; //and mark first as first
60 firstheader->len = 0; //Empty and ready.
PulkoMandy8ecb97e2014-07-01 19:14:44 +020061
62 _heapmaxavail = ramend - &progend;
kthacker62e146c2006-04-17 15:11:35 +000063}
64
65void *
66malloc (unsigned int size)
67{
68 MEMHEADER * current_header;
69 MEMHEADER * new_header;
70
71 if (size>(0xFFFF-HEADER_SIZE))
72 {
73 return NULL; //To prevent overflow in next line
74 }
75
76 size += HEADER_SIZE; //We need a memory for header too
77 current_header = firstheader;
78
79 while (1)
80 {
81 // current
82 // | len next
83 // v v v
84 //....*****.........******....
85 // ^^^^^^^^^
86 // spare
87
88 if ((((unsigned int)current_header->next) -
89 ((unsigned int)current_header) -
90 current_header->len) >= size)
91 {
92 break; //if spare is more than need
93 }
94 current_header = current_header->next; //else try next
95 if (!current_header->next)
96 {
97 return NULL; //if end_of_list reached
98 }
99 }
100
101 if (!current_header->len)
102 { //This code works only for first_header in the list and only
103 current_header->len = size; //for first allocation
104 return &current_header->mem;
105 }
106 else
107 {
108 //else create new header at the begin of spare
109 new_header = (MEMHEADER * )((char *)current_header + current_header->len);
110 new_header->next = current_header->next; //and plug it into the chain
111 new_header->prev = current_header;
112 current_header->next = new_header;
113 if (new_header->next)
114 {
115 new_header->next->prev = new_header;
116 }
117 new_header->len = size; //mark as used
118 return &new_header->mem;
119 }
120}
121
122void
123free (void *p)
124{
125 MEMHEADER *prev_header, *pthis;
126
127 if ( p ) //For allocated pointers only!
128 {
129 pthis = (MEMHEADER * )((char *) p - HEADER_SIZE); //to start of header
130 if ( pthis->prev ) // For the regular header
131 {
132 prev_header = pthis->prev;
133 prev_header->next = pthis->next;
134 if (pthis->next)
135 {
136 pthis->next->prev = prev_header;
137 }
138 }
139 else
140 {
141 pthis->len = 0; //For the first header
142 }
143 }
144}
145
PulkoMandy8ecb97e2014-07-01 19:14:44 +0200146
147/* Compute free memory */
148unsigned int _heapmemavail()
149{
150 unsigned int avail = _heapmaxavail;
151 MEMHEADER* header;
152
153 for (header = firstheader; header; header = header->next)
154 avail -= header->len + sizeof(MEMHEADER);
155
156 return avail;
157}
158
159
kthacker62e146c2006-04-17 15:11:35 +0000160#else
161
162 //--------------------------------------------------------------------
163 //Written by Dmitry S. Obukhov, 1997
164 //dso@usa.net
165 //--------------------------------------------------------------------
166 //Modified for SDCC by Sandeep Dutta, 1999
167 //sandeep.dutta@usa.net
168 //--------------------------------------------------------------------
169 //malloc and free functions implementation for embedded system
170 //Non-ANSI keywords are C51 specific.
171 // xdata - variable in external memory (just RAM)
172 //--------------------------------------------------------------------
173
174 #define MEMHEADER struct MAH// Memory Allocation Header
175
176 MEMHEADER
177 {
178 MEMHEADER xdata * next;
179 MEMHEADER xdata * prev;
180 unsigned int len;
181 unsigned char mem;
182 };
183
184 #define HEADER_SIZE (sizeof(MEMHEADER)-1)
185
186 //Static here means: can be accessed from this module only
187 static MEMHEADER xdata * FIRST_MEMORY_HEADER_PTR;
188 void init_dynamic_memory(MEMHEADER xdata * array, unsigned int size)
189 {
190
191 //This function MUST be called after the RESET.
192 //Parameters: array - pointer to memory allocated by the linker
193 // size - size of this memory pool
194 //Example:
195 // #define DYNAMIC_MEMORY_SIZE 0x2000
196 // .....
197 // unsigned char xdata dynamic_memory_pool[DYNAMIC_MEMORY_SIZE];
198 // unsigned char xdata * current_buffer;
199 // .....
200 // void main(void)
201 // {
202 // ...
203 // init_dynamic_memory(dynamic_memory_pool,DYNAMIC_MEMORY_SIZE);
204 // Now it is possible to use malloc.
205 // ...
206 // current_buffer = malloc(0x100);
207 //
208 //
209
210 if ( !array ) /*Reserved memory starts on 0x0000 but it's NULL...*/
211 { //So, we lost one byte!
212 array = (MEMHEADER xdata * )((char xdata * ) array + 1) ;
213 size --;
214 }
215 FIRST_MEMORY_HEADER_PTR = array;
216 //Reserve a mem for last header
217 array->next = (MEMHEADER xdata * )(((char xdata * ) array) + size - HEADER_SIZE);
218 array->next->next = (void xdata * ) NULL; //And mark it as last
219 array->prev = (void xdata * ) NULL; //and mark first as first
220 array->len = 0; //Empty and ready.
221 }
222
223 void xdata * malloc (unsigned int size)
224 {
225 register MEMHEADER xdata * current_header;
226 register MEMHEADER xdata * new_header;
227
228 if (size>(0xFFFF-HEADER_SIZE)) return (void xdata *) NULL; //To prevent overflow in next line
229 size += HEADER_SIZE; //We need a memory for header too
230 current_header = FIRST_MEMORY_HEADER_PTR;
231 while (1)
232 {
233
234 // current
235 // | len next
236 // v v v
237 //....*****.........******....
238 // ^^^^^^^^^
239 // spare
240
241 if ((((unsigned int)current_header->next) -
242 ((unsigned int)current_header) -
243 current_header->len) >= size) break; //if spare is more than need
244 current_header = current_header->next; //else try next
245 if (!current_header->next) return (void xdata *) NULL; //if end_of_list reached
246 }
247 if (!current_header->len)
248 { //This code works only for first_header in the list and only
249 current_header->len = size; //for first allocation
250 return ((xdata *)&(current_header->mem));
251 } //else create new header at the begin of spare
252 new_header = (MEMHEADER xdata * )((char xdata *)current_header + current_header->len);
253 new_header->next = current_header->next; //and plug it into the chain
254 new_header->prev = current_header;
255 current_header->next = new_header;
256 if (new_header->next) new_header->next->prev = new_header;
257 new_header->len = size; //mark as used
258 return ((xdata *)&(new_header->mem));
259 }
260
261 void free (void xdata * p)
262 {
263 register MEMHEADER xdata * prev_header;
264 if ( p ) //For allocated pointers only!
265 {
266 p = (MEMHEADER xdata * )((char xdata *) p - HEADER_SIZE); //to start of header
267 if ( ((MEMHEADER xdata * ) p)->prev ) // For the regular header
268 {
269 prev_header = ((MEMHEADER xdata * ) p)->prev;
270 prev_header->next = ((MEMHEADER xdata * ) p)->next;
271 if (((MEMHEADER xdata * ) p)->next)
272 ((MEMHEADER xdata * ) p)->next->prev = prev_header;
273 }
274 else ((MEMHEADER xdata * ) p)->len = 0; //For the first header
275 }
276 }
277 //END OF MODULE
278#endif