/******************************************************************************** Ultra 64 MARIO Brothers memory manager module Copyright 1996 Nintendo co., ltd. All rights reserved April 9, 1996 ********************************************************************************/ #include "headers.h" // #include #define MEMINFO 0 #define MM_ALLOC_FORE 0 #define MM_ALLOC_BACK 1 #define Limit64(n) ((uint)(n)&0xfffffff8) #define Limit128(n) ((uint)(n)&0xfffffff0) #define Align128(n) (((uint)(n)+15)&0xfffffff0) #define Align64(n) (((uint)(n)+ 7)&0xfffffff8) #define Align32(n) (((uint)(n)+ 3)&0xfffffffc) #define Align16(n) (((uint)(n)+ 1)&0xfffffffe) #define AddSize(a,s) (((uint)(a))+(s)) #define SubSize(a,s) (((uint)(a))-(s)) extern char _ULibSegmentRomStart[]; extern char _ULibSegmentRomEnd[]; extern void slidec(uchar *sou, uchar *des); /*-------------------------------------------------------------------------------- * internal types. */ typedef struct fzoneMCB { struct fzoneMCB *prev; /* pointer to the previous memory block */ struct fzoneMCB *next; /* pointer to the next memory block */ wlong pad; } FZoneMCB; typedef struct memFrame { uint size; /* free memory size */ FZoneMCB *fore; /* fore-allocation pointer */ FZoneMCB *back; /* back-allocation pointer */ struct memFrame *frame; /* memory frame pointer */ } MemFrame; typedef struct heapMCB { struct heapMCB *link; /* pointer to the next free block */ ulong size; /* size of memory block */ } HeapMCB; HeapPtr systemHeap; /* pointer to the system heap memory */ /*-------------------------------------------------------------------------------- * local works */ static uint segmentTable[NUM_SEGMENTS+16]; /* segment address table */ static uint fzoneSize; /* unused memory size */ static MemPtr fzoneHead; /* head of the free zone */ static MemPtr fzoneTail; /* tail of the free zone */ static FZoneMCB *fzoneForeptr; /* fore-allocation pointer */ static FZoneMCB *fzoneBackptr; /* back-allocation pointer */ static MemFrame *memoryFrame = NULL; /* memory frame pointer */ /*################################################################################ * * * RCP segment address oparations. * */ /********************************************************************************/ /* */ /* Set RCP segment base address. */ /* */ /********************************************************************************/ extern uint SetSegment(int number, void *cpuAddr) { segmentTable[number] = K0_TO_PHYS(cpuAddr); return(segmentTable[number]); } /********************************************************************************/ /* */ /* Get RCP segment base address. */ /* */ /********************************************************************************/ extern void * GetSegment(int number) { return((MemPtr)PHYS_TO_K0(segmentTable[number])); } /********************************************************************************/ /* */ /* Convert RCP segment address to CPU virtual address. */ /* */ /********************************************************************************/ extern void * SegmentToVirtual(void *rcpAddr) { #undef SEGMENT_NUMBER #define SEGMENT_NUMBER(x) ((u32)(x)>>24) uint number = SEGMENT_NUMBER(rcpAddr); uint offset = SEGMENT_OFFSET(rcpAddr); return((char *)PHYS_TO_K0(segmentTable[number] + offset)); } /********************************************************************************/ /* */ /* Convert CPU virtual address to RCP segment address. */ /* */ /********************************************************************************/ extern void * VirtualToSegment(int number, void *cpuAddr) { uint offset = K0_TO_PHYS(cpuAddr) - segmentTable[number]; return((void *)SEGMENT_ADDR(number, offset)); } /********************************************************************************/ /* */ /* Store segment data into the gfx list. */ /* */ /********************************************************************************/ extern void StoreSegments(void) { int number; for (number = 0; number < NUM_SEGMENTS; number++) { gSPSegment(graphPtr++, number, segmentTable[number]); } } /*################################################################################ * * * The free zone managements. * */ /********************************************************************************/ /* */ /* Initlaize the free zone. */ /* */ /********************************************************************************/ extern void InitFreeZone(MemPtr topAddr, MemPtr btmAddr) { #define BIGGER_HEAP #ifdef BIGGER_HEAP extern int _DepthbufSegmentEnd; topAddr = &_DepthbufSegmentEnd; #endif fzoneHead = (MemPtr)Align128(topAddr) + sizeof(FZoneMCB); fzoneTail = (MemPtr)Limit128(btmAddr) - sizeof(FZoneMCB); fzoneSize = fzoneTail - fzoneHead; fzoneForeptr = (FZoneMCB *)(fzoneHead - sizeof(FZoneMCB)); fzoneBackptr = (FZoneMCB *)(fzoneTail ); fzoneForeptr->prev = NULL; fzoneForeptr->next = NULL; fzoneBackptr->prev = NULL; fzoneBackptr->next = NULL; #if MEMINFO rmonpf((" : foreptr : backptr : free size : alloc size\n")); rmonpf((" initial free zone: %08XH : %08XH : %08XH\n", fzoneForeptr, fzoneBackptr, fzoneSize)); #endif } /********************************************************************************/ /* */ /* Allocate a memory block from the free zone. */ /* */ /********************************************************************************/ extern void * AllocFreeZone(uint size, int mode) { FZoneMCB *fzoneNextptr; MemPtr allocMemory = NULL; size = Align128(size) + sizeof(FZoneMCB); if (0 < size && size <= fzoneSize) { fzoneSize -= size; if (mode == MM_ALLOC_FORE) { fzoneNextptr = (FZoneMCB *)AddSize(fzoneForeptr,size); fzoneForeptr->next = fzoneNextptr; fzoneNextptr->prev = fzoneForeptr; fzoneNextptr->next = NULL; allocMemory = (MemPtr)(fzoneForeptr + 1); fzoneForeptr = fzoneNextptr; } else { fzoneNextptr = (FZoneMCB *)SubSize(fzoneBackptr,size); fzoneBackptr->prev = fzoneNextptr; fzoneNextptr->next = fzoneBackptr; fzoneNextptr->prev = NULL; fzoneBackptr = fzoneNextptr; allocMemory = (MemPtr)(fzoneBackptr + 1); } } #if MEMINFO rmonpf((" alloc free zone: %08XH : %08XH : %08XH : %08XH\n", fzoneForeptr, fzoneBackptr, fzoneSize, size)); #endif return(allocMemory); } /********************************************************************************/ /* */ /* Purge a memory block from the free zone. */ /* */ /********************************************************************************/ extern uint PurgeFreeZone(void *address) { FZoneMCB *fzoneTop = (FZoneMCB *)SubSize(address,sizeof(FZoneMCB)); FZoneMCB *fzoneBottom = (FZoneMCB *)SubSize(address,sizeof(FZoneMCB)); if (fzoneBottom < fzoneForeptr) { while (fzoneBottom->next != NULL) fzoneBottom = fzoneBottom->next; fzoneForeptr = fzoneTop; fzoneForeptr->next = NULL; fzoneSize += (uint)fzoneBottom - (uint)fzoneForeptr; } else { while (fzoneBottom->prev != NULL) fzoneBottom = fzoneBottom->prev; fzoneBackptr = fzoneTop->next; fzoneBackptr->prev = NULL; fzoneSize += (uint)fzoneBackptr - (uint)fzoneBottom; } #if MEMINFO rmonpf((" purge free zone: %08XH : %08XH : %08XH\n", fzoneForeptr, fzoneBackptr, fzoneSize)); #endif return(fzoneSize); } /********************************************************************************/ /* */ /* Resize a last memory block in the free zone. */ /* */ /********************************************************************************/ extern void * ResizeFreeZone(void *address, uint size) { MemPtr memory = NULL; FZoneMCB *fzone = (FZoneMCB *)SubSize(address,sizeof(FZoneMCB)); if (fzone->next == fzoneForeptr) { PurgeFreeZone(address); memory = AllocFreeZone(size, MM_ALLOC_FORE); } #if MEMINFO rmonpf((" resize free zone: %08XH : %08XH : %08XH : %08XH\n", fzoneForeptr, fzoneBackptr, fzoneSize, size)); #endif return(memory); } /********************************************************************************/ /* */ /* Get free memory size. */ /* */ /********************************************************************************/ extern uint FreeZoneSize(void) { return(fzoneSize - sizeof(FZoneMCB)); } /********************************************************************************/ /* */ /* Link free sone memory. */ /* */ /********************************************************************************/ extern uint LinkFreeZone(void) { MemFrame *frame = memoryFrame; uint memsize = fzoneSize; FZoneMCB *foreptr = fzoneForeptr; FZoneMCB *backptr = fzoneBackptr; memoryFrame = AllocFreeZone(sizeof(MemFrame), MM_ALLOC_FORE); memoryFrame->size = memsize; memoryFrame->fore = foreptr; memoryFrame->back = backptr; memoryFrame->frame = frame; #if MEMINFO rmonpf((" link free zone: %08XH : %08XH : %08XH\n", fzoneForeptr, fzoneBackptr, fzoneSize)); #endif return(fzoneSize); } /********************************************************************************/ /* */ /* Unlink free sone memory. */ /* */ /********************************************************************************/ extern uint UnlinkFreeZone(void) { fzoneSize = memoryFrame->size; fzoneForeptr = memoryFrame->fore; fzoneBackptr = memoryFrame->back; memoryFrame = memoryFrame->frame; #if MEMINFO rmonpf((" unlink free zone: %08XH : %08XH : %08XH\n", fzoneForeptr, fzoneBackptr, fzoneSize)); #endif return(fzoneSize); } /*################################################################################ * * * Static data loaders. * */ /********************************************************************************/ /* Read a data block from ROM. */ /********************************************************************************/ static void ReadBlock(char *ramAddr, char *romStart, char *romEnd) { uint size = Align128(romEnd - romStart); osInvalDCache(ramAddr, size); while (size > 0) { uint load = (size >= 0x1000) ? 0x1000 : size; osPiStartDma(&dmaIOMessageBuf, OS_MESG_PRI_NORMAL, OS_READ, (ulong)romStart, ramAddr, load, &dmaMessageQ); osRecvMesg(&dmaMessageQ, &dummyMessage, OS_MESG_BLOCK); ramAddr += load; romStart += load; size -= load; } } /********************************************************************************/ /* */ /* Load static data from ROM. */ /* */ /********************************************************************************/ extern MemPtr LoadData(char *romStart, char *romEnd, int mode) { MemPtr ramAddr; uint ramSize = Align128(romEnd - romStart); if ((ramAddr = AllocFreeZone(ramSize, mode)) != NULL) { ReadBlock(ramAddr, romStart, romEnd); } return(ramAddr); } /********************************************************************************/ /* */ /* Load static segment from ROM. */ /* */ /********************************************************************************/ extern MemPtr LoadSegment(int number, char *romStart, char *romEnd, int mode) { MemPtr addr; if ((addr = LoadData(romStart, romEnd, mode)) != NULL) { SetSegment(number, addr); } return(addr); } /********************************************************************************/ /* */ /* Load program from ROM. */ /* */ /********************************************************************************/ extern MemPtr LoadProgram(char *ramAddr, char *romStart, char *romEnd) { MemPtr alcAddr = NULL; uint romsize = Align128( romEnd - romStart); uint alcsize = Align128((char *)fzoneBackptr - ramAddr ); if (romsize <= alcsize) { if ((alcAddr = AllocFreeZone(alcsize, MM_ALLOC_BACK)) != NULL) { bzero(alcAddr, alcsize); osWritebackDCacheAll(); ReadBlock(alcAddr, romStart, romEnd); osInvalICache(alcAddr, alcsize); osInvalDCache(alcAddr, alcsize); } } else { rmonpf(("program code load failed AD=%08X ROM=%08X ALC=%08X\n",ramAddr,romsize,alcsize)); } return(alcAddr); } ////////////////////////////////////////////////////////////////////////////////// // // // // // Load compressed data from ROM for IRIX 5.3. // // // // ////////////////////////////////////////////////////////////////////////////////// #if 1 /********************************************************************************/ /* */ /* Load compressed data from ROM. */ /* */ /********************************************************************************/ extern MemPtr LoadCompressed(int number, char *romStart, char *romEnd) { MemPtr alcaddr = NULL; uint romsize = Align128(romEnd - romStart); MemPtr tempmem = AllocFreeZone(romsize, MM_ALLOC_BACK); uint *alcsize = (uint *)(tempmem+4); if (tempmem != NULL) { ReadBlock(tempmem, romStart, romEnd); if ((alcaddr = AllocFreeZone(*alcsize, MM_ALLOC_FORE)) != NULL) { osSyncPrintf("start decompress\n"); slidec((uchar *)tempmem, (uchar *)alcaddr); osSyncPrintf("end decompress\n"); SetSegment(number, alcaddr); PurgeFreeZone(tempmem); } else { rmonpf(("compressed data load failed (ROM:$%08X RAM:$%08X)\n", romsize, *alcsize)); } } else { rmonpf(("size of compressed data is too big\n")); } return(alcaddr); } /********************************************************************************/ /* */ /* Load compressed texture data from ROM. */ /* */ /********************************************************************************/ extern MemPtr LoadPressTexture(int number, char *romStart, char *romEnd) { MemPtr alcaddr = NULL; uint romsize = Align128(romEnd - romStart); MemPtr tempmem = AllocFreeZone(romsize, MM_ALLOC_BACK); uint *alcsize = (uint *)(tempmem+4); if (tempmem != NULL) { ReadBlock(tempmem, romStart, romEnd); slidec((uchar *)tempmem, (uchar *)textureMemory); SetSegment(number, textureMemory); PurgeFreeZone(tempmem); } else { rmonpf(("size of compressed data is too big\n")); } return((MemPtr)textureMemory); } #endif #if 0 ////////////////////////////////////////////////////////////////////////////////// // // // // // Load compressed data from ROM for IRIX 6.x. // // // // ////////////////////////////////////////////////////////////////////////////////// typedef struct { ulong pressID1; /* compredd module ID 1 */ ulong pressID2; /* compredd module ID 2 */ ulong hdrsize; /* header size */ ulong romsize; /* module size of the ROM */ ulong ramsize; /* module size of the RAM */ ulong numglbs; /* number of global tables */ } PrsHeader; typedef struct { ulong value; /* global value */ ulong offset; /* offset from top of module */ } PrsGlobal; /********************************************************************************/ /* */ /* Uncompress data. */ /* */ /********************************************************************************/ static void Uncompress(char *source, char *destination) { int count; PrsHeader * prsheader = (PrsHeader *)source; PrsGlobal * glbtable = (PrsGlobal *)(source + sizeof(PrsHeader)); char * pressed = source + prsheader->hdrsize; u32 bssSize = prsheader->ramsize - prsheader->romsize; osInvalICache(destination, prsheader->ramsize); osInvalDCache(destination, prsheader->ramsize); slidstart(source + prsheader->hdrsize, destination); for (count = 0; count < prsheader->numglbs; count++) { *((u32 *)(destination + glbtable->offset)) = glbtable->value; glbtable++; } if (bssSize > 0) bzero(destination + prsheader->romsize, bssSize); osWritebackDCache(destination, prsheader->ramsize); } /********************************************************************************/ /* */ /* Load compressed data from ROM. */ /* */ /********************************************************************************/ extern MemPtr LoadCompressed(int number, char *romStart, char *romEnd) { MemPtr alcaddr = NULL; uint romsize = Align128(romEnd - romStart); MemPtr tempmem = AllocFreeZone(romsize, MM_ALLOC_BACK); uint alcsize; if (tempmem != NULL) { ReadBlock(tempmem, romStart, romEnd); alcsize = ((PrsHeader *)tempmem)->ramsize; if ((alcaddr = AllocFreeZone(alcsize, MM_ALLOC_FORE)) != NULL) { osSyncPrintf("start decompress\n"); Uncompress(tempmem, alcaddr); osSyncPrintf("end decompress\n"); SetSegment(number, alcaddr); PurgeFreeZone(tempmem); } else { rmonpf(("compressed data load failed (ROM:$%08X RAM:$%08X)\n", romsize, alcsize)); } } else { rmonpf(("size of compressed data is too big\n")); } return(alcaddr); } /********************************************************************************/ /* */ /* Load compressed texture data from ROM. */ /* */ /********************************************************************************/ extern MemPtr LoadPressTexture(int number, char *romStart, char *romEnd) { MemPtr alcaddr = NULL; uint romsize = Align128(romEnd - romStart); MemPtr tempmem = AllocFreeZone(romsize, MM_ALLOC_BACK); if (tempmem != NULL) { ReadBlock(tempmem, romStart, romEnd); Uncompress(tempmem, (char *)textureMemory); SetSegment(number, textureMemory); PurgeFreeZone(tempmem); } else { rmonpf(("size of compressed data is too big\n")); } return((MemPtr)textureMemory); } #endif /********************************************************************************/ /* */ /* Load user library. */ /* */ /********************************************************************************/ extern void LoadUserLibrary(void) { MemPtr ramAddr = (MemPtr)ULIBCODE_START; uint ramSize = CPROGRAM_END - ULIBCODE_START; uint romSize = Align128(_ULibSegmentRomEnd - _ULibSegmentRomStart); bzero(ramAddr, ramSize); osWritebackDCacheAll(); ReadBlock(ramAddr, _ULibSegmentRomStart, _ULibSegmentRomEnd); osInvalICache(ramAddr, ramSize); osInvalDCache(ramAddr, ramSize); } /*################################################################################ * * * Arena memory management. * */ /********************************************************************************/ /* */ /* Initialize the arena. */ /* */ /********************************************************************************/ extern ArenaPtr InitArena(int size, int mode) { MemPtr memory; ArenaPtr arena = NULL; size = Align32(size); if ((memory = AllocFreeZone(size + sizeof(ArenaRecord), mode)) != NULL) { arena = (ArenaPtr)memory; arena->size = size; arena->used = 0; arena->buff = memory + sizeof(ArenaRecord); arena->free = memory + sizeof(ArenaRecord); } return(arena); } /********************************************************************************/ /* */ /* Allocate a memory block from the arena. */ /* */ /********************************************************************************/ extern void * AllocArena(ArenaPtr arena, int size) { char *memory = NULL; size = Align32(size); if (0 < size && arena->used + size <= arena->size) { memory = arena->free; arena->free += size; arena->used += size; } return(memory); } /********************************************************************************/ /* */ /* Resize a arena memory block. */ /* */ /********************************************************************************/ extern void * ResizeArena(ArenaPtr arena, int size) { MemPtr memory; size = Align32(size); if ((memory = ResizeFreeZone(arena, size + sizeof(ArenaRecord))) != NULL) { arena->size = size; } return(memory); } /*################################################################################ * * * heap memory management. * */ /********************************************************************************/ /* Print heap. (for debug) */ /********************************************************************************/ #if 0 static void PrintHeap(HeapPtr heap) { HeapMCB *free = (HeapMCB *)heap->free; rmonpf(("start print free heap\n")); while (free != NULL) { rmonpf(("%08XH - %08XH (%08XH)\n", free, AddSize(free,free->size-1), free->size)); free = free->link; } rmonpf(("end print free heap\n")); } #endif /********************************************************************************/ /* Check heap. (for debug) */ /********************************************************************************/ #if 0 static void CheckHeap(HeapPtr heap, MemPtr memory) { HeapMCB *free = (HeapMCB *)heap->free; if (free != NULL) { MemPtr next = (MemPtr)AddSize(free,free->size); while (free->link != NULL) { free = free->link; if ((MemPtr)free == next) { rmonpf(("heap broken (%08X , %08X) , %08X\n", heap->buff, heap->size, memory)); PrintHeap(heap); for(;;); } next = (MemPtr)AddSize(free,free->size); } } } #endif /********************************************************************************/ /* */ /* Initilaize the heap. */ /* */ /********************************************************************************/ extern HeapPtr InitHeap(int size, int mode) { MemPtr memory; HeapMCB *hmcb; HeapPtr heap = NULL; size = Align32(size); if ((memory = AllocFreeZone(size + sizeof(HeapRecord), mode)) != NULL) { heap = (HeapPtr)memory; heap->size = size; heap->buff = memory + sizeof(HeapRecord); heap->free = memory + sizeof(HeapRecord); hmcb = (HeapMCB *)heap->buff; hmcb->link = NULL; hmcb->size = heap->size; } // rmonpf(("Init heap\n")); // PrintHeap(heap); return(heap); } /********************************************************************************/ /* */ /* Allocate a memory block from the heap. */ /* */ /********************************************************************************/ extern void * AllocHeap(HeapPtr heap, int memsize) { HeapMCB **freeblk = (HeapMCB **)&heap->free; MemPtr memory = NULL; memsize = Align32(memsize) + sizeof(HeapMCB); while (*freeblk != NULL) { if (memsize <= (*freeblk)->size) { memory = (MemPtr)(*freeblk + 1); if (((*freeblk)->size - memsize) <= sizeof(HeapMCB)) { *freeblk = (*freeblk)->link; } else { HeapMCB *newblk = (HeapMCB *)AddSize(*freeblk, memsize); newblk->size = (*freeblk)->size - memsize; newblk->link = (*freeblk)->link; (*freeblk)->size = memsize; *freeblk = newblk; } break; } freeblk = &(*freeblk)->link; } // rmonpf(("Alloc heap (%08XH , %08XH)\n", memory, memsize)); // PrintHeap(heap); // CheckHeap(heap, memory); return(memory); } /********************************************************************************/ /* */ /* Free a memory block. */ /* */ /********************************************************************************/ extern void * FreeHeap(HeapPtr heap, void *memory) { HeapMCB *memblk = (HeapMCB *)memory - 1; HeapMCB *freeblk = (HeapMCB *)heap->free; if (heap->free == NULL) { heap->free = (MemPtr)memblk; memblk->link = NULL; } else if (memblk < (HeapMCB *)heap->free) { if (heap->free == (MemPtr)AddSize(memblk, memblk->size)) { memblk->size += freeblk->size; memblk->link = freeblk->link; heap->free = (MemPtr)memblk; } else { memblk->link = (HeapMCB *)heap->free; heap->free = (MemPtr)memblk; } } else { while (freeblk->link != NULL) { if (freeblk < memblk && memblk < freeblk->link) break; freeblk = freeblk->link; } if (memblk == (HeapMCB *)AddSize(freeblk, freeblk->size)) { freeblk->size += memblk->size; memblk = freeblk; } else { memblk->link = freeblk->link; freeblk->link = memblk; } if (memblk->link != NULL && memblk->link == (HeapMCB *)AddSize(memblk, memblk->size)) { memblk->size += (memblk->link)->size; memblk->link = (memblk->link)->link; } } // rmonpf(("Free heap (%08XH , %08XH)\n", memory, ((HeapMCB *)memory-1)->size)); // CheckHeap(heap, memory); // PrintHeap(heap); } /*################################################################################ * * Dynamic Memory management oparations * */ /********************************************************************************/ /* */ /* Allocate dynamic memory block. */ /* */ /********************************************************************************/ extern void * AllocDynamic(int size) { MemPtr memory = NULL; size = Align64(size); if ((blockPtr - size >= (MemPtr)graphPtr)) { blockPtr -= size; memory = blockPtr; } else { rmonpf(("DYnamic memory overflow\n")); } return(memory); } /*################################################################################ * * Partial manager * */ /********************************************************************************/ /* */ /* Load partition table. */ /* */ /********************************************************************************/ extern Partition * LoadPartitionTable(MemPtr romAddr) { Partition *table; int size; table = (Partition *)LoadData(romAddr, romAddr+sizeof(ulong), MM_ALLOC_FORE); size = table->nitems * 8 + 8; PurgeFreeZone(table); table = (Partition *)LoadData(romAddr, romAddr+size, MM_ALLOC_FORE); table->topaddr = romAddr; return(table); } /********************************************************************************/ /* */ /* Init partial data namagement record. */ /* */ /********************************************************************************/ extern void InitPartial(PartialPtr partial, MemPtr romAddr, MemPtr buffer) { if (romAddr != NULL) partial->ptable = LoadPartitionTable(romAddr); partial->last = NULL; partial->buffer = buffer; } /********************************************************************************/ /* */ /* Read partial data. */ /* */ /********************************************************************************/ extern int ReadPartialData(PartialPtr partial, int index) { int result = FALSE; Partition *ptable = partial->ptable; if (index < ptable->nitems) { MemPtr addr = ptable->item[index].offset + ptable->topaddr; int size = ptable->item[index].length; if (addr != partial->last) { ReadBlock(partial->buffer, addr, addr+size); partial->last = addr; result = TRUE; } } return(result); }