diff --git a/config/GM8E01_00/symbols.txt b/config/GM8E01_00/symbols.txt index 5f763c19..766b20be 100644 --- a/config/GM8E01_00/symbols.txt +++ b/config/GM8E01_00/symbols.txt @@ -15545,7 +15545,7 @@ GXSetTexCoordGen2 = .text:0x80377F94; // type:function size:0x2D0 scope:global GXSetNumTexGens = .text:0x80378264; // type:function size:0x40 scope:global GXSetMisc = .text:0x803782A4; // type:function size:0x6C scope:global GXFlush = .text:0x80378310; // type:function size:0x5C scope:global -fn_8037836C = .text:0x8037836C; // type:function size:0xB4 +GXAbortFrame = .text:0x8037836C; // type:function size:0xB4 GXSetDrawSync = .text:0x80378420; // type:function size:0xB8 scope:global GXReadDrawSync = .text:0x803784D8; // type:function size:0xC scope:global GXDrawDone = .text:0x803784E4; // type:function size:0x80 scope:global @@ -22216,10 +22216,10 @@ lbl_805A9858 = .sbss:0x805A9858; // type:object size:0x4 data:4byte lbl_805A985C = .sbss:0x805A985C; // type:object size:0x4 data:4byte lbl_805A9860 = .sbss:0x805A9860; // type:object size:0x4 data:4byte lbl_805A9864 = .sbss:0x805A9864; // type:object size:0x4 data:4byte -lbl_805A9868 = .sbss:0x805A9868; // type:object size:0x4 data:4byte -lbl_805A986C = .sbss:0x805A986C; // type:object size:0x4 data:4byte -lbl_805A9870 = .sbss:0x805A9870; // type:object size:0x1 data:byte -lbl_805A9874 = .sbss:0x805A9874; // type:object size:0xC +TokenCB = .sbss:0x805A9868; // type:object size:0x4 data:4byte +DrawDoneCB = .sbss:0x805A986C; // type:object size:0x4 data:4byte +DrawDone = .sbss:0x805A9870; // type:object size:0x1 data:byte +FinishQueue = .sbss:0x805A9874; // type:object size:0xC BootInfo = .sbss:0x805A9880; // type:object size:0x4 scope:local data:4byte BI2DebugFlag = .sbss:0x805A9884; // type:object size:0x4 scope:local data:4byte BI2DebugFlagHolder = .sbss:0x805A9888; // type:object size:0x4 scope:local data:4byte diff --git a/include/dolphin/gx.h b/include/dolphin/gx.h index 856842b7..7bb8cddc 100644 --- a/include/dolphin/gx.h +++ b/include/dolphin/gx.h @@ -4,6 +4,7 @@ #include #include +#include #include #include #include diff --git a/include/dolphin/gx/GXManage.h b/include/dolphin/gx/GXManage.h index f77c7cb3..c09ee6c0 100644 --- a/include/dolphin/gx/GXManage.h +++ b/include/dolphin/gx/GXManage.h @@ -7,6 +7,7 @@ extern "C" { #endif +typedef void (*GXDrawSyncCallback)(u16 token); typedef void (*GXDrawDoneCallback)(void); GXFifoObj* GXInit(void* base, u32 size); diff --git a/include/dolphin/gx/GXPriv.h b/include/dolphin/gx/GXPriv.h index 6df69ed5..01365b57 100644 --- a/include/dolphin/gx/GXPriv.h +++ b/include/dolphin/gx/GXPriv.h @@ -291,6 +291,11 @@ void __GXInitGX(); } #endif +#define SET_REG_FIELD(reg, size, shift, val) \ +do { \ + (reg) = ((u32)(reg) & ~(((1 << (size)) - 1) << (shift))) | ((u32)(val) << (shift)); \ +} while (0) + #define GX_BITFIELD(field, pos, size, value) (__rlwimi((field), (value), 31 - (pos) - (size) + 1, (pos), (pos) + (size) - 1)) #define GX_BITFIELD_SET(field, pos, size, value) ((field) = GX_BITFIELD(field, pos, size, value)) diff --git a/include/dolphin/gx/GXRegs.h b/include/dolphin/gx/GXRegs.h new file mode 100644 index 00000000..517e9aab --- /dev/null +++ b/include/dolphin/gx/GXRegs.h @@ -0,0 +1,42 @@ +#ifndef _DOLPHIN_GXREGS +#define _DOLPHIN_GXREGS + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern u16 *__memReg; +extern u16 *__peReg; +extern u16 *__cpReg; +extern u32 *__piReg; + +#define GX_GET_CP_REG(offset) (*(volatile u16*)((__cpReg) + (offset))) +#define GX_SET_CP_REG(offset, value) ((*(volatile u16*)((__cpReg) + (offset))) = (value)) + +inline u32 __GXReadCPCounterU32(u32 regAddrL, u32 regAddrH) +{ + u32 ctrH0; + u32 ctrH1; + u32 ctrL; + + ctrH0 = GX_GET_CP_REG(regAddrH); + while (TRUE) { + ctrH1 = ctrH0; + ctrL = GX_GET_CP_REG(regAddrL); + ctrH0 = GX_GET_CP_REG(regAddrH); + + if (ctrH0 == ctrH1) { + break; + } + } + + return (ctrH0 << 16) | (ctrL); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/Dolphin/gx/GXMisc.c b/src/Dolphin/gx/GXMisc.c new file mode 100644 index 00000000..f4bcf39a --- /dev/null +++ b/src/Dolphin/gx/GXMisc.c @@ -0,0 +1,370 @@ +#include +#include +#include +#include +#include + +static GXDrawSyncCallback TokenCB; +static GXDrawDoneCallback DrawDoneCB; +static u8 DrawDone; +static OSThreadQueue FinishQueue; + +void GXSetMisc(GXMiscToken token, u32 val) +{ + GXData* gxdata = gx; + + switch (token) { + case GX_MT_XF_FLUSH: + gxdata->vNum = val; + gxdata->vNumNot = !gxdata->vNum; + gxdata->bpSentNot = GX_TRUE; + + if (gxdata->vNum != 0) { + gxdata->dirtyState |= 8; + } + break; + case GX_MT_DL_SAVE_CONTEXT: + gxdata->dlSaveContext = (val > 0); + break; + case GX_MT_NULL: + break; + default: + break; + } +} + +void GXFlush(void) +{ + u32 i; + + if (gx->dirtyState) { + __GXSetDirtyState(); + } + + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + PPCSync(); +} + +void GXResetWriteGatherPipe(void) +{ + while (PPCMfwpar() & 1) { + } + PPCMtwpar(OSUncachedToPhysical((void *)GXFIFO_ADDR)); +} + +static inline void __GXAbortWait(u32 clocks) +{ + OSTime time0; + OSTime time1; + + time0 = OSGetTime(); + do { + time1 = OSGetTime(); + } while (time1 - time0 <= (clocks / 4)); +} + +void __GXAbort(void) { + __piReg[0x18 / 4] = 1; + __GXAbortWait(200); + __piReg[0x18 / 4] = 0; + __GXAbortWait(20); +} + +void GXAbortFrame(void) +{ + __GXAbort(); + __GXCleanGPFifo(); +} + +void GXSetDrawSync(u16 token) +{ + BOOL enabled; + u32 reg; + + enabled = OSDisableInterrupts(); + reg = token | 0x48000000; + GX_WRITE_RA_REG(reg); + SET_REG_FIELD(reg, 16, 0, token); + SET_REG_FIELD(reg, 8, 24, 0x47); + GX_WRITE_RA_REG(reg); + GXFlush(); + OSRestoreInterrupts(enabled); + gx->bpSentNot = GX_FALSE; +} + +u16 GXReadDrawSync(void) +{ + u16 token = __peReg[7]; + return token; +} + +void GXSetDrawDone(void) +{ + u32 reg; + BOOL enabled; + + enabled = OSDisableInterrupts(); + reg = 0x45000002; + GX_WRITE_RA_REG(reg); + GXFlush(); + DrawDone = 0; + OSRestoreInterrupts(enabled); +} + +void GXWaitDrawDone(void) +{ + BOOL enabled; + + enabled = OSDisableInterrupts(); + while (!DrawDone) { + OSSleepThread(&FinishQueue); + } + OSRestoreInterrupts(enabled); +} + +void GXDrawDone(void) +{ + GXSetDrawDone(); + GXWaitDrawDone(); +} + +void GXPixModeSync(void) +{ + GX_WRITE_RA_REG(gx->peCtrl); + gx->bpSentNot = GX_FALSE; +} + +void GXTexModeSync(void) +{ + u32 reg; + + reg = 0x63000000; + GX_WRITE_RAS_REG(reg); + gx->bpSentNot = GX_FALSE; +} + +#if DEBUG +void __GXBypass(u32 reg) +{ + GX_WRITE_RA_REG(reg); + gx->bpSentNot = GX_FALSE; +} + +u16 __GXReadPEReg(u32 reg) +{ + return __peReg[reg]; +} +#endif + +void GXPokeAlphaMode(GXCompare func, u8 threshold) +{ + u32 reg; + + // CHECK_GXBEGIN(0x25F, "GXPokeAlphaMode"); + reg = (func << 8) | threshold; + __peReg[3] = reg; +} + +void GXPokeAlphaRead(_GXAlphaReadMode mode) +{ + u32 reg; + + // CHECK_GXBEGIN(0x26A, "GXPokeAlphaRead"); + reg = 0; + SET_REG_FIELD(reg, 2, 0, mode); + SET_REG_FIELD(reg, 1, 2, 1); + __peReg[4] = reg; +} + +void GXPokeAlphaUpdate(GXBool update_enable) +{ + u32 reg; + + // CHECK_GXBEGIN(0x277, "GXPokeAlphaUpdate"); + reg = __peReg[1]; + SET_REG_FIELD(reg, 1, 4, update_enable); + __peReg[1] = reg; +} + +void GXPokeBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp op) +{ + u32 reg; + + // CHECK_GXBEGIN(0x284, "GXPokeBlendUpdate"); + reg = __peReg[1]; + SET_REG_FIELD(reg, 1, 0, (type == GX_BM_BLEND) || (type == GX_BM_SUBTRACT)); + SET_REG_FIELD(reg, 1, 11, (type == GX_BM_SUBTRACT)); + SET_REG_FIELD(reg, 1, 1, (type == GX_BM_LOGIC)); + SET_REG_FIELD(reg, 4, 12, op); + SET_REG_FIELD(reg, 3, 8, src_factor); + SET_REG_FIELD(reg, 3, 5, dst_factor); + SET_REG_FIELD(reg, 8, 24, 0x41); + __peReg[1] = reg; +} + +void GXPokeColorUpdate(GXBool update_enable) +{ + u32 reg; + + // CHECK_GXBEGIN(0x29D, "GXPokeColorUpdate"); + reg = __peReg[1]; + SET_REG_FIELD(reg, 1, 3, update_enable); + __peReg[1] = reg; +} + +void GXPokeDstAlpha(GXBool enable, u8 alpha) +{ + u32 reg = 0; + + // CHECK_GXBEGIN(0x2A9, "GXPokeDstAlpha"); + SET_REG_FIELD(reg, 8, 0, alpha); + SET_REG_FIELD(reg, 1, 8, enable); + __peReg[2] = reg; +} + +void GXPokeDither(GXBool dither) +{ + u32 reg; + + // CHECK_GXBEGIN(0x2B5, "GXPokeDither"); + reg = __peReg[1]; + SET_REG_FIELD(reg, 1, 2, dither); + __peReg[1] = reg; +} + +void GXPokeZMode(GXBool compare_enable, GXCompare func, GXBool update_enable) +{ + u32 reg = 0; + + // CHECK_GXBEGIN(0x2C1, "GXPokeZMode"); + + SET_REG_FIELD(reg, 1, 0, compare_enable); + SET_REG_FIELD(reg, 3, 1, func); + SET_REG_FIELD(reg, 1, 4, update_enable); + __peReg[0] = reg; +} + +void GXPeekARGB(u16 x, u16 y, u32 *color) +{ + u32 addr = (u32)OSPhysicalToUncached(0x08000000); + + SET_REG_FIELD(addr, 10, 2, x); + SET_REG_FIELD(addr, 10, 12, y); + SET_REG_FIELD(addr, 2, 22, 0); + *color = *(u32 *)addr; +} + +void GXPokeARGB(u16 x, u16 y, u32 color) +{ + u32 addr = (u32)OSPhysicalToUncached(0x08000000); + + SET_REG_FIELD(addr, 10, 2, x); + SET_REG_FIELD(addr, 10, 12, y); + SET_REG_FIELD(addr, 2, 22, 0); + *(u32 *)addr = color; +} + +void GXPeekZ(u16 x, u16 y, u32 *z) +{ + u32 addr = (u32)OSPhysicalToUncached(0x08000000); + + SET_REG_FIELD(addr, 10, 2, x); + SET_REG_FIELD(addr, 10, 12, y); + SET_REG_FIELD(addr, 2, 22, 1); + *z = *(u32 *)addr; +} + +void GXPokeZ(u16 x, u16 y, u32 z) +{ + u32 addr = (u32)OSPhysicalToUncached(0x08000000); + + SET_REG_FIELD(addr, 10, 2, x); + SET_REG_FIELD(addr, 10, 12, y); + SET_REG_FIELD(addr, 2, 22, 1); + *(u32 *)addr = z; +} + +GXDrawSyncCallback GXSetDrawSyncCallback(GXDrawSyncCallback cb) +{ + GXDrawSyncCallback oldcb; + BOOL enabled; + + oldcb = TokenCB; + enabled = OSDisableInterrupts(); + TokenCB = cb; + OSRestoreInterrupts(enabled); + return oldcb; +} + +static void GXTokenInterruptHandler(__OSInterrupt interrupt, OSContext *context) +{ + u16 token; + OSContext exceptionContext; + u32 reg; + + token = __peReg[7]; + if (TokenCB != NULL) { + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + TokenCB(token); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } + reg = __peReg[5]; + SET_REG_FIELD(reg, 1, 2, 1); + __peReg[5] = reg; +} + +GXDrawDoneCallback GXSetDrawDoneCallback(GXDrawDoneCallback cb) +{ + GXDrawDoneCallback oldcb; + BOOL enabled; + + oldcb = DrawDoneCB; + enabled = OSDisableInterrupts(); + DrawDoneCB = cb; + OSRestoreInterrupts(enabled); + return oldcb; +} + +static void GXFinishInterruptHandler(__OSInterrupt interrupt, OSContext *context) +{ + OSContext exceptionContext; + u32 reg; + + reg = __peReg[5]; + SET_REG_FIELD(reg, 1, 3, 1); + __peReg[5] = reg; + DrawDone = 1; + if (DrawDoneCB != NULL) { + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + DrawDoneCB(); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } + OSWakeupThread(&FinishQueue); +} + +void __GXPEInit(void) +{ + u32 reg; + __OSSetInterruptHandler(0x12, GXTokenInterruptHandler); + __OSSetInterruptHandler(0x13, GXFinishInterruptHandler); + OSInitThreadQueue(&FinishQueue); + __OSUnmaskInterrupts(0x2000); + __OSUnmaskInterrupts(0x1000); + reg = __peReg[5]; + SET_REG_FIELD(reg, 1, 2, 1); + SET_REG_FIELD(reg, 1, 3, 1); + SET_REG_FIELD(reg, 1, 0, 1); + SET_REG_FIELD(reg, 1, 1, 1); + __peReg[5] = reg; +} diff --git a/src/Dolphin/gx/GXPixel.c b/src/Dolphin/gx/GXPixel.c index 75afd983..48e303b4 100644 --- a/src/Dolphin/gx/GXPixel.c +++ b/src/Dolphin/gx/GXPixel.c @@ -2,50 +2,135 @@ #include "dolphin/gx/GXPriv.h" void GXSetFog(GXFogType type, f32 startz, f32 endz, f32 nearz, f32 farz, GXColor color); -void GXSetFogColor(GXColor color); -// ? GXSetFogRangeAdj(); -void GXSetBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, - GXLogicOp op); +void GXSetFogColor(GXColor color) { + GXData* gxdata = gx; + + GX_WRITE_RA_REG(color.b | (color.g << 8) | (color.r << 16) | 0xf2000000); + + gxdata->bpSentNot = GX_FALSE; +}; +// void GXSetFogRangeAdj(GXBool enable, u16 center, GXFogAdjTable *table) +void GXSetBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp op) { + GXData* gxdata = gx; + u32 reg = gxdata->cmode0; + + GX_BITFIELD_SET(reg, 20, 1, (type == GX_BM_SUBTRACT)); + GX_BITFIELD_SET(reg, 31, 1, type); + GX_BITFIELD_SET(reg, 30, 1, (type == GX_BM_LOGIC)); + GX_BITFIELD_SET(reg, 16, 4, op); + GX_BITFIELD_SET(reg, 21, 3, src_factor); + GX_BITFIELD_SET(reg, 24, 3, dst_factor); + GX_WRITE_RA_REG(reg); + + gxdata->cmode0 = reg; + gxdata->bpSentNot = GX_FALSE; +}; void GXSetColorUpdate(GXBool update_enable) { GXData* gxdata = gx; - u32 r6 = gxdata->cmode0; + u32 reg = gxdata->cmode0; - GX_BITFIELD_SET(r6, 28, 1, update_enable); - GX_WRITE_RA_REG(r6); + GX_BITFIELD_SET(reg, 28, 1, update_enable); + GX_WRITE_RA_REG(reg); - gxdata->cmode0 = r6; + gxdata->cmode0 = reg; gxdata->bpSentNot = GX_FALSE; }; void GXSetAlphaUpdate(GXBool update_enable) { GXData* gxdata = gx; - u32 r6 = gxdata->cmode0; + u32 reg = gxdata->cmode0; - GX_BITFIELD_SET(r6, 27, 1, update_enable); - GX_WRITE_RA_REG(r6); + GX_BITFIELD_SET(reg, 27, 1, update_enable); + GX_WRITE_RA_REG(reg); + + gxdata->cmode0 = reg; + gxdata->bpSentNot = GX_FALSE; +}; +void GXSetZMode(GXBool compare_enable, GXCompare func, GXBool update_enable) { + GXData* gxdata = gx; + u32 reg = gxdata->zmode; + + GX_BITFIELD_SET(reg, 31, 1, compare_enable); + GX_BITFIELD_SET(reg, 28, 3, func); + GX_BITFIELD_SET(reg, 27, 1, update_enable); + GX_WRITE_RA_REG(reg); - gxdata->cmode0 = r6; + gxdata->zmode = reg; gxdata->bpSentNot = GX_FALSE; }; -void GXSetZMode(GXBool compare_enable, GXCompare func, GXBool update_enable); void GXSetZCompLoc(GXBool before_tex) { GXData* gxdata = gx; - gxdata->peCtrl = gxdata->peCtrl & 0xffffffbf | (u32)before_tex << 6; + SET_REG_FIELD(gxdata->peCtrl, 1, 6, before_tex); GX_WRITE_RA_REG(gxdata->peCtrl); gxdata->bpSentNot = GX_FALSE; }; -void GXSetPixelFmt(GXPixelFmt pix_fmt, GXZFmt16 z_fmt); +void GXSetPixelFmt(GXPixelFmt pix_fmt, GXZFmt16 z_fmt) { + GXData* gxdata = gx; + u32 pe = gxdata->peCtrl; + u8 aa; + static u32 p2f[8] = { 0, 1, 2, 3, 4, 4, 4, 5 }; + + SET_REG_FIELD(gxdata->peCtrl, 3, 0, p2f[pix_fmt]); + SET_REG_FIELD(gxdata->peCtrl, 3, 3, z_fmt); + if (pe != gxdata->peCtrl) { + GX_WRITE_RA_REG(pe); + if (pix_fmt == GX_PF_RGB565_Z16) { + aa = 1; + } else { + aa = 0; + } + + SET_REG_FIELD(gx->genMode, 1, 9, aa); + gxdata->dirtyState |= 4; + } + + if (p2f[pix_fmt] == 4) { + SET_REG_FIELD(gx->cmode1, 2, 9, (pix_fmt - 4) & 0x3); + SET_REG_FIELD(gxdata->cmode1, 8, 24, 0x42); + GX_WRITE_RA_REG(gxdata->cmode1); + } + + gx->bpSentNot = GX_FALSE; +}; void GXSetDither(GXBool dither) { GXData* gxdata = gx; - u32 r6 = gxdata->cmode0; + u32 reg = gxdata->cmode0; + + SET_REG_FIELD(reg, 1, 2, dither); + GX_WRITE_RA_REG(reg); + + gxdata->cmode0 = reg; + gxdata->bpSentNot = GX_FALSE; +}; +void GXSetDstAlpha(GXBool enable, u8 alpha) { + GXData* gxdata = gx; + u32 r6 = gxdata->cmode1; - r6 = r6 & 0xfffffffb | (u32)dither << 2; + GX_BITFIELD_SET(r6, 24, 8, alpha); + GX_BITFIELD_SET(r6, 23, 1, enable); GX_WRITE_RA_REG(r6); - gxdata->cmode0 = r6; + gxdata->cmode1 = r6; gxdata->bpSentNot = GX_FALSE; }; -void GXSetDstAlpha(GXBool enable, u8 alpha); -// ? GXSetFieldMask(); -void GXSetFieldMode(u8 field_mode, u8 half_aspect_ratio); +void GXSetFieldMask(GXBool odd_mask, GXBool even_mask) { + u32 reg = 0; + + SET_REG_FIELD(reg, 1, 0, even_mask); + SET_REG_FIELD(reg, 1, 1, odd_mask); + SET_REG_FIELD(reg, 8, 24, 0x44); + + GX_WRITE_RA_REG(reg); + + gx->bpSentNot = GX_FALSE; +}; +void GXSetFieldMode(u8 field_mode, u8 half_aspect_ratio) { + GXData* gxdata = gx; + + SET_REG_FIELD(gxdata->lpSize, 1, 22, half_aspect_ratio); + GX_WRITE_RA_REG(gxdata->lpSize); + __GXFlushTextureState(); + GX_WRITE_RA_REG(field_mode | 0x68000000); + __GXFlushTextureState(); +};