Skip to content

Commit 4fae833

Browse files
parissebadriweb
andcommitted
libc: add VRAM2 allocator.
Co-authored-by: Adrien Bertrand <[email protected]>
1 parent 8a22267 commit 4fae833

File tree

2 files changed

+365
-3
lines changed

2 files changed

+365
-3
lines changed

src/libc/allocator.src

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,18 @@ _malloc := __simple_malloc
3333
_free := __simple_free
3434
_realloc := __simple_realloc
3535

36-
end if
37-
38-
if defined ALLOCATOR_STANDARD
36+
else if defined ALLOCATOR_STANDARD
3937

4038
_malloc := __standard_malloc
4139
_free := __standard_free
4240
_realloc := __standard_realloc
4341

42+
else if defined ALLOCATOR_VRAM2
43+
44+
_malloc := __vram2_malloc
45+
_free := __vram2_free
46+
_realloc := __vram2_realloc
47+
4448
end if
4549

4650
extern __simple_free
@@ -49,5 +53,8 @@ end if
4953
extern __standard_malloc
5054
extern __standard_free
5155
extern __standard_realloc
56+
extern __vram2_malloc
57+
extern __vram2_free
58+
extern __vram2_realloc
5259
extern __imulu
5360
extern _memset

src/libc/allocator_VRAM2.c

Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
#include <stddef.h>
2+
#include <stdint.h>
3+
#include <stdlib.h>
4+
#include <string.h>
5+
#include <sys/lcd.h>
6+
#include <debug.h>
7+
8+
// This allocator uses the 2nd part of the VRAM as the heap. It gives you 76K of memory,
9+
// but requires you to only use the first part of the VRAM for the LCD configured in 8bpp.
10+
11+
#define MALLOC_MINSIZE 6 // minimal size (avoid blocks that are too small)
12+
13+
static unsigned int freeslotpos(unsigned int n)
14+
{
15+
unsigned int r = 1;
16+
if ((n << 8) == 0)
17+
{
18+
// bit15 to 0 are 0, position must be >=16
19+
// otherwise position is <16
20+
r += 16;
21+
n >>= 16;
22+
}
23+
if ((n << 16) == 0)
24+
{
25+
// bit7 to 0 are 0, position must be >=8
26+
// otherwise position is <8
27+
r += 8;
28+
n >>= 8;
29+
}
30+
if ((n << 20) == 0)
31+
{
32+
r += 4;
33+
n >>= 4;
34+
}
35+
if ((n << 22) == 0)
36+
{
37+
r += 2;
38+
n >>= 2;
39+
}
40+
r -= n & 1;
41+
// dbg_printf("freeslotpos n=%p r=%zu\n",n,r);
42+
return r;
43+
}
44+
45+
typedef struct char2_ {
46+
char c1, c2, c3, c4;
47+
} char2_t;
48+
49+
typedef struct char3_ {
50+
char c1, c2, c3, c4, c5, c6, c7, c8, c9, c10;
51+
} char3_t;
52+
53+
typedef struct char6_ {
54+
char c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16;
55+
} char6_t;
56+
57+
typedef struct __attribute__((packed)) block
58+
{
59+
struct block* ptr;
60+
size_t size;
61+
} __attribute__((packed)) block_t;
62+
63+
extern uint8_t __heapbot[];
64+
extern uint8_t __heaptop[];
65+
66+
// assumes that heap2_ptrend<=lcd_Ram
67+
static uintptr_t heap2_ptr = (uintptr_t)__heapbot;
68+
static uintptr_t heap2_ptrend = (uintptr_t)__heaptop;
69+
70+
#define ALLOC2 (12 * INT24_WIDTH)
71+
static unsigned int freeslot2[ALLOC2 / INT24_WIDTH] = {
72+
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
73+
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
74+
};
75+
#define ALLOC3 (12 * INT24_WIDTH)
76+
static unsigned int freeslot3[ALLOC3 / INT24_WIDTH] = {
77+
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
78+
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
79+
};
80+
#define ALLOC6 (12 * INT24_WIDTH)
81+
static unsigned int freeslot6[ALLOC6 / INT24_WIDTH] = {
82+
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
83+
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
84+
};
85+
86+
#define LCD_SIZE_8BPP (LCD_WIDTH * LCD_HEIGHT)
87+
const char2_t* tab2 = lcd_Ram + LCD_SIZE_8BPP;
88+
const char3_t* tab3 = lcd_Ram + LCD_SIZE_8BPP + ALLOC2 * sizeof(char2_t);
89+
const char6_t* tab6 = lcd_Ram + LCD_SIZE_8BPP + ALLOC2 * sizeof(char2_t) + ALLOC3 * sizeof(char3_t);
90+
91+
static uintptr_t heap_ptr = (uintptr_t)(lcd_Ram + LCD_SIZE_8BPP + ALLOC2 * sizeof(char2_t) + ALLOC3 * sizeof(char3_t) + ALLOC6 * sizeof(char6_t));
92+
static uintptr_t heap_ptrend = (uintptr_t)(lcd_Ram + LCD_SIZE);
93+
94+
static block_t _alloc_base, _alloc2_base;
95+
// these are 0 initialized, pointing to a chained list of freed pointers
96+
97+
void* _vram2_malloc(const size_t alloc_size)
98+
{
99+
// dbg_printf("[malloc] %zu bytes\n", alloc_size);
100+
101+
if (alloc_size == 0)
102+
return NULL;
103+
104+
if (alloc_size == 0xFFFFFF)
105+
return (void*)((heap_ptrend - heap_ptr) + (heap2_ptrend - heap2_ptr));
106+
107+
if (alloc_size <= sizeof(char6_t))
108+
{
109+
if (tab2 && alloc_size <= sizeof(char2_t))
110+
{
111+
for (unsigned int i = 0; i < ALLOC2 / INT24_WIDTH;)
112+
{
113+
if (!(freeslot2[i] || freeslot2[i + 1]))
114+
{
115+
i += 2;
116+
continue;
117+
}
118+
if (freeslot2[i])
119+
{
120+
end2: {
121+
const unsigned int pos = freeslotpos(freeslot2[i]);
122+
freeslot2[i] &= ~(1 << pos);
123+
// dbg_printf("allocfast2 %p %p\n", tab2, tab2 + i * INT24_WIDTH + pos);
124+
return (void*)(tab2 + i * INT24_WIDTH + pos);
125+
}
126+
}
127+
++i;
128+
goto end2;
129+
}
130+
}
131+
if (tab3 && alloc_size <= sizeof(char3_t))
132+
{
133+
for (unsigned int i = 0; i < ALLOC3 / INT24_WIDTH;)
134+
{
135+
if (!(freeslot3[i] || freeslot3[i + 1]))
136+
{
137+
i += 2;
138+
continue;
139+
}
140+
if (freeslot3[i])
141+
{
142+
end3: {
143+
const unsigned int pos = freeslotpos(freeslot3[i]);
144+
freeslot3[i] &= ~(1 << pos);
145+
// dbg_printf("allocfast3 %p %p\n", tab3, tab3 + i * INT24_WIDTH + pos);
146+
return (void*)(tab3 + i * INT24_WIDTH + pos);
147+
}
148+
}
149+
i++;
150+
goto end3;
151+
}
152+
}
153+
if (tab6 && alloc_size <= sizeof(char6_t))
154+
{
155+
for (unsigned int i = 0; i < ALLOC6 / INT24_WIDTH;)
156+
{
157+
if (!(freeslot6[i] || freeslot6[i + 1]))
158+
{
159+
i += 2;
160+
continue;
161+
}
162+
if (freeslot6[i])
163+
{
164+
end6: {
165+
const unsigned int pos = freeslotpos(freeslot6[i]);
166+
freeslot6[i] &= ~(1 << pos);
167+
// dbg_printf("allocfast6 %p %p\n", tab6, tab6 + i * INT24_WIDTH + pos);
168+
return (void*)(tab6 + i * INT24_WIDTH + pos);
169+
}
170+
}
171+
++i;
172+
goto end6;
173+
}
174+
}
175+
}
176+
177+
block_t* q;
178+
block_t* r;
179+
180+
/* add size of block header to real size */
181+
size_t size = alloc_size + sizeof(block_t);
182+
if (size < alloc_size)
183+
return NULL;
184+
185+
// dbg_printf("alloc heap %p ptr=%p size=%zu\n",&_alloc_base,_alloc_base.ptr,_alloc_base.size);
186+
187+
for (block_t* p = &_alloc_base; (q = p->ptr); p = q)
188+
{
189+
if (q->size >= size)
190+
{
191+
if (q->size <= size + sizeof(block_t) + MALLOC_MINSIZE)
192+
{
193+
// dbg_printf("heap recycle full blocsize=%zu size=%zu\n", q->size, size);
194+
p->ptr = q->ptr;
195+
}
196+
else
197+
{
198+
// dbg_printf("heap recycle partial blocsize=%zu size=%zu\n", q->size, size);
199+
q->size -= size;
200+
q = (block_t*)(((uint8_t*)q) + q->size);
201+
q->size = size;
202+
}
203+
204+
return q + 1;
205+
}
206+
}
207+
208+
/* compute next heap pointer */
209+
if (heap_ptr + size < heap_ptr || heap_ptr + size >= (uintptr_t)heap_ptrend)
210+
{
211+
// dbg_printf("alloc heap2 %p ptr=%p size=%zu\n",&_alloc2_base,_alloc2_base.ptr,_alloc2_base.size);
212+
for (block_t* p = &_alloc2_base; (q = p->ptr); p = q)
213+
{
214+
if (q->size >= size)
215+
{
216+
if (q->size <= size + sizeof(block_t))
217+
{
218+
// dbg_printf("heap2 recycle full blocsize=%zu size=%zu\n", q->size, size);
219+
p->ptr = q->ptr;
220+
}
221+
else
222+
{
223+
// dbg_printf("heap2 recycle partial blocsize=%zu size=%zu\n", q->size, size);
224+
q->size -= size;
225+
q = (block_t*)(((uint8_t*)q) + q->size);
226+
q->size = size;
227+
}
228+
229+
return q + 1;
230+
}
231+
}
232+
if (heap2_ptr + size < heap2_ptr ||
233+
heap2_ptr + size >= (uintptr_t)heap2_ptrend)
234+
{
235+
lcd_Control = 0b100100101101; // TI-OS default
236+
abort();
237+
return NULL;
238+
}
239+
r = (block_t*)heap2_ptr;
240+
if (size < MALLOC_MINSIZE)
241+
size = MALLOC_MINSIZE;
242+
r->size = size;
243+
heap2_ptr = heap2_ptr + size;
244+
return r + 1;
245+
}
246+
247+
if (size < MALLOC_MINSIZE)
248+
size = MALLOC_MINSIZE;
249+
250+
r = (block_t*)heap_ptr;
251+
r->size = size;
252+
heap_ptr = heap_ptr + size;
253+
return r + 1;
254+
}
255+
256+
void _vram2_free(void* ptr)
257+
{
258+
// dbg_printf("[free] %p\n", ptr);
259+
if (ptr != NULL)
260+
{
261+
if (((size_t)ptr >= (size_t)&tab2[0]) &&
262+
((size_t)ptr < (size_t)&tab2[ALLOC2]))
263+
{
264+
const unsigned int pos = ((size_t)ptr - ((size_t)&tab2[0])) / sizeof(char2_t);
265+
// dbg_printf("deletefast2 %p pos=%i\n", ptr, pos);
266+
freeslot2[pos / INT24_WIDTH] |= (1 << (pos % INT24_WIDTH));
267+
return;
268+
}
269+
if (((size_t)ptr >= (size_t)&tab3[0]) &&
270+
((size_t)ptr < (size_t)&tab3[ALLOC3]))
271+
{
272+
const unsigned int pos = ((size_t)ptr - ((size_t)&tab3[0])) / sizeof(char3_t);
273+
// dbg_printf("deletefast3 %p pos=%i\n", ptr, pos);
274+
freeslot3[pos / INT24_WIDTH] |= (1 << (pos % INT24_WIDTH));
275+
return;
276+
}
277+
if (((size_t)ptr >= (size_t)&tab6[0]) &&
278+
((size_t)ptr < (size_t)&tab6[ALLOC6]))
279+
{
280+
const unsigned int pos = ((size_t)ptr - ((size_t)&tab6[0])) / sizeof(char6_t);
281+
// dbg_printf("deletefast6 %p pos=%i\n", ptr, pos);
282+
freeslot6[pos / INT24_WIDTH] |= (1 << (pos % INT24_WIDTH));
283+
return;
284+
}
285+
286+
block_t* q = (block_t*)ptr - 1;
287+
288+
block_t* p = ((uintptr_t)ptr <= heap2_ptrend) ? &_alloc2_base : &_alloc_base;
289+
// dbg_printf("free ptr=%p heap_end=%p p=%p pptr=%p psize=%zu\n",ptr,heap_ptrend,p,p->ptr,p->size);
290+
291+
for (; p->ptr && p->ptr < q; p = p->ptr) {}
292+
// p next pointer in the free-ed chaine list, p->ptr,
293+
// is 0 or is the first pointer >= q
294+
// (this means that p is before q)
295+
if ((uint8_t*)p->ptr == ((uint8_t*)q) + q->size)
296+
{
297+
// concatenate q and p next pointer
298+
q->size += p->ptr->size;
299+
q->ptr = p->ptr->ptr;
300+
// dbg_printf("free concatenate blocsize=%zu\n", q->size);
301+
}
302+
else
303+
{
304+
// insert in chained list: get q next cell from p next cell
305+
q->ptr = p->ptr;
306+
// dbg_printf("free add block blocsize=%zu\n", q->size);
307+
}
308+
// check if we can concatenate p and q
309+
if (((uint8_t*)p) + p->size == (uint8_t*)q)
310+
{
311+
// yes
312+
p->size += q->size;
313+
p->ptr = q->ptr;
314+
}
315+
else
316+
{
317+
// no, update next pointer for p
318+
p->ptr = q;
319+
}
320+
}
321+
}
322+
323+
void* _vram2_realloc(void* ptr, const size_t size)
324+
{
325+
// dbg_printf("[realloc] %p for %zu bytes\n", ptr, size);
326+
327+
if (ptr == NULL)
328+
{
329+
return malloc(size);
330+
}
331+
332+
if ((((size_t)ptr >= (size_t)&tab2[0]) && ((size_t)ptr < (size_t)&tab2[ALLOC2])) ||
333+
(((size_t)ptr >= (size_t)&tab3[0]) && ((size_t)ptr < (size_t)&tab3[ALLOC2])) ||
334+
(((size_t)ptr >= (size_t)&tab6[0]) && ((size_t)ptr < (size_t)&tab6[ALLOC2])))
335+
{
336+
// ok
337+
}
338+
else
339+
{
340+
const block_t* h = (block_t*)((uint8_t*)ptr - sizeof(block_t));
341+
if (h->size >= (size + sizeof(block_t)))
342+
{
343+
return ptr;
344+
}
345+
}
346+
347+
void* p = malloc(size);
348+
if (p)
349+
{
350+
memcpy(p, ptr, size);
351+
free(ptr);
352+
}
353+
354+
return p;
355+
}

0 commit comments

Comments
 (0)