(3DS) implement dynamic memory management.

heap/linear heap and stack sizes can now change dynamically at runtime,
depending on usage, no need to specify those on a per-core basis
anymore.
This commit is contained in:
aliaspider 2015-11-02 01:24:11 +01:00
parent d4f037f6d7
commit 8741ec48d5
12 changed files with 814 additions and 429 deletions

View File

@ -4,7 +4,6 @@ LIBRETRO =
DEBUG = 0
GRIFFIN_BUILD = 1
WHOLE_ARCHIVE_LINK = 0
BIG_STACK = 0
BUILD_3DSX = 1
BUILD_3DS = 1
BUILD_CIA = 1
@ -21,22 +20,15 @@ APP_RSF = ctr/tools/template.rsf
APP_SYSTEM_MODE = 64MB
APP_SYSTEM_MODE_EXT = 124MB
ifeq ($(BIG_STACK),1)
CTR_STACK_SIZE = 0x400000
else
CTR_STACK_SIZE = 0x100000
endif
CTR_LINEAR_HEAP_SIZE = 0x600000
CTR_MAX_HEAP_SIZE = 0x6000000
include ctr/Makefile.cores
CONFIG_OBJECT = ctr/ctr_config_$(CTR_STACK_SIZE)_$(CTR_LINEAR_HEAP_SIZE)_$(CTR_MAX_HEAP_SIZE).o
OBJS :=
OBJS += gfx/drivers/ctr_sprite.o
OBJS += $(CONFIG_OBJECT)
OBJS += ctr/stack_adjust.o
OBJS += ctr/ctr_system.o
OBJS += ctr/ctr_memory.o
OBJS += ctr/ctr_linear.o
ifeq ($(GRIFFIN_BUILD), 1)
OBJS += griffin/griffin.o
else
@ -270,6 +262,7 @@ ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -marm -mfpu=vfp
CFLAGS += -mword-relocations \
-fomit-frame-pointer -ffast-math \
-Werror=implicit-function-declaration \
$(ARCH)
#CFLAGS += -Wall
@ -286,19 +279,6 @@ ifeq ($(WHOLE_ARCHIVE_LINK), 1)
WHOLE_END := -Wl,--no-whole-archive
endif
ifneq ($(CTR_STACK_SIZE),)
CFLAGS += -DCTR_STACK_SIZE=$(CTR_STACK_SIZE)
endif
ifneq ($(CTR_LINEAR_HEAP_SIZE),)
CFLAGS += -DCTR_LINEAR_HEAP_SIZE=$(CTR_LINEAR_HEAP_SIZE)
endif
ifneq ($(CTR_MAX_HEAP_SIZE),)
CFLAGS += -DCTR_MAX_HEAP_SIZE=$(CTR_MAX_HEAP_SIZE)
endif
CFLAGS += -I. -Ideps/zlib -Ideps/7zip -Ilibretro-common/include
CFLAGS += -DRARCH_INTERNAL -DRARCH_CONSOLE -DSINC_LOWEST_QUALITY
@ -365,11 +345,6 @@ else
BANNERTOOL = ctr/tools/bannertool.exe
endif
$(CONFIG_OBJECT): ctr/ctr_config.c
rm -f ctr/ctr_config_*.o
$(CC) -c -o $@ $< $(CFLAGS) $(INCDIRS)
%.o: %.shader
python $(AEMSTRO)/aemstro_as.py $< $(notdir $<).shbin
$(DEVKITARM)/bin/bin2s $(notdir $<).shbin | $(PREFIX)as -o $@
@ -425,6 +400,7 @@ clean:
rm -f $(TARGET).elf
rm -f $(TARGET).3ds
rm -f $(TARGET).cia
rm -f $(TARGET).smdh
rm -f $(TARGET).bnr
rm -f $(TARGET).icn
rm -f *_shader_shbin.h

View File

