mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 18:25:35 -04:00
110 lines
4.5 KiB
C++
110 lines
4.5 KiB
C++
#include "pgxp.h"
|
|
#include "pgxp_hooks.h"
|
|
#include <atomic>
|
|
#include <cstdlib>
|
|
#include <thread>
|
|
#define CHECK(c) do { if (!(c)) std::abort(); } while (0)
|
|
extern "C" int gte_geometry_correction_lookup(uint32_t, int32_t*, int32_t*) { return 0; }
|
|
extern "C" int gte_geometry_correction_lookup_probe(uint32_t, int32_t*, int32_t*) { return 0; }
|
|
extern "C" int psx_mod_gpu_dma_memory_contains(uint32_t, uint32_t) { return 0; }
|
|
static constexpr uint32_t address = 0x80001000, packed = 0x000C0008;
|
|
static void seed(int32_t x, uint32_t at = address) {
|
|
pgxp_gte_push_sxy(x, 12 << 16, 300, packed);
|
|
pgxp_store_gte_reg(at, 15);
|
|
}
|
|
static void check(int32_t x, uint32_t at = address) {
|
|
int32_t actual_x, y;
|
|
uint16_t z;
|
|
CHECK(pgxp_load_precise_word(at, packed, &actual_x, &y, &z));
|
|
CHECK(actual_x == x && y == 12 << 16 && z == 300);
|
|
}
|
|
int main() {
|
|
pgxp_set_enabled(1);
|
|
pgxp_set_cpu_mode(1);
|
|
seed(8 << 16);
|
|
PGXPExecutionSnapshot *snapshot = nullptr;
|
|
std::thread prepare([&] { snapshot = pgxp_execution_snapshot_create(); });
|
|
prepare.join();
|
|
CHECK(snapshot && pgxp_execution_snapshot_capture(snapshot));
|
|
std::atomic<int> phase{0};
|
|
std::thread worker([&] {
|
|
CHECK(pgxp_execution_snapshot_bind(snapshot));
|
|
check(8 << 16);
|
|
seed((8 << 16) + 32768);
|
|
check((8 << 16) + 32768);
|
|
phase.store(1, std::memory_order_release);
|
|
while (phase.load(std::memory_order_acquire) != 2) { }
|
|
check((8 << 16) + 32768);
|
|
pgxp_execution_snapshot_unbind();
|
|
});
|
|
while (phase.load(std::memory_order_acquire) != 1) { }
|
|
check(8 << 16);
|
|
seed((8 << 16) + 16384);
|
|
phase.store(2, std::memory_order_release);
|
|
worker.join();
|
|
check((8 << 16) + 16384);
|
|
CHECK(pgxp_execution_snapshot_capture(snapshot));
|
|
std::thread next([&] {
|
|
CHECK(pgxp_execution_snapshot_bind(snapshot));
|
|
check((8 << 16) + 16384);
|
|
seed((8 << 16) + 49152);
|
|
pgxp_execution_snapshot_unbind();
|
|
});
|
|
next.join();
|
|
/* Re-publication must undo worker writes even if live RAM shadows have
|
|
* not changed since the preceding capture. */
|
|
CHECK(pgxp_execution_snapshot_capture(snapshot));
|
|
std::thread unchanged([&] {
|
|
CHECK(pgxp_execution_snapshot_bind(snapshot));
|
|
check((8 << 16) + 16384);
|
|
pgxp_execution_snapshot_unbind();
|
|
});
|
|
unchanged.join();
|
|
/* Independent consumers retain their publication even after several
|
|
* source stores to the same page in one epoch. */
|
|
PGXPExecutionSnapshot *other = pgxp_execution_snapshot_create();
|
|
CHECK(other);
|
|
seed((8 << 16) + 32768);
|
|
CHECK(pgxp_execution_snapshot_capture(snapshot));
|
|
seed((8 << 16) + 49152);
|
|
CHECK(pgxp_execution_snapshot_capture(other));
|
|
std::thread consumers([&] {
|
|
CHECK(pgxp_execution_snapshot_bind(snapshot)); check((8 << 16) + 32768);
|
|
pgxp_execution_snapshot_unbind();
|
|
CHECK(pgxp_execution_snapshot_bind(other)); check((8 << 16) + 49152);
|
|
pgxp_execution_snapshot_unbind();
|
|
});
|
|
consumers.join();
|
|
/* A load that invalidates precision really does mutate a RAM shadow;
|
|
* unlike a matching read, that mutation must reach the next publication. */
|
|
psx_pgxp_load(nullptr, (0x23u << 26) | (2u << 16), address, packed ^ 1u);
|
|
CHECK(pgxp_execution_snapshot_capture(snapshot));
|
|
std::thread invalidated([&] {
|
|
CHECK(pgxp_execution_snapshot_bind(snapshot));
|
|
int32_t x, y; uint16_t z;
|
|
CHECK(!pgxp_load_precise_word(address, packed ^ 1u, &x, &y, &z));
|
|
pgxp_execution_snapshot_unbind();
|
|
});
|
|
invalidated.join();
|
|
/* Adjacent words across a publication-page boundary remain independent,
|
|
* including worker writes to a page the source has not changed. */
|
|
seed(8 << 16, address + 1020); seed(9 << 16, address + 1024);
|
|
CHECK(pgxp_execution_snapshot_capture(snapshot));
|
|
std::thread boundary([&] {
|
|
CHECK(pgxp_execution_snapshot_bind(snapshot));
|
|
check(8 << 16, address + 1020); check(9 << 16, address + 1024);
|
|
seed(10 << 16, address + 1020); seed(11 << 16, address + 1024);
|
|
pgxp_execution_snapshot_unbind();
|
|
}); boundary.join();
|
|
seed(12 << 16, address + 1024);
|
|
CHECK(pgxp_execution_snapshot_capture(snapshot));
|
|
std::thread recapture([&] {
|
|
CHECK(pgxp_execution_snapshot_bind(snapshot));
|
|
check(8 << 16, address + 1020); check(12 << 16, address + 1024);
|
|
pgxp_execution_snapshot_unbind();
|
|
}); recapture.join();
|
|
pgxp_execution_snapshot_destroy(other);
|
|
pgxp_execution_snapshot_destroy(snapshot);
|
|
return 0;
|
|
}
|