Files
Pieter-Jan Briers e4afaeeeb7 OS functions start (#16)
* OS memory start

OSInit()
MEM1 size configurable via AuroraConfiguration
Fancy guard pages (who knows if it'll be useful)

* OSGetTime() and OSGetTick()

* Fix OSPhysicalToCached etc for 64-bit pointers

* Specify memory size in OS boot info

Used by TP at least

* Fix MEM1Start/MEM1End definition

oops

* Implement some OS arena functions

* DEBUG -> NDEBUG

* Implement memory translation functions

I decided to remove the macros from the header given they're very unlikely to matter perf wise and it reduces code duplication.

There's no distinction between cached and uncached. Physical is relative to MEM1.

* Fix symbol mismatches from forgetting to include the header

* Implement OSReport and similar logging functions

* Fix OSBaseAddress

Ugh

* Implement OSGetPhysicalMemSize

* Fix usage of static for global variables

* Remove ../ prefixes from OS CMake file

CLion did this

* Remaining headers needed for TP to build

* Rider's "Unversioned Files" will keep trolling me

* Remove TP-specific OSReport functions

* Hardcode OS_BUS_CLOCK in os.h

TP has it referenced in an initializer, so relying on MEM1 being initialized is impossible.

* Import TP ARAM emulation code

* Guard against double OSInit() calls.

---------

Co-authored-by: Luke Street <luke@street.dev>
2026-03-02 08:33:42 -07:00

111 lines
3.2 KiB
C++

#include <dolphin/ar.h>
#include "../internal.hpp"
#include "dolphin/os.h"
static aurora::Module Log("aurora::ar");
static u32 AR_StackPointer;
static u32* AR_BlockLength;
static u32 AR_FreeBlocks;
static BOOL AR_init_flag;
#define ARAM_STACK_START 0x4000;
// ARAM emulation: allocate a large buffer to simulate the GameCube's Auxiliary RAM.
// ARAM "addresses" are offsets into this buffer. On GameCube, ARAM is 16 MB starting
// at a base address returned by ARInit. We emulate this by malloc'ing a buffer
// and using a simple bump allocator (matching ARAlloc behavior on real hardware).
static u8* sAramBuffer = nullptr;
// Convert an ARAM "address" (offset) to a real host pointer
static u8* aramToHost(u32 aramAddr) {
if (!sAramBuffer || aramAddr >= aurora::g_config.mem2Size) {
return nullptr;
}
return sAramBuffer + aramAddr;
}
u32 ARAlloc(u32 length) {
u32 tmp;
ASSERTMSGLINE(430, !(length & 0x1F), "ARAlloc(): length is not multiple of 32bytes!");
ASSERTMSGLINE(434, length <= (__AR_Size - __AR_StackPointer), "ARAlloc(): Out of ARAM!");
ASSERTMSGLINE(435, __AR_FreeBlocks, "ARAlloc(): No more free blocks!");
tmp = AR_StackPointer;
AR_StackPointer += length;
*AR_BlockLength = length;
AR_BlockLength += 1;
AR_FreeBlocks -= 1;
return tmp;
}
u32 ARFree(u32* length) {
AR_BlockLength -= 1;
if (length) {
*length = *AR_BlockLength;
}
AR_StackPointer -= *AR_BlockLength;
AR_FreeBlocks += 1;
return AR_StackPointer;
}
BOOL ARCheckInit(void) { return AR_init_flag; }
u32 ARInit(u32* stack_index_addr, u32 num_entries) {
if (aurora::g_config.mem2Size == 0) {
Log.warn("ARInit called but no mem2Size specified in AuroraConfig. ARAM will not be available!");
return 0;
}
if (AR_init_flag == TRUE) {
return ARAM_STACK_START;
}
sAramBuffer = (u8*)calloc(1, aurora::g_config.mem2Size);
if (sAramBuffer) {
Log.debug("Initialized 0x{:X} bytes of ARAM!", aurora::g_config.mem2Size);
} else {
Log.fatal("Failed to allocate ARAM!");
}
AR_StackPointer = ARAM_STACK_START;
AR_FreeBlocks = num_entries;
AR_BlockLength = stack_index_addr;
AR_init_flag = TRUE;
return AR_StackPointer;
}
u32 ARGetSize(void) { return aurora::g_config.mem2Size; }
#pragma mark ARQ
void ARQPostRequest(ARQRequest* request, u32 owner, u32 type, u32 priority, uintptr_t source, uintptr_t dest,
u32 length, ARQCallback callback) {
// Emulate ARAM DMA transfers using memcpy.
// type 0 = MRAM -> ARAM, type 1 = ARAM -> MRAM
if (type == ARAM_DIR_MRAM_TO_ARAM) {
// Main RAM -> ARAM: source is a host pointer (cast to u32), dest is an ARAM offset
u8* hostSrc = (u8*)(uintptr_t)source;
u8* aramDst = aramToHost(dest);
if (aramDst && hostSrc) {
memcpy(aramDst, hostSrc, length);
}
} else {
// ARAM -> Main RAM: source is an ARAM offset, dest is a host pointer (cast to u32)
u8* aramSrc = aramToHost(source);
u8* hostDst = (u8*)(uintptr_t)dest;
if (aramSrc && hostDst) {
memcpy(hostDst, aramSrc, length);
}
}
// Immediately invoke the callback (synchronous on PC, no DMA latency)
if (callback) {
callback((uintptr_t)request);
}
}
void ARQInit() {
// Nothing to do on PC - ARAM is initialized in ARInit
}