@ -9,9 +9,6 @@ ifeq ($(LIBRETRO), gambatte)
APP_ICON = ctr/gambatte.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
#CTR_LINEAR_HEAP_SIZE = 0x600000
else ifeq ($(LIBRETRO), gpsp)
APP_TITLE = gpSP Libretro
@ -22,9 +19,6 @@ else ifeq ($(LIBRETRO), gpsp)
APP_ICON = ctr/gpsp.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
#CTR_LINEAR_HEAP_SIZE = 0x600000
else ifeq ($(LIBRETRO), fceumm)
APP_TITLE = FCeumm Libretro
@ -35,9 +29,6 @@ else ifeq ($(LIBRETRO), fceumm)
APP_ICON = ctr/fceumm.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
#CTR_LINEAR_HEAP_SIZE = 0x600000
else ifeq ($(LIBRETRO), nestopia)
APP_TITLE = Nestopia Libretro
@ -48,9 +39,6 @@ else ifeq ($(LIBRETRO), nestopia)
APP_ICON = ctr/nestopia.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
CTR_LINEAR_HEAP_SIZE = 0xE00000
else ifeq ($(LIBRETRO), nxengine)
APP_TITLE = NXengine Libretro
@ -61,9 +49,6 @@ else ifeq ($(LIBRETRO), nxengine)
APP_ICON = ctr/nxengine.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
#CTR_LINEAR_HEAP_SIZE = 0x600000
else ifeq ($(LIBRETRO), genesis_plus_gx)
APP_TITLE = Genesis Plus GX Libretro
@ -74,9 +59,6 @@ else ifeq ($(LIBRETRO), genesis_plus_gx)
APP_ICON = ctr/genesis_plus_gx.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
CTR_LINEAR_HEAP_SIZE = 0xE00000
else ifeq ($(LIBRETRO), catsfc)
APP_TITLE = CATSFC Libretro
@ -87,9 +69,6 @@ else ifeq ($(LIBRETRO), catsfc)
APP_ICON = ctr/catsfc.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
#CTR_LINEAR_HEAP_SIZE = 0x600000
else ifeq ($(LIBRETRO), mednafen_wswan)
APP_TITLE = Mednafen wswan Libretro
@ -100,9 +79,6 @@ else ifeq ($(LIBRETRO), mednafen_wswan)
APP_ICON = ctr/mednafen_wswan.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
CTR_LINEAR_HEAP_SIZE = 0xE00000
else ifeq ($(LIBRETRO), mednafen_vb)
APP_TITLE = Mednafen VB Libretro
@ -113,9 +89,6 @@ else ifeq ($(LIBRETRO), mednafen_vb)
APP_ICON = ctr/mednafen_vb.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
CTR_LINEAR_HEAP_SIZE = 0xE00000
else ifeq ($(LIBRETRO), mednafen_ngp)
APP_TITLE = Mednafen NGP Libretro
@ -126,9 +99,6 @@ else ifeq ($(LIBRETRO), mednafen_ngp)
APP_ICON = ctr/mednafen_ngp.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
CTR_LINEAR_HEAP_SIZE = 0xE00000
else ifeq ($(LIBRETRO), 2048)
APP_TITLE = 2048 Libretro
@ -139,9 +109,6 @@ else ifeq ($(LIBRETRO), 2048)
APP_ICON = ctr/2048.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
CTR_LINEAR_HEAP_SIZE = 0xE00000
else ifeq ($(LIBRETRO), picodrive)
APP_TITLE = Picodrive Libretro
@ -152,9 +119,6 @@ else ifeq ($(LIBRETRO), picodrive)
APP_ICON = ctr/picodrive.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
#CTR_LINEAR_HEAP_SIZE = 0x600000
else ifeq ($(LIBRETRO), snes9x_next)
APP_TITLE = Snes9x Next Libretro
@ -165,9 +129,6 @@ else ifeq ($(LIBRETRO), snes9x_next)
APP_ICON = ctr/snes9x_next.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
#CTR_LINEAR_HEAP_SIZE = 0x600000
else ifeq ($(LIBRETRO), mgba)
APP_TITLE = mGBA Libretro
@ -178,9 +139,6 @@ else ifeq ($(LIBRETRO), mgba)
APP_ICON = ctr/mgba.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
#CTR_LINEAR_HEAP_SIZE = 0x600000
else ifeq ($(LIBRETRO), quicknes)
APP_TITLE = QuickNES Libretro
@ -191,9 +149,6 @@ else ifeq ($(LIBRETRO), quicknes)
APP_ICON = ctr/quicknes.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
#CTR_LINEAR_HEAP_SIZE = 0x600000
else ifeq ($(LIBRETRO), fb_alpha_neo)
APP_TITLE = Neo Geo (FB Alpha)
@ -205,9 +160,6 @@ else ifeq ($(LIBRETRO), fb_alpha_neo)
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
APP_SYSTEM_MODE = 80MB
#APP_SYSTEM_MODE_EXT = Legacy
CTR_LINEAR_HEAP_SIZE = 0x3A0000
CTR_MAX_HEAP_SIZE = 0xC00000
else ifeq ($(LIBRETRO), fb_alpha_cps1)
APP_TITLE = Final Burn Alpha - CPS-1
@ -218,9 +170,6 @@ else ifeq ($(LIBRETRO), fb_alpha_cps1)
APP_ICON = ctr/fb_alpha_cps1.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
#CTR_LINEAR_HEAP_SIZE = 0x600000
else ifeq ($(LIBRETRO), fb_alpha_cps2)
APP_TITLE = Final Burn Alpha - CPS-2
@ -232,8 +181,6 @@ else ifeq ($(LIBRETRO), fb_alpha_cps2)
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
APP_SYSTEM_MODE = 80MB
#APP_SYSTEM_MODE_EXT = Legacy
#CTR_LINEAR_HEAP_SIZE = 0x600000
else ifeq ($(LIBRETRO), catsfc_plus)
APP_TITLE = CATSFC Plus Libretro
@ -244,9 +191,6 @@ else ifeq ($(LIBRETRO), catsfc_plus)
APP_ICON = ctr/catsfc_plus.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
#CTR_LINEAR_HEAP_SIZE = 0x600000
else ifeq ($(LIBRETRO), mednafen_pce_fast)
APP_TITLE = Mednafen/Beetle PCE FAST
@ -257,9 +201,6 @@ else ifeq ($(LIBRETRO), mednafen_pce_fast)
APP_ICON = ctr/mednafen_pce_fast.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
#CTR_LINEAR_HEAP_SIZE = 0x600000
else ifeq ($(LIBRETRO), pcsx_rearmed)
APP_TITLE = PCSX ReARMed
@ -270,9 +211,6 @@ else ifeq ($(LIBRETRO), pcsx_rearmed)
APP_ICON = ctr/pcsx_rearmed.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
CTR_LINEAR_HEAP_SIZE = 0xE00000
else ifeq ($(LIBRETRO), fmsx)
APP_TITLE = fMSX
@ -283,8 +221,5 @@ else ifeq ($(LIBRETRO), fmsx)
APP_ICON = ctr/fmsx.png
#APP_BANNER = ctr/libretro_banner.png
#APP_AUDIO = ctr/silent.wav
#APP_SYSTEM_MODE = 64MB
#APP_SYSTEM_MODE_EXT = Legacy
CTR_LINEAR_HEAP_SIZE = 0x1000000
endif

