/*---------------------------------------------------------------------------*
  Project:  TwlSDK - OS
  File:     os_alloc.c

  Copyright 2003-2009 Nintendo.  All rights reserved.

  These coded instructions, statements, and computer programs contain
  proprietary information of Nintendo of America Inc. and/or Nintendo
  Company Ltd., and are protected by Federal copyright law.  They may
  not be disclosed to third parties or copied or duplicated in any form,
  in whole or in part, without the prior written consent of Nintendo.

  $Date:: 2009-06-04#$
  $Rev: 10698 $
  $Author: okubata_ryoma $

 *---------------------------------------------------------------------------*/
#include <nitro/os.h>
#include <nitro/os/common/alloc.h>

/*---------------------------------------------------------------------------*
    Error messages of OSAlloc.c
 *---------------------------------------------------------------------------*/
#define OS_ERR_ALLOCFROMHEAP_NOHEAP         "OS_AllocFromHeap(): heap is not initialized."
#define OS_ERR_ALLOCFROMHEAP_INVSIZE        "OS_AllocFromHeap(): invalid size."
#define OS_ERR_ALLOCFROMHEAP_INVHEAP        "OS_AllocFromHeap(): invalid heap handle."
#define OS_ERR_ALLOCFROMHEAP_BROKENHEAP     "OS_AllocFromHeap(): heap is broken."
#define OS_ERR_ALLOCFIXED_NOHEAP            "OS_AllocFixed(): heap is not initialized."
#define OS_ERR_ALLOCFIXED_INVRANGE          "OS_AllocFixed(): invalid range."
#define OS_ERR_FREETOHEAP_NOHEAP            "OS_FreeToHeap(): heap is not initialized."
#define OS_ERR_FREETOHEAP_INVPTR            "OS_FreeToHeap(): invalid pointer."
#define OS_ERR_FREETOHEAP_INVHEAP           "OS_FreeToHeap(): invalid heap handle."
#define OS_ERR_SETCURRENTHEAP_NOHEAP        "OS_SetCurrentHeap(): heap is not initialized."
#define OS_ERR_SETCURRENTHEAP_INVHEAP       "OS_SetCurrentHeap(): invalid heap handle."
#define OS_ERR_INITALLOC_INVNUMHEAPS        "OS_InitAlloc(): invalid number of heaps."
#define OS_ERR_INITALLOC_INVRANGE           "OS_InitAlloc(): invalid range."
#define OS_ERR_INITALLOC_INSRANGE           "OS_InitAlloc(): too small range."
#define OS_ERR_CLEARALLOC_INVID             "OS_ClearAlloc(): invalid arena id."
#define OS_ERR_CREATEHEAP_NOHEAP            "OS_CreateHeap(): heap is not initialized."
#define OS_ERR_CREATEHEAP_INVRANGE          "OS_CreateHeap(): invalid range."
#define OS_ERR_CREATEHEAP_INSRANGE          "OS_CreateHeap(): too small range."
#define OS_ERR_DESTROYHEAP_NOHEAP           "OS_DestroyHeap(): heap is not initialized."
#define OS_ERR_DESTROYHEAP_INVHEAP          "OS_DestroyHeap(): invalid heap handle."
#define OS_ERR_ADDTOHEAP_NOHEAP             "OS_AddToHeap(): heap is not initialized."
#define OS_ERR_ADDTOHEAP_INVHEAP            "OS_AddToHeap(): invalid heap handle."
#define OS_ERR_ADDTOHEAP_INVRANGE           "OS_AddToHeap(): invalid range."
#define OS_ERR_ADDTOHEAP_INSRANGE           "OS_AddToHeap(): too small range."
#define OS_ERR_REFERENT_NOHEAP              "OS_ReferentSize(): heap is not initialized."
#define OS_ERR_REFERENT_INVPTR              "OS_ReferentSize(): invalid pointer."
#define OS_ERR_DUMPHEAP_NOHEAP              "OS_DumpHeap(): heap is not initialized."
#define OS_ERR_DUMPHEAP_INVHEAP             "OS_DumpHeap(): invalid heap handle."
#define OS_ERR_DUMPHEAP_BROKENHEAP          "OS_DumpHeap(): heap is broken."
#define OS_ERR_ALLOCFROMHEAP_INVID          "OS_AllocFromHeap(): illegal arena id."
#define OS_ERR_ALLOCFROMHEAP_NOINFO         "OS_AllocFromHeap(): heap not initialized."
#define OS_ERR_ALLOCFIXED_INVID             "OS_AllocFixed(): illegal arena id."
#define OS_ERR_ALLOCFIXED_NOINFO            "OS_AllocFixed(): heap not initialized."
#define OS_ERR_FREETOHEAP_INVID             "OS_FreeToHeap(): illegal arena id."
#define OS_ERR_FREETOHEAP_NOINFO            "OS_FreeToHeap(): heap not initialized."
#define OS_ERR_SETCURRENTHEAP_INVID         "OS_SetCurrentHeap(): illegal arena id."
#define OS_ERR_SETCURRENTHEAP_NOINFO        "OS_SetCurrentHeap(): heap not initialized."
#define OS_ERR_INITALLOC_INVID              "OS_SetInitAlloc(): illegal arena id."
#define OS_ERR_INITALLOC_INVINFO            "OS_SetInitAlloc(): heap already initialized."
#define OS_ERR_CREATEHEAP_INVID             "OS_CreateHeap(): illegal arena id."
#define OS_ERR_CREATEHEAP_NOINFO            "OS_CreateHeap(): heap not initialized."
#define OS_ERR_DESTROYHEAP_INVID            "OS_DestroyHeap(): illegal arena id."
#define OS_ERR_DESTROYHEAP_NOINFO           "OS_DestroyHeap(): heap not initialized."
#define OS_ERR_ADDTOHEAP_INVID              "OS_AddToHeap(): illegal arena id."
#define OS_ERR_ADDTOHEAP_NOINFO             "OS_AddToHeap(): heap not initialized."
#define OS_ERR_CHECKHEAP_INVID              "OS_CheckHeap(): illegal arena id."
#define OS_ERR_CHECKHEAP_NOINFO             "OS_CheckHeap(): heap not initialized."
#define OS_ERR_REFERENTSIZE_INVID           "OS_ReferentSize(): illegal arena id."
#define OS_ERR_REFERENTSIZE_NOINFO          "OS_ReferrentSize(): heap not initialized."
#define OS_ERR_DUMPHEAP_INVID               "OS_DumpHeap(): illegal arena id."
#define OS_ERR_DUMPHEAP_NOINFO              "OS_DumpHeap(): heap not initialized."
#define OS_ERR_VISITALLOCATED_INVID         "OS_VisitAllocated(): illegal arena id."
#define OS_ERR_VISITALLOCATED_NOINFO        "OS_VisitAllocated(): heap not initialized."


#define OFFSET(n, a)    (((u32) (n)) & ((a) - 1))
#define TRUNC(n, a)     (((u32) (n)) & ~((a) - 1))
#define ROUND(n, a)     (((u32) (n) + (a) - 1) & ~((a) - 1))

#define ALIGNMENT       32             // alignment in bytes
#define MINOBJSIZE      (HEADERSIZE + ALIGNMENT)        // smallest object
#define HEADERSIZE      ROUND(sizeof(Cell), ALIGNMENT)

//---- InRange():       True if a <= targ < b
#define InRange(targ, a, b)                                             \
    ((u32)(a) <= (u32)(targ) && (u32)(targ) < (u32)(b))

//---- RangeOverlap():  True if the ranges a and b overlap in any way.
#define RangeOverlap(aStart, aEnd, bStart, bEnd)                        \
    ((u32)(bStart) <= (u32)(aStart) && (u32)(aStart) < (u32)(bEnd) ||   \
     (u32)(bStart) < (u32)(aEnd) && (u32)(aEnd) <= (u32)(bEnd))

//---- RangeSubset():   True if range a is a subset of range b
//                  Assume (aStart < aEnd) and (bStart < bEnd)
#define RangeSubset(aStart, aEnd, bStart, bEnd)                         \
    ((u32)(bStart) <= (u32)(aStart) && (u32)(aEnd) <= (u32)(bEnd))

typedef struct Cell Cell;
typedef struct HeapDesc HeapDesc;

// Cell: header of object which resides HEADERSIZE bytes before payload.
//       doubly linked list are needed because of non-contiguous heaps
struct Cell
{
    Cell   *prev;
    Cell   *next;
    long    size;                      // size of object plus HEADERSIZE

#ifdef  SDK_DEBUG
    HeapDesc *hd;                      // from which the block is allocated
    // (NULL in free list).
    long    requested;                 // size of object to have been requested
#endif                                 // SDK_DEBUG
};

struct HeapDesc
{
    long    size;                      // if -1 then heap is free. Note OS_AllocFixed()
    // could make a heap empty.
    Cell   *free;                      // pointer to the first free cell
    Cell   *allocated;                 // pointer to the first used cell

#ifdef  SDK_DEBUG
    u32     paddingBytes;
    u32     headerBytes;
    u32     payloadBytes;
#endif                                 // SDK_DEBUG
};

#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
static OSArenaId OSi_ExtraHeapArenaId = (OSArenaId)-1;
static OSHeapHandle OSi_ExtraHeapHandle = -1;
#endif

//----------------
//---- struct of Heap infomation
typedef struct
{
    // volatile because some functions use this as hidden macro parameter
    volatile OSHeapHandle currentHeap;
    int     numHeaps;
    void   *arenaStart;
    void   *arenaEnd;
    HeapDesc *heapArray;
}
OSHeapInfo;

