diff --git a/include/rt64_extended_gbi.h b/include/rt64_extended_gbi.h index 452f224..928d820 100644 --- a/include/rt64_extended_gbi.h +++ b/include/rt64_extended_gbi.h @@ -72,7 +72,8 @@ #define G_EX_PUSHGEOMETRYMODE_V1 0x000029 #define G_EX_POPGEOMETRYMODE_V1 0x00002A #define G_EX_SETDITHERNOISESTRENGTH_V1 0x00002B -#define G_EX_MAX 0x00002C +#define G_EX_SETRDRAMEXTENDED_V1 0x00002C +#define G_EX_MAX 0x00002D #define G_EX_ORIGIN_NONE 0x800 #define G_EX_ORIGIN_LEFT 0x0 @@ -508,4 +509,10 @@ typedef union { PARAM((value) * 1024, 16, 0) \ ) +#define gEXSetRDRAMExtended(cmd, isExtended) \ + G_EX_COMMAND1(cmd, \ + PARAM(RT64_EXTENDED_OPCODE, 8, 24) | PARAM(G_EX_SETRDRAMEXTENDED_V1, 24, 0), \ + PARAM(isExtended, 1, 0) \ + ) + #endif // RT64_EXTENDED_GBI diff --git a/src/gbi/rt64_gbi_extended.cpp b/src/gbi/rt64_gbi_extended.cpp index 0526ce5..4d257fb 100644 --- a/src/gbi/rt64_gbi_extended.cpp +++ b/src/gbi/rt64_gbi_extended.cpp @@ -286,6 +286,11 @@ namespace RT64 { state->setDitherNoiseStrength(noiseStrength / 1024.0f); } + void setRDRAMExtendedV1(State *state, DisplayList **dl) { + const uint8_t extended = (*dl)->p1(0, 1); + state->setExtendedRDRAM(extended); + } + void noOpHook(State *state, DisplayList **dl) { uint32_t magicNumber = (*dl)->p0(0, 24); if (magicNumber == RT64_HOOK_MAGIC_NUMBER) { @@ -293,7 +298,7 @@ namespace RT64 { uint32_t hookOp = (*dl)->p1(28, 4); switch (hookOp) { case RT64_HOOK_OP_GETVERSION: { - const uint32_t rdramAddress = state->rsp->fromSegmented(hookValue); + const uint32_t rdramAddress = state->rsp->fromSegmentedMasked(hookValue); uint32_t *returnRDRAM = reinterpret_cast(state->fromRDRAM(rdramAddress)); *returnRDRAM = G_EX_VERSION; break; @@ -317,7 +322,7 @@ namespace RT64 { state->pushReturnAddress(*dl); } - const uint32_t rdramAddress = state->rsp->fromSegmented(hookValue); + const uint32_t rdramAddress = state->rsp->fromSegmentedMasked(hookValue); *dl = reinterpret_cast(state->fromRDRAM(rdramAddress)) - 1; break; } @@ -386,6 +391,7 @@ namespace RT64 { Map[G_EX_PUSHGEOMETRYMODE_V1] = &pushGeometryModeV1; Map[G_EX_POPGEOMETRYMODE_V1] = &popGeometryModeV1; Map[G_EX_SETDITHERNOISESTRENGTH_V1] = &setDitherNoiseStrengthV1; + Map[G_EX_SETRDRAMEXTENDED_V1] = &setRDRAMExtendedV1; MapInitialized = true; } } diff --git a/src/gbi/rt64_gbi_f3d.cpp b/src/gbi/rt64_gbi_f3d.cpp index e03dba0..7ae47a2 100644 --- a/src/gbi/rt64_gbi_f3d.cpp +++ b/src/gbi/rt64_gbi_f3d.cpp @@ -78,7 +78,7 @@ namespace RT64 { state->pushReturnAddress(*dl); } - const uint32_t rdramAddress = state->rsp->fromSegmented((*dl)->w1); + const uint32_t rdramAddress = state->rsp->fromSegmentedMasked((*dl)->w1); *dl = reinterpret_cast(state->fromRDRAM(rdramAddress)) - 1; } @@ -121,7 +121,7 @@ namespace RT64 { // TODO break; case G_MW_SEGMENT: - state->rsp->setSegment((*dl)->p0(10, 4), (*dl)->w1 & 0x00FFFFFF); + state->rsp->setSegment((*dl)->p0(10, 4), (*dl)->w1); break; case G_MW_FOG: state->rsp->setFog((int16_t)((*dl)->p1(16, 16)), (int16_t)((*dl)->p1(0, 16))); diff --git a/src/gbi/rt64_gbi_f3dex2.cpp b/src/gbi/rt64_gbi_f3dex2.cpp index b677246..a99bf36 100644 --- a/src/gbi/rt64_gbi_f3dex2.cpp +++ b/src/gbi/rt64_gbi_f3dex2.cpp @@ -77,7 +77,7 @@ namespace RT64 { state->rsp->setClipRatio((*dl)->w1); break; case G_MW_SEGMENT: - state->rsp->setSegment((*dl)->p0(2, 4), (*dl)->w1 & 0x00FFFFFF); + state->rsp->setSegment((*dl)->p0(2, 4), (*dl)->w1); break; case G_MW_FOG: state->rsp->setFog((int16_t)((*dl)->p1(16, 16)), (int16_t)((*dl)->p1(0, 16))); diff --git a/src/gbi/rt64_gbi_s2dex.cpp b/src/gbi/rt64_gbi_s2dex.cpp index 3501b59..21732cd 100644 --- a/src/gbi/rt64_gbi_s2dex.cpp +++ b/src/gbi/rt64_gbi_s2dex.cpp @@ -133,7 +133,7 @@ namespace RT64 { RDP *rdp = state->rdp.get(); RSP *rsp = state->rsp.get(); - const uint32_t rdramAddress = state->rsp->fromSegmented((*dl)->w1); + const uint32_t rdramAddress = state->rsp->fromSegmentedMasked((*dl)->w1); // TODO load this into the S2D struct buffer for a more accurate implementation in case there's ever command state bleed. const uObjBg *bgObject = reinterpret_cast(state->fromRDRAM(rdramAddress)); const uObjBg_t &bg = bgObject->bg; @@ -398,7 +398,7 @@ namespace RT64 { RDP *rdp = state->rdp.get(); RSP* rsp = state->rsp.get(); - const uint32_t rdramAddress = state->rsp->fromSegmented((*dl)->w1); + const uint32_t rdramAddress = state->rsp->fromSegmentedMasked((*dl)->w1); // TODO load this into the S2D struct buffer for a more accurate implementation in case there's ever command state bleed. const uObjBg *bgObject = reinterpret_cast(state->fromRDRAM(rdramAddress)); const uObjBg_t &bg = bgObject->bg; @@ -451,7 +451,7 @@ namespace RT64 { void readS2DStruct(State *state, uint32_t ptr, uint32_t loadSize) { // Convert the segmented obj pointer - uint32_t rdramAddress = state->rsp->fromSegmented(ptr); + uint32_t rdramAddress = state->rsp->fromSegmentedMasked(ptr); // Mask the address as the RSP DMA hardware would rdramAddress &= RSP_DMA_MASK; // Truncate the load size as the ucode does diff --git a/src/hle/rt64_rdp.cpp b/src/hle/rt64_rdp.cpp index b7d450b..966caf5 100644 --- a/src/hle/rt64_rdp.cpp +++ b/src/hle/rt64_rdp.cpp @@ -222,10 +222,17 @@ namespace RT64 { } }; + uint32_t RDP::maskAddress(uint32_t address) { + if (state->extended.extendRDRAM && ((address & 0xF0000000) == 0x80000000)) { + return address - 0x80000000; + } + return address & RDP_ADDRESS_MASK; + } + void RDP::setColorImage(uint8_t fmt, uint8_t siz, uint16_t width, uint32_t address) { // Make sure the new color image is actually different. Some games will set the color image // multiple times despite setting the exact same parameters. - const uint32_t newAddress = address & RDP_ADDRESS_MASK; + const uint32_t newAddress = maskAddress(address); if ((colorImage.fmt != fmt) || (colorImage.siz != siz) || (colorImage.width != width) || @@ -244,7 +251,7 @@ namespace RT64 { } void RDP::setDepthImage(uint32_t address) { - const uint32_t newAddress = address & RDP_ADDRESS_MASK; + const uint32_t newAddress = maskAddress(address); if (depthImage.address != newAddress) { depthImage.address = newAddress; depthImage.changed = true; @@ -259,7 +266,7 @@ namespace RT64 { texture.fmt = fmt; texture.siz = siz; texture.width = width; - texture.address = address & RDP_ADDRESS_MASK; + texture.address = maskAddress(address); state->updateDrawStatusAttribute(DrawAttribute::Texture); # ifdef LOG_TEXTURE_IMAGE_METHODS diff --git a/src/hle/rt64_rdp.h b/src/hle/rt64_rdp.h index 7bb639d..cd518b7 100644 --- a/src/hle/rt64_rdp.h +++ b/src/hle/rt64_rdp.h @@ -142,6 +142,7 @@ namespace RT64 { void checkFramebufferOverlap(uint32_t tmemStart, uint32_t tmemWords, uint32_t tmemMask, uint32_t addressStart, uint32_t addressEnd, uint32_t tileWidth, uint32_t tileHeight, bool RGBA32, bool makeTileCopy); void checkImageOverlap(uint32_t addressStart, uint32_t addressEnd); int32_t movedFromOrigin(int32_t x, uint16_t ori); + uint32_t maskAddress(uint32_t address); void setColorImage(uint8_t fmt, uint8_t siz, uint16_t width, uint32_t address); void setDepthImage(uint32_t address); void setTextureImage(uint8_t fmt, uint8_t siz, uint16_t width, uint32_t address); diff --git a/src/hle/rt64_rsp.cpp b/src/hle/rt64_rsp.cpp index d075fe8..871e1c1 100644 --- a/src/hle/rt64_rsp.cpp +++ b/src/hle/rt64_rsp.cpp @@ -90,17 +90,35 @@ namespace RT64 { clearExtended(); } + // Masks addresses as the RSP DMA hardware would. + uint32_t RSP::maskPhysicalAddress(uint32_t address) { + if (state->extended.extendRDRAM && ((address & 0xF0000000) == 0x80000000)) { + return address - 0x80000000; + } + return address & 0x00FFFFF8; + } + + // Performs a lookup in the segment table to convert the given address. uint32_t RSP::fromSegmented(uint32_t segAddress) { + if (state->extended.extendRDRAM && ((segAddress & 0xF0000000) == 0x80000000)) { + return segAddress; + } return segments[((segAddress) >> 24) & 0x0F] + ((segAddress) & 0x00FFFFFF); } + // Converts the given segmented address and then applies the RSP DMA physical address mask. + // Used in cases where the RSP performs a DMA with a segmented address as the input. + uint32_t RSP::fromSegmentedMasked(uint32_t segAddress) { + return maskPhysicalAddress(fromSegmented(segAddress)); + } + void RSP::setSegment(uint32_t seg, uint32_t address) { assert(seg < RSP_MAX_SEGMENTS); segments[seg] = address; } void RSP::matrix(uint32_t address, uint8_t params) { - const uint32_t rdramAddress = fromSegmented(address); + const uint32_t rdramAddress = fromSegmentedMasked(address); const FixedMatrix *fixedMatrix = reinterpret_cast(state->fromRDRAM(rdramAddress)); const hlslpp::float4x4 floatMatrix = fixedMatrix->toMatrix4x4(); @@ -258,7 +276,7 @@ namespace RT64 { RT64_LOG_PRINTF("RSP::forceMatrix(0x%08X)", address); # endif - const uint32_t rdramAddress = fromSegmented(address); + const uint32_t rdramAddress = fromSegmentedMasked(address); const FixedMatrix *fixedMatrix = reinterpret_cast(state->fromRDRAM(rdramAddress)); modelViewProjMatrix = fixedMatrix->toMatrix4x4(); modelViewProjInserted = true; @@ -294,7 +312,7 @@ namespace RT64 { return; } - const uint32_t rdramAddress = fromSegmented(address); + const uint32_t rdramAddress = fromSegmentedMasked(address); const Vertex *dlVerts = reinterpret_cast(state->fromRDRAM(rdramAddress)); memcpy(&vertices[dstIndex], dlVerts, sizeof(Vertex) * vtxCount); setVertexCommon(dstIndex, dstIndex + vtxCount); @@ -306,7 +324,7 @@ namespace RT64 { return; } - const uint32_t rdramAddress = fromSegmented(address); + const uint32_t rdramAddress = fromSegmentedMasked(address); const VertexPD *dlVerts = reinterpret_cast(state->fromRDRAM(rdramAddress)); for (uint32_t i = 0; i < vtxCount; i++) { Vertex &dst = vertices[dstIndex + i]; @@ -334,7 +352,7 @@ namespace RT64 { const int workloadCursor = state->ext.workloadQueue->writeCursor; Workload &workload = state->ext.workloadQueue->workloads[workloadCursor]; - const uint32_t rdramAddress = fromSegmented(address); + const uint32_t rdramAddress = fromSegmentedMasked(address); const VertexEXV1 *dlVerts = reinterpret_cast(state->fromRDRAM(rdramAddress)); auto &velShorts = workload.drawData.velShorts; for (uint32_t i = 0; i < vtxCount; i++) { @@ -349,7 +367,7 @@ namespace RT64 { } void RSP::setVertexColorPD(uint32_t address) { - vertexColorPDAddress = fromSegmented(address); + vertexColorPDAddress = fromSegmentedMasked(address); } Projection::Type RSP::getCurrentProjectionType() const { @@ -720,7 +738,7 @@ namespace RT64 { const float screenZ = workload.drawData.posScreen[globalIndex][2] * DepthRange; const float zValueFloat = zValue / 65536.0f; if (forceBranch || (screenZ < zValueFloat)) { - const uint32_t rdramAddress = fromSegmented(branchDl); + const uint32_t rdramAddress = fromSegmentedMasked(branchDl); *dl = reinterpret_cast(state->fromRDRAM(rdramAddress)) - 1; } } @@ -732,7 +750,7 @@ namespace RT64 { const uint32_t globalIndex = indices[vtxIndex]; const float posW = workload.drawData.posTransformed[globalIndex][3]; if (forceBranch || (posW < static_cast(wValue))) { - const uint32_t rdramAddress = fromSegmented(branchDl); + const uint32_t rdramAddress = fromSegmentedMasked(branchDl); *dl = reinterpret_cast(state->fromRDRAM(rdramAddress)) - 1; } } @@ -778,7 +796,7 @@ namespace RT64 { } void RSP::setViewport(uint32_t address, uint16_t ori, int16_t offx, int16_t offy) { - const uint32_t rdramAddress = fromSegmented(address); + const uint32_t rdramAddress = fromSegmentedMasked(address); const Vp_t *vp = reinterpret_cast(state->fromRDRAM(rdramAddress)); interop::RSPViewport &viewport = viewportStack[viewportStackSize - 1]; viewport.scale.x = float(vp->vscale[1]) / 4.0f; @@ -807,7 +825,7 @@ namespace RT64 { void RSP::setLight(uint8_t index, uint32_t address) { assert((index >= 0) && (index <= RSP_MAX_LIGHTS)); - const uint32_t rdramAddress = fromSegmented(address); + const uint32_t rdramAddress = fromSegmentedMasked(address); const uint8_t *data = reinterpret_cast(state->fromRDRAM(rdramAddress)); memcpy(&lights[index], data, sizeof(Light)); lightsChanged = true; @@ -836,7 +854,7 @@ namespace RT64 { void RSP::setLookAt(uint8_t index, uint32_t address) { assert(index < 2); - const uint32_t rdramAddress = fromSegmented(address); + const uint32_t rdramAddress = fromSegmentedMasked(address); const DirLight *dirLight = reinterpret_cast(state->fromRDRAM(rdramAddress)); auto &dstLookAt = (index == 1) ? lookAt.y : lookAt.x; if ((dirLight->dirx != 0) || (dirLight->diry != 0) || (dirLight->dirz != 0)) { @@ -1077,7 +1095,7 @@ namespace RT64 { }; if (idIsAddress && editGroup) { - const uint32_t rdramAddress = fromSegmented(id); + const uint32_t rdramAddress = fromSegmentedMasked(id); const int workloadCursor = state->ext.workloadQueue->writeCursor; Workload &workload = state->ext.workloadQueue->workloads[workloadCursor]; diff --git a/src/hle/rt64_rsp.h b/src/hle/rt64_rsp.h index 86a9340..f6563ab 100644 --- a/src/hle/rt64_rsp.h +++ b/src/hle/rt64_rsp.h @@ -221,7 +221,9 @@ namespace RT64 { void reset(); Projection::Type getCurrentProjectionType() const; void addCurrentProjection(Projection::Type type); + uint32_t maskPhysicalAddress(uint32_t address); uint32_t fromSegmented(uint32_t segAddress); + uint32_t fromSegmentedMasked(uint32_t segAddress); void setSegment(uint32_t seg, uint32_t address); void matrix(uint32_t address, uint8_t params); void popMatrix(uint32_t count); @@ -276,6 +278,7 @@ namespace RT64 { void matrixId(uint32_t id, bool push, bool proj, bool decompose, uint8_t pos, uint8_t rot, uint8_t scale, uint8_t skew, uint8_t persp, uint8_t vert, uint8_t tile, uint8_t order, uint8_t editable, bool idIsAddress, bool editGroup); void popMatrixId(uint8_t count, bool proj); void forceBranch(bool force); + void extendRDRAM(bool isExtended); void clearExtended(); void setGBI(GBI *gbi); }; diff --git a/src/hle/rt64_state.cpp b/src/hle/rt64_state.cpp index 63502b7..2b15096 100644 --- a/src/hle/rt64_state.cpp +++ b/src/hle/rt64_state.cpp @@ -2369,6 +2369,10 @@ namespace RT64 { void State::setDitherNoiseStrength(float noiseStrength) { extended.ditherNoiseStrength = noiseStrength; } + + void State::setExtendedRDRAM(bool isExtended) { + extended.extendRDRAM = isExtended; + } uint8_t *State::fromRDRAM(uint32_t rdramAddress) const { return &RDRAM[rdramAddress]; diff --git a/src/hle/rt64_state.h b/src/hle/rt64_state.h index 6ea5f79..8976d4c 100644 --- a/src/hle/rt64_state.h +++ b/src/hle/rt64_state.h @@ -125,6 +125,7 @@ namespace RT64 { uint8_t renderToRAM = UINT8_MAX; bool vertexTestZActive = false; float ditherNoiseStrength = 1.0f; + bool extendRDRAM = false; }; Extended extended; @@ -157,6 +158,7 @@ namespace RT64 { void setRefreshRate(uint16_t refreshRate); void setRenderToRAM(uint8_t renderToRAM); void setDitherNoiseStrength(float noiseStrength); + void setExtendedRDRAM(bool isExtended); uint8_t *fromRDRAM(uint32_t rdramAddress) const; void dumpRDRAM(const std::string &path); void enableExtendedGBI(uint8_t opCode);