An I/O controller for virtual pinball machines: accelerometer nudge sensing, analog plunger input, button input encoding, LedWiz compatible output controls, and more.
Dependencies: mbed FastIO FastPWM USBDevice
Fork of Pinscape_Controller by
NewMalloc.cpp
00001 #include "mbed.h" 00002 #include "NewMalloc.h" 00003 00004 extern void diagLED(int, int, int); 00005 00006 // Custom memory allocator. We use our own version of malloc() for more 00007 // efficient memory usage, and to provide diagnostics if we run out of heap. 00008 // 00009 // We can implement a more efficient malloc than the library can because we 00010 // can make an assumption that the library can't: allocations are permanent. 00011 // The normal malloc has to assume that allocations can be freed, so it has 00012 // to track blocks individually. For the purposes of this program, though, 00013 // we don't have to do this because virtually all of our allocations are 00014 // de facto permanent. We only allocate dyanmic memory during setup, and 00015 // once we set things up, we never delete anything. This means that we can 00016 // allocate memory in bare blocks without any bookkeeping overhead. 00017 // 00018 // In addition, we can make a larger overall pool of memory available in 00019 // a custom allocator. The RTL malloc() seems to have a pool of about 3K 00020 // to work with, even though there really seems to be at least 8K left after 00021 // reserving a reasonable amount of space for the stack. 00022 00023 // halt with a diagnostic display if we run out of memory 00024 void HaltOutOfMem() 00025 { 00026 printf("\r\nOut Of Memory\r\n"); 00027 // halt with the diagnostic display (by looping forever) 00028 for (;;) 00029 { 00030 diagLED(1, 0, 0); 00031 wait_us(200000); 00032 diagLED(1, 0, 1); 00033 wait_us(200000); 00034 } 00035 } 00036 00037 // For our custom malloc, we take advantage of the known layout of the 00038 // mbed library memory management. The mbed library puts all of the 00039 // static read/write data at the low end of RAM; this includes the 00040 // initialized statics and the "ZI" (zero-initialized) statics. The 00041 // malloc heap starts just after the last static, growing upwards as 00042 // memory is allocated. The stack starts at the top of RAM and grows 00043 // downwards. 00044 // 00045 // To figure out where the free memory starts, we simply call the system 00046 // malloc() to make a dummy allocation the first time we're called, and 00047 // use the address it returns as the start of our free memory pool. The 00048 // first malloc() call presumably returns the lowest byte of the pool in 00049 // the compiler RTL's way of thinking, and from what we know about the 00050 // mbed heap layout, we know everything above this point should be free, 00051 // at least until we reach the lowest address used by the stack. 00052 // 00053 // The ultimate size of the stack is of course dynamic and unpredictable. 00054 // In testing, it appears that we currently need a little over 1K. To be 00055 // conservative, we'll reserve 2K for the stack, by taking it out of the 00056 // space at top of memory we consider fair game for malloc. 00057 // 00058 // Note that we could do this a little more low-level-ly if we wanted. 00059 // The ARM linker provides a pre-defined extern char[] variable named 00060 // Image$$RW_IRAM1$$ZI$$Limit, which is always placed just after the 00061 // last static data variable. In principle, this tells us the start 00062 // of the available malloc pool. However, in testing, it doesn't seem 00063 // safe to use this as the start of our malloc pool. I'm not sure why, 00064 // but probably something in the startup code (either in the C RTL or 00065 // the mbed library) is allocating from the pool before we get control. 00066 // So we won't use that approach. Besides, that would tie us even more 00067 // closely to the ARM compiler. With our malloc() probe approach, we're 00068 // at least portable to any compiler that uses the same basic memory 00069 // layout, with the heap above the statics and the stack at top of 00070 // memory; this isn't universal, but it's very typical. 00071 00072 extern "C" { 00073 void *$Sub$$malloc(size_t); 00074 void *$Super$$malloc(size_t); 00075 void $Sub$$free(void *); 00076 }; 00077 00078 // override the system malloc 00079 void *$Sub$$malloc(size_t siz) 00080 { 00081 return xmalloc(siz); 00082 } 00083 00084 // custom allocator pool 00085 static char *xmalloc_nxt = 0; 00086 size_t xmalloc_rem = 0; 00087 00088 // custom allocator 00089 void *xmalloc(size_t siz) 00090 { 00091 // initialize the pool if we haven't already 00092 if (xmalloc_nxt == 0) 00093 { 00094 // do a dummy allocation with the system malloc() to find where 00095 // the free pool starts 00096 xmalloc_nxt = (char *)$Super$$malloc(4); 00097 00098 // figure the amount of space we can use - we have from the base 00099 // of the pool to the top of RAM, minus an allowance for the stack 00100 const uint32_t TopOfRAM = 0x20003000UL; 00101 const uint32_t StackSize = 2*1024; 00102 xmalloc_rem = TopOfRAM - StackSize - uint32_t(xmalloc_nxt); 00103 } 00104 00105 // align to a dword boundary 00106 siz = (siz + 3) & ~3; 00107 00108 // make sure we have enough space left for this chunk 00109 if (siz > xmalloc_rem) 00110 HaltOutOfMem(); 00111 00112 // carve the chunk out of the remaining free pool 00113 char *ret = xmalloc_nxt; 00114 xmalloc_nxt += siz; 00115 xmalloc_rem -= siz; 00116 00117 // return the allocated space 00118 return ret; 00119 } 00120 00121 // Remaining free memory 00122 size_t mallocBytesFree() 00123 { 00124 return xmalloc_rem; 00125 } 00126
Generated on Wed Jul 13 2022 03:30:11 by 1.7.2