void   *OSiHeapInfo[OS_ARENA_MAX] = {
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
};                                     // because OS_ARENA_MAX = 9

//================================================================================
/*---------------------------------------------------------------------------*
  Name:         DLAddFront

  Description:  Inserts /cell/ into the head of the list pointed to by /list/

  Arguments:    list : pointer to the first cell in the list
                cell : pointer to a cell to be inserted

  Returns:      a pointer to the new first cell
 *---------------------------------------------------------------------------*/
static Cell *DLAddFront(Cell * list, Cell * cell)
{
    cell->next = list;
    cell->prev = NULL;
    if (list)
    {
        list->prev = cell;
    }
    return cell;
}

/*---------------------------------------------------------------------------*
  Name:         DLLookup

  Description:  Returns /cell/ if /cell/ is found in /list/.

  Arguments:    list : pointer to the first cell in the list
                cell : pointer to a cell to look for

  Returns:      /cell/ if /cell/ is in /list/. Otherwise, NULL.
 *---------------------------------------------------------------------------*/
static Cell *DLLookup(Cell * list, Cell * cell)
{
    for (; list; list = list->next)
    {
        if (list == cell)
        {
            return list;
        }
    }
    return NULL;
}

/*---------------------------------------------------------------------------*
  Name:         DLExtract

  Description:  Extracts /target/ from the list pointed to by /list/.
                If /target/ is at the head of the list, /list/ will be changed
                to reflect its removal.

  Arguments:    list : pointer to the first cell in the list
                cell : pointer to a cell to remove

  Returns:      a pointer to the new first cell
 *---------------------------------------------------------------------------*/
static Cell *DLExtract(Cell * list, Cell * cell)
{
    if (cell->next)
    {
        cell->next->prev = cell->prev;
    }

    if (cell->prev == NULL)
    {
        return cell->next;
    }
    else
    {
        cell->prev->next = cell->next;
        return list;
    }
}

/*---------------------------------------------------------------------------*
  Name:         DLInsert

  Description:  Inserts /cell/ into the list pointed to by /list/ in sorted
                order by address.  Also attempts to coalesce forward and
                backward blocks if possible.

  Arguments:    list : pointer to the first cell in the list
                cell : pointer to a cell to be inserted

  Returns:      a pointer to the new first cell
 *---------------------------------------------------------------------------*/
static Cell *DLInsert(Cell * list, Cell * cell)
{
    Cell   *prev;
    Cell   *next;

    for (next = list, prev = NULL; next; prev = next, next = next->next)
    {
        if (cell <= next)
        {
            break;
        }
    }

    cell->next = next;
    cell->prev = prev;
    if (next)
    {
        next->prev = cell;
        if ((char *)cell + cell->size == (char *)next)
        {
            //---- Coalesce forward
            cell->size += next->size;
            cell->next = next = next->next;
            if (next)
            {
                next->prev = cell;
            }
        }
    }
    if (prev)
    {
        prev->next = cell;
        if ((char *)prev + prev->size == (char *)cell)
        {
            //---- Coalesce back
            prev->size += cell->size;
            prev->next = next;
            if (next)
            {
                next->prev = prev;
            }
        }
        return list;
    }
    else
    {
        return cell;                   // cell becomes new head of list
    }
}

/*---------------------------------------------------------------------------*
  Name:         DLOverlap

  Description:  returns true if the range delimited by /start/ and /end/
                overlaps with any element of /list/.

  Arguments:    list  : pointer to the first cell in the list
                start : start of range
                end   : end of range

  Returns:      TRUE if /start/-/end/ overlaps with any element of /list/
 *---------------------------------------------------------------------------*/
static BOOL DLOverlap(Cell * list, void *start, void *end)
{
    Cell   *cell;

    for (cell = list; cell; cell = cell->next)
    {
        if (RangeOverlap(cell, (char *)cell + cell->size, start, end))
        {
            return TRUE;
        }
    }
    return FALSE;
}

/*---------------------------------------------------------------------------*
  Name:         DLSize

  Description:  returns total number of bytes used by every element of /list/.

  Arguments:    list : pointer to the first cell in the list

  Returns:      total number of bytes used by every cell of /list/
 *---------------------------------------------------------------------------*/
static long DLSize(Cell * list)
{
    Cell   *cell;
    long    size = 0;

    for (cell = list; cell; cell = cell->next)
    {
        size += cell->size;
    }
    return size;
}

//================================================================================
/*---------------------------------------------------------------------------*
  Name:         OS_AllocFromHeap

  Description:  Allocates /size/ bytes from /heap/. Some additional memory
                will also be consumed from /heap/.

  Arguments:    id   : arena ID
                heap : handle to a heap that was returned from OS_CreateHeap()
                size : size of object to be allocated

  Returns:      a null pointer or a pointer to the allocated space aligned
                with ALIGNMENT bytes boundaries
 *---------------------------------------------------------------------------*/
void   *OS_AllocFromHeap(OSArenaId id, OSHeapHandle heap, u32 size)
{
    OSHeapInfo *heapInfo;
    HeapDesc *hd;
    Cell   *cell;                      // candidate block
    Cell   *newCell;                   // ptr to leftover block
    long    leftoverSize;              // size of any leftover
    OSIntrMode enabled = OS_DisableInterrupts();

    //OS_Printf( "id=%d heap=%x size=%x\n",id, heap, size );

#ifdef  SDK_DEBUG
    long    requested = (long)size;
#endif // SDK_DEBUG

    //---- check arena id
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_ALLOCFROMHEAP_INVID);
    SDK_ASSERTMSG(OSiHeapInfo[id], OS_ERR_ALLOCFROMHEAP_NOINFO);
    heapInfo = OSiHeapInfo[id];

    //---- check exist heap and size>0
    if (!heapInfo)
    {
        (void)OS_RestoreInterrupts(enabled);
        return NULL;
    }

    //---- heap<0  means current heap
    if (heap < 0)
    {
        heap = heapInfo->currentHeap;
    }

    SDK_ASSERTMSG(heapInfo->heapArray, OS_ERR_ALLOCFROMHEAP_NOHEAP);
    SDK_ASSERTMSG(0 < ((long)size), OS_ERR_ALLOCFROMHEAP_INVSIZE);
    SDK_ASSERTMSG(0 <= heap && heap < heapInfo->numHeaps, OS_ERR_ALLOCFROMHEAP_INVHEAP);
    SDK_ASSERTMSG(0 <= heapInfo->heapArray[heap].size, OS_ERR_ALLOCFROMHEAP_INVHEAP);

    hd = &heapInfo->heapArray[heap];

    // Enlarge size to smallest possible cell size
    size += HEADERSIZE;
    size = ROUND(size, ALIGNMENT);

    // Search for block large enough
    for (cell = hd->free; cell != NULL; cell = cell->next)
    {
        if ((long)size <= cell->size)
        {
            break;
        }
    }

    if (cell == NULL)
    {
#ifdef  SDK_DEBUG
        OS_Printf("OS_AllocFromHeap: Warning- failed to allocate %d bytes\n", size);
#endif // SDK_DEBUG
        (void)OS_RestoreInterrupts(enabled);
        return NULL;
    }

    SDK_ASSERTMSG(OFFSET(cell, ALIGNMENT) == 0, OS_ERR_ALLOCFROMHEAP_BROKENHEAP);
    SDK_ASSERTMSG(cell->hd == NULL, OS_ERR_ALLOCFROMHEAP_BROKENHEAP);

    leftoverSize = cell->size - (long)size;
    if (leftoverSize < MINOBJSIZE)
    {
        //---- Just extract this cell out since it's too small to split
        hd->free = DLExtract(hd->free, cell);
    }
    else
    {
        //---- cell is large enough to split into two pieces
        cell->size = (long)size;

        //---- Create a new cell
        newCell = (Cell *) ((char *)cell + size);
        newCell->size = leftoverSize;
#ifdef SDK_DEBUG
        newCell->hd = NULL;
#endif

        //---- Leave newCell in free, and take cell away
        newCell->prev = cell->prev;
        newCell->next = cell->next;

        if (newCell->next != NULL)
        {
            newCell->next->prev = newCell;
        }

        if (newCell->prev != NULL)
        {
            newCell->prev->next = newCell;
        }
        else
        {
            SDK_ASSERTMSG(hd->free == cell, OS_ERR_ALLOCFROMHEAP_BROKENHEAP);
            hd->free = newCell;
        }
    }

    //---- Add to allocated list
    hd->allocated = DLAddFront(hd->allocated, cell);

#ifdef  SDK_DEBUG
    cell->hd = hd;
    cell->requested = requested;
    hd->headerBytes += HEADERSIZE;
    hd->paddingBytes += cell->size - (HEADERSIZE + requested);
    hd->payloadBytes += requested;
#endif // SDK_DEBUG

    (void)OS_RestoreInterrupts(enabled);

    return (void *)((char *)cell + HEADERSIZE);
}

/*---------------------------------------------------------------------------*
  Name:         OS_AllocFixed

  Description:  Allocates the block of memory specified by /rstart/ and
                /rend/.  Will break up any heap.  Will not check for overlap
                with other fixed blocks.  May create a zero-length heap.

  Arguments:    id     : arena ID
                rstart : pointer to starting addr of block
                rend   : pointer to ending addr of block

  Returns:      a null pointer or a pointer to the allocated space aligned
                with ALIGNMENT bytes boundaries. /rstart/ and /rend/ might be
                adjusted to the boundaries of really allocated region.
 *---------------------------------------------------------------------------*/
