mirror of
https://github.com/emu-russia/pureikyubu.git
synced 2025-04-02 10:42:15 -04:00
- DVD controller Matsushita MN102-series user manual - Some Macronix ETH / DSP manuals, similar to GC - YAGCD - Duddie DSP Infos - tmbinc's article on GC DVD protection - Nintendo US patents as PDFs
728 lines
16 KiB
Text
728 lines
16 KiB
Text
volatile void *__cpReg = (u16 *)0xCC000000; // 16-bit only
|
|
volatile void *__piReg = (u32 *)0xCC003000; // 32-bit only
|
|
|
|
typedef struct __GXFifoObj
|
|
{
|
|
u32 base;
|
|
u32 top;
|
|
u32 size;
|
|
u32 hiWatermark;
|
|
u32 loWatermark;
|
|
void *rdPtr;
|
|
void *wrPtr;
|
|
u32 count;
|
|
u8 bind_cpu,
|
|
bind_gp;
|
|
} GXFifoObj;
|
|
|
|
GXFifoObj *CPUFifo, *GPFifo;
|
|
GXBool CPGPLinked;
|
|
|
|
static GXBreakPtCallback BreakPointCB;
|
|
static void * __GXCurrentBP;
|
|
|
|
static BOOL GXOverflowSuspendInProgress;
|
|
static u32 __GXOverflowCount;
|
|
|
|
static BOOL IsWGPipeRedirected;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void GXOverflowHandler(OSContext *context)
|
|
{
|
|
if(__gxVerif[4] > 1)
|
|
{
|
|
OSReport("[GXOverflowHandler]");
|
|
}
|
|
|
|
ASSERT(!GXOverflowSuspendInProgress);
|
|
|
|
__GXOverflowCount++;
|
|
|
|
__GXWriteFifoIntEnable(FALSE, TRUE);
|
|
__GXWriteFifoIntReset(TRUE, FALSE);
|
|
|
|
GXOverflowSuspendInProgress = TRUE;
|
|
|
|
if(__gxVerif[4] > 1)
|
|
{
|
|
OSReport("[GXOverflowHandler Sleeping]");
|
|
}
|
|
|
|
OSSuspendThread(__GXCurrentThread);
|
|
}
|
|
|
|
void GXUnderflowHandler(OSContext *context)
|
|
{
|
|
if(__gxVerif[4] > 1)
|
|
{
|
|
OSReport("[GXUnderflowHandler]");
|
|
}
|
|
|
|
ASSERT(GXOverflowSuspendInProgress);
|
|
|
|
OSResumeThread(__GXCurrentThread);
|
|
GXOverflowSuspendInProgress = FALSE;
|
|
|
|
__GXWriteFifoIntReset(TRUE, TRUE);
|
|
__GXWriteFifoIntEnable(TRUE, FALSE);
|
|
}
|
|
|
|
void GXBreakPointHandler(OSContext *context)
|
|
{
|
|
OSContext exceptionContext;
|
|
|
|
// disable breakpoint checking
|
|
gx.cpEnable &= ~0x0020;
|
|
__cpReg[0x02] = gx.cpEnable;
|
|
|
|
// execute breakpoint callback
|
|
if(BreakPointCB)
|
|
{
|
|
OSClearContext(&exceptionContext);
|
|
OSSetCurrentContext(exceptionContext);
|
|
BreakPointCB();
|
|
}
|
|
|
|
OSClearContext(&exceptionContext);
|
|
OSSetCurrentContext(context);
|
|
}
|
|
|
|
void GXCPInterruptHandler(__OSInterrupt interrupt, OSContext *context)
|
|
{
|
|
gx.cpStatus = __cpReg[0x00];
|
|
|
|
// low watermark interrupt
|
|
if((gx.cpEnable >> 3) & 1) // low watermark enabled ?
|
|
{
|
|
if((gx.cpStatus >> 1) & 1) // interrupt active ?
|
|
{
|
|
GXUnderflowHandler();
|
|
}
|
|
}
|
|
|
|
// high watermark interrupt // high watermark enabled ?
|
|
if((gx.cpEnable >> 2) & 1)
|
|
{
|
|
if((gx.cpStatus >> 0) & 1) // interrupt active ?
|
|
{
|
|
GXOverflowHandler();
|
|
}
|
|
}
|
|
|
|
// break interrupt
|
|
if((gx.cpEnable >> 5) & 1) // breakpoint enabled ?
|
|
{
|
|
if((gx.cpStatus >> 4) & 1) // interrupt active ?
|
|
{
|
|
GXBreakPointHandler();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void GXInitFifoBase(GXFifoObj *fifo, void *base, u32 size)
|
|
{
|
|
if(fifo == CPUFifo)
|
|
{
|
|
OSPanic("GXInitFifoBase: fifo is attached to CPU");
|
|
}
|
|
|
|
if(fifo == GPFifo)
|
|
{
|
|
OSPanic("GXInitFifoBase: fifo is attached to GP");
|
|
}
|
|
|
|
if(base & 0x1f)
|
|
{
|
|
OSPanic("GXInitFifoBase: base must be 32B aligned");
|
|
}
|
|
|
|
if(base == NULL)
|
|
{
|
|
OSPanic("GXInitFifoBase: base pointer is NULL");
|
|
}
|
|
|
|
if(size & 0x1f)
|
|
{
|
|
OSPanic("GXInitFifoBase: size must be 32B aligned");
|
|
}
|
|
|
|
if(size < GX_FIFO_MINSIZE)
|
|
{
|
|
OSPanic("GXInitFifoBase: fifo is not large enough");
|
|
}
|
|
|
|
fifo->base = base;
|
|
fifo->top = base + size - 4;
|
|
fifo->size = size;
|
|
fifo->count = 0;
|
|
|
|
GXInitFifoLimits(fifo, size - GX_FIFO_HI_WATERMARK_BUFFER, (size / 2) & ~0x1f);
|
|
GXInitFifoPtrs(fifo, base, base);
|
|
}
|
|
|
|
void GXInitFifoLimits(GXFifoObj *fifo, u32 hiWaterMark, u32 loWaterMark)
|
|
{
|
|
if(fifo == GPFifo)
|
|
{
|
|
OSPanic("GXInitFifoLimits: fifo is attached to GP");
|
|
}
|
|
|
|
if(hiWaterMark & 0x1f)
|
|
{
|
|
OSPanic("GXInitFifoLimits: hiWatermark not 32B aligned");
|
|
}
|
|
|
|
if(loWaterMark & 0x1f)
|
|
{
|
|
OSPanic("GXInitFifoLimits: loWatermark not 32B aligned");
|
|
}
|
|
|
|
if((base - top) <= hiWaterMark)
|
|
{
|
|
OSPanic("GXInitFifoLimits: hiWatermark too large");
|
|
}
|
|
|
|
if(hiWaterMark < loWaterMark)
|
|
{
|
|
OSPanic("GXInitFifoLimits: hiWatermark below lo watermark");
|
|
}
|
|
|
|
fifo->hiWatermark = hiWaterMark;
|
|
fifo->loWatermark = loWaterMark;
|
|
}
|
|
|
|
void GXInitFifoPtrs(GXFifoObj *fifo, void *readPtr, void *writePtr)
|
|
{
|
|
BOOL level;
|
|
|
|
if(fifo == CPUFifo)
|
|
{
|
|
OSPanic("GXInitFifoPtrs: fifo is attached to CPU");
|
|
}
|
|
|
|
if(fifo == GPFifo)
|
|
{
|
|
OSPanic("GXInitFifoPtrs: fifo is attached to GP");
|
|
}
|
|
|
|
if(readPtr & 0x1f)
|
|
{
|
|
OSPanic("GXInitFifoPtrs: readPtr not 32B aligned");
|
|
}
|
|
|
|
if(writePtr & 0x1f)
|
|
{
|
|
OSPanic("GXInitFifoPtrs: writePtr not 32B aligned");
|
|
}
|
|
|
|
if((readPtr < fifo->base) || (readPtr >= fifo->top))
|
|
{
|
|
OSPanic("GXInitFifoPtrs: readPtr not in fifo range");
|
|
}
|
|
|
|
if((writePtr < fifo->base) || (writePtr >= fifo->top))
|
|
{
|
|
OSPanic("GXInitFifoPtrs: writePtr not in fifo range");
|
|
}
|
|
|
|
level = OSDisableInterrupts();
|
|
|
|
fifo->rdPtr = readPtr;
|
|
fifo->wrPtr = writePtr;
|
|
if((fifo->count = (readPtr - writePtr)) < 0)
|
|
{
|
|
fifo->count += fifo->size;
|
|
}
|
|
|
|
OSRestoreInterrupts(level);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void GXSetCPUFifo(GXFifoObj *fifo)
|
|
{
|
|
BOOL enabled = OSDisableInterrupts();
|
|
|
|
CPUFifo = fifo;
|
|
|
|
// immediate mode
|
|
if(CPUFifo == GPFifo)
|
|
{
|
|
__piReg[0x0C] = fifo->base;
|
|
__piReg[0x10] = fifo->top;
|
|
__piReg[0x14] = fifo->wrPtr;
|
|
|
|
CPGPLinked = 1;
|
|
__GXWriteFifoIntReset(TRUE, TRUE);
|
|
__GXWriteFifoIntEnable(TRUE, FALSE);
|
|
__GXFifoLink(TRUE);
|
|
}
|
|
// multi-buffer mode
|
|
else
|
|
{
|
|
if(CPGPLinked)
|
|
{
|
|
__GXFifoLink(FALSE);
|
|
CPGPLinked = 0;
|
|
}
|
|
|
|
__GXWriteFifoIntEnable(FALSE, FALSE);
|
|
|
|
__piReg[0x0C] = fifo->base;
|
|
__piReg[0x10] = fifo->top;
|
|
__piReg[0x14] = fifo->wrPtr;
|
|
}
|
|
|
|
PPC_SYNC();
|
|
OSRestoreInterrupts(enabled);
|
|
}
|
|
|
|
void GXSetGPFifo(GXFifoObj *fifo)
|
|
{
|
|
BOOL enabled = OSDisableInterrupts();
|
|
|
|
__GXFifoReadDisable();
|
|
__GXWriteFifoIntEnable(FALSE, FALSE);
|
|
|
|
GPFifo = fifo;
|
|
|
|
__cpReg[0x20] = (u16)fifo->base;
|
|
__cpReg[0x22] = (u16)(fifo->base >> 16);
|
|
|
|
__cpReg[0x24] = (u16)fifo->top;
|
|
__cpReg[0x26] = (u16)(fifo->top >> 16);
|
|
|
|
__cpReg[0x30] = (u16)fifo->count;
|
|
__cpReg[0x32] = (u16)(fifo->count >> 16);
|
|
|
|
__cpReg[0x34] = (u16)fifo->wrPtr;
|
|
__cpReg[0x36] = (u16)(fifo->wrPtr >> 16);
|
|
|
|
__cpReg[0x38] = (u16)fifo->rdPtr;
|
|
__cpReg[0x3A] = (u16)(fifo->rdPtr >> 16);
|
|
|
|
__cpReg[0x28] = (u16)fifo->hiWatermark;
|
|
__cpReg[0x2A] = (u16)(fifo->hiWatermark >> 16);
|
|
|
|
__cpReg[0x2C] = (u16)fifo->loWatermark;
|
|
__cpReg[0x2E] = (u16)(fifo->loWatermark >> 16);
|
|
|
|
PPC_SYNC();
|
|
|
|
if(CPUFifo == GPFifo)
|
|
{
|
|
CPGPLinked = 1;
|
|
__GXWriteFifoIntEnable(TRUE, FALSE);
|
|
__GXFifoLink(TRUE);
|
|
}
|
|
else
|
|
{
|
|
CPGPLinked = 0;
|
|
__GXWriteFifoIntEnable(FALSE, FALSE);
|
|
__GXFifoLink(FALSE);
|
|
__GXWriteFifoIntReset(TRUE, TRUE);
|
|
}
|
|
|
|
__GXFifoReadEnable();
|
|
|
|
OSRestoreInterrupts(enabled);
|
|
}
|
|
|
|
void GXSaveCPUFifo(GXFifoObj *fifo)
|
|
{
|
|
if(CPUFifo != fifo)
|
|
{
|
|
OSPanic("GXSaveCPUFifo: fifo is not attached to CPU");
|
|
}
|
|
|
|
__GXSaveCPUFifoAux(fifo);
|
|
}
|
|
|
|
static void __GXSaveCPUFifoAux(GXFifoObj *fifo)
|
|
{
|
|
BOOL enabled = OSDisableInterrupts();
|
|
|
|
GXFlush();
|
|
|
|
fifo->base = OSPhysicalToCached(__piReg[0x0C]);
|
|
fifo->top = OSPhysicalToCached(__piReg[0x10]);
|
|
fifo->wrPtr= OSPhysicalToCached(__piReg[0x14]);
|
|
|
|
if(CPGPLinked)
|
|
{
|
|
// save also GP fifo
|
|
fifo->rdPtr = OSPhysicalToCached((__cpReg[0x3A] << 16) | __cpReg[0x38]);
|
|
fifo->count = (__cpReg[0x32] << 16) | __cpReg[0x30];
|
|
}
|
|
else
|
|
{
|
|
// dont understand :( adjust fifo ?
|
|
fifo->wrPtr = fifo->rdPtr - fifo->count;
|
|
|
|
if(fifo->wrPtr < 0)
|
|
{
|
|
fifo->wrPtr += fifo->size;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GXSaveGPFifo(GXFifoObj *fifo)
|
|
{
|
|
if(fifo != GPFifo)
|
|
{
|
|
OSPanic("GXSaveGPFifo: fifo is not attached to GP");
|
|
}
|
|
|
|
if((__cpReg[0x00] & 0x0002) == 0)
|
|
{
|
|
OSPanic("GXSaveGPFifo: GP is not idle");
|
|
}
|
|
|
|
fifo->rdPtr = OSPhysicalToCached((__cpReg[0x3A] << 16) | __cpReg[0x38]);
|
|
fifo->count = (__cpReg[0x32] << 16) | __cpReg[0x30];
|
|
}
|
|
|
|
void GXGetGPStatus(
|
|
GXBool *overhi,
|
|
GXBool *underlow,
|
|
GXBool *readIdle,
|
|
GXBool *cmdIdle,
|
|
GXBool *brkpt)
|
|
{
|
|
gx.cpStatus = __cpReg[0x00];
|
|
|
|
*overhi = (gx.cpStatus >> 0) & 1;
|
|
*underlow = (gx.cpStatus >> 1) & 1;
|
|
*readIdle = (gx.cpStatus >> 2) & 1;
|
|
*cmdIdle = (gx.cpStatus >> 3) & 1;
|
|
*brkpt = (gx.cpStatus >> 4) & 1;
|
|
}
|
|
|
|
void GXGetFifoStatus(
|
|
GXFifoObj *fifo,
|
|
GXBool *overhi,
|
|
GXBool *underlow,
|
|
u32 *fifoCount,
|
|
GXBool *cpu_write,
|
|
GXBool *gp_read,
|
|
GXBool *fifowrap)
|
|
{
|
|
...
|
|
}
|
|
|
|
void GXGetFifoPtrs(
|
|
GXFifoObj *fifo,
|
|
void **readPtr,
|
|
void **writePtr)
|
|
{
|
|
if(fifo == CPUFifo)
|
|
{
|
|
fifo->wrPtr = OSPhysicalToCached(__piReg[0x14]);
|
|
}
|
|
|
|
if(fifo == GPFifo)
|
|
{
|
|
fifo->rdPtr = OSPhysicalToCached((__cpReg[0x3A] << 16) | __cpReg[0x38]);
|
|
fifo->count = (__cpReg[0x32] << 16) | __cpReg[0x30];
|
|
}
|
|
else
|
|
{
|
|
fifo->wrPtr = fifo->rdPtr - fifo->count;
|
|
|
|
if(fifo->wrPtr < 0)
|
|
{
|
|
fifo->wrPtr += fifo->size;
|
|
}
|
|
}
|
|
|
|
*readPtr = fifo->rdPtr;
|
|
*writePtr= fifo->wrPtr;
|
|
}
|
|
|
|
void *GXGetFifoBase(GXFifoObj *fifo)
|
|
{
|
|
return fifo->rdPtr;
|
|
}
|
|
|
|
u32 GXGetFifoSize(GXFifoObj *fifo)
|
|
{
|
|
return fifo->size;
|
|
}
|
|
|
|
void GXGetFifoLimits(GXFifoObj *fifo, u32 *hi, u32 *lo)
|
|
{
|
|
*hi = fifo->hiWatermark;
|
|
*lo = fifo->loWatermark;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// breakpoint api
|
|
|
|
GXBreakPtCallback GXSetBreakPtCallback(GXBreakPtCallback cb)
|
|
{
|
|
GXBreakPtCallback oldcb = BreakPointCB;
|
|
BOOL enabled = OSDisableInterrupts();
|
|
|
|
BreakPointCB = cb;
|
|
|
|
OSRestoreInterrupts(enabled);
|
|
return oldcb;
|
|
}
|
|
|
|
void GXEnableBreakPt(void *breakPtr)
|
|
{
|
|
BOOL enabled = OSDisableInterrupts();
|
|
|
|
__GXFifoReadDisable();
|
|
|
|
__cpReg[0x3C] = (u16)breakPtr;
|
|
__cpReg[0x3E] = (u16)((u32)breakPtr >> 16);
|
|
|
|
gx.bpSentNot |= 0x0002; // clear bp int ?
|
|
gx.bpSentNot |= 0x0020;
|
|
__cpReg[2] = gx.bpSentNot;
|
|
|
|
__GXCurrentBP = breakPtr;
|
|
|
|
__GXFifoReadEnable();
|
|
|
|
OSRestoreInterrupts(enabled);
|
|
}
|
|
|
|
void GXDisableBreakPt(void)
|
|
{
|
|
BOOL enabled = OSDisableInterrupts();
|
|
|
|
gx.bpSentNot &= ~0x0022;
|
|
__cpReg[2] = gx.bpSentNot;
|
|
|
|
__GXCurrentBP = 0;
|
|
|
|
OSRestoreInterrupts(enabled);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void __GXFifoInit(void)
|
|
{
|
|
__OSSetInterruptHandler(
|
|
__OS_INTERRUPT_PI_CP,
|
|
GXCPInterruptHandler
|
|
);
|
|
__OSUnmaskInterrupts(OS_INTERRUPTMASK_PI_CP);
|
|
|
|
__GXCurrentThread = OSGetCurrentThread();
|
|
GXOverflowSuspendInProgress = FALSE;
|
|
CPUFifo = NULL;
|
|
GPFifo = NULL;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void __GXFifoReadEnable(void)
|
|
{
|
|
gx.cpEnable |= 0x0001;
|
|
__cpReg[0x02] = gx.cpEnable;
|
|
}
|
|
|
|
void __GXFifoReadDisable(void)
|
|
{
|
|
gx.cpEnable &= ~0x0001;
|
|
__cpReg[0x02] = gx.cpEnable;
|
|
}
|
|
|
|
void __GXFifoLink(u8 en)
|
|
{
|
|
u16 old = gx.cpEnable & ~0x0010;
|
|
gx.cpEnable |= (en << 4);
|
|
__cpReg[0x02] = gx.cpEnable;
|
|
}
|
|
|
|
void __GXWriteFifoIntEnable(BOOL hiWatermarkEn, BOOL loWatermarkEn)
|
|
{
|
|
u16 old = gx.cpEnable & ~0x000C;
|
|
gx.cpEnable |= (hiWatermarkEn << 2);
|
|
gx.cpEnable |= (loWatermarkEn << 3);
|
|
__cpReg[0x02] = gx.cpEnable;
|
|
}
|
|
|
|
void __GXWriteFifoIntReset(BOOL hiWatermarkClr, BOOL loWatermarkClr)
|
|
{
|
|
u16 old = gx.cpClr & ~0x0003;
|
|
gx.cpClr |= (hiWatermarkClr << 0);
|
|
gx.cpClr |= (loWatermarkClr << 1);
|
|
__cpReg[0x04] = gx.cpClr;
|
|
}
|
|
|
|
// for extensive testing of watermark triggers
|
|
void __GXInsaneWatermark(void)
|
|
{
|
|
GXFifoObj *realFifo = GPFifo;
|
|
|
|
// too slow, cough ..
|
|
realFifo->hiWatermark = realFifo->loWatermark + 512;
|
|
|
|
__cpReg[0x28] = (u16)realFifo->hiWatermark;
|
|
__cpReg[0x2A] = (u16)(realFifo->hiWatermark >> 16);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// strange ..
|
|
void __GXCleanGPFifo(void)
|
|
{
|
|
GXFifoObj dummyFifo,
|
|
*gpFifo = GXGetGPFifo(),
|
|
*cpuFifo = GXGetCPUFifo();
|
|
void *base;
|
|
|
|
base = GXGetFifoBase(gpFifo);
|
|
|
|
memset(&dummyFifo, 0, sizeof(GXFifoObj));
|
|
GXInitFifoPtrs(&dummyFifo, base, base);
|
|
|
|
GXSetGPFifo(&dummyFifo);
|
|
if(gpFifo == cpuFifo) GXSetCPUFifo(&dummyFifo);
|
|
|
|
GXInitFifoPtrs(gpFifo, base, base);
|
|
|
|
GXSetGPFifo(gpFifo);
|
|
if(gpFifo == cpuFifo) GXSetCPUFifo(cpuFifo);
|
|
}
|
|
|
|
OSThread *GXSetCurrentGXThread(void)
|
|
{
|
|
BOOL enabled = OSDisableInterrupts();
|
|
OSThread old = __GXCurrentThread;
|
|
|
|
if(GXOverflowSuspendInProgress)
|
|
{
|
|
OSPanic(
|
|
"GXSetCurrentGXThread: Two threads cannot generate"
|
|
"GX commands at the same time!"
|
|
);
|
|
}
|
|
|
|
__GXCurrentThread = OSGetCurrentThread();
|
|
|
|
OSRestoreInterrupts(enabled);
|
|
return old;
|
|
}
|
|
|
|
OSThread *GXGetCurrentGXThread(void)
|
|
{
|
|
return __GXCurrentThread;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
GXFifoObj *GXGetCPUFifo(void)
|
|
{
|
|
return CPUFifo;
|
|
}
|
|
|
|
GXFifoObj *GXGetGPFifo(void)
|
|
{
|
|
return GPFifo;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
u32 GXGetOverflowCount(void)
|
|
{
|
|
return __GXOverflowCount;
|
|
}
|
|
|
|
u32 GXResetOverflowCount(void)
|
|
{
|
|
__GXOverflowCount = 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// write gather pipe redirecting api
|
|
|
|
volatile void * GXRedirectWriteGatherPipe(void *ptr)
|
|
{
|
|
BOOL enabled = OSDisableInterrupts();
|
|
|
|
if(__GXinBegin)
|
|
{
|
|
OSPanic(
|
|
"\'GXRedirectWriteGatherPipe\' is not"
|
|
"allowed between GXBegin/GXEnd"
|
|
);
|
|
}
|
|
|
|
ASSERT(OFFSET(ptr, 32) == 0);
|
|
ASSERT(!IsWGPipeRedirected);
|
|
|
|
IsWGPipeRedirected = TRUE;
|
|
|
|
GXFlush();
|
|
|
|
// wait until pipe is not empty
|
|
while(PCMfwpar() & WPAR_BNE);
|
|
|
|
PPCMtwpar(OSUncachedToPhysical(0xCC008000));
|
|
|
|
if(CPGPLinked)
|
|
{
|
|
__GXFifoLink(0);
|
|
__GXWriteFifoIntEnable(0, 0);
|
|
}
|
|
|
|
CPUFifo->wrPtr = OSPhysicalToCached(__piReg[0x14]);
|
|
|
|
__piReg[0x0C] = 0; // base
|
|
__piReg[0x10] = 0x04000000; // top
|
|
__piReg[0x14] = OSCachedToHardwired(ptr);
|
|
|
|
PPC_SYNC();
|
|
OSRestoreInterrupts(enabled);
|
|
return 0xCC008000;
|
|
}
|
|
|
|
void GXRestoreWriteGatherPipe(void)
|
|
{
|
|
PPCWGPipe wgpipe : 0xCC008000;
|
|
BOOL enabled;
|
|
int i;
|
|
|
|
ASSERT(IsWGPipeRedirected);
|
|
|
|
IsWGPipeRedirected = FALSE;
|
|
|
|
enabled = OSDisableInterrupts();
|
|
|
|
// flush fifo
|
|
for(i=0; i<31; i++)
|
|
{
|
|
wgpipe.u8 = 0;
|
|
}
|
|
|
|
PPCSync();
|
|
|
|
// wait until pipe is not empty
|
|
while(PCMfwpar() & WPAR_BNE);
|
|
|
|
PPCMtwpar(OSUncachedToPhysical(0xCC008000));
|
|
|
|
__piReg[0x0C] = CPUFifo->base;
|
|
__piReg[0x10] = CPUFifo->top;
|
|
__piReg[0x14] = OSCachedToHardwired(CPUFifo->wrPtr);
|
|
|
|
if(CPGPLinked)
|
|
{
|
|
__GXWriteFifoIntReset(TRUE, TRUE);
|
|
__GXWriteFifoIntEnable(TRUE, FALSE);
|
|
__GXFifoLink(TRUE);
|
|
}
|
|
|
|
PPC_SYNC();
|
|
OSRestoreInterrupts(enabled);
|
|
}
|