|
| 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