void   *OS_AllocFixed(OSArenaId id, void **rstart, void **rend)
{
    OSHeapInfo *heapInfo;
    OSHeapHandle i;                    // heap iterator
    Cell   *cell;                      // object iterator
    Cell   *newCell;                   // for creating new objects if necessary
    HeapDesc *hd;
    void   *start = (void *)TRUNC(*rstart, ALIGNMENT);
    void   *end = (void *)ROUND(*rend, ALIGNMENT);
    OSIntrMode enabled = OS_DisableInterrupts();

    //---- check arena id
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_ALLOCFIXED_INVID);
    SDK_ASSERTMSG(OSiHeapInfo[id], OS_ERR_ALLOCFIXED_NOINFO);
    heapInfo = OSiHeapInfo[id];

    SDK_ASSERTMSG(heapInfo->heapArray, OS_ERR_ALLOCFIXED_NOHEAP);
    SDK_ASSERTMSG(start < end, OS_ERR_ALLOCFIXED_INVRANGE);
    SDK_ASSERTMSG(RangeSubset(start, end, heapInfo->arenaStart, heapInfo->arenaEnd), OS_ERR_ALLOCFIXED_INVRANGE);

    //---- Check overlap with any allocated blocks.
    for (i = 0; i < heapInfo->numHeaps; i++)
    {
        hd = &heapInfo->heapArray[i];
        if (hd->size < 0)              // Is inactive?
        {
            continue;
        }

        if (DLOverlap(hd->allocated, start, end))
        {
#ifdef  SDK_DEBUG
            OS_Printf("OS_AllocFixed: Warning - failed to allocate from %p to %p\n", start, end);
#endif // SDK_DEBUG
            (void)OS_RestoreInterrupts(enabled);
            return NULL;
        }
    }

    /*
       ASSUME : if we get past all this, the fixed request will
       not overlap with any non-contiguous free memory.

       Iterate over heaps breaking up appropriate blocks.
       note that we cannot change the size of the heap by simply subtracting
       out the overlap area, since the heaps may be non-contiguous.
     */
    for (i = 0; i < heapInfo->numHeaps; i++)
    {
        //---- for each free obj in heap, find and break overlaps.
        hd = &heapInfo->heapArray[i];

        if (hd->size < 0)              // Is inactive?
        {
            continue;
        }

        for (cell = hd->free; cell; cell = cell->next)
        {
            void   *cellEnd = (char *)cell + cell->size;

            if ((char *)cellEnd <= (char *)start)
            {
                continue;
            }

            if ((char *)end <= (char *)cell)
            {
                break;                 // Since free is sorted in order of start addresses
            }

            if (InRange(cell, (char *)start - HEADERSIZE, end) && InRange((char *)cellEnd, start, (char *)end + MINOBJSIZE))
            {
                if ((char *)cell < (char *)start)
                {
                    start = (void *)cell;
                }
                if ((char *)end < (char *)cellEnd)
                {
                    end = (void *)cellEnd;
                }

                //---- cell is completely overlaped. Just extract this block
                hd->free = DLExtract(hd->free, cell);   // Note cell->next is intact. XXX
                hd->size -= cell->size; // Update stats
                continue;
            }

            if (InRange(cell, (char *)start - HEADERSIZE, end))
            {
                if ((char *)cell < (char *)start)
                {
                    start = (void *)cell;
                }

                // Start of object in middle of range. break off top.
                // Avoid DLExtract() and DLInsert() since we already know
                // exactly where the block should go
                SDK_ASSERT(MINOBJSIZE <= (char *)cellEnd - (char *)end);
                newCell = (Cell *) end;
                newCell->size = (char *)cellEnd - (char *)end;
#ifdef  SDK_DEBUG
                newCell->hd = NULL;
#endif // SDK_DEBUG
                newCell->next = cell->next;
                if (newCell->next)
                {
                    newCell->next->prev = newCell;
                }
                newCell->prev = cell->prev;
                if (newCell->prev)
                {
                    newCell->prev->next = newCell;
                }
                else
                {
                    hd->free = newCell; // new head
                }
                hd->size -= (char *)end - (char *)cell;
                break;
            }

            if (InRange((char *)cellEnd, start, (char *)end + MINOBJSIZE))
            {
                if ((char *)end < (char *)cellEnd)
                {
                    end = (void *)cellEnd;
                }

                //---- Nothing to change except size
                SDK_ASSERT(MINOBJSIZE <= (char *)start - (char *)cell);
                hd->size -= (char *)cellEnd - (char *)start;
                cell->size = (char *)start - (char *)cell;
                continue;
            }

            //---- Create a new cell after end of the fixed block.
            SDK_ASSERT(MINOBJSIZE <= (char *)cellEnd - (char *)end);
            newCell = (Cell *) end;
            newCell->size = (char *)cellEnd - (char *)end;
#ifdef  SDK_DEBUG
            newCell->hd = NULL;
#endif // SDK_DEBUG
            newCell->next = cell->next;
            if (newCell->next)
            {
                newCell->next->prev = newCell;
            }
            newCell->prev = cell;
            cell->next = newCell;      // cell is before newCell
            cell->size = (char *)start - (char *)cell;
            hd->size -= (char *)end - (char *)start;
            break;
        }
        SDK_ASSERT(0 <= hd->size);
    }

    SDK_ASSERT(OFFSET(start, ALIGNMENT) == 0);
    SDK_ASSERT(OFFSET(end, ALIGNMENT) == 0);
    SDK_ASSERT(start < end);
    *rstart = start;
    *rend = end;

    (void)OS_RestoreInterrupts(enabled);
    return *rstart;
}

/*---------------------------------------------------------------------------*
  Name:         OS_FreeToHeap

  Description:  Returns obj /ptr/ to /heap/.

  Arguments:    id       : arena ID
                heap     : handle to the heap that /ptr/ was allocated from
                ptr      : pointer to object previously returned from
                           OS_Alloc() or OS_AllocFromHeap().

  Returns:      None.
 *---------------------------------------------------------------------------*/
void OS_FreeToHeap(OSArenaId id, OSHeapHandle heap, void *ptr)
{
    OSHeapInfo *heapInfo;
    HeapDesc *hd;
    Cell   *cell;

    OSIntrMode enabled = OS_DisableInterrupts();

    //---- check arena id
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_FREETOHEAP_INVID);
    SDK_ASSERTMSG(OSiHeapInfo[id], OS_ERR_FREETOHEAP_NOINFO);
    heapInfo = OSiHeapInfo[id];

    if (heap < 0)
    {
        heap = heapInfo->currentHeap;
    }

    SDK_ASSERTMSG(heapInfo->heapArray, OS_ERR_FREETOHEAP_NOHEAP);
#ifdef SDK_DEBUG
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
    if ( OSi_ExtraHeapArenaId != id || OSi_ExtraHeapHandle != heap )
    {
#endif
        SDK_ASSERTMSG(InRange(ptr, (char *)heapInfo->arenaStart + HEADERSIZE, (char *)heapInfo->arenaEnd), OS_ERR_FREETOHEAP_INVPTR);
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
    }
#endif
#endif
    SDK_ASSERTMSG(OFFSET(ptr, ALIGNMENT) == 0, OS_ERR_FREETOHEAP_INVPTR);
    SDK_ASSERTMSG(0 <= heapInfo->heapArray[heap].size, OS_ERR_FREETOHEAP_INVHEAP);

    cell = (Cell *) ((char *)ptr - HEADERSIZE);
    hd = &heapInfo->heapArray[heap];

    SDK_ASSERTMSG(cell->hd == hd, OS_ERR_FREETOHEAP_INVPTR);
    SDK_ASSERTMSG(DLLookup(hd->allocated, cell), OS_ERR_FREETOHEAP_INVPTR);

#ifdef  SDK_DEBUG
    cell->hd = NULL;
    hd->headerBytes -= HEADERSIZE;
    hd->paddingBytes -= cell->size - (HEADERSIZE + cell->requested);
    hd->payloadBytes -= cell->requested;
#endif // SDK_DEBUG

    //---- Extract from the allocated list
    hd->allocated = DLExtract(hd->allocated, cell);

    //---- Add in sorted order to free list (coalesced with next and prev)
    hd->free = DLInsert(hd->free, cell);

    (void)OS_RestoreInterrupts(enabled);
}

/*---------------------------------------------------------------------------*
  Name:         OS_FreeAllToHeap

  Description:  free all allocated block in the specified heap

  Arguments:    id       : arena ID
                heap     : handle to the heap

  Returns:      None.
 *---------------------------------------------------------------------------*/
