Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

Committer:
arnoz
Date:
Fri Oct 01 08:19:46 2021 +0000
Revision:
116:7a67265d7c19
Parent:
79:682ae3171a08
- Correct information regarding your last merge

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mjr 79:682ae3171a08 1 #include "mbed.h"
mjr 79:682ae3171a08 2 #include "NewMalloc.h"
mjr 79:682ae3171a08 3
mjr 79:682ae3171a08 4 extern void diagLED(int, int, int);
mjr 79:682ae3171a08 5
mjr 79:682ae3171a08 6 // Custom memory allocator. We use our own version of malloc() for more
mjr 79:682ae3171a08 7 // efficient memory usage, and to provide diagnostics if we run out of heap.
mjr 79:682ae3171a08 8 //
mjr 79:682ae3171a08 9 // We can implement a more efficient malloc than the library can because we
mjr 79:682ae3171a08 10 // can make an assumption that the library can't: allocations are permanent.
mjr 79:682ae3171a08 11 // The normal malloc has to assume that allocations can be freed, so it has
mjr 79:682ae3171a08 12 // to track blocks individually. For the purposes of this program, though,
mjr 79:682ae3171a08 13 // we don't have to do this because virtually all of our allocations are
mjr 79:682ae3171a08 14 // de facto permanent. We only allocate dyanmic memory during setup, and
mjr 79:682ae3171a08 15 // once we set things up, we never delete anything. This means that we can
mjr 79:682ae3171a08 16 // allocate memory in bare blocks without any bookkeeping overhead.
mjr 79:682ae3171a08 17 //
mjr 79:682ae3171a08 18 // In addition, we can make a larger overall pool of memory available in
mjr 79:682ae3171a08 19 // a custom allocator. The RTL malloc() seems to have a pool of about 3K
mjr 79:682ae3171a08 20 // to work with, even though there really seems to be at least 8K left after
mjr 79:682ae3171a08 21 // reserving a reasonable amount of space for the stack.
mjr 79:682ae3171a08 22
mjr 79:682ae3171a08 23 // halt with a diagnostic display if we run out of memory
mjr 79:682ae3171a08 24 void HaltOutOfMem()
mjr 79:682ae3171a08 25 {
mjr 79:682ae3171a08 26 printf("\r\nOut Of Memory\r\n");
mjr 79:682ae3171a08 27 // halt with the diagnostic display (by looping forever)
mjr 79:682ae3171a08 28 for (;;)
mjr 79:682ae3171a08 29 {
mjr 79:682ae3171a08 30 diagLED(1, 0, 0);
mjr 79:682ae3171a08 31 wait_us(200000);
mjr 79:682ae3171a08 32 diagLED(1, 0, 1);
mjr 79:682ae3171a08 33 wait_us(200000);
mjr 79:682ae3171a08 34 }
mjr 79:682ae3171a08 35 }
mjr 79:682ae3171a08 36
mjr 79:682ae3171a08 37 // For our custom malloc, we take advantage of the known layout of the
mjr 79:682ae3171a08 38 // mbed library memory management. The mbed library puts all of the
mjr 79:682ae3171a08 39 // static read/write data at the low end of RAM; this includes the
mjr 79:682ae3171a08 40 // initialized statics and the "ZI" (zero-initialized) statics. The
mjr 79:682ae3171a08 41 // malloc heap starts just after the last static, growing upwards as
mjr 79:682ae3171a08 42 // memory is allocated. The stack starts at the top of RAM and grows
mjr 79:682ae3171a08 43 // downwards.
mjr 79:682ae3171a08 44 //
mjr 79:682ae3171a08 45 // To figure out where the free memory starts, we simply call the system
mjr 79:682ae3171a08 46 // malloc() to make a dummy allocation the first time we're called, and
mjr 79:682ae3171a08 47 // use the address it returns as the start of our free memory pool. The
mjr 79:682ae3171a08 48 // first malloc() call presumably returns the lowest byte of the pool in
mjr 79:682ae3171a08 49 // the compiler RTL's way of thinking, and from what we know about the
mjr 79:682ae3171a08 50 // mbed heap layout, we know everything above this point should be free,
mjr 79:682ae3171a08 51 // at least until we reach the lowest address used by the stack.
mjr 79:682ae3171a08 52 //
mjr 79:682ae3171a08 53 // The ultimate size of the stack is of course dynamic and unpredictable.
mjr 79:682ae3171a08 54 // In testing, it appears that we currently need a little over 1K. To be
mjr 79:682ae3171a08 55 // conservative, we'll reserve 2K for the stack, by taking it out of the
mjr 79:682ae3171a08 56 // space at top of memory we consider fair game for malloc.
mjr 79:682ae3171a08 57 //
mjr 79:682ae3171a08 58 // Note that we could do this a little more low-level-ly if we wanted.
mjr 79:682ae3171a08 59 // The ARM linker provides a pre-defined extern char[] variable named
mjr 79:682ae3171a08 60 // Image$$RW_IRAM1$$ZI$$Limit, which is always placed just after the
mjr 79:682ae3171a08 61 // last static data variable. In principle, this tells us the start
mjr 79:682ae3171a08 62 // of the available malloc pool. However, in testing, it doesn't seem
mjr 79:682ae3171a08 63 // safe to use this as the start of our malloc pool. I'm not sure why,
mjr 79:682ae3171a08 64 // but probably something in the startup code (either in the C RTL or
mjr 79:682ae3171a08 65 // the mbed library) is allocating from the pool before we get control.
mjr 79:682ae3171a08 66 // So we won't use that approach. Besides, that would tie us even more
mjr 79:682ae3171a08 67 // closely to the ARM compiler. With our malloc() probe approach, we're
mjr 79:682ae3171a08 68 // at least portable to any compiler that uses the same basic memory
mjr 79:682ae3171a08 69 // layout, with the heap above the statics and the stack at top of
mjr 79:682ae3171a08 70 // memory; this isn't universal, but it's very typical.
mjr 79:682ae3171a08 71
mjr 79:682ae3171a08 72 extern "C" {
mjr 79:682ae3171a08 73 void *$Sub$$malloc(size_t);
mjr 79:682ae3171a08 74 void *$Super$$malloc(size_t);
mjr 79:682ae3171a08 75 void $Sub$$free(void *);
mjr 79:682ae3171a08 76 };
mjr 79:682ae3171a08 77
mjr 79:682ae3171a08 78 // override the system malloc
mjr 79:682ae3171a08 79 void *$Sub$$malloc(size_t siz)
mjr 79:682ae3171a08 80 {
mjr 79:682ae3171a08 81 return xmalloc(siz);
mjr 79:682ae3171a08 82 }
mjr 79:682ae3171a08 83
mjr 79:682ae3171a08 84 // custom allocator pool
mjr 79:682ae3171a08 85 static char *xmalloc_nxt = 0;
mjr 79:682ae3171a08 86 size_t xmalloc_rem = 0;
mjr 79:682ae3171a08 87
mjr 79:682ae3171a08 88 // custom allocator
mjr 79:682ae3171a08 89 void *xmalloc(size_t siz)
mjr 79:682ae3171a08 90 {
mjr 79:682ae3171a08 91 // initialize the pool if we haven't already
mjr 79:682ae3171a08 92 if (xmalloc_nxt == 0)
mjr 79:682ae3171a08 93 {
mjr 79:682ae3171a08 94 // do a dummy allocation with the system malloc() to find where
mjr 79:682ae3171a08 95 // the free pool starts
mjr 79:682ae3171a08 96 xmalloc_nxt = (char *)$Super$$malloc(4);
mjr 79:682ae3171a08 97
mjr 79:682ae3171a08 98 // figure the amount of space we can use - we have from the base
mjr 79:682ae3171a08 99 // of the pool to the top of RAM, minus an allowance for the stack
mjr 79:682ae3171a08 100 const uint32_t TopOfRAM = 0x20003000UL;
mjr 79:682ae3171a08 101 const uint32_t StackSize = 2*1024;
mjr 79:682ae3171a08 102 xmalloc_rem = TopOfRAM - StackSize - uint32_t(xmalloc_nxt);
mjr 79:682ae3171a08 103 }
mjr 79:682ae3171a08 104
mjr 79:682ae3171a08 105 // align to a dword boundary
mjr 79:682ae3171a08 106 siz = (siz + 3) & ~3;
mjr 79:682ae3171a08 107
mjr 79:682ae3171a08 108 // make sure we have enough space left for this chunk
mjr 79:682ae3171a08 109 if (siz > xmalloc_rem)
mjr 79:682ae3171a08 110 HaltOutOfMem();
mjr 79:682ae3171a08 111
mjr 79:682ae3171a08 112 // carve the chunk out of the remaining free pool
mjr 79:682ae3171a08 113 char *ret = xmalloc_nxt;
mjr 79:682ae3171a08 114 xmalloc_nxt += siz;
mjr 79:682ae3171a08 115 xmalloc_rem -= siz;
mjr 79:682ae3171a08 116
mjr 79:682ae3171a08 117 // return the allocated space
mjr 79:682ae3171a08 118 return ret;
mjr 79:682ae3171a08 119 }
mjr 79:682ae3171a08 120
mjr 79:682ae3171a08 121 // Remaining free memory
mjr 79:682ae3171a08 122 size_t mallocBytesFree()
mjr 79:682ae3171a08 123 {
mjr 79:682ae3171a08 124 return xmalloc_rem;
mjr 79:682ae3171a08 125 }
mjr 79:682ae3171a08 126