View File

@ -1,18 +0,0 @@
#ifndef CTR_STACK_SIZE
#define CTR_STACK_SIZE 0x100000
#endif
#ifndef CTR_LINEAR_HEAP_SIZE
#define CTR_LINEAR_HEAP_SIZE 0x600000
#endif
#ifndef CTR_MAX_HEAP_SIZE
#define CTR_MAX_HEAP_SIZE 0x6000000
#endif
int __stacksize__ = CTR_STACK_SIZE;
unsigned int __linear_heap_size = CTR_LINEAR_HEAP_SIZE;
unsigned int __heap_size = CTR_MAX_HEAP_SIZE + CTR_STACK_SIZE;

23
ctr/ctr_debug.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef _CTR_DEBUG_H__
#define _CTR_DEBUG_H__
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
void wait_for_input(void);
void dump_result_value(Result val);
#ifdef __cplusplus
}
#endif
#define DEBUG_HOLD() do{printf("%s@%s:%d.\n",__FUNCTION__, __FILE__, __LINE__);fflush(stdout);wait_for_input();}while(0)
#define DEBUG_STR(X) printf( "%s: %s\n", #X, (char*)(X))
#define DEBUG_VAR(X) printf( "%-20s: 0x%08X\n", #X, (u32)(X))
#define DEBUG_VAR64(X) printf( #X"\r\t\t\t\t : 0x%016llX\n", (u64)(X))
#define DEBUG_ERROR(X) do{if(X)dump_result_value(X)}while(0)
#define PRINTFPOS(X,Y) "\x1b["#X";"#Y"H"
#define PRINTFPOS_STR(X,Y) "\x1b["X";"Y"H"
#endif //_CTR_DEBUG_H__

273
ctr/ctr_linear.cpp Normal file
View File

@ -0,0 +1,273 @@
/* from https://github.com/smealum/ctrulib
* modified to allow reducing __linear_heap_size at runtime */
#include <3ds.h>
#include <stdlib.h>
#include <3ds/util/rbtree.h>
#include "ctr_debug.h"
struct MemChunk
{
u8* addr;
u32 size;
};
struct MemBlock
{
MemBlock *prev, *next;
u8* base;
u32 size;
static MemBlock* Create(u8* base, u32 size)
{
auto b = (MemBlock*)malloc(sizeof(MemBlock));
if (!b) return nullptr;
b->prev = nullptr;
b->next = nullptr;
b->base = base;
b->size = size;
return b;
}
};
struct MemPool
{
MemBlock *first, *last;
bool Ready() { return first != nullptr; }
void AddBlock(MemBlock* blk)
{
blk->prev = last;
if (last) last->next = blk;
if (!first) first = blk;
last = blk;
}
void DelBlock(MemBlock* b)
{
auto prev = b->prev, &pNext = prev ? prev->next : first;
auto next = b->next, &nPrev = next ? next->prev : last;
pNext = next;
nPrev = prev;
free(b);
}
void InsertBefore(MemBlock* b, MemBlock* p)
{
auto prev = b->prev, &pNext = prev ? prev->next : first;
b->prev = p;
p->next = b;
p->prev = prev;
pNext = p;
}
void InsertAfter(MemBlock* b, MemBlock* n)
{
auto next = b->next, &nPrev = next ? next->prev : last;
b->next = n;
n->prev = b;
n->next = next;
nPrev = n;
}
//void CoalesceLeft(MemBlock* b);
void CoalesceRight(MemBlock* b);
bool Allocate(MemChunk& chunk, u32 size, int align);
void Deallocate(const MemChunk& chunk);
void Destroy()
{
MemBlock* next = nullptr;
for (auto b = first; b; b = next)
{
next = b->next;
free(b);
}
first = nullptr;
last = nullptr;
}
//void Dump(const char* title);
u32 GetFreeSpace();
};
static rbtree_t sAddrMap;
struct addrMapNode
{
rbtree_node node;
MemChunk chunk;
};
#define getAddrMapNode(x) rbtree_item((x), addrMapNode, node)
static int addrMapNodeComparator(const rbtree_node_t* _lhs, const rbtree_node_t* _rhs)
{
auto lhs = getAddrMapNode(_lhs)->chunk.addr;
auto rhs = getAddrMapNode(_rhs)->chunk.addr;
if (lhs < rhs)
return -1;
if (lhs > rhs)
return 1;
return 0;
}
static void addrMapNodeDestructor(rbtree_node_t* a)
{
free(getAddrMapNode(a));
}
static addrMapNode* getNode(void* addr)
{
addrMapNode n;
n.chunk.addr = (u8*)addr;
auto p = rbtree_find(&sAddrMap, &n.node);
return p ? getAddrMapNode(p) : nullptr;
}
static addrMapNode* newNode(const MemChunk& chunk)
{
auto p = (addrMapNode*)malloc(sizeof(addrMapNode));
if (!p) return nullptr;
p->chunk = chunk;
return p;
}
static void delNode(addrMapNode* node)
{
rbtree_remove(&sAddrMap, &node->node, addrMapNodeDestructor);
}
extern u32 __linear_heap, __linear_heap_size;
static MemPool sLinearPool;
static u32 sLinearPool_maxaddr;
static bool linearInit()
{
auto blk = MemBlock::Create((u8*)__linear_heap, __linear_heap_size);
if (blk)
{
sLinearPool.AddBlock(blk);
sLinearPool_maxaddr = __linear_heap;
rbtree_init(&sAddrMap, addrMapNodeComparator);
return true;
}
return false;
}
void* linearMemAlign(size_t size, size_t alignment)
{
// Enforce minimum alignment
if (alignment < 16)
alignment = 16;
// Convert alignment to shift amount
int shift;
for (shift = 4; shift < 32; shift ++)
{
if ((1U<<shift) == alignment)
break;
}
if (shift == 32) // Invalid alignment
return nullptr;
// Initialize the pool if it is not ready
if (!sLinearPool.Ready() && !linearInit())
return nullptr;
// Allocate the chunk
MemChunk chunk;
if (!sLinearPool.Allocate(chunk, size, shift))
return nullptr;
auto node = newNode(chunk);
if (!node)
{
sLinearPool.Deallocate(chunk);
return nullptr;
}
if (rbtree_insert(&sAddrMap, &node->node));
if (sLinearPool_maxaddr < (u32)sLinearPool.last->base)
sLinearPool_maxaddr = (u32)sLinearPool.last->base;
return chunk.addr;
}
void* linearAlloc(size_t size)
{
// extern PrintConsole* currentConsole;
// if(currentConsole->consoleInitialised)
// {
// printf("linearAlloc : 0x%08X\n", size);
// DEBUG_HOLD();
// }
return linearMemAlign(size, 0x80);
}
void* linearRealloc(void* mem, size_t size)
{
// TODO
return NULL;
}
void linearFree(void* mem)
{
auto node = getNode(mem);
if (!node) return;
// Free the chunk
sLinearPool.Deallocate(node->chunk);
// Free the node
delNode(node);
}
u32 linearSpaceFree()
{
return sLinearPool.GetFreeSpace();
}
extern "C" u32 ctr_get_linear_free(void)
{
if(sLinearPool.last->base + sLinearPool.last->size != (u8*)__linear_heap + __linear_heap_size)
return 0;
return sLinearPool.last->size;
}
extern "C" u32 ctr_get_linear_unused(void)
{
return __linear_heap + __linear_heap_size - sLinearPool_maxaddr;
}
extern "C" void ctr_linear_free_pages(u32 pages)
{
if(sLinearPool.last->base + sLinearPool.last->size != (u8*)__linear_heap + __linear_heap_size)
return;
u32 size = pages << 12;
if(size > sLinearPool.last->size)
return;
sLinearPool.last->size -= size;
__linear_heap_size -= size;
u32 tmp;
svcControlMemory(&tmp, __linear_heap + __linear_heap_size, 0x0, size,
MEMOP_FREE, (MemPerm)(MEMPERM_READ | MEMPERM_WRITE));
// printf("l:0x%08X-->0x%08X(-0x%08X) \n", sLinearPool.last->size + size, sLinearPool.last->size, size);
// DEBUG_HOLD();
}
extern "C" void ctr_linear_get_stats(void)
{
printf("last:\n");
printf("0x%08X --> 0x%08X (0x%08X) \n", sLinearPool.last->base,
sLinearPool.last->base + sLinearPool.last->size, sLinearPool.last->size);
printf("free: 0x%08X unused: 0x%08X \n", ctr_get_linear_unused(), ctr_get_linear_free());
}

