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