mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-10-03 19:08:24 -04:00
Feature vu1 cache (#158)
* feat: explode vu1 in files feat: added way more tests for vu1 * feat: added VU1 cache
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
#include "runtime/ps2_memory.h"
|
||||
#include "runtime/ps2_gs_gpu.h"
|
||||
#include "runtime/ps2_gs_psmct32.h"
|
||||
#include "runtime/ps2_vu1.h"
|
||||
#include "ps2_runtime.h"
|
||||
#include "ps2_runtime_macros.h"
|
||||
#include "Stubs/DMA.h"
|
||||
@@ -156,17 +155,6 @@ namespace
|
||||
appendU64(packet, 0u);
|
||||
}
|
||||
|
||||
uint32_t makeVuLowerSpecial(uint8_t specialOp, uint8_t is, uint8_t it = 0u, uint8_t id = 0u, uint8_t dest = 0u)
|
||||
{
|
||||
return (0x40u << 25) |
|
||||
(static_cast<uint32_t>(dest & 0xFu) << 21) |
|
||||
(static_cast<uint32_t>(it & 0x1Fu) << 16) |
|
||||
(static_cast<uint32_t>(is & 0x1Fu) << 11) |
|
||||
(static_cast<uint32_t>(id & 0x1Fu) << 6) |
|
||||
(static_cast<uint32_t>(specialOp & 0x7Cu) << 4) |
|
||||
static_cast<uint32_t>(specialOp & 0x3u) |
|
||||
0x3Cu;
|
||||
}
|
||||
}
|
||||
|
||||
void register_ps2_memory_tests()
|
||||
@@ -1732,72 +1720,6 @@ void register_ps2_memory_tests()
|
||||
t.Equals(mem.readIORegister(kDstadr), 0u, "sceDmaReset should clear D_STADR");
|
||||
});
|
||||
|
||||
tc.Run("VU1 XGKICK wraps packet payload across VU1 memory boundary", [](TestCase &t)
|
||||
{
|
||||
PS2Memory mem;
|
||||
t.IsTrue(mem.initialize(), "PS2Memory initialize should succeed");
|
||||
|
||||
std::vector<std::vector<uint8_t>> captured;
|
||||
mem.setGifPacketCallback([&](const uint8_t *data, uint32_t sizeBytes)
|
||||
{
|
||||
captured.emplace_back(data, data + sizeBytes);
|
||||
});
|
||||
|
||||
std::vector<uint8_t> vram(PS2_GS_VRAM_SIZE, 0u);
|
||||
GS gs;
|
||||
gs.init(vram.data(), static_cast<uint32_t>(vram.size()), nullptr);
|
||||
|
||||
uint8_t *vuCode = mem.getVU1Code();
|
||||
uint8_t *vuData = mem.getVU1Data();
|
||||
std::memset(vuCode, 0, PS2_VU1_CODE_SIZE);
|
||||
std::memset(vuData, 0, PS2_VU1_DATA_SIZE);
|
||||
|
||||
constexpr uint32_t kLastQw = (PS2_VU1_DATA_SIZE / 16u) - 1u;
|
||||
const uint32_t tagOffset = kLastQw * 16u;
|
||||
|
||||
const uint64_t imageTag = makeGifTag(1u, GIF_FMT_IMAGE, 0u, true);
|
||||
std::memcpy(vuData + tagOffset, &imageTag, sizeof(imageTag));
|
||||
|
||||
for (uint32_t i = 0; i < 16u; ++i)
|
||||
{
|
||||
vuData[i] = static_cast<uint8_t>(0xC0u + i);
|
||||
}
|
||||
|
||||
const uint32_t lower = makeVuLowerSpecial(0x6Cu, 1u);
|
||||
std::memcpy(vuCode + 0u, &lower, sizeof(lower));
|
||||
const uint32_t upper = 0u;
|
||||
std::memcpy(vuCode + 4u, &upper, sizeof(upper));
|
||||
|
||||
VU1Interpreter vu1;
|
||||
vu1.state().vi[1] = static_cast<int32_t>(kLastQw);
|
||||
vu1.execute(vuCode,
|
||||
PS2_VU1_CODE_SIZE,
|
||||
vuData,
|
||||
PS2_VU1_DATA_SIZE,
|
||||
gs,
|
||||
&mem,
|
||||
0u,
|
||||
0u,
|
||||
0u,
|
||||
1u);
|
||||
|
||||
t.Equals(captured.size(), static_cast<size_t>(1u), "XGKICK should emit one wrapped GIF packet");
|
||||
if (!captured.empty())
|
||||
{
|
||||
t.Equals(captured[0].size(), static_cast<size_t>(32u), "wrapped packet should include tag plus one qword payload");
|
||||
bool payloadOk = true;
|
||||
for (uint32_t i = 0; i < 16u; ++i)
|
||||
{
|
||||
if (captured[0].size() < 32u || captured[0][16u + i] != static_cast<uint8_t>(0xC0u + i))
|
||||
{
|
||||
payloadOk = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
t.IsTrue(payloadOk, "wrapped payload should be copied from start of VU1 memory");
|
||||
}
|
||||
});
|
||||
|
||||
tc.Run("VIF1 DMA DIRECT image packet reaches GS through arbiter", [](TestCase &t)
|
||||
{
|
||||
PS2Memory mem;
|
||||
@@ -1919,85 +1841,6 @@ void register_ps2_memory_tests()
|
||||
t.IsTrue(imageOk, "raw qwords after a DIRECT image tag should continue the PATH2 image upload");
|
||||
});
|
||||
|
||||
tc.Run("VIF MSCAL callback can execute XGKICK and update GS VRAM", [](TestCase &t)
|
||||
{
|
||||
PS2Memory mem;
|
||||
t.IsTrue(mem.initialize(), "PS2Memory initialize should succeed");
|
||||
|
||||
GS gs;
|
||||
gs.init(mem.getGSVRAM(), static_cast<uint32_t>(PS2_GS_VRAM_SIZE), &mem.gs());
|
||||
GifArbiter arbiter([&](const uint8_t *data, uint32_t sizeBytes)
|
||||
{
|
||||
gs.processGIFPacket(data, sizeBytes);
|
||||
});
|
||||
mem.setGifArbiter(&arbiter);
|
||||
|
||||
const uint64_t bitblt =
|
||||
(static_cast<uint64_t>(0u) << 0) |
|
||||
(static_cast<uint64_t>(1u) << 16) |
|
||||
(static_cast<uint64_t>(0u) << 24) |
|
||||
(static_cast<uint64_t>(0u) << 32) |
|
||||
(static_cast<uint64_t>(1u) << 48) |
|
||||
(static_cast<uint64_t>(0u) << 56);
|
||||
gs.writeRegister(GS_REG_BITBLTBUF, bitblt);
|
||||
gs.writeRegister(GS_REG_TRXPOS, 0ull);
|
||||
gs.writeRegister(GS_REG_TRXREG, (4ull << 0) | (1ull << 32));
|
||||
gs.writeRegister(GS_REG_TRXDIR, 0ull);
|
||||
|
||||
uint8_t *vuCode = mem.getVU1Code();
|
||||
uint8_t *vuData = mem.getVU1Data();
|
||||
std::memset(vuCode, 0, PS2_VU1_CODE_SIZE);
|
||||
std::memset(vuData, 0, PS2_VU1_DATA_SIZE);
|
||||
|
||||
const uint32_t lower = makeVuLowerSpecial(0x6Cu, 0u);
|
||||
std::memcpy(vuCode + 0u, &lower, sizeof(lower));
|
||||
const uint32_t upper = 0u;
|
||||
std::memcpy(vuCode + 4u, &upper, sizeof(upper));
|
||||
|
||||
const uint64_t gifTag = makeGifTag(1u, GIF_FMT_IMAGE, 0u, true);
|
||||
std::memcpy(vuData + 0u, &gifTag, sizeof(gifTag));
|
||||
const uint64_t tagHi = 0u;
|
||||
std::memcpy(vuData + 8u, &tagHi, sizeof(tagHi));
|
||||
for (uint32_t i = 0; i < 16u; ++i)
|
||||
{
|
||||
vuData[16u + i] = static_cast<uint8_t>(0x90u + i);
|
||||
}
|
||||
|
||||
VU1Interpreter vu1;
|
||||
mem.setVu1MscalCallback([&](uint32_t startPC, uint32_t top, uint32_t itop)
|
||||
{
|
||||
vu1.execute(vuCode,
|
||||
PS2_VU1_CODE_SIZE,
|
||||
vuData,
|
||||
PS2_VU1_DATA_SIZE,
|
||||
gs,
|
||||
&mem,
|
||||
startPC,
|
||||
top,
|
||||
itop,
|
||||
1u);
|
||||
});
|
||||
|
||||
const uint32_t mscalCmd = makeVifCmd(0x14u, 0u, 0u);
|
||||
mem.processVIF1Data(reinterpret_cast<const uint8_t *>(&mscalCmd), sizeof(mscalCmd));
|
||||
|
||||
const uint8_t *vramOut = mem.getGSVRAM();
|
||||
bool imageOk = true;
|
||||
for (uint32_t x = 0; x < 4u && imageOk; ++x)
|
||||
{
|
||||
const uint32_t off = GSPSMCT32::addrPSMCT32(0u, 1u, x, 0u);
|
||||
for (uint32_t c = 0; c < 4u; ++c)
|
||||
{
|
||||
if (vramOut[off + c] != static_cast<uint8_t>(0x90u + x * 4u + c))
|
||||
{
|
||||
imageOk = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
t.IsTrue(imageOk, "MSCAL-triggered XGKICK should route PATH1 packet into GS VRAM");
|
||||
});
|
||||
|
||||
tc.Run("unaligned accesses throw", [](TestCase &t)
|
||||
{
|
||||
PS2Memory mem;
|
||||
|
||||
Reference in New Issue
Block a user