void OS_FreeAllToHeap(OSArenaId id, OSHeapHandle heap)
{
    OSHeapInfo *heapInfo;
    HeapDesc *hd;
    Cell   *cell;

    OSIntrMode enabled = OS_DisableInterrupts();

    //---- check arena id
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_FREETOHEAP_INVID);
    SDK_ASSERTMSG(OSiHeapInfo[id], OS_ERR_FREETOHEAP_NOINFO);
    heapInfo = OSiHeapInfo[id];

    if (heap < 0)
    {
        heap = heapInfo->currentHeap;
    }

    SDK_ASSERTMSG(heapInfo->heapArray, "heap not initialized");
    SDK_ASSERTMSG(0 <= heapInfo->heapArray[heap].size, "invalid heap handle");

    hd = &heapInfo->heapArray[heap];
    while ((cell = hd->allocated) != NULL)
    {
        SDK_ASSERT(cell->hd == hd);
        SDK_ASSERT(DLLookup(hd->allocated, cell));

#ifdef  SDK_DEBUG
        cell->hd = NULL;
        hd->headerBytes -= HEADERSIZE;
        hd->paddingBytes -= cell->size - (HEADERSIZE + cell->requested);
        hd->payloadBytes -= cell->requested;
#endif // SDK_DEBUG

        //---- Extract from the allocated list
        hd->allocated = DLExtract(hd->allocated, cell);

        //---- Add in sorted order to free list (coalesced with next and prev)
        hd->free = DLInsert(hd->free, cell);
    }

    (void)OS_RestoreInterrupts(enabled);
}

/*---------------------------------------------------------------------------*
  Name:         OS_SetCurrentHeap

  Description:  Sets OSi_CurrentHeap to /heap/.  All subsequent calls to
                OS_Alloc() will be performed on this heap until another
                call to OS_SetCurrentHeap().

  Arguments:    id   : arena ID
                heap : handle to a heap that was returned from OS_CreateHeap()

  Returns:      previous heap handle.
 *---------------------------------------------------------------------------*/
OSHeapHandle OS_SetCurrentHeap(OSArenaId id, OSHeapHandle heap)
{
    OSHeapInfo *heapInfo;
    OSHeapHandle prev;
    OSIntrMode enabled = OS_DisableInterrupts();

    //---- check arena id
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_SETCURRENTHEAP_INVID);
    SDK_ASSERTMSG(OSiHeapInfo[id], OS_ERR_SETCURRENTHEAP_NOINFO);
    heapInfo = OSiHeapInfo[id];

    SDK_ASSERTMSG(heapInfo->heapArray, OS_ERR_SETCURRENTHEAP_NOHEAP);
    SDK_ASSERTMSG(0 <= heap && heap < heapInfo->numHeaps, OS_ERR_SETCURRENTHEAP_INVHEAP);
    SDK_ASSERTMSG(0 <= heapInfo->heapArray[heap].size, OS_ERR_SETCURRENTHEAP_INVHEAP);
    prev = heapInfo->currentHeap;
    heapInfo->currentHeap = heap;

    (void)OS_RestoreInterrupts(enabled);
    return prev;
}

/*---------------------------------------------------------------------------*
  Name:         OS_InitAlloc

  Description:  Initializes the arena in which all heaps will reside.
                Reserves some small amount of memory for array of heap
                descriptors.

  Arguments:    id         : arena ID
                arenaStart : beginning addr of arena
                arenaEnd   : ending addr of arena
                maxHeaps   : Maximum number of active heaps that will be
                           : used in lifetime of program

  Returns:      start of real arena, aligned with 32 bytes boundaries, after
                heap array has been allocated
 *---------------------------------------------------------------------------*/
void   *OS_InitAlloc(OSArenaId id, void *arenaStart, void *arenaEnd, int maxHeaps)
{
    OSHeapInfo *heapInfo;
    u32     arraySize;
    OSHeapHandle i;
    OSIntrMode enabled = OS_DisableInterrupts();

    //---- check arena id
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_INITALLOC_INVID);
    SDK_ASSERTMSG(OSiHeapInfo[id] == NULL, OS_ERR_INITALLOC_INVINFO);

    SDK_ASSERTMSG(0 < maxHeaps, OS_ERR_INITALLOC_INVNUMHEAPS);
    SDK_ASSERTMSG((char *)arenaStart < (char *)arenaEnd, OS_ERR_INITALLOC_INVRANGE);
    SDK_ASSERTMSG(maxHeaps <= ((char *)arenaEnd - (char *)arenaStart) / sizeof(HeapDesc), OS_ERR_INITALLOC_INSRANGE);

    //---- save heapInfo
    heapInfo = arenaStart;
    OSiHeapInfo[id] = heapInfo;

    //---- Place HeapArray at head of the arena
    arraySize = sizeof(HeapDesc) * maxHeaps;
    heapInfo->heapArray = (void *)((u32)arenaStart + sizeof(OSHeapInfo));
    heapInfo->numHeaps = maxHeaps;

    for (i = 0; i < heapInfo->numHeaps; i++)
    {
        HeapDesc *hd = &heapInfo->heapArray[i];

        hd->size = -1;
        hd->free = hd->allocated = NULL;
#ifdef  SDK_DEBUG
        hd->paddingBytes = hd->headerBytes = hd->payloadBytes = 0;
#endif // SDK_DEBUG
    }

    //---- Set OSi_CurrentHeap to an invalid value
    heapInfo->currentHeap = -1;

    //---- Reset arenaStart to the nearest reasonable location
    arenaStart = (void *)((char *)heapInfo->heapArray + arraySize);
    arenaStart = (void *)ROUND(arenaStart, ALIGNMENT);

    heapInfo->arenaStart = arenaStart;
    heapInfo->arenaEnd = (void *)TRUNC(arenaEnd, ALIGNMENT);
    SDK_ASSERTMSG(MINOBJSIZE <= (char *)heapInfo->arenaEnd - (char *)heapInfo->arenaStart, OS_ERR_INITALLOC_INSRANGE);

    (void)OS_RestoreInterrupts(enabled);
    return heapInfo->arenaStart;
}

/*---------------------------------------------------------------------------*
  Name:         OS_ClearAlloc

  Description:  Clear heap pointer in system shared.
                After calling this, you can call OS_InitAlloc() again.

  Arguments:    id  :   arena ID

  Returns:      None
 *---------------------------------------------------------------------------*/
void OS_ClearAlloc(OSArenaId id)
{
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_CLEARALLOC_INVID);
    OSiHeapInfo[id] = NULL;
}

/*---------------------------------------------------------------------------*
  Name:         OS_CreateHeap

  Description:  Reserves area of memory from /start/ to /end/ for use as a
                heap.  Initializes heap descriptor and free list.
                Will consume one entry in heap array.

  Arguments:    id    : arena ID
                start : starting addr of heap
                end   : ending addr of heap

  Returns:      If the function succeeds, it returns a new handle to heap
                for use in OS_AllocFromHeap(), OS_FreeToHeap(), etc.
                If the function fails, the return value is -1.
 *---------------------------------------------------------------------------*/
OSHeapHandle OS_CreateHeap(OSArenaId id, void *start, void *end)
{
    OSHeapInfo *heapInfo;
    OSHeapHandle heap;
    HeapDesc *hd;
    Cell   *cell;

    OSIntrMode enabled = OS_DisableInterrupts();

    //OS_Printf( "OS_CreateHeap  id=%d start=%x, end=%x\n", id, start, end );
    //---- check arena id
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_CREATEHEAP_INVID);
    SDK_ASSERTMSG(OSiHeapInfo[id], OS_ERR_CREATEHEAP_NOINFO);
    heapInfo = OSiHeapInfo[id];

    SDK_ASSERTMSG(heapInfo->heapArray, OS_ERR_CREATEHEAP_NOHEAP);
    SDK_ASSERTMSG(start < end, OS_ERR_CREATEHEAP_INVRANGE);
    start = (void *)ROUND(start, ALIGNMENT);
    end = (void *)TRUNC(end, ALIGNMENT);
    SDK_ASSERTMSG(start < end, OS_ERR_CREATEHEAP_INVRANGE);
    SDK_ASSERTMSG(RangeSubset(start, end, heapInfo->arenaStart, heapInfo->arenaEnd), OS_ERR_CREATEHEAP_INVRANGE);
    SDK_ASSERTMSG(MINOBJSIZE <= (char *)end - (char *)start, OS_ERR_CREATEHEAP_INSRANGE);

#ifdef  SDK_DEBUG
    //---- Check that the range does not overlap with
    //     any other block in this or other heaps.
    for (heap = 0; heap < heapInfo->numHeaps; heap++)
    {
        if (heapInfo->heapArray[heap].size < 0)
        {
            continue;
        }
        SDK_ASSERTMSG(!DLOverlap(heapInfo->heapArray[heap].free, start, end), OS_ERR_CREATEHEAP_INVRANGE);
        SDK_ASSERTMSG(!DLOverlap(heapInfo->heapArray[heap].allocated, start, end), OS_ERR_CREATEHEAP_INVRANGE);
    }
#endif // SDK_DEBUG

    //---- Search for free descriptor
    for (heap = 0; heap < heapInfo->numHeaps; heap++)
    {
        hd = &heapInfo->heapArray[heap];
        if (hd->size < 0)
        {
            hd->size = (char *)end - (char *)start;

            cell = (Cell *) start;
            cell->prev = NULL;
            cell->next = NULL;
            cell->size = hd->size;
#ifdef  SDK_DEBUG
            cell->hd = NULL;
#endif // SDK_DEBUG

            hd->free = cell;
            hd->allocated = 0;
#ifdef  SDK_DEBUG
            hd->paddingBytes = hd->headerBytes = hd->payloadBytes = 0;
#endif // SDK_DEBUG

            (void)OS_RestoreInterrupts(enabled);
            return heap;
        }
    }

    //---- Could not find free descriptor
#ifdef  SDK_DEBUG
    OS_Printf("OS_CreateHeap: Warning - Failed to find free heap descriptor.");
#endif // SDK_DEBUG

    (void)OS_RestoreInterrupts(enabled);
    return -1;
}