151
ctr/ctr_memory.c Normal file
View File

@ -0,0 +1,151 @@
#include <3ds.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include "ctr_debug.h"
//void* malloc(size_t nbytes)
//{
// void* ret = _malloc_r (_REENT, nbytes);
// return ret;
//}
//void free (void* aptr)
//{
// _free_r (_REENT, aptr);
//}
extern u32 __heapBase;
extern u32 __heap_size;
extern u32 __stack_bottom;
extern u32 __stack_size_extra;
extern u32 __stacksize__;
u32 ctr_get_linear_free(void);
u32 ctr_get_linear_unused(void);
u32 ctr_get_stack_free(void)
{
extern u32 __stack_bottom;
uint32_t* stack_bottom_current = (u32*)__stack_bottom;
while(*stack_bottom_current++ == 0xFCFCFCFC);
stack_bottom_current--;
return ((u32)stack_bottom_current - __stack_bottom);
}
u32 ctr_get_stack_usage(void)
{
extern u32 __stacksize__;
u32 stack_free = ctr_get_stack_free();
return __stacksize__ > stack_free? __stacksize__ - stack_free: 0;
}
void ctr_linear_free_pages(u32 pages);
void ctr_free_pages(u32 pages)
{
if(!pages)
return;
u32 linear_free_pages = ctr_get_linear_free() >> 12;
if((ctr_get_linear_unused() >> 12) > pages + 0x100)
return ctr_linear_free_pages(pages);
// if(linear_free_pages > pages + 0x400)
// return ctr_linear_free_pages(pages);
u32 stack_free = ctr_get_stack_free();
u32 stack_usage = __stacksize__ > stack_free? __stacksize__ - stack_free: 0;
stack_free = stack_free > __stack_size_extra ? __stack_size_extra : stack_free;
u32 stack_free_pages = stack_free >> 12;
if(linear_free_pages + (stack_free_pages - (stack_usage >> 12)) > pages)
{
stack_free_pages -= (stack_usage >> 12);
stack_free_pages = stack_free_pages > pages ? pages : stack_free_pages;
linear_free_pages = pages - stack_free_pages;
}
else if(linear_free_pages + stack_free_pages > pages)
stack_free_pages = pages - linear_free_pages;
else
return;
if(linear_free_pages)
ctr_linear_free_pages(linear_free_pages);
if(stack_free_pages)
{
u32 tmp;
svcControlMemory(&tmp, __stack_bottom,
0x0,
stack_free_pages << 12,
MEMOP_FREE, MEMPERM_READ | MEMPERM_WRITE);
__stack_bottom += stack_free_pages << 12;
__stack_size_extra -= stack_free_pages << 12;
__stacksize__ -= stack_free_pages << 12;
// printf("s:0x%08X-->0x%08X(-0x%08X) \n", stack_free,
// stack_free - (stack_free_pages << 12), stack_free_pages << 12);
// DEBUG_HOLD();
}
}
u32 ctr_get_free_space(void)
{
u32 app_memory = *((u32*)0x1FF80040);
s64 mem_used;
svcGetSystemInfo(&mem_used, 0, 1);
return app_memory - (u32)mem_used;
}
void ctr_request_free_pages(u32 pages)
{
u32 free_pages = ctr_get_free_space() >> 12;
if (pages > free_pages)
{
ctr_free_pages(pages - free_pages);
free_pages = ctr_get_free_space() >> 12;
}
}
void* _sbrk_r(struct _reent *ptr, ptrdiff_t incr)
{
static u32 sbrk_top = 0;
if (!sbrk_top)
sbrk_top = __heapBase;
u32 tmp;
int diff = ((sbrk_top + incr + 0xFFF) & ~0xFFF)
- (__heapBase + __heap_size);
if (diff > 0)
{
ctr_request_free_pages(diff >> 12);
if (svcControlMemory(&tmp, __heapBase + __heap_size,
0x0, diff, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE) < 0)
{
ptr->_errno = ENOMEM;
return (caddr_t) -1;
}
}
__heap_size += diff;
if (diff < 0)
svcControlMemory(&tmp, __heapBase + __heap_size,
0x0, -diff, MEMOP_FREE, MEMPERM_READ | MEMPERM_WRITE);
sbrk_top += incr;
return (caddr_t)(sbrk_top - incr);
}

