mirror of
https://github.com/encounter/aurora.git
synced 2026-03-30 10:57:39 -07:00
8cbbba0179
For audio implementation in TP.
116 lines
3.2 KiB
C++
116 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
|
|
}
|
|
|
|
void* ARGetStorageAddress() {
|
|
return sAramBuffer;
|
|
}
|