/*---------------------------------------------------------------------------*
  Name:         OS_CreateExtraHeap

  Description:  Create extra heap using the parameter area of TWL ROM.
                So Cannot be available on TWL mode.
                Available only on NITRO of HYBRID.

  Arguments:    id    : arena ID

  Returns:      -1 ... Failed.
                0< ... Success. Value is heap handle.
 *---------------------------------------------------------------------------*/
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
OSHeapHandle OS_CreateExtraHeap(OSArenaId id)
{
    OSHeapInfo *heapInfo;
    OSHeapHandle heap;
    HeapDesc *hd;
    Cell   *cell;

    OSIntrMode enabled = OS_DisableInterrupts();
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_CREATEHEAP_INVID);

    heapInfo = OSiHeapInfo[id];
    SDK_ASSERTMSG(heapInfo, OS_ERR_CREATEHEAP_NOINFO);
    SDK_ASSERTMSG(heapInfo->heapArray, OS_ERR_CREATEHEAP_NOHEAP);

    //---- available only on NITRO
    if ( ! OS_IsRunOnTwl() && OSi_ExtraHeapHandle < 0 )
    {
        //---- Search for free descriptor
        for (heap = 0; heap < heapInfo->numHeaps; heap++)
        {
            hd = &heapInfo->heapArray[heap];
            if (hd->size < 0)
            {
                hd->size = HW_MAIN_MEM_PARAMETER_BUF_SIZE;

                //---- initial free cell is from whole parameter buffer (NITRO does not use)
                cell = (Cell*)HW_MAIN_MEM_PARAMETER_BUF;
                cell->prev = NULL;
                cell->next = NULL;
                cell->size = HW_MAIN_MEM_PARAMETER_BUF_SIZE;
#ifdef SDK_DEBUG
                cell->hd = NULL;
#endif
                hd->free = cell;
                hd->allocated = 0;
#ifdef SDK_DEBUG
                hd->paddingBytes = hd->headerBytes = hd->payloadBytes = 0;
#endif
                OSi_ExtraHeapArenaId = id;
                OSi_ExtraHeapHandle = heap;

                (void) OS_RestoreInterrupts(enabled);
                return heap;
            }
        }
    }

    //---- Could not find free descriptor
    (void)OS_RestoreInterrupts(enabled);
    return -1;
}
#endif // defined(SDK_TWL) && !defined(SDK_TWLLTD)

/*---------------------------------------------------------------------------*
  Name:         OS_DestroyHeap

  Description:  Frees up the descriptor for the /heap/.  Subsequent
                allocation requests from this heap will fail unless another
                heap is created with the same handle.

  Arguments:    id   : arena ID
                heap : handle to a live heap, previously created with OS_CreateHeap().

  Returns:      None.
 *---------------------------------------------------------------------------*/
void OS_DestroyHeap(OSArenaId id, OSHeapHandle heap)
{
    OSHeapInfo *heapInfo;
    HeapDesc *hd;
#ifdef  SDK_DEBUG
    long    size;
#endif
    OSIntrMode enabled = OS_DisableInterrupts();

    //---- check arena id
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_DESTROYHEAP_INVID);
    SDK_ASSERTMSG(OSiHeapInfo[id], OS_ERR_DESTROYHEAP_NOINFO);
    heapInfo = OSiHeapInfo[id];

    SDK_ASSERTMSG(heapInfo->heapArray, OS_ERR_DESTROYHEAP_NOHEAP);
    SDK_ASSERTMSG(0 <= heap && heap < heapInfo->numHeaps, OS_ERR_DESTROYHEAP_INVHEAP);
    SDK_ASSERTMSG(0 <= heapInfo->heapArray[heap].size, OS_ERR_DESTROYHEAP_INVHEAP);

    hd = &heapInfo->heapArray[heap];

#ifdef SDK_DEBUG
    //---- Check whether entire heap is empty
    size = DLSize(hd->free);
    if (hd->size != size)
    {
        OS_Printf("OS_DestroyHeap(%d): Warning - free list size %d, heap size %d\n", heap, size, hd->size);
    }
#endif // SDK_DEBUG

#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
    //---- Check whether heap is the EXTRA HEAP
    if ( OSi_ExtraHeapArenaId == id && OSi_ExtraHeapHandle == heap )
    {
        OSi_ExtraHeapArenaId = (OSArenaId)-1;
        OSi_ExtraHeapHandle = -1;
    }
#endif // defined(SDK_TWL) && !defined(SDK_TWLLTD)

    hd->size = -1;
    hd->free = hd->allocated = NULL;   // add to dolphin src

#ifdef  SDK_DEBUG
    hd->paddingBytes = hd->headerBytes = hd->payloadBytes = 0;
    if (heapInfo->currentHeap == heap)
    {
        heapInfo->currentHeap = -1;
    }
#endif // SDK_DEBUG

    (void)OS_RestoreInterrupts(enabled);
}

/*---------------------------------------------------------------------------*
  Name:         OS_AddToHeap

  Description:  Adds an arbitrary block of memory to /heap/.  Used to free
                blocks previously allocated with OS_AllocFixed(), or to
                create non-contiguous heaps.

  Arguments:    id    : arena ID
                heap  : handle to live heap, previously created with OS_CreateHeap().
                start : starting addr of block to add to /heap/
                end   : ending addr of block to add to /heap/

  Returns:      None.
 *---------------------------------------------------------------------------*/
void OS_AddToHeap(OSArenaId id, OSHeapHandle heap, void *start, void *end)
{
    OSHeapInfo *heapInfo;
    HeapDesc *hd;
    Cell   *cell;
#ifdef  SDK_DEBUG
    OSHeapHandle i;
#endif // SDK_DEBUG
    OSIntrMode enabled = OS_DisableInterrupts();

    //---- check arena id
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_ADDTOHEAP_INVID);
    SDK_ASSERTMSG(OSiHeapInfo[id], OS_ERR_ADDTOHEAP_NOINFO);
    heapInfo = OSiHeapInfo[id];

    SDK_ASSERTMSG(heapInfo->heapArray, OS_ERR_ADDTOHEAP_NOHEAP);
    SDK_ASSERTMSG(0 <= heap && heap < heapInfo->numHeaps, OS_ERR_ADDTOHEAP_INVHEAP);
    SDK_ASSERTMSG(0 <= heapInfo->heapArray[heap].size, OS_ERR_ADDTOHEAP_INVHEAP);

    hd = &heapInfo->heapArray[heap];

    SDK_ASSERTMSG(start < end, OS_ERR_ADDTOHEAP_INVRANGE);

    start = (void *)ROUND(start, ALIGNMENT);
    end = (void *)TRUNC(end, ALIGNMENT);
    SDK_ASSERTMSG(MINOBJSIZE <= (char *)end - (char *)start, OS_ERR_ADDTOHEAP_INSRANGE);

#ifdef SDK_DEBUG
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
    if ((u32)start != (u32)HW_MAIN_MEM_PARAMETER_BUF && (u32)end != (u32)(HW_MAIN_MEM_PARAMETER_BUF + HW_MAIN_MEM_PARAMETER_BUF_SIZE) )
    {
#endif
        SDK_ASSERTMSG(RangeSubset(start, end, heapInfo->arenaStart, heapInfo->arenaEnd), OS_ERR_ADDTOHEAP_INVRANGE);
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
    }
#endif
#endif

#ifdef  SDK_DEBUG
    //---- Check that the range does not already overlap with
    //     any other block in this or other heaps.
    for (i = 0; i < heapInfo->numHeaps; i++)
    {
        if (heapInfo->heapArray[i].size < 0)
        {
            continue;
        }
        SDK_ASSERTMSG(!DLOverlap(heapInfo->heapArray[i].free, start, end), OS_ERR_ADDTOHEAP_INVRANGE);
        SDK_ASSERTMSG(!DLOverlap(heapInfo->heapArray[i].allocated, start, end), OS_ERR_ADDTOHEAP_INVRANGE);
    }
#endif // SDK_DEBUG

    //---- Create a new cell
    cell = (Cell *) start;
    cell->size = (char *)end - (char *)start;
#ifdef  SDK_DEBUG
    cell->hd = NULL;
#endif // SDK_DEBUG

    //---- Insert new cell in free
    hd->size += cell->size;
    hd->free = DLInsert(hd->free, cell);

    (void)OS_RestoreInterrupts(enabled);
}

/*---------------------------------------------------------------------------*
  Name:         OS_AddExtraToHeap

  Description:  Adds extra area (top 16KB of main memory ) to /heap/.  Used to
                free blocks previously allocated with OS_AllocFixed(), or to
                create non-contiguous heaps.

  Arguments:    id    : arena ID
                heap  : handle to live heap, previously created with OS_CreateHeap().

  Returns:      None.
 *---------------------------------------------------------------------------*/
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
void OS_AddExtraAreaToHeap(OSArenaId id, OSHeapHandle heap)
{
    if ( ! OS_IsRunOnTwl() )
    {
        OS_AddToHeap(id, heap,
                     (void*)HW_MAIN_MEM_PARAMETER_BUF,
                     (void*)(HW_MAIN_MEM_PARAMETER_BUF + HW_MAIN_MEM_PARAMETER_BUF_SIZE ) );
        OSi_ExtraHeapArenaId = id;
        OSi_ExtraHeapHandle = heap;
    }
}
#endif