238
ctr/ctr_system.c Normal file
View File

@ -0,0 +1,238 @@
#include <3ds.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#define CTR_APPMEMALLOC_PTR ((u32*)0x1FF80040)
u32 __stacksize__ = 0x00400000;
u32 __linear_heap_size = 0x01000000;
u32 __heap_size;
u32 __linear_heap;
u32 __heapBase;
extern u32 __linear_heap_size_hbl;
extern u32 __heap_size_hbl;
extern void (*__system_retAddr)(void);
void __destroy_handle_list(void);
void __appExit();
void __libc_fini_array(void);
void __libctru_init(void (*retAddr)(void));
void __appInit();
void __libc_init_array(void);
u32 __stack_bottom;
u32 __stack_size_extra;
void __system_allocateHeaps() {
u32 tmp=0;
MemInfo stack_memInfo;
PageInfo stack_pageInfo;
register u32 sp_val __asm__("sp");
svcQueryMemory(&stack_memInfo, &stack_pageInfo, sp_val);
__stacksize__ += 0xFFF;
__stacksize__ &= ~0xFFF;
__stack_size_extra = __stacksize__ > stack_memInfo.size ? __stacksize__ - stack_memInfo.size: 0;
__stack_bottom = stack_memInfo.base_addr - __stack_size_extra;
if (__stack_size_extra)
{
svcControlMemory(&tmp, __stack_bottom, 0x0, __stack_size_extra, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE);
memset((void*)__stack_bottom, 0xFC, __stack_size_extra);
}
// setup the application heap
__heapBase = 0x08000000;
__heap_size = 0;
// Allocate the linear heap
svcControlMemory(&__linear_heap, 0x0, 0x0, __linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE);
// Set up newlib heap
extern char* fake_heap_end;
fake_heap_end = 0x13F00000;
}
Result __sync_fini(void) __attribute__((weak));
extern char** __system_argv;
void __attribute__((noreturn)) __libctru_exit(int rc)
{
u32 tmp=0;
if(__system_argv)
free(__system_argv);
// Unmap the linear heap
svcControlMemory(&tmp, __linear_heap, 0x0, __linear_heap_size, MEMOP_FREE, 0x0);
// Unmap the application heap
svcControlMemory(&tmp, __heapBase, 0x0, __heap_size, MEMOP_FREE, 0x0);
if (__stack_size_extra)
svcControlMemory(&tmp, __stack_bottom, 0x0, __stack_size_extra, MEMOP_FREE, 0x0);
// Close some handles
__destroy_handle_list();
if (__sync_fini)
__sync_fini();
// Jump to the loader if it provided a callback
if (__system_retAddr)
__system_retAddr();
// Since above did not jump, end this process
svcExitProcess();
}
#include <3ds/types.h>
#include <string.h>
// System globals we define here
int __system_argc;
char** __system_argv;
extern const char* __system_arglist;
//extern char* fake_heap_start;
extern char* fake_heap_end;
void __system_initArgv()
{
int i;
const char* temp = __system_arglist;
// Check if the argument list is present
if (!temp)
return;
// Retrieve argc
__system_argc = *(u32*)temp;
temp += sizeof(u32);
// Find the end of the argument data
for (i = 0; i < __system_argc; i ++)
{
for (; *temp; temp ++);
temp ++;
}
// Reserve heap memory for argv data
u32 argSize = temp - __system_arglist - sizeof(u32);
// __system_argv = (char**)fake_heap_start;
// fake_heap_start += sizeof(char**)*(__system_argc + 1);
// char* argCopy = fake_heap_start;
// fake_heap_start += argSize;
__system_argv = malloc(sizeof(char**)*(__system_argc + 1) + argSize);
char* argCopy = (char*)__system_argv + sizeof(char**)*(__system_argc + 1);
// Fill argv array
memcpy(argCopy, &__system_arglist[4], argSize);
temp = argCopy;
for (i = 0; i < __system_argc; i ++)
{
__system_argv[i] = (char*)temp;
for (; *temp; temp ++);
temp ++;
}
__system_argv[__system_argc] = NULL;
}
//void initSystem(void (*retAddr)(void))
//{
// __libctru_init(retAddr);
// __appInit();
// __libc_init_array();
//}
//void __attribute__((noreturn)) __ctru_exit(int rc)
//{
// __libc_fini_array();
// __appExit();
// __libctru_exit(rc);
//}
typedef union{
struct
{
unsigned description : 10;
unsigned module : 8;
unsigned : 3;
unsigned summary : 6;
unsigned level : 5;
};
Result val;
}ctr_result_value;
void dump_result_value(Result val)
{
ctr_result_value res;
res.val = val;
printf("result : 0x%08X\n", val);
printf("description : %u\n", res.description);
printf("module : %u\n", res.module);
printf("summary : %u\n", res.summary);
printf("level : %u\n", res.level);
}
bool select_pressed = false;
void wait_for_input(void)
{
printf("\n\nPress Start.\n\n");
fflush(stdout);
while(aptMainLoop())
{
u32 kDown;
hidScanInput();
kDown = hidKeysDown();
if (kDown & KEY_START)
break;
if (kDown & KEY_SELECT)
exit(0);
#if 0
select_pressed = true;
#endif
svcSleepThread(1000000);
}
}
int usleep (useconds_t us)
{
svcSleepThread((int64_t)us * 1000);
}
long sysconf(int name)
{
switch(name)
{
case _SC_NPROCESSORS_ONLN:
return 2;
}
return -1;
}

