/*---------------------------------------------------------------------------* Project: MEM library File: mem_unitHeap.c Programmers: Takano Makoto Copyright 2005 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. *---------------------------------------------------------------------------*/ #include #include "heapCommoni.h" /* ======================================================================== Macro Constants ======================================================================== */ // Minimum alignment value #define MIN_ALIGNMENT 4 /* ======================================================================== static functions ======================================================================== */ /* ------------------------------------------------------------------------ Memory Block List Operations ------------------------------------------------------------------------ */ /*---------------------------------------------------------------------------* Name: PopMBlock_ Description: Gets the memory block from the top of the list. Arguments: link: pointer to list Returns: None. *---------------------------------------------------------------------------*/ static MEMiUntHeapMBlockHead* PopMBlock_( MEMiUntMBlockList* list ) { MEMiUntHeapMBlockHead* block = list->head; if ( block ) { list->head = block->pMBlkHdNext; } return block; } /*---------------------------------------------------------------------------* Name: PushMBlock_ Description: Adds a memory block to the top of the list. Arguments: link: The list to be added to block: The memory block to add Returns: None. *---------------------------------------------------------------------------*/ static inline void PushMBlock_( MEMiUntMBlockList* list, MEMiUntHeapMBlockHead* block ) { block->pMBlkHdNext = list->head; list->head = block; } /*---------------------------------------------------------------------------* Name: GetUnitHeapHeadPtrFromHeapHead_ Description: Gets the pointer to the unit heap header from the pointer to heap header. Arguments: pHeapHd: Pointer to the heap header. Returns: Returns the pointer to the unit heap header. *---------------------------------------------------------------------------*/ static inline MEMiUntHeapHead* GetUnitHeapHeadPtrFromHeapHead_( MEMiHeapHead* pHeapHd ) { return (MEMiUntHeapHead*)AddU32ToPtr( pHeapHd, sizeof(MEMiHeapHead) ); } /*---------------------------------------------------------------------------* Name: IsValidUnitHeapHandle_ Description: Checks the signature to determine whether the heap handle is valid. Arguments: handle: The heap handle Returns: TRUE: The heap handle is valid FALSE: The heap handle is not valid *---------------------------------------------------------------------------*/ static inline BOOL IsValidUnitHeapHandle_( MEMHeapHandle handle ) { if ( handle == MEM_HEAP_INVALID_HANDLE ) { return FALSE; } { MEMiHeapHead* pHeapHd = handle; return pHeapHd->signature == MEMi_UNTHEAP_SIGNATURE; } } /* ======================================================================== External Functions (Non-Public) ======================================================================== */ /*---------------------------------------------------------------------------* Name: MEMiDumpUnitHeap Description: Displays the information in the unit heap. This function is used for debugging. Arguments: heap: unit heap handle Returns: None. *---------------------------------------------------------------------------*/ #if defined(_DEBUG) void MEMiDumpUnitHeap( MEMHeapHandle heap ) { ASSERT( IsValidUnitHeapHandle_( heap ) ); { MEMiHeapHead *const pHeapHd = heap; MEMiUntHeapHead *const pUnitHeapHd = GetUnitHeapHeadPtrFromHeapHead_( pHeapHd ); const u32 heapSize = GetOffsetFromPtr( pHeapHd->heapStart, pHeapHd->heapEnd ); const u32 freeSize = MEMCountFreeBlockForUnitHeap( heap ) * pUnitHeapHd->mBlkSize; const u32 usedSize = heapSize - freeSize; MEMiDumpHeapHead(pHeapHd); OSReport(" %d / %d bytes (%6.2f%%) used\n", usedSize, heapSize, 100.0f * usedSize / heapSize); } } // #if defined(_DEBUG) #endif /* ======================================================================== External functions (public) ======================================================================== */ /*---------------------------------------------------------------------------* Name: MEMCreateUnitHeapEx Description: Creates unit heap Arguments: startAddress: Start address of heap area heapSize: Size of heap area memBlockSize: Memory block size alignment: Alignment of the memory block The values 4, 8, 16, or 32 can be specified. optFlag: Option flag. Returns: If the function succeeds, a handle for the created unit heap is returned. MEM_INVALID_HEAP_HANDLE is returned if the function fails. *---------------------------------------------------------------------------*/ MEMHeapHandle MEMCreateUnitHeapEx( void* startAddress, u32 heapSize, u32 memBlockSize, int alignment, u16 optFlag ) { MEMiHeapHead* pHeapHd; void* heapEnd; ASSERT(startAddress != NULL); // alignment check ASSERT( alignment % MIN_ALIGNMENT == 0 ); ASSERT( MIN_ALIGNMENT <= alignment && alignment <= 32 ); pHeapHd = (MEMiHeapHead*)RoundUpPtr( startAddress, MIN_ALIGNMENT ); heapEnd = RoundDownPtr( AddU32ToPtr( startAddress, heapSize ), MIN_ALIGNMENT ); if ( ComparePtr( pHeapHd, heapEnd ) > 0 ) { return MEM_HEAP_INVALID_HANDLE; } memBlockSize = RoundUp( memBlockSize, alignment ); // Actual block size { MEMiUntHeapHead* pUntHeapHd = GetUnitHeapHeadPtrFromHeapHead_( pHeapHd ); void* heapStart = RoundUpPtr( AddU32ToPtr( pUntHeapHd, sizeof(MEMiUntHeapHead) ), alignment ); u32 elementNum; if ( ComparePtr( heapStart, heapEnd ) > 0 ) { return MEM_HEAP_INVALID_HANDLE; } elementNum = GetOffsetFromPtr( heapStart, heapEnd ) / memBlockSize; if ( elementNum == 0 ) { return MEM_HEAP_INVALID_HANDLE; } heapEnd = AddU32ToPtr( heapStart, elementNum * memBlockSize ); MEMiInitHeapHead( // Heap common initialization pHeapHd, MEMi_UNTHEAP_SIGNATURE, heapStart, heapEnd, optFlag ); pUntHeapHd->mbFreeList.head = (MEMiUntHeapMBlockHead*)heapStart; pUntHeapHd->mBlkSize = memBlockSize; { MEMiUntHeapMBlockHead* pMBlkHd = pUntHeapHd->mbFreeList.head; int i; for ( i = 0; i < elementNum - 1; ++i, pMBlkHd = pMBlkHd->pMBlkHdNext ) { pMBlkHd->pMBlkHdNext = (MEMiUntHeapMBlockHead*)AddU32ToPtr( pMBlkHd, memBlockSize ); } pMBlkHd->pMBlkHdNext = NULL; } return pHeapHd; } } /*---------------------------------------------------------------------------* Name: MEMDestroyUnitHeap Description: Destroys the unit heap. Arguments: heap: unit heap handle Returns: Returns a pointer to the region occupied by the destroyed heap. *---------------------------------------------------------------------------*/ void* MEMDestroyUnitHeap( MEMHeapHandle heap ) { ASSERT( IsValidUnitHeapHandle_(heap) ); MEMiFinalizeHeap(heap); return (void*)heap; } /*---------------------------------------------------------------------------* Name: MEMAllocFromUnitHeap Description: Allocates a memory block from the unit heap. Arguments: heap: unit heap handle Returns: Returns the pointer to the allocated memory block if the memory block was successfully allocated. If the operation fails, NULL is returned. *---------------------------------------------------------------------------*/ void* MEMAllocFromUnitHeap( MEMHeapHandle heap ) { MEMiUntHeapMBlockHead* pMBlkHd; ASSERT( IsValidUnitHeapHandle_( heap ) ); { MEMiUntHeapHead* pUntHeapHd = GetUnitHeapHeadPtrFromHeapHead_( heap ); LockHeap( heap ); pMBlkHd = PopMBlock_( &pUntHeapHd->mbFreeList ); UnlockHeap( heap ); if ( pMBlkHd ) { FillAllocMemory( heap, pMBlkHd, pUntHeapHd->mBlkSize ); } } return pMBlkHd; } /*---------------------------------------------------------------------------* Name: MEMFreeToUnitHeap Description: This function returns the memory block to the unit heap. Arguments: heap: unit heap handle memBlock: Pointer to the memory block to be returned. Returns: None. *---------------------------------------------------------------------------*/ void MEMFreeToUnitHeap( MEMHeapHandle heap, void* memBlock ) { ASSERT( IsValidUnitHeapHandle_( heap ) ); if ( memBlock == NULL ) { return; } { MEMiUntHeapHead* pUntHeapHd = GetUnitHeapHeadPtrFromHeapHead_( heap ); FillFreeMemory( heap, memBlock, pUntHeapHd->mBlkSize ); LockHeap( heap ); PushMBlock_( &pUntHeapHd->mbFreeList, (MEMiUntHeapMBlockHead*)memBlock ); UnlockHeap( heap ); } } /*---------------------------------------------------------------------------* Name: MEMCountFreeBlockForUnitHeap Description: Gets the number of free memory blocks in the unit heap. Arguments: heap: unit heap handle Returns: Returns the number of free memory blocks in the unit heap. *---------------------------------------------------------------------------*/ u32 MEMCountFreeBlockForUnitHeap( MEMHeapHandle heap ) { u32 cnt = 0; ASSERT(IsValidUnitHeapHandle_(heap)); LockHeap( heap ); { MEMiUntHeapHead* pUntHeapHd = GetUnitHeapHeadPtrFromHeapHead_( heap ); MEMiUntHeapMBlockHead* pMBlkHd = pUntHeapHd->mbFreeList.head; for ( ; pMBlkHd; pMBlkHd = pMBlkHd->pMBlkHdNext ) { ++cnt; } } UnlockHeap( heap ); return cnt; } /*---------------------------------------------------------------------------* Name: MEMCalcHeapSizeForUnitHeap Description: Gets the required heap size based on the size and number of memory blocks. Arguments: memBlockSize: Size of memory blocks (in bytes) memBlockNum: Total number of memory blocks to be allocated. alignment: Alignment of the memory block Returns: Returns the required heap size. *---------------------------------------------------------------------------*/ u32 MEMCalcHeapSizeForUnitHeap( u32 memBlockSize, u32 memBlockNum, int alignment ) { return sizeof(MEMiHeapHead) + sizeof(MEMiUntHeapHead) // Size that the heap uses internally + (alignment - 4) // Maximum size required for adjusting the alignment + memBlockNum * RoundUp( memBlockSize, alignment ); // Size required by all units }