marioparty4/src/dolphin/ai.c

362 lines
8 KiB
C

#include "dolphin/ai.h"
#include "dolphin/hw_regs.h"
#include "dolphin/os.h"
const char *__AIVersion = "<< Dolphin SDK - AI\trelease build: Sep 5 2002 05:34:25 (0x2301) >>";
static AISCallback __AIS_Callback = NULL;
static AIDCallback __AID_Callback = NULL;
static u8 *__CallbackStack;
static u8 *__OldStack;
static volatile s32 __AI_init_flag = FALSE;
static volatile s32 __AID_Active = FALSE;
static OSTime bound_32KHz;
static OSTime bound_48KHz;
static OSTime min_wait;
static OSTime max_wait;
static OSTime buffer;
void __AISHandler(s16 interrupt, OSContext *context);
void __AIDHandler(s16 interrupt, OSContext *context);
void __AICallbackStackSwitch(register AIDCallback cb);
void __AI_SRC_INIT(void);
AIDCallback AIRegisterDMACallback(AIDCallback callback)
{
s32 oldInts;
AIDCallback ret;
ret = __AID_Callback;
oldInts = OSDisableInterrupts();
__AID_Callback = callback;
OSRestoreInterrupts(oldInts);
return ret;
}
void AIInitDMA(u32 addr, u32 length)
{
s32 oldInts;
oldInts = OSDisableInterrupts();
__DSPRegs[24] = (u16)((__DSPRegs[24] & ~0x3FF) | (addr >> 16));
__DSPRegs[25] = (u16)((__DSPRegs[25] & ~0xFFE0) | (0xffff & addr));
__DSPRegs[27] = (u16)((__DSPRegs[27] & ~0x7FFF) | (u16)((length >> 5) & 0xFFFF));
OSRestoreInterrupts(oldInts);
}
void AIStartDMA()
{
__DSPRegs[27] |= 0x8000;
}
void AIStopDMA(void)
{
__DSPRegs[27] &= ~0x8000;
}
u32 AIGetDMAStartAddr(void)
{
return (u32)((__DSPRegs[24] & 0x03ff) << 16) | (__DSPRegs[25] & 0xffe0);
}
AISCallback AIRegisterStreamCallback(AISCallback callback)
{
AISCallback ret;
s32 oldInts;
ret = __AIS_Callback;
oldInts = OSDisableInterrupts();
__AIS_Callback = callback;
OSRestoreInterrupts(oldInts);
return ret;
}
void AIResetStreamSampleCount(void)
{
__AIRegs[0] = (__AIRegs[0] & ~0x20) | 0x20;
}
void AISetStreamTrigger(u32 trigger)
{
__AIRegs[3] = trigger;
}
void AISetStreamPlayState(u32 state)
{
s32 oldInts;
u8 volRight;
u8 volLeft;
if (state == AIGetStreamPlayState()) {
return;
}
if ((AIGetStreamSampleRate() == 0U) && (state == 1)) {
volRight = AIGetStreamVolRight();
volLeft = AIGetStreamVolLeft();
AISetStreamVolRight(0);
AISetStreamVolLeft(0);
oldInts = OSDisableInterrupts();
__AI_SRC_INIT();
__AIRegs[0] = (__AIRegs[0] & ~0x20) | 0x20;
__AIRegs[0] = (__AIRegs[0] & ~1) | 1;
OSRestoreInterrupts(oldInts);
AISetStreamVolLeft(volRight);
AISetStreamVolRight(volLeft);
}
else {
__AIRegs[0] = (__AIRegs[0] & ~1) | state;
}
}
u32 AIGetStreamPlayState()
{
return __AIRegs[0] & 1;
}
void AISetDSPSampleRate(u32 rate)
{
u32 state;
s32 oldInts;
u8 left;
u8 right;
u32 sampleRate;
if (rate == AIGetDSPSampleRate()) {
return;
}
__AIRegs[0] &= ~0x40;
if (rate == 0) {
left = AIGetStreamVolLeft();
right = AIGetStreamVolRight();
state = AIGetStreamPlayState();
sampleRate = AIGetStreamSampleRate();
AISetStreamVolLeft(0);
AISetStreamVolRight(0);
oldInts = OSDisableInterrupts();
__AI_SRC_INIT();
__AIRegs[0] = (__AIRegs[0] & ~0x20) | 0x20;
__AIRegs[0] = (__AIRegs[0] & ~2) | (sampleRate * 2);
__AIRegs[0] = (__AIRegs[0] & ~1) | state;
__AIRegs[0] |= 0x40;
OSRestoreInterrupts(oldInts);
AISetStreamVolLeft(left);
AISetStreamVolRight(right);
}
}
u32 AIGetDSPSampleRate()
{
return ((__AIRegs[0] >> 6) & 1) ^ 1;
}
void __AI_set_stream_sample_rate(u32 rate)
{
s32 oldInts;
s32 state;
u8 left;
u8 right;
s32 temp_r26;
if (rate == AIGetStreamSampleRate()) {
return;
}
state = AIGetStreamPlayState();
left = AIGetStreamVolLeft();
right = AIGetStreamVolRight();
AISetStreamVolRight(0);
AISetStreamVolLeft(0);
temp_r26 = __AIRegs[0] & 0x40;
__AIRegs[0] &= ~0x40;
oldInts = OSDisableInterrupts();
__AI_SRC_INIT();
__AIRegs[0] |= temp_r26;
__AIRegs[0] = (__AIRegs[0] & ~0x20) | 0x20;
__AIRegs[0] = (__AIRegs[0] & ~2) | (rate * 2);
OSRestoreInterrupts(oldInts);
AISetStreamPlayState(state);
AISetStreamVolLeft(left);
AISetStreamVolRight(right);
}
u32 AIGetStreamSampleRate()
{
return (__AIRegs[0] >> 1) & 1;
}
void AISetStreamVolLeft(u8 volume)
{
__AIRegs[1] = (__AIRegs[1] & ~0xFF) | (volume & 0xFF);
}
u8 AIGetStreamVolLeft()
{
return __AIRegs[1];
}
void AISetStreamVolRight(u8 volume)
{
__AIRegs[1] = (__AIRegs[1] & ~0xFF00) | ((volume & 0xFF) << 8);
}
u8 AIGetStreamVolRight()
{
return __AIRegs[1] >> 8;
}
void AIInit(u8 *stack)
{
if (__AI_init_flag == TRUE) {
return;
}
bound_32KHz = OSNanosecondsToTicks(31524);
bound_48KHz = OSNanosecondsToTicks(42024);
min_wait = OSNanosecondsToTicks(42000);
max_wait = OSNanosecondsToTicks(63000);
buffer = OSNanosecondsToTicks(3000);
AISetStreamVolRight(0);
AISetStreamVolLeft(0);
AISetStreamTrigger(0);
AIResetStreamSampleCount();
__AI_set_stream_sample_rate(1);
AISetDSPSampleRate(0);
__AIS_Callback = 0;
__AID_Callback = 0;
__CallbackStack = stack;
__OSSetInterruptHandler(5, __AIDHandler);
__OSUnmaskInterrupts(0x04000000);
__OSSetInterruptHandler(8, __AISHandler);
__OSUnmaskInterrupts(0x800000);
__AI_init_flag = TRUE;
}
void __AISHandler(s16 interrupt, OSContext *context)
{
OSContext tmpContext;
__AIRegs[0] |= 8;
OSClearContext(&tmpContext);
OSSetCurrentContext(&tmpContext);
if (__AIS_Callback != NULL) {
__AIS_Callback(__AIRegs[2]);
}
OSClearContext(&tmpContext);
OSSetCurrentContext(context);
}
void __AIDHandler(s16 interrupt, OSContext *context)
{
OSContext tempContext;
u16 temp = __DSPRegs[5];
__DSPRegs[5] = (temp & ~0xA0) | 8;
OSClearContext(&tempContext);
OSSetCurrentContext(&tempContext);
if (__AID_Callback) {
if (__CallbackStack) {
__AICallbackStackSwitch(__AID_Callback);
}
else {
__AID_Callback();
}
}
OSClearContext(&tempContext);
OSSetCurrentContext(context);
}
// clang-format off
asm void __AICallbackStackSwitch(register AIDCallback cb) {
// Allocate stack frame
fralloc
// Store current stack
lis r5, __OldStack@ha
addi r5, r5, __OldStack@l
stw r1, 0(r5)
// Load stack for callback
lis r5, __CallbackStack@ha
addi r5, r5, __CallbackStack@l
lwz r1,0(r5)
// Move stack down 8 bytes
subi r1, r1, 8
// Call callback
mtlr cb
blrl
// Restore old stack
lis r5, __OldStack @ha
addi r5, r5, __OldStack@l
lwz r1,0(r5)
// Free stack frame
frfree
blr
}
// clang-format on
void __AI_SRC_INIT(void)
{
OSTime rise32 = 0;
OSTime rise48 = 0;
OSTime diff = 0;
OSTime unused1 = 0;
OSTime temp = 0;
u32 temp0 = 0;
u32 temp1 = 0;
u32 done = 0;
u32 walking = 0;
u32 unused2 = 0;
u32 initCnt = 0;
walking = 0;
initCnt = 0;
temp = 0;
while (!done) {
__AIRegs[0] = (__AIRegs[0] & ~0x20) | 0x20;
__AIRegs[0] &= ~2;
__AIRegs[0] = (__AIRegs[0] & ~1) | 1;
temp0 = __AIRegs[2];
while (temp0 == __AIRegs[2])
;
rise32 = OSGetTime();
__AIRegs[0] = (__AIRegs[0] & ~2) | 2;
__AIRegs[0] = (__AIRegs[0] & ~1) | 1;
temp1 = __AIRegs[2];
while (temp1 == __AIRegs[2])
;
rise48 = OSGetTime();
diff = rise48 - rise32;
__AIRegs[0] &= ~2;
__AIRegs[0] &= ~1;
if (diff < (bound_32KHz - buffer)) {
temp = min_wait;
done = 1;
++initCnt;
}
else if (diff >= (bound_32KHz + buffer) && diff < (bound_48KHz - buffer)) {
temp = max_wait;
done = 1;
++initCnt;
}
else {
done = 0;
walking = 1;
++initCnt;
}
}
while ((rise48 + temp) > OSGetTime())
;
}