49
ctr/stack_adjust.s Normal file
View File

@ -0,0 +1,49 @@
.arm
.align 2
.global initSystem
.type initSystem, %function
initSystem:
ldr r2, =saved_stack
str sp, [r2]
str lr, [r2,#4]
bics sp, sp, #7
bl __libctru_init
bl __appInit
bl __libc_init_array
ldr r2, =saved_stack
ldr lr, [r2,#4]
bx lr
.global __ctru_exit
.type __ctru_exit, %function
__ctru_exit:
bl __libc_fini_array
bl __appExit
ldr r2, =saved_stack
ldr sp, [r2]
b __libctru_exit
.data
.align 2
__stacksize__:
.word 0x100000
.weak __stacksize__
.bss
.align 2
saved_stack:
.space 8

View File

@ -174,7 +174,7 @@ AccessControlInfo:
SystemControlInfo:
RemasterVersion: 2
StackSize: 0x40000
StackSize: 0x4000
# Modules that run services listed above should be included below
# Maximum 48 dependencies
# If a module is listed that isn't present on the 3DS, the title will get stuck at the logo (3ds waves)

View File

@ -16,7 +16,6 @@
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <boolean.h>
@ -31,6 +30,8 @@
#include "retroarch.h"
#include "audio/audio_driver.h"
#include "ctr/ctr_debug.h"
#ifdef IS_SALAMANDER
#include "../../file_ext.h"
#else
@ -39,90 +40,6 @@
const char* elf_path_cst = "sdmc:/retroarch/test.3dsx";
#ifndef DEBUG_HOLD
void wait_for_input(void);
void dump_result_value(Result val);
#define DEBUG_HOLD() do{printf("%s@%s:%d.\n",__FUNCTION__, __FILE__, __LINE__);fflush(stdout);wait_for_input();}while(0)
#define DEBUG_VAR(X) printf( "%-20s: 0x%08X\n", #X, (u32)(X))
#define DEBUG_VAR64(X) printf( #X"\r\t\t\t\t : 0x%016llX\n", (u64)(X))
#define DEBUG_ERROR(X) do{if(X)dump_result_value(X)}while(0)
#define PRINTFPOS(X,Y) "\x1b["#X";"#Y"H"
#define PRINTFPOS_STR(X,Y) "\x1b["X";"Y"H"
#endif
#define CTR_APPMEMALLOC_PTR ((u32*)0x1FF80040)
extern char* fake_heap_start;
extern char* fake_heap_end;
u32 __linear_heap;
u32 __heapBase;
extern u32 __linear_heap_size;
extern u32 __heap_size;
extern u32 __linear_heap_size_hbl;
extern u32 __heap_size_hbl;
extern void (*__system_retAddr)(void);
void __destroy_handle_list(void);
void __appExit();
void __libc_fini_array(void);
void __system_allocateHeaps() {
extern unsigned int __service_ptr;
u32 tmp=0;
int64_t mem_used;
u32 mem_available;
u32 app_memory;
svcGetSystemInfo(&mem_used, 0, 1);
if(__service_ptr)
{
app_memory = mem_used + __linear_heap_size_hbl + __heap_size_hbl;
app_memory = app_memory < 0x04000000 ? 0x04000000 : app_memory;
}
else
app_memory = *CTR_APPMEMALLOC_PTR;
mem_available = (app_memory - mem_used - __linear_heap_size - 0x10000) & 0xFFFFF000;
__heap_size = __heap_size > mem_available ? mem_available : __heap_size;
__heap_size = __heap_size > 0x6000000 ? 0x6000000 : __heap_size;
// __linear_heap_size = (app_memory - mem_used - __heap_size - 0x10000) & 0xFFFFF000;
// Allocate the application heap
__heapBase = 0x08000000;
svcControlMemory(&tmp, __heapBase, 0x0, __heap_size, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE);
// Allocate the linear heap
svcControlMemory(&__linear_heap, 0x0, 0x0, __linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE);
// Set up newlib heap
fake_heap_start = (char*)__heapBase;
fake_heap_end = fake_heap_start + __heap_size;
}
void __attribute__((noreturn)) __libctru_exit(int rc)
{
u32 tmp=0;
// Unmap the linear heap
svcControlMemory(&tmp, __linear_heap, 0x0, __linear_heap_size, MEMOP_FREE, 0x0);
// Unmap the application heap
svcControlMemory(&tmp, __heapBase, 0x0, __heap_size, MEMOP_FREE, 0x0);
// Close some handles
__destroy_handle_list();
// Jump to the loader if it provided a callback
if (__system_retAddr)
__system_retAddr();
// Since above did not jump, end this process
svcExitProcess();
}
static void frontend_ctr_get_environment_settings(int *argc, char *argv[],
void *args, void *params_data)
{
@ -161,9 +78,15 @@ static void frontend_ctr_get_environment_settings(int *argc, char *argv[],
fill_pathname_join(g_defaults.path.config, g_defaults.dir.port,
"retroarch.cfg", sizeof(g_defaults.path.config));
*argc = 0;
#if 0
int i;
DEBUG_VAR(*argc);
for (i=0; i < *argc; i++)
DEBUG_STR(argv[i]);
DEBUG_HOLD();
#endif
*argc=0;
*argc = 0;
#ifndef IS_SALAMANDER
#if 0
@ -324,190 +247,6 @@ static int frontend_ctr_get_rating(void)
return 3;
}
bool select_pressed = false;
typedef union{
struct
{
unsigned description : 10;
unsigned module : 8;
unsigned : 3;
unsigned summary : 6;
unsigned level : 5;
};
Result val;
}ctr_result_value;
void dump_result_value(Result val)
{
ctr_result_value res;
res.val = val;
printf("result : 0x%08X\n", val);
printf("description : %u\n", res.description);
printf("module : %u\n", res.module);
printf("summary : %u\n", res.summary);
printf("level : %u\n", res.level);
}
#if 0
static void ctr_crawl_memory(uint32_t* total_size, uint32_t size)
{
void* tmp = malloc(size);
if(tmp)
*total_size += size;
else
size >>= 1;
if (size > 4)
ctr_crawl_memory(total_size, size);
free(tmp);
}
void ctr_get_memory_info(uint32_t* available, uint32_t* max_block)
{
*available = 0;
ctr_crawl_memory(available, 1<<27);
void* tmp;
*max_block = 0;
int i;
for (i=27; i>2; i--)
{
tmp = malloc(*max_block + (1 << i));
if(tmp)
{
*max_block += 1 << i;
free(tmp);
}
}
}
uint32_t malloc_calls = 0;
uint32_t min_malloc_addr = 0xFFFFFFFF;
uint32_t max_malloc_addr = 0x0;
void* malloc(size_t nbytes)
{
void* ret = _malloc_r (_REENT, nbytes);
if (ret)
{
if(max_malloc_addr < ((uint32_t)ret + nbytes))
max_malloc_addr = ((uint32_t)ret + nbytes);
if(min_malloc_addr > (uint32_t)ret)
min_malloc_addr = (uint32_t)ret;
}
malloc_calls++;
return ret;
}
void free (void* aptr)
{
_free_r (_REENT, aptr);
}
uint32_t sbrk_calls = 0;
uint32_t sbrk_max_incr = 0;
uint32_t sbrk_total_incr = 0;
uint32_t sbrk_heap_start = 0;
uint32_t sbrk_heap_end = 0;
#include "errno.h"
extern char *fake_heap_end;
extern char *fake_heap_start;
/* Register name faking - works in collusion with the linker. */
register char * stack_ptr asm ("sp");
void * _sbrk_r (struct _reent *ptr, ptrdiff_t incr) {
extern char end asm ("__end__"); /* Defined by the linker. */
static char * heap_start;
char * prev_heap_start;
char * heap_end;
if (heap_start == NULL) {
if (fake_heap_start == NULL) {
heap_start = &end;
} else {
heap_start = fake_heap_start;
}
}
prev_heap_start = heap_start;
if (fake_heap_end == NULL) {
heap_end = stack_ptr;
} else {
heap_end = fake_heap_end;
}
if (heap_start + incr > heap_end) {
ptr->_errno = ENOMEM;
return (caddr_t) -1;
}
heap_start += incr;
sbrk_calls++;
if ((incr > 0) && (sbrk_max_incr < incr))
sbrk_max_incr = incr;
sbrk_total_incr += incr;
sbrk_heap_start = (uint32_t) heap_start;
sbrk_heap_end = (uint32_t) heap_end;
return (caddr_t) prev_heap_start;
}
#endif
void wait_for_input(void)
{
printf("\n\nPress Start.\n\n");
fflush(stdout);
while(aptMainLoop())
{
u32 kDown;
hidScanInput();
kDown = hidKeysDown();
if (kDown & KEY_START)
break;
if (kDown & KEY_SELECT)
exit(0);
#if 0
select_pressed = true;
#endif
retro_sleep(1);
}
}
int usleep (useconds_t us)
{
svcSleepThread((int64_t)us * 1000);
}
long sysconf(int name)
{
switch(name)
{
case _SC_NPROCESSORS_ONLN:
return 2;
}
return -1;
}
enum frontend_architecture frontend_ctr_get_architecture(void)
{
return FRONTEND_ARCH_ARM;

View File

@ -461,30 +461,56 @@ static bool ctr_frame(void* data, const void* frame,
frames = 0;
}
#if 0
// extern u32 gpuCmdBufOffset;
// if(!(frames & 0x3F))
// {
// u32 available,max_block;
// void ctr_get_memory_info(u32* available, u32* max_block);
// ctr_get_memory_info(&available, &max_block);
// printf(PRINTFPOS(28,0)"u:0x%08X f:0x%08X b:0x%08X\n", __heap_size - available, available, max_block);
// }
//#define CTR_INSPECT_MEMORY_USAGE
#ifdef CTR_INSPECT_MEMORY_USAGE
uint32_t ctr_get_stack_usage(void);
void ctr_linear_get_stats(void);
extern u32 __linear_heap_size;
extern u32 __heap_size;
extern uint32_t sbrk_calls, sbrk_max_incr, sbrk_total_incr, sbrk_heap_start, sbrk_heap_end;
printf(PRINTFPOS(25,0)"c:0x%08X m:0x%08X c:0x%08X\n", sbrk_calls, sbrk_max_incr, sbrk_total_incr);
printf(PRINTFPOS(26,0)"s:0x%08X e:0x%08X \n", sbrk_heap_start, sbrk_heap_end);
extern uint32_t malloc_calls, min_malloc_addr, max_malloc_addr;
printf(PRINTFPOS(27,0)"n:0x%08X l:0x%08X h:0x%08X\n", malloc_calls, min_malloc_addr, max_malloc_addr);
printf(PRINTFPOS(28,0)"0x%08X 0x%08X 0x%08X\r", __heap_size, gpuCmdBufOffset, (__linear_heap_size - linearSpaceFree() +0x3FF) & ~0x3FF);
#endif
// printf(PRINTFPOS(29,0)"fps: %8.4f frames: %i (%X)\r", fps, total_frames++, (__linear_heap_size - linearSpaceFree()));
MemInfo mem_info;
PageInfo page_info;
u32 query_addr = 0x08000000;
printf(PRINTFPOS(0,0));
while (query_addr < 0x40000000)
{
svcQueryMemory(&mem_info, &page_info, query_addr);
printf("0x%08X --> 0x%08X (0x%08X) \n", mem_info.base_addr, mem_info.base_addr + mem_info.size, mem_info.size);
query_addr = mem_info.base_addr + mem_info.size;
if(query_addr == 0x1F000000)
query_addr = 0x30000000;
}
// static u32* dummy_pointer;
// if(total_frames == 500)
// dummy_pointer = malloc(0x2000000);
// if(total_frames == 1000)
// free(dummy_pointer);
printf("========================================");
printf("0x%08X 0x%08X 0x%08X\n", __heap_size, gpuCmdBufOffset, (__linear_heap_size - linearSpaceFree()));
printf("fps: %8.4f frames: %i (%X)\n", fps, total_frames++, (__linear_heap_size - linearSpaceFree()));
printf("========================================");
u32 app_memory = *((u32*)0x1FF80040);
u64 mem_used;
svcGetSystemInfo(&mem_used, 0, 1);
printf("total mem : 0x%08X \n", app_memory);
printf("used: 0x%08X free: 0x%08X \n", (u32)mem_used, app_memory - (u32)mem_used);
static u32 stack_usage = 0;
extern u32 __stack_bottom;
if(!(total_frames & 0x3F))
stack_usage = ctr_get_stack_usage();
printf("stack total:0x%08X used: 0x%08X\n", 0x10000000 - __stack_bottom, stack_usage);
printf("========================================");
ctr_linear_get_stats();
printf("========================================");
#else
printf(PRINTFPOS(29,0)"fps: %8.4f frames: %i\r", fps, total_frames++);
#endif
fflush(stdout);
rarch_perf_init(&ctrframe_f, "ctrframe_f");

View File

@ -31,14 +31,6 @@
#define CTRGU_SIZE(W,H) (((u32)(W)&0xFFFF)|((u32)(H)<<16))
/* from ctrulib/great-refactor */
#define GPU_TEVOP_RGB_SRC_G 0x8
#define GPU_TEVOP_RGB_SRC_B 0xC
#define GPU_TEVOP_RGB_SRC_ALPHA 0x2
#define GPU_MULTIPLY_ADD 0x8
/*******************************/
/* DMA flags */
#define CTRGU_DMA_VFLIP (1 << 0)
#define CTRGU_DMA_L_TO_T (1 << 1)
@ -62,6 +54,7 @@
#ifndef DEBUG_HOLD
void wait_for_input(void);
#define PRINTFPOS(X,Y) "\x1b["#X";"#Y"H"
#define PRINTF_LINE(X) "\x1b["X";0H"
#define DEBUG_HOLD() do{printf("%s@%s:%d.\n",__FUNCTION__, __FILE__, __LINE__);fflush(stdout);wait_for_input();}while(0)
#define DEBUG_VAR(X) printf( "%-20s: 0x%08X\n", #X, (u32)(X))
#define DEBUG_VAR64(X) printf( #X"\r\t\t\t\t : 0x%016llX\n", (u64)(X))