1 /**
2 * @file lv_mem.c
3 * General and portable implementation of malloc and free.
4 * The dynamic memory monitoring is also supported.
5 */
6
7 /*********************
8 * INCLUDES
9 *********************/
10 #include "lv_mem.h"
11 #include "lv_math.h"
12 #include "lv_gc.h"
13 #include <string.h>
14
15 #if LV_MEM_CUSTOM != 0
16 #include LV_MEM_CUSTOM_INCLUDE
17 #endif
18
19 #if defined(LV_GC_INCLUDE)
20 #include LV_GC_INCLUDE
21 #endif /* LV_ENABLE_GC */
22
23 /*********************
24 * DEFINES
25 *********************/
26 /*Add memory junk on alloc (0xaa) and free(0xbb) (just for testing purposes)*/
27 #ifndef LV_MEM_ADD_JUNK
28 #define LV_MEM_ADD_JUNK 0
29 #endif
30
31 #ifndef LV_MEM_FULL_DEFRAG_CNT
32 #define LV_MEM_FULL_DEFRAG_CNT 16
33 #endif
34
35 #ifdef LV_ARCH_64
36 #define MEM_UNIT uint64_t
37 #else
38 #define MEM_UNIT uint32_t
39 #endif
40
41 /**********************
42 * TYPEDEFS
43 **********************/
44
45 #if LV_ENABLE_GC == 0 /*gc custom allocations must not include header*/
46
47 /*The size of this union must be 4 bytes (uint32_t)*/
48 typedef union {
49 struct {
50 MEM_UNIT used : 1; /* 1: if the entry is used*/
51 MEM_UNIT d_size : 31; /* Size off the data (1 means 4 bytes)*/
52 } s;
53 MEM_UNIT header; /* The header (used + d_size)*/
54 } lv_mem_header_t;
55
56 typedef struct {
57 lv_mem_header_t header;
58 uint8_t first_data; /*First data byte in the allocated data (Just for easily create a pointer)*/
59 } lv_mem_ent_t;
60
61 #endif /* LV_ENABLE_GC */
62
63 #ifdef LV_ARCH_64
64 #define ALIGN_MASK 0x7
65 #else
66 #define ALIGN_MASK 0x3
67 #endif
68
69 #define MEM_BUF_SMALL_SIZE 16
70
71 /**********************
72 * STATIC PROTOTYPES
73 **********************/
74 #if LV_MEM_CUSTOM == 0
75 static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e);
76 static void * ent_alloc(lv_mem_ent_t * e, size_t size);
77 static void ent_trunc(lv_mem_ent_t * e, size_t size);
78 #endif
79
80 /**********************
81 * STATIC VARIABLES
82 **********************/
83 #if LV_MEM_CUSTOM == 0
84 static uint8_t * work_mem;
85 #endif
86
87 static uint32_t zero_mem; /*Give the address of this variable if 0 byte should be allocated*/
88
89 #if LV_MEM_CUSTOM == 0
90 static uint32_t mem_max_size; /*Tracks the maximum total size of memory ever used from the internal heap*/
91 #endif
92
93 static uint8_t mem_buf1_32[MEM_BUF_SMALL_SIZE];
94 static uint8_t mem_buf2_32[MEM_BUF_SMALL_SIZE];
95
96 static lv_mem_buf_t mem_buf_small[] = {{.p = mem_buf1_32, .size = MEM_BUF_SMALL_SIZE, .used = 0},
97 {.p = mem_buf2_32, .size = MEM_BUF_SMALL_SIZE, .used = 0}
98 };
99
100 /**********************
101 * MACROS
102 **********************/
103
104 #define COPY32 *d32 = *s32; d32++; s32++;
105 #define COPY8 *d8 = *s8; d8++; s8++;
106 #define SET32(x) *d32 = x; d32++;
107 #define REPEAT8(expr) expr expr expr expr expr expr expr expr
108
109 /**********************
110 * GLOBAL FUNCTIONS
111 **********************/
112
113 /**
114 * Initialize the dyn_mem module (work memory and other variables)
115 */
_lv_mem_init(void)116 void _lv_mem_init(void)
117 {
118 #if LV_MEM_CUSTOM == 0
119
120 #if LV_MEM_ADR == 0
121 /*Allocate a large array to store the dynamically allocated data*/
122 static LV_MEM_ATTR MEM_UNIT work_mem_int[LV_MEM_SIZE / sizeof(MEM_UNIT)];
123 work_mem = (uint8_t *)work_mem_int;
124 mem_max_size = 0;
125 #else
126 work_mem = (uint8_t *)LV_MEM_ADR;
127 #endif
128
129 lv_mem_ent_t * full = (lv_mem_ent_t *)work_mem;
130 full->header.s.used = 0;
131 /*The total mem size id reduced by the first header and the close patterns */
132 full->header.s.d_size = LV_MEM_SIZE - sizeof(lv_mem_header_t);
133 #endif
134 }
135
136 /**
137 * Clean up the memory buffer which frees all the allocated memories.
138 * @note It work only if `LV_MEM_CUSTOM == 0`
139 */
_lv_mem_deinit(void)140 void _lv_mem_deinit(void)
141 {
142 #if LV_MEM_CUSTOM == 0
143 _lv_memset_00(work_mem, (LV_MEM_SIZE / sizeof(MEM_UNIT)) * sizeof(MEM_UNIT));
144 lv_mem_ent_t * full = (lv_mem_ent_t *)work_mem;
145 full->header.s.used = 0;
146 /*The total mem size id reduced by the first header and the close patterns */
147 full->header.s.d_size = LV_MEM_SIZE - sizeof(lv_mem_header_t);
148 #endif
149 }
150
151 /**
152 * Allocate a memory dynamically
153 * @param size size of the memory to allocate in bytes
154 * @return pointer to the allocated memory
155 */
lv_mem_alloc(size_t size)156 void * lv_mem_alloc(size_t size)
157 {
158 if(size == 0) {
159 return &zero_mem;
160 }
161
162 #ifdef LV_ARCH_64
163 /*Round the size up to 8*/
164 size = (size + 7) & (~0x7);
165 #else
166 /*Round the size up to 4*/
167 size = (size + 3) & (~0x3);
168 #endif
169 void * alloc = NULL;
170
171 #if LV_MEM_CUSTOM == 0
172 /*Use the built-in allocators*/
173 lv_mem_ent_t * e = NULL;
174
175 /* Search for a appropriate entry*/
176 do {
177 /* Get the next entry*/
178 e = ent_get_next(e);
179
180 /*If there is next entry then try to allocate there*/
181 if(e != NULL) {
182 alloc = ent_alloc(e, size);
183 }
184 /* End if there is not next entry OR the alloc. is successful*/
185 } while(e != NULL && alloc == NULL);
186
187 #else
188 /*Use custom, user defined malloc function*/
189 #if LV_ENABLE_GC == 1 /*gc must not include header*/
190 alloc = LV_MEM_CUSTOM_ALLOC(size);
191 #else /* LV_ENABLE_GC */
192 /*Allocate a header too to store the size*/
193 alloc = LV_MEM_CUSTOM_ALLOC(size + sizeof(lv_mem_header_t));
194 if(alloc != NULL) {
195 ((lv_mem_ent_t *)alloc)->header.s.d_size = size;
196 ((lv_mem_ent_t *)alloc)->header.s.used = 1;
197
198 alloc = &((lv_mem_ent_t *)alloc)->first_data;
199 }
200 #endif /* LV_ENABLE_GC */
201 #endif /* LV_MEM_CUSTOM */
202
203 #if LV_MEM_ADD_JUNK
204 if(alloc != NULL) _lv_memset(alloc, 0xaa, size);
205 #endif
206
207 if(alloc == NULL) {
208 LV_LOG_WARN("Couldn't allocate memory");
209 }
210 else {
211 #if LV_MEM_CUSTOM == 0
212 /* just a safety check, should always be true */
213 if((uintptr_t) alloc > (uintptr_t) work_mem) {
214 if((((uintptr_t) alloc - (uintptr_t) work_mem) + size) > mem_max_size) {
215 mem_max_size = ((uintptr_t) alloc - (uintptr_t) work_mem) + size;
216 }
217 }
218 #endif
219 }
220
221 return alloc;
222 }
223
224 /**
225 * Free an allocated data
226 * @param data pointer to an allocated memory
227 */
lv_mem_free(const void * data)228 void lv_mem_free(const void * data)
229 {
230 if(data == &zero_mem) return;
231 if(data == NULL) return;
232
233 #if LV_MEM_ADD_JUNK
234 _lv_memset((void *)data, 0xbb, _lv_mem_get_size(data));
235 #endif
236
237 #if LV_ENABLE_GC == 0
238 /*e points to the header*/
239 lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *)data - sizeof(lv_mem_header_t));
240 e->header.s.used = 0;
241 #endif
242
243 #if LV_MEM_CUSTOM == 0
244 #if LV_MEM_AUTO_DEFRAG
245 static uint16_t full_defrag_cnt = 0;
246 full_defrag_cnt++;
247 if(full_defrag_cnt < LV_MEM_FULL_DEFRAG_CNT) {
248 /* Make a simple defrag.
249 * Join the following free entries after this*/
250 lv_mem_ent_t * e_next;
251 e_next = ent_get_next(e);
252 while(e_next != NULL) {
253 if(e_next->header.s.used == 0) {
254 e->header.s.d_size += e_next->header.s.d_size + sizeof(e->header);
255 }
256 else {
257 break;
258 }
259 e_next = ent_get_next(e_next);
260 }
261 }
262 else {
263 full_defrag_cnt = 0;
264 lv_mem_defrag();
265
266 }
267
268
269 #endif /*LV_MEM_AUTO_DEFRAG*/
270 #else /*Use custom, user defined free function*/
271 #if LV_ENABLE_GC == 0
272 LV_MEM_CUSTOM_FREE(e);
273 #else
274 LV_MEM_CUSTOM_FREE((void *)data);
275 #endif /*LV_ENABLE_GC*/
276 #endif
277 }
278
279 /**
280 * Reallocate a memory with a new size. The old content will be kept.
281 * @param data pointer to an allocated memory.
282 * Its content will be copied to the new memory block and freed
283 * @param new_size the desired new size in byte
284 * @return pointer to the new memory
285 */
286
287 #if LV_ENABLE_GC == 0
288
lv_mem_realloc(void * data_p,size_t new_size)289 void * lv_mem_realloc(void * data_p, size_t new_size)
290 {
291
292 #ifdef LV_ARCH_64
293 /*Round the size up to 8*/
294 new_size = (new_size + 7) & (~0x7);
295 #else
296 /*Round the size up to 4*/
297 new_size = (new_size + 3) & (~0x3);
298 #endif
299
300 /*data_p could be previously freed pointer (in this case it is invalid)*/
301 if(data_p != NULL) {
302 lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *)data_p - sizeof(lv_mem_header_t));
303 if(e->header.s.used == 0) {
304 data_p = NULL;
305 }
306 }
307
308 uint32_t old_size = _lv_mem_get_size(data_p);
309 if(old_size == new_size) return data_p; /*Also avoid reallocating the same memory*/
310
311 #if LV_MEM_CUSTOM == 0
312 /* Truncate the memory if the new size is smaller. */
313 if(new_size < old_size) {
314 lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *)data_p - sizeof(lv_mem_header_t));
315 ent_trunc(e, new_size);
316 return &e->first_data;
317 }
318 #endif
319
320 void * new_p;
321 new_p = lv_mem_alloc(new_size);
322 if(new_p == NULL) {
323 LV_LOG_WARN("Couldn't allocate memory");
324 return NULL;
325 }
326
327 if(data_p != NULL) {
328 /*Copy the old data to the new. Use the smaller size*/
329 if(old_size != 0) {
330 _lv_memcpy(new_p, data_p, LV_MATH_MIN(new_size, old_size));
331 lv_mem_free(data_p);
332 }
333 }
334
335
336 return new_p;
337 }
338
339 #else /* LV_ENABLE_GC */
340
lv_mem_realloc(void * data_p,size_t new_size)341 void * lv_mem_realloc(void * data_p, size_t new_size)
342 {
343 void * new_p = LV_MEM_CUSTOM_REALLOC(data_p, new_size);
344 if(new_p == NULL) LV_LOG_WARN("Couldn't allocate memory");
345 return new_p;
346 }
347
348 #endif /* lv_enable_gc */
349
350 /**
351 * Join the adjacent free memory blocks
352 */
lv_mem_defrag(void)353 void lv_mem_defrag(void)
354 {
355 #if LV_MEM_CUSTOM == 0
356 lv_mem_ent_t * e_free;
357 lv_mem_ent_t * e_next;
358 e_free = ent_get_next(NULL);
359
360 while(1) {
361 /*Search the next free entry*/
362 while(e_free != NULL) {
363 if(e_free->header.s.used != 0) {
364 e_free = ent_get_next(e_free);
365 }
366 else {
367 break;
368 }
369 }
370
371 if(e_free == NULL) return;
372
373 /*Joint the following free entries to the free*/
374 e_next = ent_get_next(e_free);
375 while(e_next != NULL) {
376 if(e_next->header.s.used == 0) {
377 e_free->header.s.d_size += e_next->header.s.d_size + sizeof(e_next->header);
378 }
379 else {
380 break;
381 }
382
383 e_next = ent_get_next(e_next);
384 }
385
386 if(e_next == NULL) return;
387
388 /*Continue from the lastly checked entry*/
389 e_free = e_next;
390 }
391 #endif
392 }
393
lv_mem_test(void)394 lv_res_t lv_mem_test(void)
395 {
396 #if LV_MEM_CUSTOM == 0
397 lv_mem_ent_t * e;
398 e = ent_get_next(NULL);
399 while(e) {
400 if(e->header.s.d_size > LV_MEM_SIZE) {
401 return LV_RES_INV;
402 }
403 uint8_t * e8 = (uint8_t *) e;
404 if(e8 + e->header.s.d_size > work_mem + LV_MEM_SIZE) {
405 return LV_RES_INV;
406 }
407 e = ent_get_next(e);
408 }
409 #endif
410 return LV_RES_OK;
411 }
412
413 /**
414 * Give information about the work memory of dynamic allocation
415 * @param mon_p pointer to a dm_mon_p variable,
416 * the result of the analysis will be stored here
417 */
lv_mem_monitor(lv_mem_monitor_t * mon_p)418 void lv_mem_monitor(lv_mem_monitor_t * mon_p)
419 {
420 /*Init the data*/
421 _lv_memset(mon_p, 0, sizeof(lv_mem_monitor_t));
422 #if LV_MEM_CUSTOM == 0
423 lv_mem_ent_t * e;
424 e = NULL;
425
426 e = ent_get_next(e);
427
428 while(e != NULL) {
429 if(e->header.s.used == 0) {
430 mon_p->free_cnt++;
431 mon_p->free_size += e->header.s.d_size;
432 if(e->header.s.d_size > mon_p->free_biggest_size) {
433 mon_p->free_biggest_size = e->header.s.d_size;
434 }
435 }
436 else {
437 mon_p->used_cnt++;
438 }
439
440 e = ent_get_next(e);
441 }
442 mon_p->total_size = LV_MEM_SIZE;
443 mon_p->max_used = mem_max_size;
444 mon_p->used_pct = 100 - (100U * mon_p->free_size) / mon_p->total_size;
445 if(mon_p->free_size > 0) {
446 mon_p->frag_pct = (uint32_t)mon_p->free_biggest_size * 100U / mon_p->free_size;
447 mon_p->frag_pct = 100 - mon_p->frag_pct;
448 }
449 else {
450 mon_p->frag_pct = 0; /*no fragmentation if all the RAM is used*/
451 }
452 #endif
453 }
454
455 /**
456 * Give the size of an allocated memory
457 * @param data pointer to an allocated memory
458 * @return the size of data memory in bytes
459 */
460
461 #if LV_ENABLE_GC == 0
462
_lv_mem_get_size(const void * data)463 uint32_t _lv_mem_get_size(const void * data)
464 {
465 if(data == NULL) return 0;
466 if(data == &zero_mem) return 0;
467
468 lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *)data - sizeof(lv_mem_header_t));
469
470 return e->header.s.d_size;
471 }
472
473 #else /* LV_ENABLE_GC */
474
_lv_mem_get_size(const void * data)475 uint32_t _lv_mem_get_size(const void * data)
476 {
477 return LV_MEM_CUSTOM_GET_SIZE(data);
478 }
479
480 #endif /*LV_ENABLE_GC*/
481
482 /**
483 * Get a temporal buffer with the given size.
484 * @param size the required size
485 */
_lv_mem_buf_get(uint32_t size)486 void * _lv_mem_buf_get(uint32_t size)
487 {
488 if(size == 0) return NULL;
489
490 /*Try small static buffers first*/
491 uint8_t i;
492 if(size <= MEM_BUF_SMALL_SIZE) {
493 for(i = 0; i < sizeof(mem_buf_small) / sizeof(mem_buf_small[0]); i++) {
494 if(mem_buf_small[i].used == 0) {
495 mem_buf_small[i].used = 1;
496 return mem_buf_small[i].p;
497 }
498 }
499 }
500
501 /*Try to find a free buffer with suitable size */
502 int8_t i_guess = -1;
503 for(i = 0; i < LV_MEM_BUF_MAX_NUM; i++) {
504 if(LV_GC_ROOT(_lv_mem_buf[i]).used == 0 && LV_GC_ROOT(_lv_mem_buf[i]).size >= size) {
505 if(LV_GC_ROOT(_lv_mem_buf[i]).size == size) {
506 LV_GC_ROOT(_lv_mem_buf[i]).used = 1;
507 return LV_GC_ROOT(_lv_mem_buf[i]).p;
508 }
509 else if(i_guess < 0) {
510 i_guess = i;
511 }
512 /*If size of `i` is closer to `size` prefer it*/
513 else if(LV_GC_ROOT(_lv_mem_buf[i]).size < LV_GC_ROOT(_lv_mem_buf[i_guess]).size) {
514 i_guess = i;
515 }
516 }
517 }
518
519 if(i_guess >= 0) {
520 LV_GC_ROOT(_lv_mem_buf[i_guess]).used = 1;
521 return LV_GC_ROOT(_lv_mem_buf[i_guess]).p;
522 }
523
524
525 /*Reallocate a free buffer*/
526 for(i = 0; i < LV_MEM_BUF_MAX_NUM; i++) {
527 if(LV_GC_ROOT(_lv_mem_buf[i]).used == 0) {
528 LV_GC_ROOT(_lv_mem_buf[i]).used = 1;
529 LV_GC_ROOT(_lv_mem_buf[i]).size = size;
530 /*if this fails you probably need to increase your LV_MEM_SIZE/heap size*/
531 LV_GC_ROOT(_lv_mem_buf[i]).p = lv_mem_realloc(LV_GC_ROOT(_lv_mem_buf[i]).p, size);
532 if(LV_GC_ROOT(_lv_mem_buf[i]).p == NULL) {
533 LV_DEBUG_ASSERT(false, "Out of memory, can't allocate a new buffer (increase your LV_MEM_SIZE/heap size", 0x00);
534 }
535 return LV_GC_ROOT(_lv_mem_buf[i]).p;
536 }
537 }
538
539 LV_DEBUG_ASSERT(false, "No free buffer. Increase LV_DRAW_BUF_MAX_NUM.", 0x00);
540 return NULL;
541 }
542
543 /**
544 * Release a memory buffer
545 * @param p buffer to release
546 */
_lv_mem_buf_release(void * p)547 void _lv_mem_buf_release(void * p)
548 {
549 uint8_t i;
550
551 /*Try small static buffers first*/
552 for(i = 0; i < sizeof(mem_buf_small) / sizeof(mem_buf_small[0]); i++) {
553 if(mem_buf_small[i].p == p) {
554 mem_buf_small[i].used = 0;
555 return;
556 }
557 }
558
559 for(i = 0; i < LV_MEM_BUF_MAX_NUM; i++) {
560 if(LV_GC_ROOT(_lv_mem_buf[i]).p == p) {
561 LV_GC_ROOT(_lv_mem_buf[i]).used = 0;
562 return;
563 }
564 }
565
566 LV_LOG_ERROR("lv_mem_buf_release: p is not a known buffer")
567 }
568
569 /**
570 * Free all memory buffers
571 */
_lv_mem_buf_free_all(void)572 void _lv_mem_buf_free_all(void)
573 {
574 uint8_t i;
575 for(i = 0; i < sizeof(mem_buf_small) / sizeof(mem_buf_small[0]); i++) {
576 mem_buf_small[i].used = 0;
577 }
578
579 for(i = 0; i < LV_MEM_BUF_MAX_NUM; i++) {
580 if(LV_GC_ROOT(_lv_mem_buf[i]).p) {
581 lv_mem_free(LV_GC_ROOT(_lv_mem_buf[i]).p);
582 LV_GC_ROOT(_lv_mem_buf[i]).p = NULL;
583 LV_GC_ROOT(_lv_mem_buf[i]).used = 0;
584 LV_GC_ROOT(_lv_mem_buf[i]).size = 0;
585 }
586 }
587 }
588
589 #if LV_MEMCPY_MEMSET_STD == 0
590 /**
591 * Same as `memcpy` but optimized for 4 byte operation.
592 * @param dst pointer to the destination buffer
593 * @param src pointer to the source buffer
594 * @param len number of byte to copy
595 */
_lv_memcpy(void * dst,const void * src,size_t len)596 LV_ATTRIBUTE_FAST_MEM void * _lv_memcpy(void * dst, const void * src, size_t len)
597 {
598 uint8_t * d8 = dst;
599 const uint8_t * s8 = src;
600
601 lv_uintptr_t d_align = (lv_uintptr_t)d8 & ALIGN_MASK;
602 lv_uintptr_t s_align = (lv_uintptr_t)s8 & ALIGN_MASK;
603
604 /*Byte copy for unaligned memories*/
605 if(s_align != d_align) {
606 while(len > 32) {
607 REPEAT8(COPY8);
608 REPEAT8(COPY8);
609 REPEAT8(COPY8);
610 REPEAT8(COPY8);
611 len -= 32;
612 }
613 while(len) {
614 COPY8
615 len--;
616 }
617 return dst;
618 }
619
620
621 /*Make the memories aligned*/
622 if(d_align) {
623 d_align = ALIGN_MASK + 1 - d_align;
624 while(d_align && len) {
625 COPY8;
626 d_align--;
627 len--;
628 }
629 }
630
631 uint32_t * d32 = (uint32_t *)d8;
632 const uint32_t * s32 = (uint32_t *)s8;
633 while(len > 32) {
634 REPEAT8(COPY32)
635 len -= 32;
636 }
637
638 while(len > 4) {
639 COPY32;
640 len -= 4;
641 }
642
643 d8 = (uint8_t *)d32;
644 s8 = (const uint8_t *)s32;
645 while(len) {
646 COPY8
647 len--;
648 }
649
650 return dst;
651 }
652
653
654 /**
655 * Same as `memset` but optimized for 4 byte operation.
656 * @param dst pointer to the destination buffer
657 * @param v value to set [0..255]
658 * @param len number of byte to set
659 */
_lv_memset(void * dst,uint8_t v,size_t len)660 LV_ATTRIBUTE_FAST_MEM void _lv_memset(void * dst, uint8_t v, size_t len)
661 {
662
663 uint8_t * d8 = (uint8_t *) dst;
664
665 uintptr_t d_align = (lv_uintptr_t) d8 & ALIGN_MASK;
666
667 /*Make the address aligned*/
668 if(d_align) {
669 d_align = ALIGN_MASK + 1 - d_align;
670 while(d_align && len) {
671 *d8 = v;
672 d8++;
673 len--;
674 d_align--;
675 }
676 }
677
678 uint32_t v32 = v + (v << 8) + (v << 16) + (v << 24);
679
680 uint32_t * d32 = (uint32_t *)d8;
681
682 while(len > 32) {
683 SET32(v32);
684 SET32(v32);
685 SET32(v32);
686 SET32(v32);
687 SET32(v32);
688 SET32(v32);
689 SET32(v32);
690 SET32(v32);
691 len -= 32;
692 }
693
694 while(len > 4) {
695 SET32(v32);
696 len -= 4;
697 }
698
699
700 d8 = (uint8_t *)d32;
701 while(len) {
702 *d8 = v;
703 d8++;
704 len--;
705 }
706 }
707
708 /**
709 * Same as `memset(dst, 0x00, len)` but optimized for 4 byte operation.
710 * @param dst pointer to the destination buffer
711 * @param len number of byte to set
712 */
_lv_memset_00(void * dst,size_t len)713 LV_ATTRIBUTE_FAST_MEM void _lv_memset_00(void * dst, size_t len)
714 {
715 uint8_t * d8 = (uint8_t *) dst;
716 uintptr_t d_align = (lv_uintptr_t) d8 & ALIGN_MASK;
717
718
719 /*Make the address aligned*/
720 if(d_align) {
721 d_align = ALIGN_MASK + 1 - d_align;
722 while(d_align && len) {
723 *d8 = 0x00;
724 d8++;
725 len--;
726 d_align--;
727 }
728 }
729
730 uint32_t * d32 = (uint32_t *)d8;
731 while(len > 32) {
732 SET32(0);
733 SET32(0);
734 SET32(0);
735 SET32(0);
736 SET32(0);
737 SET32(0);
738 SET32(0);
739 SET32(0);
740 len -= 32;
741 }
742
743 while(len > 4) {
744 SET32(0);
745 len -= 4;
746 }
747
748
749 d8 = (uint8_t *)d32;
750 while(len) {
751 *d8 = 0;
752 d8++;
753 len--;
754 }
755 }
756
757 /**
758 * Same as `memset(dst, 0xFF, len)` but optimized for 4 byte operation.
759 * @param dst pointer to the destination buffer
760 * @param len number of byte to set
761 */
_lv_memset_ff(void * dst,size_t len)762 LV_ATTRIBUTE_FAST_MEM void _lv_memset_ff(void * dst, size_t len)
763 {
764 uint8_t * d8 = (uint8_t *) dst;
765 uintptr_t d_align = (lv_uintptr_t) d8 & ALIGN_MASK;
766
767
768 /*Make the address aligned*/
769 if(d_align) {
770 d_align = ALIGN_MASK + 1 - d_align;
771 while(d_align && len) {
772 *d8 = 0xFF;
773 d8++;
774 len--;
775 d_align--;
776 }
777 }
778
779 uint32_t * d32 = (uint32_t *)d8;
780 while(len > 32) {
781 SET32(0xFFFFFFFF);
782 SET32(0xFFFFFFFF);
783 SET32(0xFFFFFFFF);
784 SET32(0xFFFFFFFF);
785 SET32(0xFFFFFFFF);
786 SET32(0xFFFFFFFF);
787 SET32(0xFFFFFFFF);
788 SET32(0xFFFFFFFF);
789 len -= 32;
790 }
791
792 while(len > 4) {
793 SET32(0xFFFFFFFF);
794 len -= 4;
795 }
796
797
798 d8 = (uint8_t *)d32;
799 while(len) {
800 *d8 = 0xFF;
801 d8++;
802 len--;
803 }
804 }
805
806 #endif /*LV_MEMCPY_MEMSET_STD*/
807
808 /**********************
809 * STATIC FUNCTIONS
810 **********************/
811
812 #if LV_MEM_CUSTOM == 0
813 /**
814 * Give the next entry after 'act_e'
815 * @param act_e pointer to an entry
816 * @return pointer to an entry after 'act_e'
817 */
ent_get_next(lv_mem_ent_t * act_e)818 static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e)
819 {
820 lv_mem_ent_t * next_e = NULL;
821
822 if(act_e == NULL) { /*NULL means: get the first entry*/
823 next_e = (lv_mem_ent_t *)work_mem;
824 }
825 else { /*Get the next entry */
826 uint8_t * data = &act_e->first_data;
827 next_e = (lv_mem_ent_t *)&data[act_e->header.s.d_size];
828
829 if(&next_e->first_data >= &work_mem[LV_MEM_SIZE]) next_e = NULL;
830 }
831
832 return next_e;
833 }
834
835 /**
836 * Try to do the real allocation with a given size
837 * @param e try to allocate to this entry
838 * @param size size of the new memory in bytes
839 * @return pointer to the allocated memory or NULL if not enough memory in the entry
840 */
ent_alloc(lv_mem_ent_t * e,size_t size)841 static void * ent_alloc(lv_mem_ent_t * e, size_t size)
842 {
843 void * alloc = NULL;
844 /*If the memory is free and big enough then use it */
845 if(e->header.s.used == 0 && e->header.s.d_size >= size) {
846 /*Truncate the entry to the desired size */
847 ent_trunc(e, size);
848 e->header.s.used = 1;
849
850 /*Save the allocated data*/
851 alloc = &e->first_data;
852 }
853
854 return alloc;
855 }
856
857 /**
858 * Truncate the data of entry to the given size
859 * @param e Pointer to an entry
860 * @param size new size in bytes
861 */
ent_trunc(lv_mem_ent_t * e,size_t size)862 static void ent_trunc(lv_mem_ent_t * e, size_t size)
863 {
864
865 #ifdef LV_ARCH_64
866 /*Round the size up to 8*/
867 size = (size + 7) & (~0x7);
868 #else
869 /*Round the size up to 4*/
870 size = (size + 3) & (~0x3);
871 #endif
872
873 /*Don't let empty space only for a header without data*/
874 if(e->header.s.d_size == size + sizeof(lv_mem_header_t)) {
875 size = e->header.s.d_size;
876 }
877
878 /* Create the new entry after the current if there is space for it */
879 if(e->header.s.d_size != size) {
880 uint8_t * e_data = &e->first_data;
881 lv_mem_ent_t * after_new_e = (lv_mem_ent_t *)&e_data[size];
882 after_new_e->header.s.used = 0;
883 after_new_e->header.s.d_size = (uint32_t)e->header.s.d_size - size - sizeof(lv_mem_header_t);
884 }
885
886 /* Set the new size for the original entry */
887 e->header.s.d_size = (uint32_t)size;
888 }
889
890 #endif
891