diff --git a/CMakeLists.txt b/CMakeLists.txt index a5e5ca3..caec2e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ project(Gint VERSION 2.7.1 LANGUAGES C ASM) include(GitVersionNumber) include(Fxconv) -option(GINT_USER_VRAM "Put all VRAMs into the user stack (fx-CG 50 only)") +option(GINT_NO_OS_STACK "Do not use the OS stack as a memory pool (fx-CG only)") option(GINT_STATIC_GRAY "Use static memory instead of malloc for gray buffers (fx-9860G only)") option(GINT_KMALLOC_DEBUG "Enable debug functions for kmalloc") diff --git a/include/gint/config.h.in b/include/gint/config.h.in index 800749e..33d9bcf 100644 --- a/include/gint/config.h.in +++ b/include/gint/config.h.in @@ -16,10 +16,18 @@ 0x03f7c0a0 = Commit 3f7c0a0 */ #define GINT_HASH 0x@GINT_GIT_HASH@ -/* GINT_USER_VRAM: Selects whether to store VRAMs in the user stack (occupying - 350k/512k of the area) or in the system stack (the default). (fx-CG 50) */ +/* GINT_NO_OS_STACK: Disables using a chunk of the OS stack as a heap. The top + section covering 355/512 ko is otherwise used. (fx-CG 50) */ +#cmakedefine GINT_NO_OS_STACK + +/* GINT_USER_VRAM: Selects whether to store VRAMs in the user stack or in the + OS stack. Deprecated, now controlled by GINT_NO_OS_STACK. (fx-CG 50) */ #cmakedefine GINT_USER_VRAM +#ifdef GINT_USER_VRAM +# define GINT_NO_OS_STACK +#endif + /* GINT_STATIC_GRAY: Selects whether additional gray VRAMs are allocated statically or in the system heap (fx-9860G) */ #cmakedefine GINT_STATIC_GRAY diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 8aca9b1..5d6378c 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -91,15 +92,35 @@ void kinit(void) static_ram.is_default = isSH4(); static_ram.start = mmu_uram() + ((uint32_t)&euram - 0x08100000); static_ram.end = (void *)uram_end; - kmalloc_init_arena(&static_ram, true); kmalloc_add_arena(&static_ram); + /* Create an arena in the OS stack as well, for VRAM and more data */ + #if defined(FXCG50) && !defined(GINT_NO_OS_STACK) + static kmalloc_arena_t os_stack = { 0 }; + os_stack.name = "_ostk"; + os_stack.is_default = true; + if(gint[HWCALC] == HWCALC_PRIZM || gint[HWCALC] == HWCALC_FXCG_MANAGER) + os_stack.start = (void *)0x880f0000; + else + os_stack.start = (void *)0x8c0f0000; + os_stack.end = os_stack.start + (350 * 1024); + kmalloc_init_arena(&os_stack, true); + kmalloc_add_arena(&os_stack); + #endif /* FXCG50 && !GINT_NO_OS_STACK */ + /* Allocate world buffers for the OS and for gint */ gint_world_os = gint_world_alloc(); gint_world_addin = gint_world_alloc(); gint_driver_flags = malloc(gint_driver_count()); + #ifdef FXCG50 + /* Allocate VRAMs, which is important for panic screens */ + extern bool dvram_init(void); + if(!dvram_init()) + abort(); + #endif + if(!gint_world_os || !gint_world_addin || !gint_driver_flags) gint_panic(0x1060); diff --git a/src/render-cg/dupdate.c b/src/render-cg/dupdate.c index ea70ef7..11a7256 100644 --- a/src/render-cg/dupdate.c +++ b/src/render-cg/dupdate.c @@ -2,15 +2,19 @@ #include #include "render-cg.h" -/* dupdate() - Push the video RAM to the display driver */ +/* dupdate(): Push the video RAM to the display driver */ void dupdate(void) { - r61524_display(gint_vram, 0, 224, R61524_DMA); + /* If triple buffering is enabled, don't wait for the DMA to finish */ + uint16_t *vram_1, *vram_2; + dgetvram(&vram_1, &vram_2); + int method = (vram_1 == vram_2) ? R61524_DMA_WAIT : R61524_DMA; + + r61524_display(gint_vram, 0, 224, method); gint_call_t hook = dupdate_get_hook(); if(hook.function) gint_call(hook); - /* The DMA is still running, so we need to switch VRAMs to avoid - overwriting the data which is about to be sent. */ + /* Switch buffers if triple buffering is enabled */ dvram_switch(); } diff --git a/src/render-cg/dvram.c b/src/render-cg/dvram.c index e9f7b83..491e3e1 100644 --- a/src/render-cg/dvram.c +++ b/src/render-cg/dvram.c @@ -1,67 +1,62 @@ #include -#include -#include +#include -#ifdef GINT_USER_VRAM -/* We want to put the VRAM in the user section, however we can't use the - virtualized P0 address as this will mess up the DMA. As the static RAM is - always fully mapped at a fixed place, we can use the target P1 address. We - just need to allocate the space for the linker. This special section ensures - that the first address of the user stack will be used */ -GALIGNED(4) GSECTION(".bss.vram") int8_t _gint_vram_buffers[396*224*2]; +/* Up to two VRAM pointers can be set, for triple buffering. */ +static uint16_t *vram_1 = NULL, *vram_2 = NULL; +/* Current VRAM pointer, always equal to either vram_1 or vram_2. */ +uint16_t *gint_vram = NULL; -/* In this case, we can define pointers to our user stack directly, these will - be the physical address associated with _gint_vram_buffers */ -static uint16_t *main = (void *)0xac161400; -static uint16_t *scnd = (void *)0xac18c900; - -/* Shared VRAM pointer, the one exposed by */ -uint16_t *gint_vram = (void *)0xac161400; - -#else - -/* Otherwise, just put both VRAMs in the system stack! */ -static uint16_t *main = (void *)0xac0f0000; -static uint16_t *scnd = (void *)0xac11b500; -uint16_t *gint_vram = (void *)0xac0f0000; -#endif - -/* On Prizm: should be: 0xa80f0000 and 0xa811b500 */ - -__attribute__((constructor)) -static void init_vram(void) +bool dvram_init(void) { - /* On Prizm and fx-CG Manager, move address to 0xa8000000 */ - /* TODO: Detect base RAM address in BSC rather than hardcoding it */ - if(gint[HWCALC] == HWCALC_PRIZM || gint[HWCALC] == HWCALC_FXCG_MANAGER) - { - main = (void *)main - 0x04000000; - scnd = (void *)scnd - 0x04000000; - gint_vram = (void *)gint_vram - 0x04000000; - } + int const MARGIN = 32; + + /* Leave MARGIN bytes on each side of the region; this enables some + important optimisations in the image renderer. We also add another + 32 bytes so we can manually 32-align the region */ + uint32_t region = (uint32_t)malloc(DWIDTH * DHEIGHT * 2 + MARGIN + 32); + if(region == 0) + return false; + + /* 32-align the region */ + region = (region + 31) & -32; + /* Skip a MARGIN */ + region += MARGIN; + /* Use an uncached address */ + region = (region & 0x1fffffff) | 0xa0000000; + + /* Don't enable triple buffering by default */ + vram_1 = (void *)region; + vram_2 = vram_1; + gint_vram = vram_1; + return true; } -/* dsetvram() - Control video RAM address and triple buffering */ -void dsetvram(uint16_t *new_main, uint16_t *new_secondary) +/* dsetvram(): Control video RAM address and triple buffering */ +void dsetvram(uint16_t *new_vram_1, uint16_t *new_vram_2) { - if(gint_vram == main) gint_vram = new_main; - else if(gint_vram == scnd) gint_vram = new_secondary; + if(!new_vram_1 && !new_vram_2) return; + if(!new_vram_1) new_vram_1 = new_vram_2; + if(!new_vram_2) new_vram_2 = new_vram_1; - main = new_main; - scnd = new_secondary; + if(gint_vram == vram_1) + gint_vram = new_vram_1; + else if(gint_vram == vram_2) + gint_vram = new_vram_2; + + vram_1 = new_vram_1; + vram_2 = new_vram_2; } -/* dgetvram() - Get VRAM addresses */ -void dgetvram(uint16_t **ptr_main, uint16_t **ptr_scnd) +/* dgetvram(): Get VRAM addresses */ +void dgetvram(uint16_t **ptr_vram_1, uint16_t **ptr_vram_2) { - if(ptr_main) *ptr_main = main; - if(ptr_scnd) *ptr_scnd = scnd; + if(ptr_vram_1) *ptr_vram_1 = vram_1; + if(ptr_vram_2) *ptr_vram_2 = vram_2; } -/* dvram_switch() - Triple buffering switch - This function is not public, it is used only by dupdate(). */ +/* dvram_switch(): Triple buffering switch + This function is not part of the API; it is used only by dupdate(). */ void dvram_switch(void) { - if(gint_vram == main) gint_vram = scnd; - else gint_vram = main; + gint_vram = (gint_vram == vram_1) ? vram_2 : vram_1; }