blob: 4ce50b1756168294c3eaf14bbeb5aa9c4bc45146 [file] [log] [blame]
kthacker62e146c2006-04-17 15:11:35 +00001#include <sdcc-lib.h>
Adrien Destugues69a6e722017-06-03 10:17:17 +02002#include <stdlib.h>
kthacker62e146c2006-04-17 15:11:35 +00003
4typedef struct _MEMHEADER MEMHEADER;
5
6struct _MEMHEADER
7{
8 MEMHEADER * next;
9 MEMHEADER * prev;
10 unsigned int len;
11 unsigned char mem;
12};
13
14#define HEADER_SIZE (sizeof(MEMHEADER)-sizeof(char))
15
16/* These veriables are defined through the crt0 functions. */
17/* Base of this variable is the first byte of the heap. */
18//extern MEMHEADER _sdcc_heap_start;
19/* Address of this variable is the last byte of the heap. */
20//extern char _sdcc_heap_end;
21
kthacker62e146c2006-04-17 15:11:35 +000022extern char progend;
23
PulkoMandy8ecb97e2014-07-01 19:14:44 +020024unsigned int _heapmaxavail;
25
kthacker62e146c2006-04-17 15:11:35 +000026static 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
PulkoMandy8ecb97e2014-07-01 19:14:44 +020041 /* this is our first mem header - right after the end of the code area */
PulkoMandy66b4e3c2014-06-28 17:12:39 +020042 firstheader = (MEMHEADER *)(&progend);
kthacker62e146c2006-04-17 15:11:35 +000043
PulkoMandy8ecb97e2014-07-01 19:14:44 +020044 /* this is the size of ram available - read from firmware */
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.
PulkoMandy8ecb97e2014-07-01 19:14:44 +020059
60 _heapmaxavail = ramend - &progend;
kthacker62e146c2006-04-17 15:11:35 +000061}
62
63void *
64malloc (unsigned int size)
65{
66 MEMHEADER * current_header;
67 MEMHEADER * new_header;
68
69 if (size>(0xFFFF-HEADER_SIZE))
70 {
71 return NULL; //To prevent overflow in next line
72 }
73
74 size += HEADER_SIZE; //We need a memory for header too
75 current_header = firstheader;
76
77 while (1)
78 {
79 // current
80 // | len next
81 // v v v
82 //....*****.........******....
83 // ^^^^^^^^^
84 // spare
85
86 if ((((unsigned int)current_header->next) -
87 ((unsigned int)current_header) -
88 current_header->len) >= size)
89 {
90 break; //if spare is more than need
91 }
92 current_header = current_header->next; //else try next
93 if (!current_header->next)
94 {
95 return NULL; //if end_of_list reached
96 }
97 }
98
99 if (!current_header->len)
100 { //This code works only for first_header in the list and only
101 current_header->len = size; //for first allocation
102 return &current_header->mem;
103 }
104 else
105 {
106 //else create new header at the begin of spare
107 new_header = (MEMHEADER * )((char *)current_header + current_header->len);
108 new_header->next = current_header->next; //and plug it into the chain
109 new_header->prev = current_header;
110 current_header->next = new_header;
111 if (new_header->next)
112 {
113 new_header->next->prev = new_header;
114 }
115 new_header->len = size; //mark as used
116 return &new_header->mem;
117 }
118}
119
120void
121free (void *p)
122{
123 MEMHEADER *prev_header, *pthis;
124
125 if ( p ) //For allocated pointers only!
126 {
127 pthis = (MEMHEADER * )((char *) p - HEADER_SIZE); //to start of header
128 if ( pthis->prev ) // For the regular header
129 {
130 prev_header = pthis->prev;
131 prev_header->next = pthis->next;
132 if (pthis->next)
133 {
134 pthis->next->prev = prev_header;
135 }
136 }
137 else
138 {
139 pthis->len = 0; //For the first header
140 }
141 }
142}
143
PulkoMandy8ecb97e2014-07-01 19:14:44 +0200144
145/* Compute free memory */
146unsigned int _heapmemavail()
147{
148 unsigned int avail = _heapmaxavail;
149 MEMHEADER* header;
150
151 for (header = firstheader; header; header = header->next)
152 avail -= header->len + sizeof(MEMHEADER);
153
154 return avail;
155}