blob: 281077c781f69283f39e9870cc817fee995e5d03 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001#include "tinyalloc.h"
2//#include <stdint.h>
3
4#ifndef TA_ALIGN
5#define TA_ALIGN 32
6#endif
7
8#define true 1
9#define false 0
10
11//#ifndef TA_BASE
12//#define TA_BASE 0x400
13//#endif
14
15//#ifndef TA_HEAP_START
16//#define TA_HEAP_START (TA_BASE + sizeof(Heap))
17//#endif
18
19unsigned int TA_HEAP_START;
20
21//#ifndef TA_HEAP_LIMIT
22//#define TA_HEAP_LIMIT (1 << 24)
23//#endif
24unsigned int TA_HEAP_LIMIT;
25
26#ifndef TA_HEAP_BLOCKS
27#define TA_HEAP_BLOCKS 256
28#endif
29
30#ifndef TA_SPLIT_THRESH
31#define TA_SPLIT_THRESH 16
32#endif
33
34//#define TA_DEBUG
35
36#define ta_printf obm_printf
37
38#ifdef TA_DEBUG
39#define print_s(x) obm_printf("%s\n\r", (x))
40#define print_i(x) obm_printf("0x%x\n\r", (x));
41#else
42#define print_s(X)
43#define print_i(X)
44#endif
45
46typedef struct Block Block;
47
48struct Block {
49 void *addr;
50 Block *next;
51 size_t size;
52};
53
54typedef struct {
55 Block *free; // first free block
56 Block *used; // first used block
57 Block *fresh; // first available blank block
58 size_t top; // top free addr
59 Block blocks[TA_HEAP_BLOCKS];
60} Heap;
61
62static Heap *heap = NULL; // = (Heap *)TA_BASE;
63
64/**
65 * If compaction is enabled, inserts block
66 * into free list, sorted by addr.
67 * If disabled, add block has new head of
68 * the free list.
69 */
70static void insert_block(Block *block) {
71#ifndef TA_DISABLE_COMPACT
72 Block *ptr = heap->free;
73 Block *prev = NULL;
74 while (ptr != NULL) {
75 if ((size_t)block->addr <= (size_t)ptr->addr) {
76 print_s("insert");
77 print_i((size_t)ptr);
78 break;
79 }
80 prev = ptr;
81 ptr = ptr->next;
82 }
83 if (prev != NULL) {
84 if (ptr == NULL) {
85 print_s("new tail");
86 }
87 prev->next = block;
88 } else {
89 print_s("new head");
90 heap->free = block;
91 }
92 block->next = ptr;
93#else
94 block->next = heap->free;
95 heap->free = block;
96#endif
97}
98
99#ifndef TA_DISABLE_COMPACT
100static void release_blocks(Block *scan, Block *to) {
101 Block *scan_next;
102 while (scan != to) {
103 print_s("release");
104 print_i((size_t)scan);
105 scan_next = scan->next;
106 scan->next = heap->fresh;
107 heap->fresh = scan;
108 scan->addr = 0;
109 scan->size = 0;
110 scan = scan_next;
111 }
112}
113
114static void compact() {
115 Block *ptr = heap->free;
116 Block *prev;
117 Block *scan;
118 while (ptr != NULL) {
119 prev = ptr;
120 scan = ptr->next;
121 while (scan != NULL &&
122 (size_t)prev->addr + prev->size == (size_t)scan->addr) {
123 print_s("merge");
124 print_i((size_t)scan);
125 prev = scan;
126 scan = scan->next;
127 }
128 if (prev != ptr) {
129 size_t new_size =
130 (size_t)prev->addr - (size_t)ptr->addr + prev->size;
131 print_s("new size");
132 print_i(new_size);
133 ptr->size = new_size;
134 Block *next = prev->next;
135 // make merged blocks available
136 release_blocks(ptr->next, prev->next);
137 // relink
138 ptr->next = next;
139 }
140 ptr = ptr->next;
141 }
142}
143#endif
144
145int is_heap_init(void) {
146 return (heap != NULL) ? true:false;
147}
148
149int ta_init(unsigned int ta_base, unsigned int length) {
150 heap = (Heap *)ta_base;
151 TA_HEAP_START = ta_base + sizeof(Heap);
152 TA_HEAP_LIMIT = ta_base + length;
153 heap->free = NULL;
154 heap->used = NULL;
155 heap->fresh = heap->blocks;
156 heap->top = TA_HEAP_START;
157 Block *block = heap->blocks;
158 size_t i = TA_HEAP_BLOCKS - 1;
159 while (i--) {
160 block->next = block + 1;
161 block++;
162 }
163 block->next = NULL;
164 return true;
165}
166
167int ta_free(void *free) {
168 Block *block = heap->used;
169 Block *prev = NULL;
170 while (block != NULL) {
171 if (free == block->addr) {
172 if (prev) {
173 prev->next = block->next;
174 } else {
175 heap->used = block->next;
176 }
177 insert_block(block);
178#ifndef TA_DISABLE_COMPACT
179 compact();
180#endif
181 return true;
182 }
183 prev = block;
184 block = block->next;
185 }
186 return false;
187}
188
189static Block *alloc_block(size_t num) {
190 Block *ptr = heap->free;
191 Block *prev = NULL;
192 size_t top = heap->top;
193 num = (num + TA_ALIGN - 1) & -TA_ALIGN;
194 while (ptr != NULL) {
195 const int is_top = ((size_t)ptr->addr + ptr->size >= top) && ((size_t)ptr->addr + num <= TA_HEAP_LIMIT);
196 if (is_top || ptr->size >= num) {
197 if (prev != NULL) {
198 prev->next = ptr->next;
199 } else {
200 heap->free = ptr->next;
201 }
202 ptr->next = heap->used;
203 heap->used = ptr;
204 if (is_top) {
205 print_s("resize top block");
206 ptr->size = num;
207 heap->top = (size_t)ptr->addr + num;
208#ifndef TA_DISABLE_SPLIT
209 } else if (heap->fresh != NULL) {
210 size_t excess = ptr->size - num;
211 if (excess >= TA_SPLIT_THRESH) {
212 ptr->size = num;
213 Block *split = heap->fresh;
214 heap->fresh = split->next;
215 split->addr = (void *)((size_t)ptr->addr + num);
216 print_s("split");
217 print_i((size_t)split->addr);
218 split->size = excess;
219 insert_block(split);
220#ifndef TA_DISABLE_COMPACT
221 compact();
222#endif
223 }
224#endif
225 }
226 return ptr;
227 }
228 prev = ptr;
229 ptr = ptr->next;
230 }
231 // no matching free blocks
232 // see if any other blocks available
233 size_t new_top = top + num;
234 if (heap->fresh != NULL && new_top <= TA_HEAP_LIMIT) {
235 ptr = heap->fresh;
236 heap->fresh = ptr->next;
237 ptr->addr = (void *)top;
238 ptr->next = heap->used;
239 ptr->size = num;
240 heap->used = ptr;
241 heap->top = new_top;
242 return ptr;
243 }
244 return NULL;
245}
246
247void *ta_alloc(size_t num) {
248 Block *block = alloc_block(num);
249 if (block != NULL) {
250 return block->addr;
251 }
252 return NULL;
253}
254
255static void memclear(void *ptr, size_t num) {
256 size_t *ptrw = (size_t *)ptr;
257 size_t numw = (num & -sizeof(size_t)) / sizeof(size_t);
258 while (numw--) {
259 *ptrw++ = 0;
260 }
261 num &= (sizeof(size_t) - 1);
262 uint8_t *ptrb = (uint8_t *)ptrw;
263 while (num--) {
264 *ptrb++ = 0;
265 }
266}
267
268void *ta_calloc(size_t num, size_t size) {
269 num *= size;
270 Block *block = alloc_block(num);
271 if (block != NULL) {
272 memclear(block->addr, num);
273 return block->addr;
274 }
275 return NULL;
276}
277
278static size_t count_blocks(Block *ptr) {
279 size_t num = 0;
280 while (ptr != NULL) {
281 num++;
282 ptr = ptr->next;
283 }
284 return num;
285}
286
287size_t ta_num_free() {
288 return count_blocks(heap->free);
289}
290
291size_t ta_num_used() {
292 return count_blocks(heap->used);
293}
294
295size_t ta_num_fresh() {
296 return count_blocks(heap->fresh);
297}
298
299int ta_check() {
300 return TA_HEAP_BLOCKS == ta_num_free() + ta_num_used() + ta_num_fresh();
301}
302
303static int mem_reserve_in_free_block(Block *fptr, Block *prev,
304 unsigned int start, size_t num)
305{
306 unsigned int bmargin, amargin;
307 Block *aptr = NULL, *bptr = NULL;
308
309 bmargin = start - (unsigned int)fptr->addr;
310 amargin = ((unsigned int)fptr->addr + fptr->size) - start - num;
311
312 if ( bmargin >= TA_SPLIT_THRESH && ta_num_fresh() > 1)
313 {
314 bptr = heap->fresh;
315 heap->fresh = bptr->next;
316 bptr->addr = fptr->addr;
317 bptr->next = heap->free;
318 bptr->size = bmargin;
319 fptr->addr = start;
320 }
321
322 if (amargin >= TA_SPLIT_THRESH && ta_num_fresh() > 1)
323 {
324 aptr = heap->fresh;
325 heap->fresh = aptr->next;
326 aptr->addr = (void *)(start + num);
327 aptr->size = amargin;
328 }
329
330 fptr->size = (start + num) - (unsigned int)fptr->addr;
331
332 /* remove from free list */
333 if (prev == NULL) {
334 heap->free = fptr->next;
335 } else{
336 prev->next = fptr->next;
337 }
338 /* add to used list */
339 fptr->next = heap->used;
340 heap->used = fptr;
341
342 if ( bptr ) {
343 insert_block(bptr);
344#ifndef TA_DISABLE_COMPACT
345 compact();
346#endif
347 }
348
349 if ( aptr ) {
350 insert_block(aptr);
351#ifndef TA_DISABLE_COMPACT
352 compact();
353#endif
354 }
355
356 return 0;
357}
358
359static int mem_reserve_in_clean_heap(unsigned int start, size_t num)
360{
361 Block *ptr;
362 unsigned int new_top, old_top, len;
363
364 new_top = start + num;
365
366 if( new_top > TA_HEAP_LIMIT ) {
367 ta_printf("reserved buffer exceeds heap limit %d\n\r", __LINE__);
368 return -1;
369 }
370
371 if(heap->fresh != NULL ) {
372 len = start - heap->top;
373 old_top = heap->top;
374 ptr = heap->fresh;
375 heap->fresh = ptr->next;
376 ptr->addr = (void *)start;
377 ptr->next = heap->used;
378 ptr->size = num;
379 heap->used = ptr;
380 heap->top = new_top;
381
382 if ( len && heap->fresh != NULL) {
383 ptr = heap->fresh;
384 heap->fresh = ptr->next;
385 ptr->addr = old_top;
386 ptr->size = len;
387
388 insert_block(ptr);
389#ifndef TA_DISABLE_COMPACT
390 compact();
391#endif
392 }
393
394 if(len && heap->fresh == NULL)
395 ta_printf("warning, buffer 0x%x@0x%x lost\n\r", len, old_top);
396
397 return 0; /* ok to reserve */
398 }
399
400 return -1;
401}
402
403int mreserve(unsigned int start, unsigned int num)
404{
405
406#ifdef TA_DISABLE_COMPACT
407 /* compact must be enabled */
408 return -1;
409#endif
410 int ret;
411
412 Block *fptr, *fprev;
413 unsigned int end, fend;
414
415 if( start & (TA_ALIGN - 1) ) {
416 ta_printf("reserved buffer must align to 0x%x\n\r", TA_ALIGN);
417 return -1;
418 }
419
420 num = (num + TA_ALIGN - 1) & -TA_ALIGN;
421 end = start + num;
422
423 /* reserved buff in clean heap */
424 if ( start >= heap->top ) {
425 return mem_reserve_in_clean_heap(start, num);
426 }
427
428 fprev = NULL;
429 fptr = heap->free;
430 while ( fptr != NULL ) {
431 fend = (unsigned int)fptr->addr + fptr->size; /* free block end */
432 if( start >= (unsigned int)fptr->addr && end <= fend )
433 {
434 return mem_reserve_in_free_block(fptr, fprev, start, num);
435 }
436
437 /* buffer to reserve cross free and top */
438 if(start >= (unsigned int)fptr->addr && fend >= heap->top)
439 {
440 heap->top = end;
441 fptr->size = end - (unsigned int)fptr->addr;
442 return mem_reserve_in_free_block(fptr, fprev, start, heap->top - start);
443 }
444 fprev = fptr;
445 fptr = fptr->next;
446 }
447
448 return -1;
449}
450
451
452int free(void *free)
453{
454#ifdef TA_DEBUG
455 unsigned int lr;
456 asm volatile(
457 " mov %0, lr @ get lr\n"
458 : "=r" (lr)
459 :
460 : "memory", "cc");
461 ta_printf("ta free buffer 0x%x from PC@0x%x\n\r", (unsigned int)free, lr-4);
462#endif
463 return ta_free(free);
464}
465
466void *malloc(size_t num)
467{
468#ifdef TA_DEBUG
469 void *buff;
470 unsigned int lr;
471 asm volatile(
472 " mov %0, lr @ get lr\n"
473 : "=r" (lr)
474 :
475 : "memory", "cc");
476 buff = ta_alloc(num);
477 ta_printf("ta malloc buffer 0x%x@0x%x from PC@0x%x\n\r", num, (unsigned int)buff, lr-4);
478 return buff;
479#else
480 return ta_alloc(num);
481#endif
482}
483
484void *calloc(size_t num, size_t size)
485{
486 return ta_calloc(num, size);
487}
488
489int malloc_init(unsigned int ta_base, unsigned int length)
490{
491 return ta_init(ta_base, length);
492}
493
494#ifdef TA_DEBUG
495void ta_info_dump()
496{
497 Block *ptr;
498 ta_printf("\n\r---------------------------\n\r");
499 ta_printf("TA info\n\r");
500 ta_printf("Free num: %d\n\r", ta_num_free());
501 ta_printf("Used num: %d\n\r", ta_num_used());
502 ta_printf("Fresh num: %d\n\r", ta_num_fresh());
503 ta_printf("Heap top: 0x%x\n\r", heap->top);
504
505 ptr = heap->free;
506 if(ptr) {
507 ta_printf("Free blocks:\n\r");
508 while(ptr != NULL) {
509 ta_printf("0x%x --> 0x%x: 0x%x\n\r", (unsigned int)ptr->addr,
510 ((unsigned int)ptr->addr)+ptr->size, ptr->size);
511 ptr = ptr->next;
512 }
513
514 ta_printf("\n\r---------------------------\n\r");
515 }
516
517
518 ptr = heap->used;
519 if(ptr) {
520 ta_printf("Used blocks:\n\r");
521 while(ptr != NULL) {
522 ta_printf("0x%x --> 0x%x: 0x%x\n\r", (unsigned int)ptr->addr,
523 ((unsigned int)ptr->addr)+ptr->size, ptr->size);
524 ptr = ptr->next;
525 }
526 ta_printf("\n\r---------------------------\n\r");
527 }
528}
529
530void ta_test(void)
531{
532 void *buff[10];
533
534 malloc_init(0x1000000, 0x1000000);
535
536 ta_printf("Initial state: \n\r");
537 ta_info_dump();
538
539 buff[0] = malloc(0x4000);
540 buff[1] = malloc(0x8000);
541 buff[2] = malloc(0x6000);
542 buff[3] = malloc(0x2000);
543 buff[4] = malloc(0x10000);
544 buff[5] = malloc(0x20000);
545 buff[6] = malloc(0x80000);
546 buff[7] = malloc(0x100000);
547 buff[8] = malloc(0x80000);
548 buff[9] = malloc(0x200000);
549
550 ta_printf("malloc 10 buffers state: \n\r");
551 ta_info_dump();
552
553 free(buff[1]);
554 free(buff[4]);
555 free(buff[5]);
556 free(buff[7]);
557 free(buff[9]);
558
559 ta_printf("free 5 buffers state: \n\r");
560 ta_info_dump();
561
562 ta_printf("reserve a buffer\n\r");
563 mem_reserve(0x1300000, 0x100000);
564 ta_info_dump();
565
566 ta_printf("reserve a buffer\n\r");
567 mem_reserve(0x1600000, 0x100000);
568 ta_info_dump();
569
570}
571#endif