RTL8710_SDK_GCC_VERSION/component/os/os_dep/tcm_heap.c
RtlduinoMan 1d3357d3b0 GCC SDK RTL8710 basic version (including the window platform cygwin installation and Ubuntu platform Linux Installation routines),
including cross compilation of the installation, compile, link, run, debug, and so on.
SDK implementation of the function:
1, WiFi connection settings (including AP mode and STA mode).
2, peripheral resource control (including GPIO, SPI, UART, IIC, etc.).
3, the user uses the sample method.
2016-09-08 20:52:17 +08:00

352 lines
7.9 KiB
C

//#include <autoconf.h>
#include "tcm_heap.h"
#include <string.h> // memset()
#include <osdep_service.h>
//#define _DEBUG
#if CONFIG_USE_TCM_HEAP
#define FREE_FILL_CODE 0xDEAD
#define ALLOC_FILL_CODE 0xBEEF
#define ROUND_UP2(x, pad) (((x) + ((pad) - 1)) & ~((pad) - 1))
#define TCM_HEAP_SIZE (40*1024)
static struct Heap g_tcm_heap;
#if defined (__ICCARM__)
#pragma location=".tcm.heap"
#else
__attribute__((section(".tcm.heap")))
#endif
HEAP_DEFINE_BUF(tcm_heap, TCM_HEAP_SIZE);
//unsigned char tcm_heap[TCM_HEAP_SIZE];
static int g_heap_inited=0;
static _lock tcm_lock;
extern void vPortSetExtFree( void (*free)( void *p ), uint32_t upper, uint32_t lower );
void tcm_heap_init(void)
{
//#ifdef _DEBUG
//memset(memory, FREE_FILL_CODE, size);
//#endif
//ASSERT2(((int)memory % alignof(heap_buf_t)) == 0,
//"memory buffer is unaligned, please use the HEAP_DEFINE_BUF() macro to declare heap buffers!\n");
/* Initialize heap with a single big chunk */
g_tcm_heap.FreeList = (MemChunk *)&tcm_heap;
g_tcm_heap.FreeList->next = NULL;
g_tcm_heap.FreeList->size = sizeof(tcm_heap);
g_heap_inited = 1;
rtw_spinlock_init(&tcm_lock);
#if PLATFORM_FREERTOS
// let RTOS know how to free memory if using as task stack
vPortSetExtFree(tcm_heap_free, 0x20000000, 0x1fff0000);
#endif
}
void tcm_heap_dump(void)
{
MemChunk *chunk, *prev;
struct Heap* h = &g_tcm_heap;
printf("---Free List--\n\r");
for (prev = (MemChunk *)&h->FreeList, chunk = h->FreeList;
chunk;
prev = chunk, chunk = chunk->next)
{
printf(" prev %x, chunk %x, size %d \n\r", prev, chunk, chunk->size);
}
printf("--------------\n\r");
}
void *tcm_heap_allocmem(int size)
{
MemChunk *chunk, *prev;
struct Heap* h = &g_tcm_heap;
_irqL irqL;
rtw_enter_critical(&tcm_lock, &irqL);
if(!g_heap_inited) tcm_heap_init();
/* Round size up to the allocation granularity */
size = ROUND_UP2(size, sizeof(MemChunk));
/* Handle allocations of 0 bytes */
if (!size)
size = sizeof(MemChunk);
/* Walk on the free list looking for any chunk big enough to
* fit the requested block size.
*/
for (prev = (MemChunk *)&h->FreeList, chunk = h->FreeList;
chunk;
prev = chunk, chunk = chunk->next)
{
if (chunk->size >= size)
{
if (chunk->size == size)
{
/* Just remove this chunk from the free list */
prev->next = chunk->next;
#ifdef _DEBUG
memset(chunk, ALLOC_FILL_CODE, size);
#endif
rtw_exit_critical(&tcm_lock, &irqL);
//printf("----ALLOC1-----\n\r");
//tcm_heap_dump();
//printf("--------------\n\r");
return (void *)chunk;
}
else
{
/* Allocate from the END of an existing chunk */
chunk->size -= size;
#ifdef _DEBUG
memset((uint8_t *)chunk + chunk->size, ALLOC_FILL_CODE, size);
#endif
rtw_exit_critical(&tcm_lock, &irqL);
//printf("----ALLOC2-----\n\r");
//tcm_heap_dump();
//printf("--------------\n\r");
return (void *)((uint8_t *)chunk + chunk->size);
}
}
}
rtw_exit_critical(&tcm_lock, &irqL);
//printf("----ALLOC3-----\n\r");
//tcm_heap_dump();
//printf("--------------\n\r");
return NULL; /* fail */
}
void tcm_heap_freemem(void *mem, int size)
{
MemChunk *prev;
//ASSERT(mem);
struct Heap* h = &g_tcm_heap;
_irqL irqL;
rtw_enter_critical(&tcm_lock, &irqL);
if(!g_heap_inited) tcm_heap_init();
#ifdef _DEBUG
memset(mem, FREE_FILL_CODE, size);
#endif
/* Round size up to the allocation granularity */
size = ROUND_UP2(size, sizeof(MemChunk));
/* Handle allocations of 0 bytes */
if (!size)
size = sizeof(MemChunk);
/* Special cases: first chunk in the free list or memory completely full */
//ASSERT((uint8_t*)mem != (uint8_t*)h->FreeList);
if (((uint8_t *)mem) < ((uint8_t *)h->FreeList) || !h->FreeList)
{
/* Insert memory block before the current free list head */
prev = (MemChunk *)mem;
prev->next = h->FreeList;
prev->size = size;
h->FreeList = prev;
}
else /* Normal case: not the first chunk in the free list */
{
/*
* Walk on the free list. Stop at the insertion point (when mem
* is between prev and prev->next)
*/
prev = h->FreeList;
while (prev->next < (MemChunk *)mem && prev->next)
prev = prev->next;
/* Make sure mem is not *within* prev */
//ASSERT((uint8_t*)mem >= (uint8_t*)prev + prev->size);
/* Should it be merged with previous block? */
if (((uint8_t *)prev) + prev->size == ((uint8_t *)mem))
{
/* Yes */
prev->size += size;
}
else /* not merged with previous chunk */
{
MemChunk *curr = (MemChunk*)mem;
/* insert it after the previous node
* and move the 'prev' pointer forward
* for the following operations
*/
curr->next = prev->next;
curr->size = size;
prev->next = curr;
/* Adjust for the following test */
prev = curr;
}
}
/* Also merge with next chunk? */
if (((uint8_t *)prev) + prev->size == ((uint8_t *)prev->next))
{
prev->size += prev->next->size;
prev->next = prev->next->next;
/* There should be only one merge opportunity, becuase we always merge on free */
//ASSERT((uint8_t*)prev + prev->size != (uint8_t*)prev->next);
}
rtw_exit_critical(&tcm_lock, &irqL);
//printf("---FREE %x--\n\r", mem);
//tcm_heap_dump();
//printf("--------------\n\r");
}
int tcm_heap_freeSpace(void)
{
int free_mem = 0;
struct Heap* h = &g_tcm_heap;
_irqL irqL;
MemChunk *chunk;
rtw_enter_critical(&tcm_lock, &irqL);
if(!g_heap_inited) tcm_heap_init();
for (chunk = h->FreeList; chunk; chunk = chunk->next)
free_mem += chunk->size;
rtw_exit_critical(&tcm_lock, &irqL);
return free_mem;
}
/**
* Standard malloc interface
*/
void *tcm_heap_malloc(int size)
{
int *mem;
size += sizeof(int);
if ((mem = (int*)tcm_heap_allocmem(size))){
*mem++ = size;
}
return mem;
}
/**
* Standard calloc interface
*/
void *tcm_heap_calloc(int size)
{
void *mem;
if ((mem = tcm_heap_malloc(size)))
memset(mem, 0, size);
return mem;
}
/**
* Free a block of memory, determining its size automatically.
*
* \param h Heap from which the block was allocated.
* \param mem Pointer to a block of memory previously allocated with
* either heap_malloc() or heap_calloc().
*
* \note If \a mem is a NULL pointer, no operation is performed.
*
* \note Freeing the same memory block twice has undefined behavior.
*
* \note This function works like the ANSI C free().
*/
void tcm_heap_free(void *mem)
{
int *_mem = (int *)mem;
if (_mem)
{
--_mem;
tcm_heap_freemem(_mem, *_mem);
}
}
static void alloc_test(int size, int test_len)
{
//Simple test
uint8_t *a[100];
int i, j;
for (i = 0; i < test_len; i++)
{
a[i] = tcm_heap_allocmem(size);
//ASSERT(a[i]);
for (j = 0; j < size; j++)
a[i][j] = i;
}
//ASSERT(heap_freeSpace(&h) == HEAP_SIZE - test_len * ROUND_UP2(size, sizeof(MemChunk)));
for (i = 0; i < test_len; i++)
{
for (j = 0; j < size; j++)
{
printf("a[%d][%d] = %d\n", i, j, a[i][j]);
//ASSERT(a[i][j] == i);
}
tcm_heap_freemem(a[i], size);
}
//ASSERT(heap_freeSpace(&h) == HEAP_SIZE);
}
#define ALLOC_SIZE 256
#define ALLOC_SIZE2 1024
#define TEST_LEN 20
#define TEST_LEN2 10
#define HEAP_SIZE 59*1024
int tcm_heap_testRun(void)
{
alloc_test(ALLOC_SIZE, TEST_LEN);
alloc_test(ALLOC_SIZE2, TEST_LEN2);
/* Try to allocate the whole heap */
uint8_t *b = tcm_heap_allocmem(HEAP_SIZE);
int i, j;
//ASSERT(b);
//ASSERT(heap_freeSpace(&h) == 0);
//ASSERT(!heap_allocmem(&h, HEAP_SIZE));
for (j = 0; j < HEAP_SIZE; j++)
b[j] = j;
for (j = 0; j < HEAP_SIZE; j++)
{
printf("b[%d] = %d\n", j, j);
//ASSERT(b[j] == (j & 0xff));
}
tcm_heap_freemem(b, HEAP_SIZE);
//ASSERT(heap_freeSpace(&h) == HEAP_SIZE);
return 0;
}
#endif