diff --git a/include/dolphin/gx/GXStruct.h b/include/dolphin/gx/GXStruct.h index 50cc08e..3189ed2 100644 --- a/include/dolphin/gx/GXStruct.h +++ b/include/dolphin/gx/GXStruct.h @@ -15,10 +15,10 @@ typedef struct _GXRenderModeObj { /* 0x10 */ u16 viHeight; /* 0x14 */ VIXFBMode xFBmode; /* 0x18 */ u8 field_rendering; - /* 0x?? */ u8 aa; - /* 0x?? */ u8 sample_pattern[12][2]; - /* 0x?? */ u8 vfilter[7]; -} GXRenderModeObj; + /* 0x19 */ u8 aa; + /* 0x1A */ u8 sample_pattern[12][2]; + /* 0x32 */ u8 vfilter[7]; +} GXRenderModeObj; // size = 0x3C typedef struct _GXColor { u8 r; diff --git a/include/emulator/frame.h b/include/emulator/frame.h index 7cd7410..df7e116 100644 --- a/include/emulator/frame.h +++ b/include/emulator/frame.h @@ -3,6 +3,7 @@ #include "dolphin.h" #include "emulator/rdp.h" +#include "emulator/rsp.h" #include "emulator/xlObject.h" #define FRAME_SYNC_TOKEN 0x7D00 @@ -286,7 +287,7 @@ typedef struct Frame { /* 0x0008C */ u32 nMode; /* 0x00090 */ u32 aMode[FMT_COUNT]; /* 0x000B8 */ Viewport viewport; - /* 0x000C8 */ FrameBuffer aBuffer[4]; + /* 0x000C8 */ FrameBuffer aBuffer[FBT_COUNT]; /* 0x00118 */ u32 nOffsetDepth0; /* 0x0011C */ u32 nOffsetDepth1; /* 0x00120 */ s32 nWidthLine; @@ -386,9 +387,24 @@ bool frameBeginOK(Frame* pFrame); bool frameBegin(Frame* pFrame, s32 nCountVertex); bool frameEnd(Frame* pFrame); bool frameDrawReset(Frame* pFrame, s32 nFlag); -bool frameSetBuffer(Frame* pFrame, FrameBufferType eType); + +bool frameSetFill(Frame* pFrame, bool bFill); bool frameSetSize(Frame* pFrame, FrameSize eSize, s32 nSizeX, s32 nSizeY); -bool frameFixMatrixHint(Frame* pFrame, u32 nAddressFloat, u32 nAddressFixed); +bool frameSetMode(Frame* pFrame, FrameModeType eType, u32 nMode); +bool frameGetMode(Frame* pFrame, FrameModeType eType, u32* pnMode); +bool frameSetMatrix(Frame* pFrame, Mtx44 matrix, FrameMatrixType eType, bool bLoad, bool bPush, s32 nAddressN64); +bool frameGetMatrix(Frame* pFrame, Mtx44 matrix, FrameMatrixType eType, bool bPull); +bool frameLoadVertex(Frame* pFrame, void* pBuffer, s32 iVertex0, s32 nCount); +bool frameCullDL(Frame* pFrame, s32 nVertexStart, s32 nVertexEnd); +bool frameLoadTLUT(Frame* pFrame, s32 nCount, s32 iTile); +bool frameLoadTMEM(Frame* pFrame, FrameLoadType eType, s32 iTile); +bool frameSetLightCount(Frame* pFrame, s32 nCount); +bool frameSetLight(Frame* pFrame, s32 iLight, s8* pData); +bool frameSetLookAt(Frame* pFrame, s32 iLookAt, s8* pData); +bool frameSetViewport(Frame* pFrame, s16* pData); +bool frameResetUCode(Frame* pFrame, RspUCodeType eType); +bool frameSetBuffer(Frame* pFrame, FrameBufferType eType); +bool frameFixMatrixHint(Frame* pFrame, s32 nAddressFloat, s32 nAddressFixed); bool frameSetMatrixHint(Frame* pFrame, FrameMatrixProjection eProjection, s32 nAddressFloat, s32 nAddressFixed, f32 rNear, f32 rFar, f32 rFOVY, f32 rAspect, f32 rScale); bool frameInvalidateCache(Frame* pFrame, s32 nOffset0, s32 nOffset1); diff --git a/include/emulator/rdp.h b/include/emulator/rdp.h index 028ff4d..0832b5d 100644 --- a/include/emulator/rdp.h +++ b/include/emulator/rdp.h @@ -2,9 +2,9 @@ #define _RDP_H #include "dolphin.h" +#include "emulator/rsp.h" #include "emulator/xlObject.h" -// __anon_0x52CD0 typedef struct Rdp { /* 0x00 */ s32 nBIST; /* 0x04 */ s32 nStatus; @@ -20,7 +20,8 @@ typedef struct Rdp { /* 0x2C */ s32 nClockTMEM; } Rdp; // size = 0x30 -s32 rdpEvent(Rdp* pRDP, s32 nEvent, void* pArgument); +bool rdpParseGBI(Rdp* pRDP, u64** ppnGBI, RspUCodeType eTypeUCode); +bool rdpEvent(Rdp* pRDP, s32 nEvent, void* pArgument); extern _XL_OBJECTTYPE gClassRDP; diff --git a/include/emulator/rsp.h b/include/emulator/rsp.h index 6c61208..241edba 100644 --- a/include/emulator/rsp.h +++ b/include/emulator/rsp.h @@ -19,7 +19,7 @@ typedef enum __anon_0x581E7 { RUT_UNKNOWN = 4, } __anon_0x581E7; -typedef enum __anon_0x60B3F { +typedef enum RspUCodeType { RUT_NONE = -1, RUT_TURBO = 0, RUT_SPRITE2D = 1, @@ -35,7 +35,7 @@ typedef enum __anon_0x60B3F { RUT_AUDIO1 = 11, RUT_AUDIO2 = 12, RUT_JPEG = 13, -} __anon_0x60B3F; +} RspUCodeType; // __anon_0x44829 typedef enum RspUpdateMode { @@ -43,7 +43,7 @@ typedef enum RspUpdateMode { RUM_IDLE = 1, } RspUpdateMode; -typedef struct __anon_0x575BD { +typedef struct RspTask { /* 0x00 */ s32 nType; /* 0x04 */ s32 nFlag; /* 0x08 */ s32 nOffsetBoot; @@ -60,19 +60,19 @@ typedef struct __anon_0x575BD { /* 0x34 */ s32 nLengthMBI; /* 0x38 */ s32 nOffsetYield; /* 0x3C */ s32 nLengthYield; -} __anon_0x575BD; // size = 0x40 +} RspTask; // size = 0x40 -typedef struct __anon_0x57890 { +typedef struct RspYield { /* 0x00 */ s32 iDL; /* 0x04 */ bool bValid; - /* 0x08 */ struct __anon_0x575BD task; + /* 0x08 */ RspTask task; /* 0x48 */ s32 nCountVertex; - /* 0x4C */ __anon_0x60B3F eTypeUCode; + /* 0x4C */ RspUCodeType eTypeUCode; /* 0x50 */ u32 n2TriMult; /* 0x54 */ u32 nVersionUCode; /* 0x58 */ s32 anBaseSegment[16]; /* 0x98 */ u64* apDL[16]; -} __anon_0x57890; // size = 0xD8 +} RspYield; // size = 0xD8 typedef struct __anon_0x57AB1 { /* 0x00 */ f32 aRotations[2][2]; @@ -119,7 +119,7 @@ typedef struct __anon_0x58107 { // __anon_0x5845E typedef struct Rsp { /* 0x0000 */ s32 nMode; - /* 0x0004 */ struct __anon_0x57890 yield; + /* 0x0004 */ RspYield yield; /* 0x00DC */ u32 nTickLast; /* 0x00E0 */ s32 (*pfUpdateWaiting)(void); /* 0x00E4 */ u32 n2TriMult; @@ -200,7 +200,7 @@ typedef struct Rsp { /* 0x3914 */ s32 nAddressRDRAM; /* 0x3918 */ struct tXL_LIST* pListUCode; /* 0x391C */ s32 nCountVertex; - /* 0x3920 */ enum __anon_0x60B3F eTypeUCode; + /* 0x3920 */ RspUCodeType eTypeUCode; /* 0x3924 */ u32 nVersionUCode; /* 0x3928 */ s32 anBaseSegment[16]; /* 0x3968 */ u64* apDL[16]; diff --git a/src/emulator/frame.c b/src/emulator/frame.c index ef3443e..02f321f 100644 --- a/src/emulator/frame.c +++ b/src/emulator/frame.c @@ -621,7 +621,7 @@ static bool frameCheckTriangleDivide(Frame* pFrame, Primitive* pPrimitive); bool frameDrawTriangle_C3T3(Frame* pFrame, Primitive* pPrimitive) { u32 pad[20]; - if (gpSystem->eTypeROM == SRT_ZELDA1 && pPrimitive->nCount == 3 && (pFrame->aMode[4] & 0xC00) == 0xC00) { + if (gpSystem->eTypeROM == SRT_ZELDA1 && pPrimitive->nCount == 3 && (pFrame->aMode[FMT_OTHER0] & 0xC00) == 0xC00) { Mtx44Ptr pMatrix = pFrame->aMatrixModel[pFrame->iMatrixModel]; Vertex* vtx = &pFrame->aVertex[pPrimitive->anData[0]]; if ((vtx->rSum == 53.0f && pMatrix[3][0] == -3080.0f && pMatrix[3][2] == 6067.0f) || @@ -863,7 +863,7 @@ bool frameEnd(Frame* pFrame) { pFrame->nCountFrames++; gbFrameValid = true; - if (pFrame->aBuffer[0].nAddress != 0) { + if (pFrame->aBuffer[FBT_DEPTH].nAddress != 0) { pData = &sTempZBuf; GXSetTexCopySrc(0, 0, GC_FRAME_WIDTH, GC_FRAME_HEIGHT); @@ -1454,7 +1454,7 @@ bool frameHackCIMG_Zelda2(Frame* pFrame, FrameBuffer* pBuffer, u64* pnGBI, u32 n u32* pGBI; s32 pad[2]; - if (pBuffer->nAddress == pFrame->aBuffer[0].nAddress) { + if (pBuffer->nAddress == pFrame->aBuffer[FBT_DEPTH].nAddress) { pFrame->nHackCount += 1; } @@ -1541,7 +1541,7 @@ bool frameHackCIMG_Zelda(Frame* pFrame, FrameBuffer* pBuffer, u64* pnGBI, u32 nC } } - if (pBuffer->nAddress == pFrame->aBuffer[0].nAddress && pBuffer->nWidth == N64_FRAME_WIDTH) { + if (pBuffer->nAddress == pFrame->aBuffer[FBT_DEPTH].nAddress && pBuffer->nWidth == N64_FRAME_WIDTH) { low2 = pnGBI[1]; high2 = pnGBI[1] >> 32; if (high2 == 0xFD10013F) { @@ -2529,13 +2529,13 @@ bool frameSetLookAt(Frame* pFrame, s32 iLookAt, s8* pData) { bool frameSetBuffer(Frame* pFrame, FrameBufferType eType) { if (((u32)(eType - 2) > 1) && (eType == FBT_DEPTH)) { - pFrame->nOffsetDepth0 = pFrame->aBuffer[0].nAddress & 0x03FFFFFF; + pFrame->nOffsetDepth0 = pFrame->aBuffer[FBT_DEPTH].nAddress & 0x03FFFFFF; pFrame->nOffsetDepth1 = pFrame->nOffsetDepth0 + 0x257FC; } return true; } -bool frameFixMatrixHint(Frame* pFrame, u32 nAddressFloat, u32 nAddressFixed) { +bool frameFixMatrixHint(Frame* pFrame, s32 nAddressFloat, s32 nAddressFixed) { s32 iHint; s32 iHintTest; diff --git a/src/emulator/rdp.c b/src/emulator/rdp.c index 9f75ac7..0cfb304 100644 --- a/src/emulator/rdp.c +++ b/src/emulator/rdp.c @@ -1,5 +1,13 @@ #include "emulator/rdp.h" +#include "dolphin.h" +#include "emulator/frame.h" +#include "emulator/ram.h" #include "emulator/rdp_jumptables.h" +#include "emulator/rsp.h" +#include "emulator/simGCN.h" +#include "emulator/system.h" +#include "emulator/xlCoreGCN.h" +#include "macros.h" _XL_OBJECTTYPE gClassRDP = { "RDP", @@ -8,11 +16,14 @@ _XL_OBJECTTYPE gClassRDP = { (EventFunc)rdpEvent, }; +#ifndef NON_MATCHING +// rdpParseGBI static u32 sCommandCodes[] = { 0xED000000, 0x005003C0, 0xDE010000, }; +#endif void* jtbl_800EDF5C[13] = { &lbl_80070090, &lbl_800700CC, &lbl_800700CC, &lbl_800700CC, &lbl_800700A0, &lbl_800700CC, &lbl_800700CC, @@ -40,6 +51,8 @@ void* jtbl_800EE038[29] = { &lbl_8007031C, &lbl_80070314, &lbl_80070314, &lbl_80070314, &lbl_8007031C, }; +#ifndef NON_MATCHING +// rdpParseGBI void* jtbl_800EE0AC[64] = { &lbl_800715A8, &lbl_800715A0, &lbl_800715A0, &lbl_800715A0, &lbl_800715A0, &lbl_800715A0, &lbl_800715A0, &lbl_800715A0, &lbl_800715A8, &lbl_800715A8, &lbl_800715A8, &lbl_800715A8, &lbl_800715A8, &lbl_800715A8, @@ -52,7 +65,12 @@ void* jtbl_800EE0AC[64] = { &lbl_80070B80, &lbl_80070B60, &lbl_80070B2C, &lbl_80070B0C, &lbl_80070924, &lbl_80070808, &lbl_8007077C, &lbl_800703CC, }; +#else +void* jtbl_800EE0AC[64] = {0}; +#endif +#ifndef NON_MATCHING +// rdpParseGBI static s32 nCount; static s32 nBlurCount; static s32 nNoteCount; @@ -68,8 +86,582 @@ const f32 D_8013601C = 320.0f; const f32 D_80136020 = 240.0f; const f64 D_80136028 = 4503599627370496.0; const f64 D_80136030 = 4503601774854144.0; +#endif +// Matches but data doesn't +#ifndef NON_MATCHING #pragma GLOBAL_ASM("asm/non_matchings/rdp/rdpParseGBI.s") +#else +bool rdpParseGBI(Rdp* pRDP, u64** ppnGBI, RspUCodeType eTypeUCode) { + u32 nA; + u32 nB; + u32 nC; + u32 nD; + u64* pnGBI; + u32 nCommandLo; + u32 nCommandHi; + Frame* pFrame; + + pnGBI = *ppnGBI; + pFrame = SYSTEM_FRAME(pRDP->pHost); + nCommandHi = GBI_COMMAND_HI(pnGBI); + nCommandLo = GBI_COMMAND_LO(pnGBI); + + *ppnGBI = ++pnGBI; + pFrame->pnGBI = pnGBI; + + switch (nCommandHi >> 24) { + case 0xC0: // G_NOOP + break; + case 0xFF: { // G_SETCIMG + bool nFound = false; + s32 i; + u32 nAddress; + bool nSetLens = false; + FrameBuffer* pBuffer = &pFrame->aBuffer[FBT_COLOR_DRAW]; + + pBuffer->nFormat = (nCommandHi >> 21) & 7; + pBuffer->nSize = (nCommandHi >> 19) & 3; + pBuffer->nWidth = (nCommandHi & 0xFFF) + 1; + + nAddress = SEGMENT_ADDRESS(SYSTEM_RSP(pRDP->pHost), nCommandLo); + pBuffer->nAddress = nAddress; + + if (!ramGetBuffer(SYSTEM_RAM(pRDP->pHost), &pBuffer->pData, nAddress, NULL)) { + return false; + } + if (!frameSetBuffer(pFrame, FBT_COLOR_DRAW)) { + return false; + } + + for (i = 0; i < pFrame->nNumCIMGAddresses && i < 8; i++) { + if (nAddress == pFrame->anCIMGAddresses[i]) { + nFound = true; + break; + } + } + if (!nFound) { + pFrame->anCIMGAddresses[i] = nAddress; + pFrame->nNumCIMGAddresses++; + } + switch (gpSystem->eTypeROM) { + case SRT_ZELDA1: + if (!frameHackCIMG_Zelda(pFrame, pBuffer, pnGBI, nCommandLo, nCommandHi)) { + return false; + } + break; + case SRT_ZELDA2: { + static s32 nCount; + static s32 nBlurCount; + static s32 nNoteCount; + static s32 nZCount; + static s32 nZBufferCount; + + if (nAddress == 0x0042EEC0 || nAddress == 0x003A9480 || nAddress == 0x003A92C0) { + nBlurCount = nCount; + } + if (nAddress == 0x00780000) { + nNoteCount = nCount; + } + if (!(nAddress == 0x004096C0 || nAddress == 0x00383C80 || nAddress == 0x00383AC0) && + pFrame->bCameFromBomberNotes) { + nZCount += 1; + } else { + nZCount = 0; + pFrame->bCameFromBomberNotes = false; + } + if (nAddress == 0x004096C0 || nAddress == 0x00383C80 || nAddress == 0x00383AC0) { + nZBufferCount = nCount; + pFrame->nZBufferSets++; + } + if (nAddress == 0x00784600) { + static u32 sCommandCodes[] = { + 0xED000000, + 0x005003C0, + 0xDE010000, + }; + s32 i; + u32* pGBI = (u32*)pnGBI; + + for (i = 0; i < ARRAY_COUNT(sCommandCodes); i++) { + if (pGBI[i] != sCommandCodes[i]) { + break; + } + } + + if (i == 3) { + pFrame->bUsingLens = true; + nSetLens = true; + } + if (pGBI[0] == 0xFD900000) { + nSetLens = true; + } + } + if (nZCount > 11) { + pFrame->bPauseThisFrame = true; + } + if (nCount - nNoteCount < 11) { + pFrame->bInBomberNotes = true; + } else { + pFrame->bInBomberNotes = false; + } + if (nCount - nBlurCount < 11) { + pFrame->bBlurOn = true; + } else { + pFrame->bBlurOn = false; + } + nCount += 1; + if (!frameHackCIMG_Zelda2(pFrame, pBuffer, pnGBI, nCommandLo, nCommandHi)) { + return false; + } + frameHackCIMG_Zelda2_Shrink(pRDP, pFrame, ppnGBI); + if (nSetLens == 0) { + frameHackCIMG_Zelda2_Camera(pFrame, pBuffer, 0, 0); + } + break; + } + case SRT_PANEL: + if (nAddress == 0x0023E800 || nAddress == 0x00245D00 || nAddress == 0x00358800) { + frameHackCIMG_Panel(pRDP, pFrame, pBuffer, ppnGBI); + } + /* fallthrough */ + case SRT_DRMARIO: + if (!(nAddress == 0x003B5000 || nAddress == 0x003DA800)) { + pFrame->bGrabbedFrame = true; + } + break; + default: + break; + } + break; + } + case 0xFE: { // G_SETZIMG + s32 nAddress; + FrameBuffer* pBuffer = &pFrame->aBuffer[FBT_DEPTH]; + + pBuffer->nFormat = (nCommandHi >> 21) & 7; + pBuffer->nSize = (nCommandHi >> 19) & 3; + pBuffer->nWidth = (nCommandHi & 0xFFF) + 1; + + nAddress = SEGMENT_ADDRESS(SYSTEM_RSP(pRDP->pHost), nCommandLo); + pBuffer->nAddress = nAddress; + + if (!ramGetBuffer(SYSTEM_RAM(pRDP->pHost), &pBuffer->pData, nAddress, NULL)) { + return false; + } + if (!frameSetBuffer(pFrame, FBT_DEPTH)) { + return false; + } + break; + } + case 0xFD: { // G_SETTIMG + s32 nAddress; + FrameBuffer* pBuffer = &pFrame->aBuffer[FBT_IMAGE]; + + switch (gpSystem->eTypeROM) { + case SRT_ZELDA1: + if (!frameHackTIMG_Zelda(pFrame, &pnGBI, &nCommandLo, &nCommandHi)) { + return false; + } + break; + case SRT_ZELDA2: + if (!frameHackTIMG_Zelda(pFrame, &pnGBI, &nCommandLo, &nCommandHi)) { + return false; + } + break; + default: + break; + } + pBuffer->nFormat = (nCommandHi >> 21) & 7; + pBuffer->nSize = (nCommandHi >> 19) & 3; + pBuffer->nWidth = (nCommandHi & 0xFFF) + 1; + pBuffer->nAddress = nCommandLo; + + nAddress = SEGMENT_ADDRESS(SYSTEM_RSP(pRDP->pHost), nCommandLo); + if (!ramGetBuffer(SYSTEM_RAM(pRDP->pHost), &pBuffer->pData, nAddress, NULL)) { + return false; + } + if (!frameSetBuffer(pFrame, FBT_IMAGE)) { + return false; + } + switch (gpSystem->eTypeROM) { + case SRT_PANEL: + frameHackTIMG_Panel(pFrame, pBuffer); + break; + default: + break; + } + break; + } + case 0xFC: // G_SETCOMBINE + if ((nA = (nCommandHi >> 20) & 0xF) == 0xF) { + nA = 0x1F; + } + if ((nB = (nCommandLo >> 28) & 0xF) == 0xF) { + nB = 0x1F; + } + if ((nC = (nCommandHi >> 15) & 0x1F) == 0x1F) { + nC = 0x1F; + } + if ((nD = (nCommandLo >> 15) & 7) == 7) { + nD = 0x1F; + } + if (!frameSetMode(pFrame, FMT_COMBINE_COLOR1, nA | (nB << 8) | (nC << 16) | (nD << 24))) { + return false; + } + + if ((nA = (nCommandHi >> 12) & 7) == 7) { + nA = 7; + } + if ((nB = (nCommandLo >> 12) & 7) == 7) { + nB = 7; + } + if ((nC = (nCommandHi >> 9) & 7) == 7) { + nC = 7; + } + if ((nD = (nCommandLo >> 9) & 7) == 7) { + nD = 7; + } + if (!frameSetMode(pFrame, FMT_COMBINE_ALPHA1, nA | (nB << 8) | (nC << 16) | (nD << 24))) { + return false; + } + + if ((nA = (nCommandHi >> 5) & 0xF) == 0xF) { + nA = 0x1F; + } + if ((nB = (nCommandLo >> 24) & 0xF) == 0xF) { + nB = 0x1F; + } + if ((nC = (nCommandHi >> 0) & 0x1F) == 0x1F) { + nC = 0x1F; + } + if ((nD = (nCommandLo >> 6) & 7) == 7) { + nD = 0x1F; + } + if (!frameSetMode(pFrame, FMT_COMBINE_COLOR2, nA | (nB << 8) | (nC << 16) | (nD << 24))) { + return false; + } + + if ((nA = (nCommandLo >> 21) & 7) == 7) { + nA = 7; + } + if ((nB = (nCommandLo >> 3) & 7) == 7) { + nB = 7; + } + if ((nC = (nCommandLo >> 18) & 7) == 7) { + nC = 7; + } + if ((nD = (nCommandLo >> 0) & 7) == 7) { + nD = 7; + } + if (!frameSetMode(pFrame, FMT_COMBINE_ALPHA2, nA | (nB << 8) | (nC << 16) | (nD << 24))) { + return false; + } + break; + case 0xFB: // G_SETENVCOLOR + if (!frameSetColor(pFrame, FCT_ENVIRONMENT, nCommandLo)) { + return false; + } + break; + case 0xFA: // G_SETPRIMCOLOR + pFrame->primLODfrac = nCommandHi & 0xFF; + pFrame->primLODmin = (nCommandHi >> 8) & 0xFF; + if (!frameSetColor(pFrame, FCT_PRIMITIVE, nCommandLo)) { + return false; + } + break; + case 0xF9: // G_SETBLENDCOLOR + if (!frameSetColor(pFrame, FCT_BLEND, nCommandLo)) { + return false; + } + break; + case 0xF8: // G_SETFOGCOLOR + if (!frameSetColor(pFrame, FCT_FOG, nCommandLo)) { + return false; + } + break; + case 0xF7: { // G_SETFILLCOLOR + u32 nColor = ((nCommandLo >> 11) & 0x1F) << 27 | ((nCommandLo >> 6) & 0x1F) << 19 | + ((nCommandLo >> 1) & 0x1F) << 11 | ((nCommandLo & 1) << 7); + + if (!frameSetColor(pFrame, FCT_FILL, nColor)) { + return false; + } + break; + } + case 0xF6: { // G_FILLRECT + Rectangle primitive; + + primitive.nX1 = (nCommandHi >> 14) & 0x3FF; + primitive.nY1 = (nCommandHi >> 2) & 0x3FF; + primitive.nX0 = (nCommandLo >> 14) & 0x3FF; + primitive.nY0 = (nCommandLo >> 2) & 0x3FF; + if (gpSystem->eTypeROM == SRT_ZELDA2) { + if (primitive.nY1 == N64_FRAME_HEIGHT - 1 && primitive.nY0 > 0) { + primitive.nY0 -= 1; + } + frameHackCIMG_Zelda2_Camera(pFrame, NULL, nCommandHi, nCommandLo); + } + if (!pFrame->aDraw[2](pFrame, &primitive)) { + return false; + } + break; + } + case 0xF5: { // G_SETTILE + s32 iTile = (nCommandLo >> 24) & 7; + Tile* pTile = &pFrame->aTile[iTile]; + + pTile->nSize = (nCommandHi >> 19) & 3; + pTile->nTMEM = nCommandHi & 0x1FF; + pTile->iTLUT = (nCommandLo >> 20) & 0xF; + pTile->nSizeX = (nCommandHi >> 9) & 0x1FF; + pTile->nFormat = (nCommandHi >> 21) & 7; + pTile->nMaskS = (nCommandLo >> 4) & 0xF; + pTile->nMaskT = (nCommandLo >> 14) & 0xF; + pTile->nModeS = (nCommandLo >> 8) & 3; + pTile->nModeT = (nCommandLo >> 18) & 3; + pTile->nShiftS = (nCommandLo >> 0) & 0xF; + pTile->nShiftT = (nCommandLo >> 10) & 0xF; + pTile->nCodePixel = pFrame->nCodePixel; + + pFrame->lastTile = iTile; + if (!frameDrawReset(pFrame, 1)) { + return false; + } + break; + } + case 0xF4: { // G_LOADTILE + s32 iTile = (nCommandLo >> 24) & 7; + + pFrame->aTile[iTile].nX0 = (nCommandHi >> 12) & 0xFFF; + pFrame->aTile[iTile].nY0 = nCommandHi & 0xFFF; + pFrame->aTile[iTile].nX1 = (nCommandLo >> 12) & 0xFFF; + pFrame->aTile[iTile].nY1 = nCommandLo & 0xFFF; + + pFrame->n2dLoadTexType = 0xFC1034; + pFrame->nLastX0 = pFrame->aTile[iTile].nX0; + pFrame->nLastY0 = pFrame->aTile[iTile].nY0; + pFrame->nLastX1 = pFrame->aTile[iTile].nX1; + pFrame->nLastY1 = pFrame->aTile[iTile].nY1; + if (!frameLoadTMEM(pFrame, FLT_TILE, iTile)) { + return false; + } + pFrame->aTile[pFrame->lastTile].nCodePixel = pFrame->nCodePixel; + break; + } + case 0xF3: { // G_LOADBLOCK + s32 iTile = (nCommandLo >> 24) & 7; + + pFrame->aTile[iTile].nX0 = (nCommandHi >> 12) & 0xFFF; + pFrame->aTile[iTile].nY0 = nCommandHi & 0xFFF; + pFrame->aTile[iTile].nX1 = (nCommandLo >> 12) & 0xFFF; + pFrame->aTile[iTile].nY1 = nCommandLo & 0xFFF; + pFrame->n2dLoadTexType = 0x1033; + if (!frameLoadTMEM(pFrame, FLT_BLOCK, iTile)) { + return false; + } + break; + } + case 0xF2: { // G_SETTILESIZE + s32 iTile = (nCommandLo >> 24) & 7; + Tile* pTile = &pFrame->aTile[iTile]; + + pTile->nX0 = (nCommandHi >> 12) & 0xFFF; + pTile->nY0 = nCommandHi & 0xFFF; + pTile->nX1 = (nCommandLo >> 12) & 0xFFF; + pTile->nY1 = nCommandLo & 0xFFF; + if (!frameDrawReset(pFrame, 1)) { + return false; + } + break; + } + case 0xF0: { // G_LOADTLUT + s32 iTile = (nCommandLo >> 24) & 7; + s32 nCount = (nCommandLo >> 14) & 0x3FF; + + if (!frameLoadTLUT(pFrame, nCount, iTile)) { + return false; + } + break; + } + case 0xEF: // G_RDPSETOTHERMODE + if (!frameSetMode(pFrame, FMT_OTHER0, nCommandLo)) { + return false; + } + if (!frameSetMode(pFrame, FMT_OTHER1, nCommandHi)) { + return false; + } + break; + case 0xEE: { // G_SETPRIMDEPTH + f32 rDepth = ((nCommandLo >> 16) & 0x7FFF) / 32768.0f; + f32 rDelta = (nCommandLo & 0xFFFF) / 65536.0f; + + if (!frameSetDepth(pFrame, rDepth, rDelta)) { + return false; + } + break; + } + case 0xED: { // G_SETSCISSOR + Rectangle rectangle; + s32 pad; + + rectangle.nX0 = (nCommandHi >> 12) & 0xFFF; + rectangle.nY0 = nCommandHi & 0xFFF; + rectangle.nX1 = (nCommandLo >> 12) & 0xFFF; + rectangle.nY1 = nCommandLo & 0xFFF; + if (!frameSetScissor(pFrame, &rectangle)) { + return false; + } + break; + } + case 0xEC: // G_SETCONVERT + case 0xEB: // G_SETKEYR + case 0xEA: // G_SETKEYGB + case 0xE9: // G_RDPFULLSYNC + case 0xE8: // G_RDPTILESYNC + case 0xE7: // G_RDPPIPESYNC + case 0xE6: // G_RDPLOADSYNC + break; + case 0xE5: // G_TEXRECTFLIP + case 0xE4: // G_TEXRECT + { + Rectangle primitive; + f32 rX0; + f32 rY0; + f32 rX1; + f32 rY1; + u32* pGBI; + + primitive.nX0 = (nCommandLo >> 12) & 0xFFF; + primitive.nY0 = nCommandLo & 0xFFF; + primitive.nX1 = (nCommandHi >> 12) & 0xFFF; + primitive.nY1 = nCommandHi & 0xFFF; + + rX0 = (primitive.nX0 + 3) >> 2; + rX1 = (primitive.nX1 + 3) >> 2; + rY0 = (primitive.nY0 + 3) >> 2; + rY1 = (primitive.nY1 + 3) >> 2; + + primitive.iTile = (nCommandLo >> 24) & 7; + primitive.bFlip = nCommandHi >> 24 == 0xE5 ? true : false; + + if (gpSystem->eTypeROM == SRT_ZELDA2 && (pFrame->bSnapShot & 0xF) != 0 && (s32)nCommandHi == 0xE43C023C && + nCommandLo == 0x0014021C) { + pFrame->bSnapShot |= 0x100; + } + + nCommandHi = GBI_COMMAND_HI(pnGBI); + nCommandLo = GBI_COMMAND_LO(pnGBI); + *ppnGBI = ++pnGBI; + + // TODO: translate commands to enum + if (nCommandHi >> 24 == 0xB4 || nCommandHi >> 24 == 0xE1 || nCommandHi >> 24 == 0xB3) { + primitive.rS = (s16)(nCommandLo >> 16) / 32.0f; + primitive.rT = (s16)(nCommandLo & 0xFFFF) / 32.0f; + + nCommandHi = GBI_COMMAND_HI(pnGBI); + nCommandLo = GBI_COMMAND_LO(pnGBI); + *ppnGBI = ++pnGBI; + + primitive.rDeltaS = (s16)(nCommandLo >> 16) / 1024.0f; + primitive.rDeltaT = (s16)(nCommandLo & 0xFFFF) / 1024.0f; + + rX0 = (primitive.nX0 + 3) >> 2; + rX1 = (primitive.nX1 + 3) >> 2; + rY0 = (primitive.nY0 + 3) >> 2; + rY1 = (primitive.nY1 + 3) >> 2; + } else { + primitive.rS = (s16)(nCommandHi >> 16) / 32.0f; + primitive.rT = (s16)(nCommandHi & 0xFFFF) / 32.0f; + primitive.rDeltaS = (s16)(nCommandLo >> 16) / 1024.0f; + primitive.rDeltaT = (s16)(nCommandLo & 0xFFFF) / 1024.0f; + } + if (pFrame->iTileDrawn != primitive.iTile) { + frameDrawReset(pFrame, 1); + } + pFrame->iTileDrawn = primitive.iTile; + if (gpSystem->eTypeROM == SRT_ZELDA2 && rX0 == 0.0f && rX1 == N64_FRAME_WIDTH && rY0 == 0.0f && + rY1 == N64_FRAME_HEIGHT && pFrame->bUsingLens) { + u32* pGBI = (u32*)pnGBI; + + if (pGBI[4] == 0xF8000000) { + GXSetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL); + GXSetCopyFilter(rmode->aa, rmode->sample_pattern, GX_TRUE, rmode->vfilter); + GXSetColorUpdate(GX_FALSE); + pFrame->bModifyZBuffer = true; + } + if (pGBI[4] == 0xF9000000) { + GXSetColorUpdate(GX_FALSE); + if (pFrame->aMode[FMT_COMBINE_COLOR1] == 0x1F031F01 && + pFrame->aMode[FMT_COMBINE_ALPHA1] == 0x07030701 && + pFrame->aMode[FMT_COMBINE_COLOR2] == 0x1F031F01 && + pFrame->aMode[FMT_COMBINE_ALPHA2] == 0x7030701) { + pFrame->aMode[FMT_COMBINE_COLOR1] = 0x1F030106; + pFrame->aMode[FMT_COMBINE_ALPHA1] = 0x07030106; + pFrame->aMode[FMT_COMBINE_COLOR2] = 0x1F030106; + pFrame->aMode[FMT_COMBINE_ALPHA2] = 0x07030106; + } else if (pFrame->aMode[FMT_COMBINE_COLOR1] == 0x1F030106 && + pFrame->aMode[FMT_COMBINE_ALPHA1] == 0x07030106 && + pFrame->aMode[FMT_COMBINE_COLOR2] == 0x1F030106 && + pFrame->aMode[FMT_COMBINE_ALPHA2] == 0x07030106) { + pFrame->aMode[FMT_COMBINE_COLOR1] = 0x1F031F01; + pFrame->aMode[FMT_COMBINE_ALPHA1] = 0x07030701; + pFrame->aMode[FMT_COMBINE_COLOR2] = 0x1F031F01; + pFrame->aMode[FMT_COMBINE_ALPHA2] = 0x07030701; + } + if (!frameSetColor(pFrame, FCT_PRIMITIVE, 0x000000FF)) { + return false; + } + if (!frameSetColor(pFrame, FCT_BLEND, 0x00000008)) { + return false; + } + pFrame->primLODfrac = 0; + pFrame->primLODmin = 0; + pFrame->aMode[FMT_OTHER0] = 0xAF504365; + pFrame->aMode[FMT_OTHER1] = 0xEF002C30; + pFrame->aMode[FMT_FOG] = 0; + pFrame->aMode[FMT_GEOMETRY] = 0; + pFrame->aMode[FMT_TEXTURE1] = 0; + pFrame->aMode[FMT_TEXTURE2] = 0; + pFrame->bOverrideDepth = true; + pFrame->bModifyZBuffer = true; + pFrame->nMode = 0x0C1203F0; + } + } + + if (!pFrame->aDraw[3](pFrame, &primitive)) { + return false; + } + + pGBI = (u32*)pnGBI; + if (gpSystem->eTypeROM == SRT_ZELDA2 && rX0 == 0.0f && rX1 == N64_FRAME_WIDTH && rY0 == 0.0f && + rY1 == N64_FRAME_HEIGHT && pFrame->bUsingLens) { + + if (pGBI[4] == 0xF8000000) { + pFrame->bOverrideDepth = false; + } else if (pGBI[4] == 0xF9000000) { + pFrame->bOverrideDepth = false; + } + } + GXSetColorUpdate(GX_TRUE); + break; + } + case 0xC8: // G_TRI_FILL + case 0xCC: // G_TRI_SHADE + case 0xCA: // G_TRI_TXTR + case 0xCE: // G_TRI_SHADE_TXTR + case 0xC9: // G_TRI_FILL_ZBUFF + case 0xCD: // G_TRI_SHADE_ZBUFF + case 0xCB: // G_TRI_TXTR_ZBUFF + case 0xCF: // G_TRI_SHADE_TXTR_ZBUFF + break; + default: + return false; + } + + return true; +} +#endif #pragma GLOBAL_ASM("asm/non_matchings/rdp/rdpPut8.s") diff --git a/src/emulator/rsp.c b/src/emulator/rsp.c index 67eed7e..a7e5f1d 100644 --- a/src/emulator/rsp.c +++ b/src/emulator/rsp.c @@ -1,5 +1,6 @@ #include "emulator/rsp.h" #include "emulator/cpu.h" +#include "emulator/frame.h" #include "emulator/ram.h" #include "emulator/rdp.h" #include "emulator/rsp_jumptables.h" @@ -47,10 +48,15 @@ void* jtbl_800EE338[29] = { &lbl_80072998, &lbl_80072948, &lbl_80072948, &lbl_80072948, &lbl_8007293C, }; +#ifndef NON_MATCHING +// rspParseGBI void* jtbl_800EE3AC[11] = { &lbl_80072AC0, &lbl_80072AC0, &lbl_80072AC0, &lbl_80072AD4, &lbl_80072AE8, &lbl_80072AC0, &lbl_80072AD4, &lbl_80072AC0, &lbl_80072AD4, &lbl_80072AC0, &lbl_80072AD4, }; +#else +void* jtbl_800EE3AC[11] = {0}; +#endif void* jtbl_800EE3D8[13] = { &lbl_80075608, &lbl_8007600C, &lbl_8007600C, &lbl_8007600C, &lbl_80075630, &lbl_8007600C, &lbl_8007600C, @@ -313,10 +319,12 @@ const f32 D_80136074 = 1.52587890625e-05; #pragma GLOBAL_ASM("asm/non_matchings/rsp/rspSetGeometryMode1.s") +static bool rspParseGBI_F3DEX1(Rsp* pRSP, u64** ppnGBI, bool* pbDone); #pragma GLOBAL_ASM("asm/non_matchings/rsp/rspParseGBI_F3DEX1.s") #pragma GLOBAL_ASM("asm/non_matchings/rsp/rspGeometryMode.s") +static bool rspParseGBI_F3DEX2(Rsp* pRSP, u64** ppnGBI, bool* pbDone); #pragma GLOBAL_ASM("asm/non_matchings/rsp/rspParseGBI_F3DEX2.s") // Matches but data doesn't @@ -446,15 +454,147 @@ static bool rspLoadMatrix(Rsp* pRSP, s32 nAddress, Mtx44 matrix) { } #endif +inline bool rspSetDL(Rsp* pRSP, s32 nOffsetRDRAM, bool bPush) { + s32 nAddress; + s32* pDL; + + nAddress = SEGMENT_ADDRESS(pRSP, nOffsetRDRAM); + if (!ramGetBuffer(SYSTEM_RAM(pRSP->pHost), &pDL, nAddress, NULL)) { + return false; + } + + if (bPush && ++pRSP->iDL >= ARRAY_COUNT(pRSP->apDL)) { + return false; + } + + pRSP->apDL[pRSP->iDL] = (u64*)pDL; + return true; +} + +inline bool rspPopDL(Rsp* pRSP) { + if (pRSP->iDL == 0) { + return false; + } else { + pRSP->iDL--; + return true; + } +} + +static bool rspFindUCode(Rsp* pRSP, RspTask* pTask); #pragma GLOBAL_ASM("asm/non_matchings/rsp/rspFindUCode.s") #pragma GLOBAL_ASM("asm/non_matchings/rsp/rspSaveYield.s") #pragma GLOBAL_ASM("asm/non_matchings/rsp/rspLoadYield.s") -#pragma GLOBAL_ASM("asm/non_matchings/rsp/rspParseGBI_Setup.s") +static bool rspParseGBI_Setup(Rsp* pRSP, RspTask* pTask) { + s32 iSegment; + if (pRSP->yield.bValid) { + pRSP->yield.bValid = false; + } + + pRSP->nGeometryMode = 0; + pRSP->iDL = 0; + + if (!rspSetDL(pRSP, pTask->nOffsetMBI & 0x7FFFFF, false)) { + return false; + } + + for (iSegment = 0; iSegment < ARRAY_COUNT(pRSP->anBaseSegment); iSegment++) { + pRSP->anBaseSegment[iSegment] = 0; + } + + if (!rspFindUCode(pRSP, pTask)) { + return false; + } + + if (pRSP->eTypeUCode != RUT_ZSORT || pRSP->nPass == 1) { + if (!frameBegin(SYSTEM_FRAME(pRSP->pHost), pRSP->nCountVertex)) { + return false; + } + } + + PAD_STACK(); + return true; +} + +// Matches but data doesn't +#ifndef NON_MATCHING +static bool rspParseGBI(Rsp* pRSP, bool* pbDone, s32 nCount); #pragma GLOBAL_ASM("asm/non_matchings/rsp/rspParseGBI.s") +#else +static bool rspParseGBI(Rsp* pRSP, bool* pbDone, s32 nCount) { + bool bDone; + s32 nStatus; + u64* pDL; + Cpu* pCPU; + + pCPU = SYSTEM_CPU(pRSP->pHost); + bDone = false; + + while (!bDone) { + pDL = pRSP->apDL[pRSP->iDL]; + switch (pRSP->eTypeUCode) { + case RUT_TURBO: + case RUT_SPRITE2D: + case RUT_FAST3D: + case RUT_F3DEX1: + case RUT_S2DEX1: + case RUT_L3DEX1: + nStatus = rspParseGBI_F3DEX1(pRSP, &pRSP->apDL[pRSP->iDL], &bDone); + break; + case RUT_ZSORT: + case RUT_F3DEX2: + case RUT_S2DEX2: + case RUT_L3DEX2: + nStatus = rspParseGBI_F3DEX2(pRSP, &pRSP->apDL[pRSP->iDL], &bDone); + break; + default: + return false; + } + + if (nStatus == 0) { + pRSP->apDL[pRSP->iDL] = pDL; + if (!rdpParseGBI(SYSTEM_RDP(pRSP->pHost), &pRSP->apDL[pRSP->iDL], pRSP->eTypeUCode)) { + if (!rspPopDL(pRSP)) { + bDone = true; + } + } + } + + if (nCount == -1) { + if (pCPU->nRetrace != pCPU->nRetraceUsed) { + break; + } + } else if (nCount != 0) { + if (--nCount == 0) { + break; + } + } + } + + if (pRSP->eTypeUCode == RUT_ZSORT) { + if (pRSP->nPass == 1) { + pRSP->nPass = 2; + } else { + pRSP->nPass = 1; + } + } else { + pRSP->nPass = 2; + } + + if (bDone) { + pRSP->nMode |= 8; + } + + if (pbDone != NULL) { + *pbDone = bDone; + } + + return true; +} +#endif #pragma GLOBAL_ASM("asm/non_matchings/rsp/rspPut8.s") @@ -476,8 +616,74 @@ static bool rspLoadMatrix(Rsp* pRSP, s32 nAddress, Mtx44 matrix) { #pragma GLOBAL_ASM("asm/non_matchings/rsp/rspEnableABI.s") -#pragma GLOBAL_ASM("asm/non_matchings/rsp/rspFrameComplete.s") +bool rspFrameComplete(Rsp* pRSP) { + if (pRSP->yield.bValid) { + OSReport(D_800EE27C); + } -#pragma GLOBAL_ASM("asm/non_matchings/rsp/rspUpdate.s") + pRSP->nMode |= 4; + return true; +} + +bool rspUpdate(Rsp* pRSP, RspUpdateMode eMode) { + RspTask* pTask; + bool bDone; + s32 nCount = 0; + Frame* pFrame = SYSTEM_FRAME(pRSP->pHost); + + if ((pRSP->nMode & 4) && (pRSP->nMode & 8)) { + if (pRSP->nMode & 0x10) { + gNoSwapBuffer = true; + pRSP->nMode |= 0x20; + } + if (!frameEnd(pFrame)) { + return false; + } + pRSP->nMode &= ~0xC; + } + + if (!(pRSP->nStatus & 1)) { + if (pRSP->nMode & 0x20) { + pRSP->nMode &= ~0x30; + pRSP->nStatus |= 0x201; + xlObjectEvent(pRSP->pHost, 0x1000, (void*)5); + xlObjectEvent(pRSP->pHost, 0x1000, (void*)10); + } else { + if (pRSP->nMode & 2) { + if (frameBeginOK(pFrame) && eMode == RUM_IDLE) { + pRSP->nMode &= ~0x2; + pRSP->nMode |= 0x10; + + pTask = (RspTask*)((u8*)pRSP->pDMEM + 0xFC0); + if (!rspParseGBI_Setup(pRSP, pTask)) { + return false; + } + } else { + return true; + } + } + + if (eMode == RUM_IDLE) { + nCount = -1; + } + + if (nCount != 0) { + if (rspParseGBI(pRSP, &bDone, nCount)) { + if (bDone) { + pRSP->nMode &= ~0x10; + pRSP->nStatus |= 0x201; + xlObjectEvent(pRSP->pHost, 0x1000, (void*)5); + xlObjectEvent(pRSP->pHost, 0x1000, (void*)10); + } + } else { + __cpuBreak(SYSTEM_CPU(pRSP->pHost)); + } + pRSP->nTickLast = OSGetTick(); + } + } + } + + return true; +} #pragma GLOBAL_ASM("asm/non_matchings/rsp/rspEvent.s") diff --git a/src/emulator/video.c b/src/emulator/video.c index 7e3671f..9108369 100644 --- a/src/emulator/video.c +++ b/src/emulator/video.c @@ -26,7 +26,7 @@ bool videoPut32(Video* pVideo, u32 nAddress, s32* pData) { case 0x4: pVideo->nAddress = *pData & 0xFFFFFF; pFrame = SYSTEM_FRAME(pVideo->pHost); - pBuffer = &pFrame->aBuffer[2]; + pBuffer = &pFrame->aBuffer[FBT_COLOR_SHOW]; if (!ramGetBuffer(SYSTEM_RAM(pVideo->pHost), &pRAM, pVideo->nAddress, NULL)) { return false;