mirror of https://github.com/PrimeDecomp/prime.git
parent
0fc9980411
commit
d74a026c82
|
@ -946,7 +946,7 @@ LIBS = [
|
||||||
["musyx/runtime/snd_midictrl", False],
|
["musyx/runtime/snd_midictrl", False],
|
||||||
["musyx/runtime/snd_service", True],
|
["musyx/runtime/snd_service", True],
|
||||||
["musyx/runtime/hardware", True],
|
["musyx/runtime/hardware", True],
|
||||||
"musyx/runtime/hw_aramdma",
|
["musyx/runtime/hw_aramdma", True],
|
||||||
["musyx/runtime/dsp_import", True],
|
["musyx/runtime/dsp_import", True],
|
||||||
["musyx/runtime/hw_dolphin", True],
|
["musyx/runtime/hw_dolphin", True],
|
||||||
["musyx/runtime/hw_memory", True],
|
["musyx/runtime/hw_memory", True],
|
||||||
|
|
|
@ -39,7 +39,12 @@ void ARQInit(void);
|
||||||
void ARQReset(void);
|
void ARQReset(void);
|
||||||
void ARQPostRequest(ARQRequest* task, u32 owner, u32 type, u32 priority, u32 source, u32 dest,
|
void ARQPostRequest(ARQRequest* task, u32 owner, u32 type, u32 priority, u32 source, u32 dest,
|
||||||
u32 length, ARQCallback callback);
|
u32 length, ARQCallback callback);
|
||||||
|
void ARQRemoveRequest(ARQRequest* task);
|
||||||
|
void ARQRemoveOwnerRequest(u32 owner);
|
||||||
|
void ARQFlushQueue(void);
|
||||||
|
void ARQSetChunkSize(u32 size);
|
||||||
u32 ARQGetChunkSize(void);
|
u32 ARQGetChunkSize(void);
|
||||||
|
BOOL ARQCheckInit(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,342 @@
|
||||||
|
#include "musyx/musyx_priv.h"
|
||||||
|
#include <dolphin/ar.h>
|
||||||
|
#include <dolphin/arq.h>
|
||||||
|
#include <dolphin/os.h>
|
||||||
|
|
||||||
|
typedef struct ARAMTransferJob {
|
||||||
|
// total size: 0x28
|
||||||
|
ARQRequest arq; // offset 0x0, size 0x20
|
||||||
|
void (*callback)(unsigned long); // offset 0x20, size 0x4
|
||||||
|
unsigned long user; // offset 0x24, size 0x4
|
||||||
|
} ARAMTransferJob;
|
||||||
|
|
||||||
|
typedef struct ARAMTransferQueue {
|
||||||
|
// total size: 0x284
|
||||||
|
ARAMTransferJob queue[16]; // offset 0x0, size 0x280
|
||||||
|
vu8 write; // offset 0x280, size 0x1
|
||||||
|
vu8 valid; // offset 0x281, size 0x1
|
||||||
|
} ARAMTransferQueue;
|
||||||
|
|
||||||
|
typedef struct STREAM_BUFFER {
|
||||||
|
// total size: 0x10
|
||||||
|
struct STREAM_BUFFER* next; // offset 0x0, size 0x4
|
||||||
|
unsigned long aram; // offset 0x4, size 0x4
|
||||||
|
unsigned long length; // offset 0x8, size 0x4
|
||||||
|
unsigned long allocLength; // offset 0xC, size 0x4
|
||||||
|
} STREAM_BUFFER;
|
||||||
|
|
||||||
|
static unsigned long aramTop; // size: 0x4
|
||||||
|
static unsigned long aramWrite; // size: 0x4
|
||||||
|
static unsigned long aramStream; // size: 0x4
|
||||||
|
static void* (*aramUploadCallback)(unsigned long, unsigned long); // size: 0x4
|
||||||
|
static unsigned long aramUploadChunkSize; // size: 0x4
|
||||||
|
|
||||||
|
static ARAMTransferQueue aramQueueLo;
|
||||||
|
static ARAMTransferQueue aramQueueHi;
|
||||||
|
|
||||||
|
static STREAM_BUFFER aramStreamBuffers[64];
|
||||||
|
static STREAM_BUFFER* aramUsedStreamBuffers;
|
||||||
|
static STREAM_BUFFER* aramFreeStreamBuffers;
|
||||||
|
static STREAM_BUFFER* aramIdleStreamBuffers;
|
||||||
|
|
||||||
|
static void InitStreamBuffers();
|
||||||
|
|
||||||
|
static void aramQueueInit() {
|
||||||
|
aramQueueLo.write = aramQueueLo.valid = 0;
|
||||||
|
aramQueueHi.write = aramQueueHi.valid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aramQueueCallback(unsigned long ptr) {
|
||||||
|
u32 i; // r31
|
||||||
|
ARQRequest* arq; // r29
|
||||||
|
ARAMTransferQueue* aramQueue; // r30
|
||||||
|
|
||||||
|
arq = (ARQRequest*)ptr;
|
||||||
|
if (arq->priority == 1) {
|
||||||
|
aramQueue = &aramQueueHi;
|
||||||
|
} else {
|
||||||
|
aramQueue = &aramQueueLo;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 16; ++i) {
|
||||||
|
if (arq == &aramQueue->queue[i].arq && aramQueue->queue[i].callback) {
|
||||||
|
aramQueue->queue[i].callback(aramQueue->queue[i].user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
--aramQueue->valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void aramUploadData(void* mram, unsigned long aram, unsigned long len, unsigned long highPrio,
|
||||||
|
void (*callback)(unsigned long), unsigned long user) {
|
||||||
|
ARAMTransferQueue* aramQueue; // r31
|
||||||
|
int old; // r30
|
||||||
|
|
||||||
|
aramQueue = highPrio != 0 ? &aramQueueHi : &aramQueueLo;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
old = OSDisableInterrupts();
|
||||||
|
if (aramQueue->valid < 16) {
|
||||||
|
aramQueue->queue[aramQueue->write].arq.owner = 42;
|
||||||
|
aramQueue->queue[aramQueue->write].arq.type = 0;
|
||||||
|
aramQueue->queue[aramQueue->write].arq.priority = highPrio != 0 ? 1 : 0;
|
||||||
|
aramQueue->queue[aramQueue->write].arq.source = (u32)mram;
|
||||||
|
aramQueue->queue[aramQueue->write].arq.dest = aram;
|
||||||
|
aramQueue->queue[aramQueue->write].arq.length = len;
|
||||||
|
aramQueue->queue[aramQueue->write].arq.callback = aramQueueCallback;
|
||||||
|
aramQueue->queue[aramQueue->write].callback = callback;
|
||||||
|
aramQueue->queue[aramQueue->write].user = user;
|
||||||
|
ARQPostRequest(&aramQueue->queue[aramQueue->write].arq,
|
||||||
|
aramQueue->queue[aramQueue->write].arq.owner,
|
||||||
|
aramQueue->queue[aramQueue->write].arq.type,
|
||||||
|
aramQueue->queue[aramQueue->write].arq.priority,
|
||||||
|
aramQueue->queue[aramQueue->write].arq.source,
|
||||||
|
aramQueue->queue[aramQueue->write].arq.dest,
|
||||||
|
aramQueue->queue[aramQueue->write].arq.length,
|
||||||
|
aramQueue->queue[aramQueue->write].arq.callback);
|
||||||
|
++aramQueue->valid;
|
||||||
|
aramQueue->write = (aramQueue->write + 1) % 16;
|
||||||
|
OSRestoreInterrupts(old);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OSRestoreInterrupts(old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void aramSyncTransferQueue() {
|
||||||
|
while (aramQueueLo.valid != 0) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void aramInit(unsigned long length) {
|
||||||
|
signed short* tmpMem; // r30
|
||||||
|
unsigned long i; // r29
|
||||||
|
unsigned long aramBase; // r28
|
||||||
|
#line 173
|
||||||
|
MUSY_ASSERT_MSG(length > sizeof(s16) * 640, "ARAM size is too small");
|
||||||
|
|
||||||
|
aramBase = ARGetBaseAddress();
|
||||||
|
|
||||||
|
tmpMem = (s16*)salMalloc(sizeof(s16) * 640);
|
||||||
|
#line 182
|
||||||
|
MUSY_ASSERT_MSG(tmpMem != NULL, "Could not allocate temporary storage");
|
||||||
|
|
||||||
|
for (i = 0; i < 640; ++i) {
|
||||||
|
tmpMem[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DCFlushRange(tmpMem, sizeof(s16) * 640);
|
||||||
|
aramQueueInit();
|
||||||
|
aramUploadData(tmpMem, aramBase, sizeof(s16) * 640, 0, NULL, 0);
|
||||||
|
aramSyncTransferQueue();
|
||||||
|
salFree(tmpMem);
|
||||||
|
aramTop = aramBase + length;
|
||||||
|
if (aramTop > ARGetSize()) {
|
||||||
|
aramTop = ARGetSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
aramWrite = aramBase + sizeof(s16) * 640;
|
||||||
|
aramUploadCallback = NULL;
|
||||||
|
InitStreamBuffers();
|
||||||
|
#if _DEBUG
|
||||||
|
OSReport("MusyX ARAM handler initialized\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void aramExit() {}
|
||||||
|
|
||||||
|
unsigned long aramGetZeroBuffer() { return ARGetBaseAddress(); }
|
||||||
|
|
||||||
|
void aramSetUploadCallback(void* (*callback)(unsigned long, unsigned long),
|
||||||
|
unsigned long chunckSize) {
|
||||||
|
unsigned long acs; // r30
|
||||||
|
|
||||||
|
if (callback != NULL) {
|
||||||
|
chunckSize = (chunckSize + 31) & ~31;
|
||||||
|
acs = ARQGetChunkSize();
|
||||||
|
aramUploadChunkSize = chunckSize < acs ? acs : chunckSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
aramUploadCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* aramStoreData(void* src, unsigned long len) {
|
||||||
|
unsigned long addr; // r26
|
||||||
|
void* buffer; // r27
|
||||||
|
unsigned long blkSize; // r30
|
||||||
|
len = (len + 31) & ~31;
|
||||||
|
#line 266
|
||||||
|
MUSY_ASSERT_MSG(aramWrite + len <= aramStream, "Data will not fit in remaining ARAM space");
|
||||||
|
addr = aramWrite;
|
||||||
|
if (aramUploadCallback == NULL) {
|
||||||
|
#line 276
|
||||||
|
MUSY_ASSERT_MSG(!((u32)src & 31), "MRAM address is not aligned properly");
|
||||||
|
DCFlushRange(src, len);
|
||||||
|
aramUploadData(src, aramWrite, len, 0, NULL, 0);
|
||||||
|
aramWrite += len;
|
||||||
|
return (void*)addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (len != 0) {
|
||||||
|
blkSize = len >= aramUploadChunkSize ? aramUploadChunkSize : len;
|
||||||
|
buffer = (void*)aramUploadCallback((u32)src, blkSize);
|
||||||
|
#line 297
|
||||||
|
MUSY_ASSERT_MSG(!((u32)buffer & 31), "MRAM address is not aligned properly");
|
||||||
|
DCFlushRange(buffer, blkSize);
|
||||||
|
aramUploadData(buffer, aramWrite, blkSize, 0, NULL, 0);
|
||||||
|
len -= blkSize;
|
||||||
|
aramWrite += blkSize;
|
||||||
|
src = (void*)((u32)src + blkSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void*)addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void aramRemoveData(void* aram, unsigned long len) {
|
||||||
|
len = (len + 31) & ~31;
|
||||||
|
aramWrite -= len;
|
||||||
|
#line 328
|
||||||
|
MUSY_ASSERT_MSG((u32)aram == aramWrite,
|
||||||
|
"Current ARAM address does not match originally allocated one");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InitStreamBuffers() {
|
||||||
|
unsigned long i; // r31
|
||||||
|
aramUsedStreamBuffers = NULL;
|
||||||
|
aramFreeStreamBuffers = NULL;
|
||||||
|
aramIdleStreamBuffers = aramStreamBuffers;
|
||||||
|
for (i = 1; i < 64; ++i) {
|
||||||
|
aramStreamBuffers[i - 1].next = &aramStreamBuffers[i];
|
||||||
|
}
|
||||||
|
aramStreamBuffers[i - 1].next = NULL;
|
||||||
|
aramStream = aramTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char aramAllocateStreamBuffer(unsigned long len) {
|
||||||
|
STREAM_BUFFER* sb; // r30
|
||||||
|
STREAM_BUFFER* oSb; // r31
|
||||||
|
STREAM_BUFFER* lastSb; // r28
|
||||||
|
u32 minLen; // r27
|
||||||
|
|
||||||
|
len = (len + 31) & ~31;
|
||||||
|
lastSb = oSb = NULL;
|
||||||
|
minLen = -1;
|
||||||
|
|
||||||
|
for (sb = aramFreeStreamBuffers; sb != NULL; sb = sb->next) {
|
||||||
|
if (sb->allocLength == len) {
|
||||||
|
oSb = sb;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sb->allocLength > len && minLen > sb->allocLength) {
|
||||||
|
oSb = sb;
|
||||||
|
minLen = sb->allocLength;
|
||||||
|
}
|
||||||
|
lastSb = sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oSb == NULL) {
|
||||||
|
if (aramIdleStreamBuffers != NULL && aramStream - len >= aramWrite) {
|
||||||
|
oSb = aramIdleStreamBuffers;
|
||||||
|
aramIdleStreamBuffers = oSb->next;
|
||||||
|
oSb->allocLength = len;
|
||||||
|
oSb->length = len;
|
||||||
|
aramStream -= len;
|
||||||
|
oSb->aram = aramStream;
|
||||||
|
oSb->next = aramUsedStreamBuffers;
|
||||||
|
aramUsedStreamBuffers = oSb;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (lastSb != NULL) {
|
||||||
|
lastSb->next = oSb->next;
|
||||||
|
} else {
|
||||||
|
aramFreeStreamBuffers = oSb->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
oSb->length = len;
|
||||||
|
oSb->next = aramUsedStreamBuffers;
|
||||||
|
aramUsedStreamBuffers = oSb;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oSb == NULL) {
|
||||||
|
#if _DEBUG
|
||||||
|
OSReport("No stream buffer slots available or ARAM.\n\n");
|
||||||
|
#endif
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (oSb - aramStreamBuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long aramGetStreamBufferAddress(unsigned char id, unsigned long* len) {
|
||||||
|
#line 467
|
||||||
|
MUSY_ASSERT_MSG(id != 0xFF, "Stream buffer ID is invalid");
|
||||||
|
|
||||||
|
if (len != NULL) {
|
||||||
|
*len = aramStreamBuffers[id].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return aramStreamBuffers[id].aram;
|
||||||
|
}
|
||||||
|
|
||||||
|
void aramFreeStreamBuffer(unsigned char id) {
|
||||||
|
struct STREAM_BUFFER* fSb; // r30
|
||||||
|
struct STREAM_BUFFER* sb; // r31
|
||||||
|
struct STREAM_BUFFER* lastSb; // r29
|
||||||
|
struct STREAM_BUFFER* nextSb; // r27
|
||||||
|
unsigned long minAddr; // r28
|
||||||
|
|
||||||
|
MUSY_ASSERT_MSG(id != 0xFF, "Stream buffer ID is invalid");
|
||||||
|
fSb = &aramStreamBuffers[id];
|
||||||
|
lastSb = NULL;
|
||||||
|
sb = aramUsedStreamBuffers;
|
||||||
|
|
||||||
|
while (sb != NULL) {
|
||||||
|
if (sb == fSb) {
|
||||||
|
if (lastSb != NULL) {
|
||||||
|
lastSb->next = fSb->next;
|
||||||
|
} else {
|
||||||
|
aramUsedStreamBuffers = fSb->next;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
lastSb = sb;
|
||||||
|
sb = sb->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fSb->aram == aramStream) {
|
||||||
|
fSb->next = aramIdleStreamBuffers;
|
||||||
|
aramIdleStreamBuffers = fSb;
|
||||||
|
minAddr = -1;
|
||||||
|
sb = aramUsedStreamBuffers;
|
||||||
|
while (sb != NULL) {
|
||||||
|
if (sb->aram <= minAddr) {
|
||||||
|
minAddr = sb->aram;
|
||||||
|
}
|
||||||
|
sb = sb->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastSb = NULL;
|
||||||
|
sb = aramFreeStreamBuffers;
|
||||||
|
while (sb != NULL) {
|
||||||
|
nextSb = sb->next;
|
||||||
|
if (sb->aram < minAddr) {
|
||||||
|
if (lastSb != NULL) {
|
||||||
|
lastSb->next = sb->next;
|
||||||
|
} else {
|
||||||
|
aramFreeStreamBuffers = sb->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb->next = aramIdleStreamBuffers;
|
||||||
|
aramIdleStreamBuffers = sb;
|
||||||
|
}
|
||||||
|
sb = nextSb;
|
||||||
|
}
|
||||||
|
|
||||||
|
aramStream = minAddr != -1 ? minAddr : aramTop;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fSb->next = aramFreeStreamBuffers;
|
||||||
|
aramFreeStreamBuffers = fSb;
|
||||||
|
}
|
Loading…
Reference in New Issue