/*---------------------------------------------------------------------------*
  Name:         OS_CheckHeap

  Description:  Checks heap sanity for debugging

  Arguments:    id   : arena ID
                heap : handle to a live heap.

  Returns:      -1 if heap is not consistent. Otherwise, returns number
                of bytes available in free.
 *---------------------------------------------------------------------------*/

#ifndef  SDK_NO_MESSAGE
#ifdef SDK_ARM9
#define OSi_CHECK( exp )                                                 \
    do                                                                       \
{                                                                        \
    if ( !(exp) )                                                        \
    {                                                                    \
        OS_Printf( "OS_CheckHeap: Failed " #exp " in %d\n", __LINE__ );  \
        goto exit_OS_CheckHeap; /* goto is not beautiful, but less codes */ \
    }                                                                    \
} while (0)
#else /* SDK_ARM9 */
#define OSi_CHECK( exp )                                                 \
    do                                                                       \
{                                                                        \
    if ( !(exp) )                                                        \
    {                                                                    \
        OS_Printf( "OS_CheckHeap: Failed in %d\n", __LINE__ );  \
        goto exit_OS_CheckHeap; /* goto is not beautiful, but less codes */ \
    }                                                                    \
} while (0)
#endif
#else
#define OSi_CHECK( exp )                                                 \
    do                                                                       \
{                                                                        \
    if ( !(exp) )                                                        \
    {                                                                    \
        goto exit_OS_CheckHeap; /* goto is not beautiful, but less codes */ \
    }                                                                    \
} while (0)
#endif

s32 OS_CheckHeap(OSArenaId id, OSHeapHandle heap)
{
    OSHeapInfo *heapInfo;
    HeapDesc *hd;
    Cell   *cell;
    long    total = 0;
    long    free = 0;
    long    retValue = -1;
    OSIntrMode enabled = OS_DisableInterrupts();

    //---- check arena id
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_CHECKHEAP_INVID);
    SDK_ASSERTMSG(OSiHeapInfo[id], OS_ERR_CHECKHEAP_NOINFO);
    heapInfo = OSiHeapInfo[id];

    //---- heap<0  means current heap
    if (heap == OS_CURRENT_HEAP_HANDLE)
    {
        heap = heapInfo->currentHeap;
    }
    SDK_ASSERT(heap >= 0);

    OSi_CHECK(heapInfo->heapArray);
    OSi_CHECK(0 <= heap && heap < heapInfo->numHeaps);

    hd = &heapInfo->heapArray[heap];
    OSi_CHECK(0 <= hd->size);

    OSi_CHECK(hd->allocated == NULL || hd->allocated->prev == NULL);
    for (cell = hd->allocated; cell; cell = cell->next)
    {
#ifdef SDK_DEBUG
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
        if ( OSi_ExtraHeapArenaId != id || OSi_ExtraHeapHandle != heap )
        {
#endif
            OSi_CHECK(InRange(cell, heapInfo->arenaStart, heapInfo->arenaEnd));
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
        }
#endif
#endif
        OSi_CHECK(OFFSET(cell, ALIGNMENT) == 0);
        OSi_CHECK(cell->next == NULL || cell->next->prev == cell);
        OSi_CHECK(MINOBJSIZE <= cell->size);
        OSi_CHECK(OFFSET(cell->size, ALIGNMENT) == 0);

        total += cell->size;
        OSi_CHECK(0 < total && total <= hd->size);

#ifdef  SDK_DEBUG
        OSi_CHECK(cell->hd == hd);
        OSi_CHECK(HEADERSIZE + cell->requested <= cell->size);
#endif // SDK_DEBUG
    }

    OSi_CHECK(hd->free == NULL || hd->free->prev == NULL);
    for (cell = hd->free; cell; cell = cell->next)
    {
#ifdef SDK_DEBUG
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
        if ( OSi_ExtraHeapArenaId != id || OSi_ExtraHeapHandle != heap )
        {
#endif
            OSi_CHECK(InRange(cell, heapInfo->arenaStart, heapInfo->arenaEnd));
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
        }
#endif
#endif
        OSi_CHECK(OFFSET(cell, ALIGNMENT) == 0);
        OSi_CHECK(cell->next == NULL || cell->next->prev == cell);
        OSi_CHECK(MINOBJSIZE <= cell->size);
        OSi_CHECK(OFFSET(cell->size, ALIGNMENT) == 0);
        OSi_CHECK(cell->next == NULL || (char *)cell + cell->size < (char *)cell->next);

        total += cell->size;
        free += cell->size - HEADERSIZE;
        OSi_CHECK(0 < total && total <= hd->size);

#ifdef  SDK_DEBUG
        OSi_CHECK(cell->hd == NULL);
#endif // SDK_DEBUG
    }

    OSi_CHECK(total == hd->size);
    retValue = free;

  exit_OS_CheckHeap:
    (void)OS_RestoreInterrupts(enabled);
    return retValue;
}

/*---------------------------------------------------------------------------*
  Name:         OS_ReferentSize

  Description:  Returns size of payload

  Arguments:    id  : arena ID
                ptr : pointer to object previously returned from
                      OS_Alloc() or OSAllocFromHeap().

  Returns:      size of payload
 *---------------------------------------------------------------------------*/
u32 OS_ReferentSize(OSArenaId id, void *ptr)
{
    OSHeapInfo *heapInfo;
    Cell   *cell;
    OSIntrMode enabled = OS_DisableInterrupts();

    //---- check arena id
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_REFERENTSIZE_INVID);
    SDK_ASSERTMSG(OSiHeapInfo[id], OS_ERR_REFERENTSIZE_NOINFO);
    heapInfo = OSiHeapInfo[id];

    SDK_ASSERTMSG(heapInfo->heapArray, OS_ERR_REFERENT_NOHEAP);
#ifdef SDK_DEBUG
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
        if ( OSi_ExtraHeapArenaId != id )
        {
#endif
    SDK_ASSERTMSG(InRange(ptr, (char *)heapInfo->arenaStart + HEADERSIZE, (char *)heapInfo->arenaEnd), OS_ERR_REFERENT_INVPTR);
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
        }
#endif
#endif
    SDK_ASSERTMSG(OFFSET(ptr, ALIGNMENT) == 0, OS_ERR_REFERENT_INVPTR);

    cell = (Cell *) ((char *)ptr - HEADERSIZE);

    SDK_ASSERTMSG(cell->hd, OS_ERR_REFERENT_INVPTR);
    SDK_ASSERTMSG(((char *)cell->hd - (char *)heapInfo->heapArray) % sizeof(HeapDesc) == 0, OS_ERR_REFERENT_INVPTR);
    SDK_ASSERTMSG(heapInfo->heapArray <= cell->hd && cell->hd < &heapInfo->heapArray[heapInfo->numHeaps], OS_ERR_REFERENT_INVPTR);
    SDK_ASSERTMSG(0 <= cell->hd->size, OS_ERR_REFERENT_INVPTR);
    SDK_ASSERTMSG(DLLookup(cell->hd->allocated, cell), OS_ERR_REFERENT_INVPTR);

    (void)OS_RestoreInterrupts(enabled);
    return (u32)(cell->size - HEADERSIZE);
}

/*---------------------------------------------------------------------------*
  Name:         OS_DumpHeap

  Description:  Dumps statistics and elements of a heap

  Arguments:    id   :  arena ID
                heap :  handle to a heap.

  Returns:      None.
 *---------------------------------------------------------------------------*/
void OS_DumpHeap(OSArenaId id, OSHeapHandle heap)
{
#ifndef SDK_FINALROM
    OSHeapInfo *heapInfo;
    HeapDesc *hd;
    Cell   *cell;
    OSIntrMode enabled = OS_DisableInterrupts();

    //---- check arena id
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_DUMPHEAP_INVID);
    SDK_ASSERTMSG(OSiHeapInfo[id], OS_ERR_DUMPHEAP_NOINFO);
    heapInfo = OSiHeapInfo[id];

    SDK_ASSERTMSG(heapInfo && heapInfo->heapArray, OS_ERR_DUMPHEAP_NOHEAP);

    //---- heap<0  means current heap
    if (heap < 0)
    {
        heap = heapInfo->currentHeap;
    }
    SDK_ASSERTMSG(0 <= heap && heap < heapInfo->numHeaps, OS_ERR_DUMPHEAP_INVHEAP);

    hd = &heapInfo->heapArray[heap];
    if (hd->size < 0)
    {
        OS_Printf("----Inactive\n");
        return;
    }

    SDK_ASSERTMSG(0 <= OS_CheckHeap(id, heap), OS_ERR_DUMPHEAP_BROKENHEAP);

#ifdef  SDK_DEBUG
    OS_Printf("padding %d/(%f%%) header %d/(%f%%) payload %d/(%f%%)\n",
              hd->paddingBytes, 100.0 * hd->paddingBytes / hd->size,
              hd->headerBytes, 100.0 * hd->headerBytes / hd->size,
              hd->payloadBytes, 100.0 * hd->payloadBytes / hd->size);
#endif // SDK_DEBUG

    OS_Printf("  addr    size     end      prev     next\n");

    OS_Printf("----Allocated\n");
    SDK_ASSERTMSG(hd->allocated == NULL || hd->allocated->prev == NULL, OS_ERR_DUMPHEAP_BROKENHEAP);
    if ( ! hd->allocated )
    {
        OS_Printf("None.\n");
    }
    else
    {
        for (cell = hd->allocated; cell; cell = cell->next)
        {
            OS_Printf("%08x %6x %08x %08x %08x\n",
                      cell, cell->size, (char *)cell + cell->size, cell->prev, cell->next);
        }
    }

    OS_Printf("----Free\n");
    if ( ! hd->free )
    {
        OS_Printf("None.\n");
    }
    else
    {
        for (cell = hd->free; cell; cell = cell->next)
        {
            OS_Printf("%08x %6x %08x %08x %08x\n",
                      cell, cell->size, (char *)cell + cell->size, cell->prev, cell->next);
        }
    }

    (void)OS_RestoreInterrupts(enabled);
