diff --git a/cpu/msp430_common/Makefile.include b/cpu/msp430_common/Makefile.include index b807ff2eb6..d3c40b273d 100644 --- a/cpu/msp430_common/Makefile.include +++ b/cpu/msp430_common/Makefile.include @@ -1,10 +1,9 @@ -PSEUDOMODULES += msp430_malloc - INCLUDES += -I$(RIOTCPU)/msp430_common/include/ CFLAGS += -DCPU_MODEL_$(call uppercase_and_underscore,$(CPU_MODEL)) UNDEF += $(BINDIR)/msp430_common/startup.o +USEMODULE += msp430_common msp430_common_periph periph_common # include the msp430 common Makefile include $(RIOTMAKE)/arch/msp430.inc.mk diff --git a/cpu/msp430_common/malloc.c b/cpu/msp430_common/malloc.c deleted file mode 100644 index bae6ce9db4..0000000000 --- a/cpu/msp430_common/malloc.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Copyright (c) 2002, 2004, 2010 Joerg Wunsch - * Copyright (c) 2010 Gerben van den Broeke - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of the copyright holders nor the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * Modified by Gunar Schorcht - */ - -/** - * @ingroup cpu - * @{ - * - * @file - * @brief MSP430 malloc/free memory management functions - * - * AVR libc functions adapted for MSP430 CPUs. - * - * @author Gunar Schorcht - * - * @} - */ - -#include -#include - -#include "irq.h" - -#ifdef MODULE_MSP430_MALLOC - -#define asmv(arg) __asm__ __volatile__(arg) - -#define STACK_EXTRA 32 - -#define __brkval cur_break -#define __malloc_heap_end __heap_end - -/* May be changed by the user only before the first malloc() call. */ -extern int _end; /* provided by linker script */ -extern char *cur_break; -extern char *__heap_end; - -struct __freelist { - size_t sz; - struct __freelist *nx; -}; - -size_t __malloc_margin = STACK_EXTRA; -char *__malloc_heap_start = (char*)&_end; - -struct __freelist *__flp; - -void * -malloc(size_t len) -{ - struct __freelist *fp1, *fp2, *sfp1, *sfp2; - char *cp; - size_t s; - unsigned state; - - state = irq_disable(); - - /* - * Our minimum chunk size is the size of a pointer (plus the - * size of the "sz" field, but we don't need to account for - * this), otherwise we could not possibly fit a freelist entry - * into the chunk later. - */ - if (len < sizeof(struct __freelist) - sizeof(size_t)) { - len = sizeof(struct __freelist) - sizeof(size_t); - } - - /* - * First, walk the free list and try finding a chunk that - * would match exactly. If we found one, we are done. While - * walking, note down the smallest chunk we found that would - * still fit the request -- we need it for step 2. - * - */ - for (s = 0, fp1 = __flp, fp2 = 0; fp1; fp2 = fp1, fp1 = fp1->nx) { - if (fp1->sz < len) { - continue; - } - if (fp1->sz == len) { - /* - * Found it. Disconnect the chunk from the - * freelist, and return it. - */ - if (fp2) { - fp2->nx = fp1->nx; - } - else { - __flp = fp1->nx; - } - irq_restore(state); - return &(fp1->nx); - } - else { - if (s == 0 || fp1->sz < s) { - /* this is the smallest chunk found so far */ - s = fp1->sz; - sfp1 = fp1; - sfp2 = fp2; - } - } - } - /* - * Step 2: If we found a chunk on the freelist that would fit - * (but was too large), look it up again and use it, since it - * is our closest match now. Since the freelist entry needs - * to be split into two entries then, watch out that the - * difference between the requested size and the size of the - * chunk found is large enough for another freelist entry; if - * not, just enlarge the request size to what we have found, - * and use the entire chunk. - */ - if (s) { - if (s - len < sizeof(struct __freelist)) { - /* Disconnect it from freelist and return it. */ - if (sfp2) { - sfp2->nx = sfp1->nx; - } - else { - __flp = sfp1->nx; - } - irq_restore(state); - return &(sfp1->nx); - } - /* - * Split them up. Note that we leave the first part - * as the new (smaller) freelist entry, and return the - * upper portion to the caller. This saves us the - * work to fix up the freelist chain; we just need to - * fixup the size of the current entry, and note down - * the size of the new chunk before returning it to - * the caller. - */ - cp = (char *)sfp1; - s -= len; - cp += s; - sfp2 = (struct __freelist *)cp; - sfp2->sz = len; - sfp1->sz = s - sizeof(size_t); - irq_restore(state); - return &(sfp2->nx); - } - /* - * Step 3: If the request could not be satisfied from a - * freelist entry, just prepare a new chunk. This means we - * need to obtain more memory first. The largest address just - * not allocated so far is remembered in the brkval variable. - * Under Unix, the "break value" was the end of the data - * segment as dynamically requested from the operating system. - * Since we don't have an operating system, just make sure - * that we don't collide with the stack. - */ - size_t avail; - if (__brkval == NULL) { - __brkval = __malloc_heap_start; - } - cp = __malloc_heap_end; - if (cp == NULL) { - char *stack_pointer; - asmv("mov r1, %0" : "=r"(stack_pointer)); - cp = stack_pointer - __malloc_margin; - } - if (cp <= __brkval) { - /* - * Memory exhausted. - */ - irq_restore(state); - return 0; - } - avail = cp - __brkval; - /* - * Both tests below are needed to catch the case len >= 0xfffe. - */ - if (avail >= len && avail >= len + sizeof(size_t)) { - fp1 = (struct __freelist *)__brkval; - __brkval += len + sizeof(size_t); - fp1->sz = len; - irq_restore(state); - return &(fp1->nx); - } - /* - * Step 4: There's no help, just fail. :-/ - */ - irq_restore(state); - return 0; -} - -void -free(void *p) -{ - struct __freelist *fp1, *fp2, *fpnew; - char *cp1, *cp2, *cpnew; - unsigned state; - - state = irq_disable(); - - if (__brkval == NULL) { - __brkval = __malloc_heap_start; - } - - /* ISO C says free(NULL) must be a no-op */ - if (p == NULL) { - irq_restore(state); - return; - } - - cpnew = p; - cpnew -= sizeof(size_t); - fpnew = (struct __freelist *)cpnew; - fpnew->nx = 0; - - /* - * Trivial case first: if there's no freelist yet, our entry - * will be the only one on it. If this is the last entry, we - * can reduce __brkval instead. - */ - if (__flp == NULL) { - if ((char *)p + fpnew->sz == __brkval) { - __brkval = cpnew; - } - else { - __flp = fpnew; - } - irq_restore(state); - return; - } - - /* - * Now, find the position where our new entry belongs onto the - * freelist. Try to aggregate the chunk with adjacent chunks - * if possible. - */ - for (fp1 = __flp, fp2 = 0; - fp1; - fp2 = fp1, fp1 = fp1->nx) { - if (fp1 < fpnew) { - continue; - } - cp1 = (char *)fp1; - fpnew->nx = fp1; - if ((char *)&(fpnew->nx) + fpnew->sz == cp1) { - /* upper chunk adjacent, assimilate it */ - fpnew->sz += fp1->sz + sizeof(size_t); - fpnew->nx = fp1->nx; - } - if (fp2 == NULL) { - /* new head of freelist */ - __flp = fpnew; - irq_restore(state); - return; - } - break; - } - /* - * Note that we get here either if we hit the "break" above, - * or if we fell off the end of the loop. The latter means - * we've got a new topmost chunk. Either way, try aggregating - * with the lower chunk if possible. - */ - fp2->nx = fpnew; - cp2 = (char *)&(fp2->nx); - if (cp2 + fp2->sz == cpnew) { - /* lower junk adjacent, merge */ - fp2->sz += fpnew->sz + sizeof(size_t); - fp2->nx = fpnew->nx; - } - /* - * If there's a new topmost chunk, lower __brkval instead. - */ - for (fp1 = __flp, fp2 = 0; - fp1->nx != NULL; - fp2 = fp1, fp1 = fp1->nx) - /* advance to entry just before end of list */; - cp2 = (char *)&(fp1->nx); - if (cp2 + fp1->sz == __brkval) { - if (fp2 == NULL) { - /* Freelist is empty now. */ - __flp = NULL; - } - else { - fp2->nx = NULL; - } - __brkval = cp2 - sizeof(size_t); - } - - irq_restore(state); -} - -#include - -void * -realloc(void *ptr, size_t len) -{ - struct __freelist *fp1, *fp2, *fp3, *ofp3; - char *cp, *cp1; - void *memp; - size_t s, incr; - unsigned state; - - /* Trivial case, required by C standard. */ - if (ptr == NULL) { - return malloc(len); - } - - state = irq_disable(); - - cp1 = (char *)ptr; - cp1 -= sizeof(size_t); - fp1 = (struct __freelist *)cp1; - - cp = (char *)ptr + len; /* new next pointer */ - if (cp < cp1) { - /* Pointer wrapped across top of RAM, fail. */ - irq_restore(state); - return 0; - } - /* - * See whether we are growing or shrinking. When shrinking, - * we split off a chunk for the released portion, and call - * free() on it. Therefore, we can only shrink if the new - * size is at least sizeof(struct __freelist) smaller than the - * previous size. - */ - if (len <= fp1->sz) { - /* The first test catches a possible unsigned int - * rollover condition. */ - if (fp1->sz <= sizeof(struct __freelist) || - len > fp1->sz - sizeof(struct __freelist)) { - irq_restore(state); - return ptr; - } - fp2 = (struct __freelist *)cp; - fp2->sz = fp1->sz - len - sizeof(size_t); - fp1->sz = len; - free(&(fp2->nx)); - irq_restore(state); - return ptr; - } - - /* - * If we get here, we are growing. First, see whether there - * is space in the free list on top of our current chunk. - */ - incr = len - fp1->sz; - cp = (char *)ptr + fp1->sz; - fp2 = (struct __freelist *)cp; - for (s = 0, ofp3 = 0, fp3 = __flp; - fp3; - ofp3 = fp3, fp3 = fp3->nx) { - if (fp3 == fp2 && fp3->sz + sizeof(size_t) >= incr) { - /* found something that fits */ - if (fp3->sz + sizeof(size_t) - incr > sizeof(struct __freelist)) { - /* split off a new freelist entry */ - cp = (char *)ptr + len; - fp2 = (struct __freelist *)cp; - fp2->nx = fp3->nx; - fp2->sz = fp3->sz - incr; - fp1->sz = len; - } - else { - /* it just fits, so use it entirely */ - fp1->sz += fp3->sz + sizeof(size_t); - fp2 = fp3->nx; - } - if (ofp3) { - ofp3->nx = fp2; - } - else { - __flp = fp2; - } - irq_restore(state); - return ptr; - } - /* - * Find the largest chunk on the freelist while - * walking it. - */ - if (fp3->sz > s) { - s = fp3->sz; - } - } - /* - * If we are the topmost chunk in memory, and there was no - * large enough chunk on the freelist that could be re-used - * (by a call to malloc() below), quickly extend the - * allocation area if possible, without need to copy the old - * data. - */ - if (__brkval == (char *)ptr + fp1->sz && len > s) { - cp1 = __malloc_heap_end; - cp = (char *)ptr + len; - if (cp1 == NULL) { - char *stack_pointer; - asmv("mov r1, %0" : "=r"(stack_pointer)); - cp1 = stack_pointer - __malloc_margin; - } - if (cp < cp1) { - __brkval = cp; - fp1->sz = len; - irq_restore(state); - return ptr; - } - /* If that failed, we are out of luck. */ - irq_restore(state); - return 0; - } - - /* - * Call malloc() for a new chunk, then copy over the data, and - * release the old region. - */ - if ((memp = malloc(len)) == NULL) { - irq_restore(state); - return 0; - } - memcpy(memp, ptr, fp1->sz); - free(ptr); - irq_restore(state); - return memp; -} - -void * -calloc(size_t nele, size_t size) -{ - void *p; - - if ((p = malloc(nele * size)) == NULL) { - return 0; - } - memset(p, 0, nele * size); - return p; -} - -void heap_stats(void) -{ - if (__brkval == NULL) { - __brkval = __malloc_heap_start; - } - - long int heap_size = __malloc_heap_end - __malloc_heap_start; - long int free = __malloc_heap_end - __brkval; - struct __freelist *fp; - for (fp = __flp; fp; fp = fp->nx) { - free += fp->sz; - } - printf("heap: %ld (used %ld, free %ld) [bytes]\n", - heap_size, heap_size - free, free); -} - -#else - -void heap_stats(void) { - puts("heap statistics are not supported"); -} - -#endif /* MODULE_MSP430_MALLOC */ diff --git a/cpu/msp430_common/msp430-main.c b/cpu/msp430_common/msp430-main.c index aabc4d96ba..7b5b25e61d 100644 --- a/cpu/msp430_common/msp430-main.c +++ b/cpu/msp430_common/msp430-main.c @@ -107,7 +107,7 @@ init_ports(void) /*---------------------------------------------------------------------------*/ /* msp430-ld may align _end incorrectly. Workaround in cpu_init. */ extern int _end; /* Not in sys/unistd.h */ -char *cur_break = (char *) &_end; +static char *cur_break = (char *) &_end; void msp430_cpu_init(void) {