Add egbi command to bypass the segment table for K0 CPU addresses to allow extending rdram (#54)

* Add egbi command to bypass the segment table for K0 CPU addresses to allow extending rdram

* Fix capitalization of RDRAM for consistency
This commit is contained in:
Wiseguy 2024-07-05 21:13:53 -04:00 committed by GitHub
parent 5c1562d66a
commit eb981eb47b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 72 additions and 24 deletions

View File

@ -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

View File

@ -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<uint32_t *>(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<DisplayList *>(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;
}
}

View File

@ -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<DisplayList *>(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)));

View File

@ -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)));

View File

@ -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<const uObjBg *>(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<const uObjBg *>(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

View File

@ -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

View File

@ -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);

View File

@ -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<FixedMatrix *>(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<FixedMatrix *>(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<const Vertex *>(state->fromRDRAM(rdramAddress));
memcpy(&vertices[dstIndex], dlVerts, sizeof(Vertex) * vtxCount);
setVertexCommon<true>(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<const VertexPD *>(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<const VertexEXV1 *>(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<DisplayList *>(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<float>(wValue))) {
const uint32_t rdramAddress = fromSegmented(branchDl);
const uint32_t rdramAddress = fromSegmentedMasked(branchDl);
*dl = reinterpret_cast<DisplayList *>(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<const Vp_t *>(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<const uint8_t *>(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<const DirLight *>(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];

View File

@ -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);
};

View File

@ -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];

View File

@ -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);