#else  // ifndef SDK_FINALROM

#pragma unused( id, heap )

#endif // ifndef SDK_FINALROM
}


/*---------------------------------------------------------------------------*
  Name:         OS_VisitAllocated

  Description:  Visits every element of every allocated block of memory,
                calling a routine on each one.

  Arguments:    id      : arena ID
                visitor : function to be called on each cell

  Returns:      None.
 *---------------------------------------------------------------------------*/
void OS_VisitAllocated(OSArenaId id, OSAllocVisitor visitor)
{
    OSHeapInfo *heapInfo;
    u32     heap;
    Cell   *cell;

    OSIntrMode enabled = OS_DisableInterrupts();

    //---- check arena id
    SDK_ASSERTMSG(id < OS_ARENA_MAX, OS_ERR_VISITALLOCATED_INVID);
    SDK_ASSERTMSG(OSiHeapInfo[id], OS_ERR_VISITALLOCATED_NOINFO);
    heapInfo = OSiHeapInfo[id];

    for (heap = 0; heap < heapInfo->numHeaps; heap++)
    {
        if (heapInfo->heapArray[heap].size >= 0)
        {
            for (cell = heapInfo->heapArray[heap].allocated; cell; cell = cell->next)
            {
                visitor((void *)((u8 *)cell + HEADERSIZE), (u32)(cell->size - HEADERSIZE));
            }
        }
    }

    (void)OS_RestoreInterrupts(enabled);
}

//================================================================================
//     Get information about heap
//================================================================================
/*---------------------------------------------------------------------------*
  Name:         OSi_GetTotalAllocSize

  Description:  Get sum of allocated block size.
                Subroutine for OS_GetTotalAllocSize and OS_GetTotalOccupiedSize.

  Arguments:    id            : arena ID
                heap          : handle to a heap.
                isHeadInclude : whether if including block header.

  Returns:      sum of allocated block size
 *---------------------------------------------------------------------------*/
u32 OSi_GetTotalAllocSize(OSArenaId id, OSHeapHandle heap, BOOL isHeadInclude)
{
    OSHeapInfo *heapInfo;
    Cell   *cell;
    u32     sum = 0;
    OSIntrMode enabled = OS_DisableInterrupts();

    SDK_ASSERT(id < OS_ARENA_MAX);
    heapInfo = OSiHeapInfo[id];
    SDK_ASSERT(heapInfo);
    SDK_ASSERT(heap < heapInfo->numHeaps);

    //---- heap<0  means current heap
    if (heap < 0)
    {
        heap = heapInfo->currentHeap;
    }

    if (isHeadInclude)
    {
        for (cell = heapInfo->heapArray[heap].allocated; cell; cell = cell->next)
        {
            sum += (u32)(cell->size);
        }
    }
    else
    {
        for (cell = heapInfo->heapArray[heap].allocated; cell; cell = cell->next)
        {
            sum += (u32)(cell->size - HEADERSIZE);
        }
    }

    (void)OS_RestoreInterrupts(enabled);

    return sum;
}

/*---------------------------------------------------------------------------*
  Name:         OS_GetTotalFreeSize

  Description:  Get sum of free block size,
                not includeing of block header.

  Arguments:    id   :  arena ID
                heap :  handle to a heap.

  Returns:      sum of free block size
 *---------------------------------------------------------------------------*/
u32 OS_GetTotalFreeSize(OSArenaId id, OSHeapHandle heap)
{
    OSHeapInfo *heapInfo;
    Cell   *cell;
    u32     sum = 0;
    OSIntrMode enabled = OS_DisableInterrupts();

    SDK_ASSERT(id < OS_ARENA_MAX);
    heapInfo = OSiHeapInfo[id];
    SDK_ASSERT(heapInfo);
    SDK_ASSERT(heap < heapInfo->numHeaps);

    //---- heap<0  means current heap
    if (heap < 0)
    {
        heap = heapInfo->currentHeap;
    }

    for (cell = heapInfo->heapArray[heap].free; cell; cell = cell->next)
    {
        sum += (u32)(cell->size - HEADERSIZE);
    }

    (void)OS_RestoreInterrupts(enabled);

    return sum;
}

/*---------------------------------------------------------------------------*
  Name:         OS_GetMaxFreeSize

  Description:  Get maximun free block size

  Arguments:    id   :  arena ID
                heap :  handle to a heap.

  Returns:      maximum free block size.
 *---------------------------------------------------------------------------*/
u32 OS_GetMaxFreeSize(OSArenaId id, OSHeapHandle heap)
{
    OSHeapInfo *heapInfo;
    Cell   *cell;
    u32     candidate = 0;
    OSIntrMode enabled = OS_DisableInterrupts();

    SDK_ASSERT(id < OS_ARENA_MAX);
    heapInfo = OSiHeapInfo[id];
    SDK_ASSERT(heapInfo);
    SDK_ASSERT(heap < heapInfo->numHeaps);

    //---- heap<0  means current heap
    if (heap < 0)
    {
        heap = heapInfo->currentHeap;
    }

    for (cell = heapInfo->heapArray[heap].free; cell; cell = cell->next)
    {
        u32     size = (u32)(cell->size - HEADERSIZE);
        if (size > candidate)
        {
            candidate = size;
        }
    }

    (void)OS_RestoreInterrupts(enabled);

    return candidate;
}

//================================================================================
//     re-initialize heap.
//================================================================================
/*---------------------------------------------------------------------------*
  Name:         OS_ClearHeap

  Description:  re-initialize heap.

  Arguments:    id   :  arena ID
                heap :  handle to a heap.
                start:  starting addr of heap
                end  :  endinf addr of heap

  Returns:      None.
 *---------------------------------------------------------------------------*/
void OS_ClearHeap(OSArenaId id, OSHeapHandle heap, void *start, void *end)
{
    OSHeapInfo *heapInfo;
    HeapDesc *hd;
    Cell   *cell;

    OSIntrMode enabled = OS_DisableInterrupts();

    //---- check arena id
    SDK_ASSERTMSG(id < OS_ARENA_MAX, "invalid id");

    heapInfo = OSiHeapInfo[id];

    SDK_ASSERTMSG(heapInfo && heapInfo->heapArray, "heap not initialized");
    SDK_ASSERTMSG(start < end, "invalid range");
    start = (void *)ROUND(start, ALIGNMENT);
    end = (void *)TRUNC(end, ALIGNMENT);
    SDK_ASSERTMSG(start < end, "invalid range");
#ifdef SDK_DEBUG
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
    if ( OSi_ExtraHeapArenaId != id || OSi_ExtraHeapHandle != heap )
    {
#endif
        SDK_ASSERTMSG(RangeSubset(start, end, heapInfo->arenaStart, heapInfo->arenaEnd), "invalid range");
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
    }
#endif
#endif
    SDK_ASSERTMSG(MINOBJSIZE <= (char *)end - (char *)start, "too small range");

    //---- heap<0  means current heap
    if (heap < 0)
    {
        heap = heapInfo->currentHeap;
    }

    //---- Search for free descriptor
    hd = &heapInfo->heapArray[heap];
    hd->size = (char *)end - (char *)start;

    cell = (Cell *) start;
    cell->prev = NULL;
    cell->next = NULL;
    cell->size = hd->size;
#ifdef  SDK_DEBUG
    cell->hd = NULL;
#endif // SDK_DEBUG

    hd->free = cell;
    hd->allocated = 0;
#ifdef  SDK_DEBUG
    hd->paddingBytes = hd->headerBytes = hd->payloadBytes = 0;
#endif // SDK_DEBUG

    (void)OS_RestoreInterrupts(enabled);
}
/*---------------------------------------------------------------------------*
  Name:         OS_ClearExtraHeap

  Description:  re-initialize extra heap.

  Arguments:    id   :  arena ID
                heap :  handle to a heap.

  Returns:      None.
 *---------------------------------------------------------------------------*/
#if defined(SDK_TWL) && !defined(SDK_TWLLTD)
void OS_ClearExtraHeap(OSArenaId id, OSHeapHandle heap)
{
    if ( ! OS_IsRunOnTwl() )
    {
        if ( OSi_ExtraHeapArenaId == id || OSi_ExtraHeapHandle == heap )
        {
            OS_ClearHeap(id, heap,
                         (void*)HW_MAIN_MEM_PARAMETER_BUF,
                         (void*)(HW_MAIN_MEM_PARAMETER_BUF + HW_MAIN_MEM_PARAMETER_BUF_SIZE ) );
        }
    }
}
#endif

//================================================================================
//     Check Alocated Memory
//================================================================================
/*---------------------------------------------------------------------------*
  Name:         OS_IsOnMainMemory

  Description:  check memory address to which a pointer points is on main RAM.

  Arguments:    ptr  : pointer

  Returns:      TRUE if ptr points is on main RAM.
 *---------------------------------------------------------------------------*/
BOOL OS_IsOnMainMemory(void* ptr)
{
#ifdef SDK_TWL
    if( OS_IsRunOnTwl() )
    {
        /* TWL */
        if( (u32)ptr >= HW_TWL_MAIN_MEM && (u32)ptr < HW_TWL_MAIN_MEM_END )
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
    else
#endif //SDK_TWL
    {
        /* NITRO */
        if( (u32)ptr >= HW_MAIN_MEM && (u32)ptr < HW_MAIN_MEM_END )
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
    return FALSE; /* Do Not Return HERE */
}

/*---------------------------------------------------------------------------*
  Name:         OS_IsOnExtendedMainMemory

  Description:  check memory address to which a pointer points is on extended main RAM.

  Arguments:    ptr  : pointer

  Returns:      TRUE if ptr points is on extended main RAM.
 *---------------------------------------------------------------------------*/
BOOL OS_IsOnExtendedMainMemory(void* ptr)
{
#ifdef SDK_TWL
    if( OS_IsRunOnTwl() )
    {
        /* TWL */
        if( (u32)ptr >= HW_TWL_MAIN_MEM_EX && (u32)ptr < HW_TWL_MAIN_MEM_EX_END )
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
    else
#endif //SDK_TWL
    {
        /* NITRO */
        if( (u32)ptr >= HW_MAIN_MEM_END && (u32)ptr < HW_MAIN_MEM_EX_END )
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
    return FALSE; /* Do Not Return HERE */
}




/*---------------------------------------------------------------------------*
  Name:         OS_IsOnWramB

  Description:  check memory address to which a pointer points is on WRAM B.

  Arguments:    ptr  : pointer

  Returns:      TRUE if ptr points is on WRAM B.
 *---------------------------------------------------------------------------*/
BOOL OS_IsOnWramB(void* ptr)
{
#ifdef SDK_TWL
    if( OS_IsRunOnTwl() )
    {
        /* TWL */
        if( (u32)ptr >= HW_WRAM_B && (u32)ptr < HW_WRAM_B_END )
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
#else
    #pragma unused(ptr)
#endif //SDK_TWL
    return FALSE;
}

/*---------------------------------------------------------------------------*
  Name:         OSi_IsOnWramC

  Description:  check memory address to which a pointer points is on WRAM C.

  Arguments:    ptr  : pointer

  Returns:      TRUE if ptr points is on WRAM C.
 *---------------------------------------------------------------------------*/
BOOL OS_IsOnWramC(void* ptr)
{
#ifdef SDK_TWL
    if( OS_IsRunOnTwl() )
    {
        /* TWL */
        if( (u32)ptr >= HW_WRAM_C && (u32)ptr < HW_WRAM_C_END )
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
#else
    #pragma unused(ptr)
#endif //SDK_TWL
    return FALSE;
}

/*---------------------------------------------------------------------------*
  Name:         OS_IsOnWram0

  Description:  check memory address to which a pointer points is on WRAM 0.

  Arguments:    ptr  : pointer

  Returns:      TRUE if ptr points is on WRAM 0.
 *---------------------------------------------------------------------------*/
BOOL OS_IsOnWram0(void* ptr)
{
#ifdef SDK_TWL
#ifdef SDK_ARM7
    if( OS_IsRunOnTwl() )
    {
#ifdef SDK_TWLLTD
        if( (u32)ptr >= HW_WRAM_0_LTD && (u32)ptr < HW_WRAM_0_LTD_END )
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
#else   
       // !SDK_TWLLTD
        if( (u32)ptr >= HW_WRAM_0_HYB && (u32)ptr < HW_WRAM_0_HYB_END )
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
#endif  //SDK_TWLLTD
    }
#else
 //!SDK_ARM7
    #pragma unused(ptr)
#endif  //SDK_ARM7
#else
      //!SDK_TWL
    {
        if( (u32)ptr >= HW_WRAM_0 && (u32)ptr < HW_WRAM_0_END )
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
#endif // SDK_ARM7

    return FALSE;
}

/*---------------------------------------------------------------------------*
  Name:         OS_IsOnWram1

  Description:  check memory address to which a pointer points is on WRAM 1.

  Arguments:    ptr  : pointer

  Returns:      TRUE if ptr points is on WRAM 1.
 *---------------------------------------------------------------------------*/
BOOL OS_IsOnWram1(void* ptr)
{
#ifdef SDK_TWL
#ifdef SDK_ARM7
    if( OS_IsRunOnTwl() )
    {
#ifdef SDK_TWLLTD
        if( (u32)ptr >= HW_WRAM_1_LTD && (u32)ptr < HW_WRAM_1_LTD_END )
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
#else   
       // !SDK_TWLLTD
        if( (u32)ptr >= HW_WRAM_1_HYB && (u32)ptr < HW_WRAM_1_HYB_END )
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
#endif  //SDK_TWLLTD
    }
#else
  //SDK_TWL && !SDK_ARM7
    #pragma unused(ptr)
#endif  //SDK_ARM7
#else
      //!SDK_TWL
    {
        if( (u32)ptr >= HW_WRAM_1 && (u32)ptr < HW_WRAM_1_END )
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
#endif // SDK_ARM7

    return FALSE;
}

/*---------------------------------------------------------------------------*
  Name:         OS_IsOnWram

  Description:  check memory address to which a pointer points is on WRAM.

  Arguments:    ptr  : pointer

  Returns:      TRUE if ptr points is on WRAM.
 *---------------------------------------------------------------------------*/
BOOL OS_IsOnWram(void* ptr)
{
    return ( OS_IsOnWramA(ptr) || OS_IsOnWramB(ptr) || OS_IsOnWramC(ptr) ||OS_IsOnWram0(ptr) ||OS_IsOnWram1(ptr) );
}


/*---------------------------------------------------------------------------*
  Name:         OS_IsOnVram

  Description:  check memory address to which a pointer points is on VRAM.

  Arguments:    ptr  : pointer

  Returns:      TRUE if ptr points is on VRAM.
 *---------------------------------------------------------------------------*/
BOOL OS_IsOnVram(void* ptr)
{
#ifdef SDK_ARM9
    if( (u32)ptr >= HW_PLTT && (u32)ptr < HW_DB_OAM_END )
    {
        return TRUE;
    }
#else
    #pragma unused(ptr)
#endif
    return FALSE;
}


/*---------------------------------------------------------------------------*
  Name:         OS_IsOnDtcm

  Description:  check memory address to which a pointer points is on DTCM.

  Arguments:    ptr  : pointer

  Returns:      TRUE if ptr points is on DTCM.
 *---------------------------------------------------------------------------*/
BOOL OS_IsOnDtcm(void* ptr)
{
#ifdef SDK_ARM9
    u32 dtcm;
    u32 dtcm_end;
    
    dtcm = OS_GetDTCMAddress();
    dtcm_end = dtcm + HW_DTCM_SIZE;
    
    if( (u32)ptr >= dtcm && (u32)ptr < dtcm_end )
    {
        return TRUE;
    }
#else
    #pragma unused(ptr)
#endif
    return FALSE;
}

/*---------------------------------------------------------------------------*
  Name:         OS_IsOnItcm

  Description:  check memory address to which a pointer points is on ITCM.

  Arguments:    ptr  : pointer

  Returns:      TRUE if ptr points is on ITCM.
 *---------------------------------------------------------------------------*/
BOOL OS_IsOnItcm(void* ptr)
{
#ifdef SDK_ARM9
    u32 itcm;
    u32 itcm_end;
    
    itcm = OS_GetITCMAddress();
    itcm_end = itcm + HW_ITCM_SIZE;
    
    if( (u32)ptr >= itcm && (u32)ptr < itcm_end )
    {
        return TRUE;
    }
#else
    #pragma unused(ptr)
#endif
    return FALSE;
}

/*---------------------------------------------------------------------------*
  Name:         OS_IsOnWramA

  Description:  check memory address to which a pointer points is on WRAM A.

  Arguments:    ptr  : pointer

  Returns:      TRUE if ptr points is on WRAM A.
 *---------------------------------------------------------------------------*/
BOOL OS_IsOnWramA(void* ptr)
{
#ifdef SDK_TWL
#ifdef SDK_ARM7
    if( OS_IsRunOnTwl() )
    {
#ifdef SDK_TWLLTD
        /* TWL LTD */
        if( (u32)ptr >= HW_WRAM_A_LTD && (u32)ptr < HW_WRAM_A_LTD_END )
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
#else
        /* TWL HYB */
        if( (u32)ptr >= HW_WRAM_A_HYB && (u32)ptr < HW_WRAM_A_HYB_END )
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
#endif  //SDK_TWLLTD
    }
#else   
   // SDK_TWL && !SDK_ARM7
    #pragma unused(ptr)
#endif //SDK_ARM7

#else
   // !SDK_TWL
    #pragma unused(ptr)
#endif //SDK_TWL
    return FALSE;
}

/*---------------------------------------------------------------------------*
  Name:         OS_IsOnArm7PrvWram

  Description:  check memory address to which a pointer points is on ARM7 Private WRAM.

  Arguments:    ptr  : pointer

  Returns:      TRUE if ptr points is on ARM7 Private WRAM.
 *---------------------------------------------------------------------------*/
BOOL OS_IsOnArm7PrvWram(void* ptr)
{
#ifdef SDK_ARM7
        if( (u32)ptr >= HW_PRV_WRAM && (u32)ptr < HW_PRV_WRAM_END )
        {
            return TRUE;
        }
#else
    #pragma unused(ptr)
#endif //SDK_ARM7
    return FALSE;
}

