mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-27 01:03:31 -04:00
8c8a97af65
* feat: added ffmepg as dependency * feat: wip decoder video * feat: some perf and cleanup * feat: added generic MPEG stream notification * feat: CMakeLists.txt in ps2xStudio to configure SDL2 build options for static linking. fix: fix ffmpeg setup for linux fix: now MPEG decoder now identify that movie has ended and can play again anytime feat: better audio stub to not block games * feat: fix expansion test * feat: foo * a * feat: finally added a helper to to prevent thread starvation * feat: added basic vu0 code execution * feat: added yield Guest Execution After Wake to prevent deadlock * feat: added options on cmake for logs feat: better input for keyboard pad * feat: small corrections like top and itop vu branches etc * feat: changes * feat: working feature * feat: fatal frame iop * feat: test fix feat: z buffer fix * fix: gix GsPutIMR IMR * feat: added rl imgui * feat: added helper to get snapshot * feat: added debug panel consuming snapshots * feat: added pad snapshot feat: added RCP debug events * feat: final cleanup from old code * feat: added EE timer counter feat: applyed sound driver for Lotr feat: better check for sound driver compat layout feat: enquee and cosumed DMa cause feat: added Pad execCMd feat: update GS vsync signal flag feat: custom IOPs for LotR * feat: small cleanups * fix: fix wrong import
483 lines
23 KiB
C++
483 lines
23 KiB
C++
#include "MiniTest.h"
|
|
#include "ps2_stubs.h"
|
|
#include "ps2_syscalls.h"
|
|
#include "Stubs/Pad.h"
|
|
|
|
#include <vector>
|
|
#include <cstdint>
|
|
#include <string>
|
|
|
|
|
|
namespace
|
|
{
|
|
constexpr uint32_t kPadDataAddr = 0x1000;
|
|
|
|
constexpr uint16_t kPadBtnSelect = 1u << 0;
|
|
constexpr uint16_t kPadBtnL3 = 1u << 1;
|
|
constexpr uint16_t kPadBtnR3 = 1u << 2;
|
|
constexpr uint16_t kPadBtnStart = 1u << 3;
|
|
constexpr uint16_t kPadBtnUp = 1u << 4;
|
|
constexpr uint16_t kPadBtnRight = 1u << 5;
|
|
constexpr uint16_t kPadBtnDown = 1u << 6;
|
|
constexpr uint16_t kPadBtnLeft = 1u << 7;
|
|
constexpr uint16_t kPadBtnL2 = 1u << 8;
|
|
constexpr uint16_t kPadBtnR2 = 1u << 9;
|
|
constexpr uint16_t kPadBtnL1 = 1u << 10;
|
|
constexpr uint16_t kPadBtnR1 = 1u << 11;
|
|
constexpr uint16_t kPadBtnTriangle = 1u << 12;
|
|
constexpr uint16_t kPadBtnCircle = 1u << 13;
|
|
constexpr uint16_t kPadBtnCross = 1u << 14;
|
|
constexpr uint16_t kPadBtnSquare = 1u << 15;
|
|
|
|
void setRegU32(R5900Context &ctx, int reg, uint32_t value)
|
|
{
|
|
ctx.r[reg] = _mm_set_epi64x(0, static_cast<int64_t>(value));
|
|
}
|
|
|
|
void openPadPort(R5900Context &ctx, std::vector<uint8_t> &rdram, uint32_t port = 0, uint32_t slot = 0)
|
|
{
|
|
setRegU32(ctx, 4, port);
|
|
setRegU32(ctx, 5, slot);
|
|
setRegU32(ctx, 6, kPadDataAddr + 0x200u);
|
|
ps2_stubs::scePadPortOpen(rdram.data(), &ctx, nullptr);
|
|
}
|
|
|
|
void closePadPort(R5900Context &ctx, std::vector<uint8_t> &rdram, uint32_t port = 0, uint32_t slot = 0)
|
|
{
|
|
setRegU32(ctx, 4, port);
|
|
setRegU32(ctx, 5, slot);
|
|
ps2_stubs::scePadPortClose(rdram.data(), &ctx, nullptr);
|
|
}
|
|
|
|
void runPadRead(R5900Context &ctx, std::vector<uint8_t> &rdram)
|
|
{
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
setRegU32(ctx, 6, kPadDataAddr); // a2
|
|
ps2_stubs::scePadRead(rdram.data(), &ctx, nullptr);
|
|
}
|
|
|
|
uint16_t readButtons(const std::vector<uint8_t> &rdram)
|
|
{
|
|
const uint8_t *data = rdram.data() + kPadDataAddr;
|
|
return static_cast<uint16_t>(data[2] | (data[3] << 8));
|
|
}
|
|
}
|
|
|
|
void register_pad_input_tests()
|
|
{
|
|
MiniTest::Case("PadInput", [](TestCase &tc)
|
|
{
|
|
tc.Run("scePadRead uses override state", [](TestCase &t)
|
|
{
|
|
std::vector<uint8_t> rdram(PS2_RAM_SIZE, 0);
|
|
R5900Context ctx;
|
|
|
|
ps2_stubs::scePadInit(rdram.data(), &ctx, nullptr);
|
|
openPadPort(ctx, rdram);
|
|
|
|
const uint16_t buttons = static_cast<uint16_t>(0xFFFFu & ~kPadBtnCross & ~kPadBtnStart);
|
|
ps2_stubs::setPadOverrideState(buttons, 0x00, 0xFF, 0x10, 0xEE);
|
|
|
|
runPadRead(ctx, rdram);
|
|
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadRead should return 1");
|
|
t.Equals(readButtons(rdram), buttons, "button bitmask should match override state");
|
|
const uint8_t *data = rdram.data() + kPadDataAddr;
|
|
t.Equals(data[4], static_cast<uint8_t>(0x10), "rx should match override");
|
|
t.Equals(data[5], static_cast<uint8_t>(0xEE), "ry should match override");
|
|
t.Equals(data[6], static_cast<uint8_t>(0x00), "lx should match override");
|
|
t.Equals(data[7], static_cast<uint8_t>(0xFF), "ly should match override");
|
|
|
|
ps2_stubs::clearPadOverrideState();
|
|
closePadPort(ctx, rdram);
|
|
});
|
|
|
|
tc.Run("scePadRead button bits are active-low", [](TestCase &t)
|
|
{
|
|
std::vector<uint8_t> rdram(PS2_RAM_SIZE, 0);
|
|
R5900Context ctx;
|
|
|
|
ps2_stubs::scePadInit(rdram.data(), &ctx, nullptr);
|
|
openPadPort(ctx, rdram);
|
|
|
|
struct ButtonCase
|
|
{
|
|
uint16_t mask;
|
|
const char *name;
|
|
};
|
|
|
|
const ButtonCase cases[] = {
|
|
{kPadBtnSelect, "select"},
|
|
{kPadBtnL3, "l3"},
|
|
{kPadBtnR3, "r3"},
|
|
{kPadBtnStart, "start"},
|
|
{kPadBtnUp, "up"},
|
|
{kPadBtnRight, "right"},
|
|
{kPadBtnDown, "down"},
|
|
{kPadBtnLeft, "left"},
|
|
{kPadBtnL2, "l2"},
|
|
{kPadBtnR2, "r2"},
|
|
{kPadBtnL1, "l1"},
|
|
{kPadBtnR1, "r1"},
|
|
{kPadBtnTriangle, "triangle"},
|
|
{kPadBtnCircle, "circle"},
|
|
{kPadBtnCross, "cross"},
|
|
{kPadBtnSquare, "square"}};
|
|
|
|
for (const auto &entry : cases)
|
|
{
|
|
const uint16_t buttons = static_cast<uint16_t>(0xFFFFu & ~entry.mask);
|
|
ps2_stubs::setPadOverrideState(buttons, 0x80, 0x80, 0x80, 0x80);
|
|
runPadRead(ctx, rdram);
|
|
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadRead should succeed for opened ports");
|
|
const uint16_t mask = readButtons(rdram);
|
|
t.IsTrue((mask & entry.mask) == 0, std::string("button should be active-low: ").append(entry.name));
|
|
}
|
|
|
|
ps2_stubs::clearPadOverrideState();
|
|
closePadPort(ctx, rdram);
|
|
});
|
|
|
|
tc.Run("scePadGetButtonMask returns all buttons", [](TestCase &t)
|
|
{
|
|
R5900Context ctx;
|
|
ps2_stubs::scePadGetButtonMask(nullptr, &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(0xFFFF), "button mask should be 0xFFFF");
|
|
});
|
|
|
|
tc.Run("basic pad init/port/state functions return expected values", [](TestCase &t)
|
|
{
|
|
std::vector<uint8_t> rdram(PS2_RAM_SIZE, 0);
|
|
R5900Context ctx;
|
|
|
|
ps2_stubs::scePadInit(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadInit should succeed");
|
|
|
|
ps2_stubs::scePadInit2(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadInit2 should succeed");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadGetState(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(0), "closed port should report DISCONNECTED");
|
|
|
|
openPadPort(ctx, rdram);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadPortOpen should succeed");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadGetState(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(6), "scePadGetState should return STABLE");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadGetReqState(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(0), "scePadGetReqState should return completed");
|
|
|
|
ps2_stubs::scePadGetPortMax(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(2), "scePadGetPortMax should be 2");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
ps2_stubs::scePadGetSlotMax(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadGetSlotMax should be 1");
|
|
|
|
ps2_stubs::scePadGetModVersion(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(0x0200), "scePadGetModVersion should be 0x0200");
|
|
|
|
closePadPort(ctx, rdram);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadPortClose should succeed");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadGetState(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(0), "closed port should return DISCONNECTED after close");
|
|
});
|
|
|
|
tc.Run("pad command state reports EXECCMD once before returning STABLE", [](TestCase &t)
|
|
{
|
|
std::vector<uint8_t> rdram(PS2_RAM_SIZE, 0);
|
|
R5900Context ctx;
|
|
|
|
ps2_stubs::scePadInit(rdram.data(), &ctx, nullptr);
|
|
openPadPort(ctx, rdram);
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
setRegU32(ctx, 6, 1u);
|
|
setRegU32(ctx, 7, 3u);
|
|
ps2_stubs::scePadSetMainMode(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadSetMainMode should succeed");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadGetState(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(5), "first state after mode command should be EXECCMD");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadGetState(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(6), "second state after mode command should return STABLE");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadEnterPressMode(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadEnterPressMode should succeed");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadGetState(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(5), "first state after press-mode command should be EXECCMD");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadGetState(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(6), "second state after press-mode command should return STABLE");
|
|
|
|
closePadPort(ctx, rdram);
|
|
});
|
|
|
|
tc.Run("pad info and mode helpers return consistent values", [](TestCase &t)
|
|
{
|
|
std::vector<uint8_t> rdram(PS2_RAM_SIZE, 0);
|
|
R5900Context ctx;
|
|
|
|
ps2_stubs::scePadInit(rdram.data(), &ctx, nullptr);
|
|
openPadPort(ctx, rdram);
|
|
|
|
setRegU32(ctx, 6, static_cast<uint32_t>(-1));
|
|
ps2_stubs::scePadInfoAct(rdram.data(), &ctx, nullptr);
|
|
t.IsTrue(static_cast<uint32_t>(getRegU32(&ctx, 2)) >= 1u, "scePadInfoAct should report at least one actuator descriptor");
|
|
|
|
ps2_stubs::scePadInfoComb(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(0), "scePadInfoComb should return 0");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
setRegU32(ctx, 6, 1);
|
|
setRegU32(ctx, 7, 0);
|
|
ps2_stubs::scePadInfoMode(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(7), "scePadInfoMode CURID should return DualShock");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
setRegU32(ctx, 6, 4);
|
|
setRegU32(ctx, 7, static_cast<uint32_t>(-1));
|
|
ps2_stubs::scePadInfoMode(rdram.data(), &ctx, nullptr);
|
|
t.IsTrue(static_cast<uint32_t>(getRegU32(&ctx, 2)) >= 1u, "scePadInfoMode table count should be non-zero");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadInfoPressMode(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadInfoPressMode should report pressure support");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
setRegU32(ctx, 6, 0u);
|
|
setRegU32(ctx, 7, 3u);
|
|
ps2_stubs::scePadSetMainMode(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadSetMainMode should accept digital mode");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
setRegU32(ctx, 6, 1u);
|
|
setRegU32(ctx, 7, 0u);
|
|
ps2_stubs::scePadInfoMode(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(4), "CURID should switch to digital mode");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
setRegU32(ctx, 6, 1u);
|
|
setRegU32(ctx, 7, 3u);
|
|
ps2_stubs::scePadSetMainMode(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadSetMainMode should accept analog mode");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
setRegU32(ctx, 6, 4);
|
|
setRegU32(ctx, 7, 0u);
|
|
ps2_stubs::scePadInfoMode(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(7), "mode table entry should return DualShock in analog mode");
|
|
|
|
closePadPort(ctx, rdram);
|
|
});
|
|
|
|
tc.Run("pad setters return success", [](TestCase &t)
|
|
{
|
|
std::vector<uint8_t> rdram(PS2_RAM_SIZE, 0);
|
|
R5900Context ctx;
|
|
|
|
ps2_stubs::scePadInit(rdram.data(), &ctx, nullptr);
|
|
openPadPort(ctx, rdram);
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadSetActAlign(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadSetActAlign should succeed");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadSetActDirect(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadSetActDirect should succeed");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
setRegU32(ctx, 6, 0xFFFFu);
|
|
ps2_stubs::scePadSetButtonInfo(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadSetButtonInfo should succeed");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
setRegU32(ctx, 6, 1u);
|
|
setRegU32(ctx, 7, 3u);
|
|
ps2_stubs::scePadSetMainMode(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadSetMainMode should succeed");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadSetReqState(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadSetReqState should succeed");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadSetVrefParam(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadSetVrefParam should succeed");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadSetWarningLevel(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(0), "scePadSetWarningLevel should return 0");
|
|
|
|
ps2_stubs::scePadEnd(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadEnd should succeed");
|
|
|
|
openPadPort(ctx, rdram);
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadEnterPressMode(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadEnterPressMode should succeed");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadExitPressMode(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadExitPressMode should succeed");
|
|
|
|
closePadPort(ctx, rdram);
|
|
});
|
|
|
|
tc.Run("scePadRead fills pressure bytes and honors button info mask", [](TestCase &t)
|
|
{
|
|
std::vector<uint8_t> rdram(PS2_RAM_SIZE, 0);
|
|
R5900Context ctx;
|
|
|
|
ps2_stubs::scePadInit(rdram.data(), &ctx, nullptr);
|
|
openPadPort(ctx, rdram);
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
setRegU32(ctx, 6, 0xFFFFu);
|
|
ps2_stubs::scePadSetButtonInfo(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadSetButtonInfo should accept all buttons");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
ps2_stubs::scePadEnterPressMode(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadEnterPressMode should enable pressure data");
|
|
|
|
const uint16_t pressedButtons = static_cast<uint16_t>(0xFFFFu &
|
|
~kPadBtnLeft &
|
|
~kPadBtnUp &
|
|
~kPadBtnTriangle &
|
|
~kPadBtnCross &
|
|
~kPadBtnL1 &
|
|
~kPadBtnR2);
|
|
ps2_stubs::setPadOverrideState(pressedButtons, 0x80, 0x80, 0x80, 0x80);
|
|
runPadRead(ctx, rdram);
|
|
|
|
const uint8_t *data = rdram.data() + kPadDataAddr;
|
|
t.Equals(data[8], static_cast<uint8_t>(0x00), "right pressure should be clear when not pressed");
|
|
t.Equals(data[9], static_cast<uint8_t>(0xFF), "left pressure should be populated when pressed");
|
|
t.Equals(data[10], static_cast<uint8_t>(0xFF), "up pressure should be populated when pressed");
|
|
t.Equals(data[11], static_cast<uint8_t>(0x00), "down pressure should be clear when not pressed");
|
|
t.Equals(data[12], static_cast<uint8_t>(0xFF), "triangle pressure should be populated when pressed");
|
|
t.Equals(data[13], static_cast<uint8_t>(0x00), "circle pressure should be clear when not pressed");
|
|
t.Equals(data[14], static_cast<uint8_t>(0xFF), "cross pressure should be populated when pressed");
|
|
t.Equals(data[15], static_cast<uint8_t>(0x00), "square pressure should be clear when not pressed");
|
|
t.Equals(data[16], static_cast<uint8_t>(0xFF), "L1 pressure should be populated when pressed");
|
|
t.Equals(data[17], static_cast<uint8_t>(0x00), "L2 pressure should be clear when not pressed");
|
|
t.Equals(data[18], static_cast<uint8_t>(0x00), "R1 pressure should be clear when not pressed");
|
|
t.Equals(data[19], static_cast<uint8_t>(0xFF), "R2 pressure should be populated when pressed");
|
|
|
|
setRegU32(ctx, 4, 0u);
|
|
setRegU32(ctx, 5, 0u);
|
|
setRegU32(ctx, 6, static_cast<uint32_t>(kPadBtnL1 | kPadBtnR2));
|
|
ps2_stubs::scePadSetButtonInfo(rdram.data(), &ctx, nullptr);
|
|
t.Equals(static_cast<uint32_t>(getRegU32(&ctx, 2)), static_cast<uint32_t>(1), "scePadSetButtonInfo should narrow the enabled pressure mask");
|
|
|
|
runPadRead(ctx, rdram);
|
|
|
|
t.Equals(data[9], static_cast<uint8_t>(0x00), "masked-out direction pressure should clear");
|
|
t.Equals(data[10], static_cast<uint8_t>(0x00), "masked-out direction pressure should clear");
|
|
t.Equals(data[12], static_cast<uint8_t>(0x00), "masked-out face-button pressure should clear");
|
|
t.Equals(data[14], static_cast<uint8_t>(0x00), "masked-out face-button pressure should clear");
|
|
t.Equals(data[16], static_cast<uint8_t>(0xFF), "enabled L1 pressure should remain populated");
|
|
t.Equals(data[19], static_cast<uint8_t>(0xFF), "enabled R2 pressure should remain populated");
|
|
|
|
ps2_stubs::clearPadOverrideState();
|
|
closePadPort(ctx, rdram);
|
|
});
|
|
|
|
tc.Run("pad string helpers map state codes", [](TestCase &t)
|
|
{
|
|
std::vector<uint8_t> rdram(PS2_RAM_SIZE, 0);
|
|
R5900Context ctx;
|
|
|
|
setRegU32(ctx, 4, 1);
|
|
setRegU32(ctx, 5, kPadDataAddr);
|
|
ps2_stubs::scePadStateIntToStr(rdram.data(), &ctx, nullptr);
|
|
t.IsTrue(std::string(reinterpret_cast<const char *>(rdram.data() + kPadDataAddr)).find("FINDPAD") != std::string::npos,
|
|
"state 1 should map to FINDPAD");
|
|
|
|
setRegU32(ctx, 4, 0);
|
|
setRegU32(ctx, 5, kPadDataAddr + 64);
|
|
ps2_stubs::scePadStateIntToStr(rdram.data(), &ctx, nullptr);
|
|
t.IsTrue(std::string(reinterpret_cast<const char *>(rdram.data() + kPadDataAddr + 64)).find("DISCONNECTED") != std::string::npos,
|
|
"state 0 should map to DISCONNECTED");
|
|
|
|
setRegU32(ctx, 4, 1);
|
|
setRegU32(ctx, 5, kPadDataAddr + 128);
|
|
ps2_stubs::scePadReqIntToStr(rdram.data(), &ctx, nullptr);
|
|
t.IsTrue(std::string(reinterpret_cast<const char *>(rdram.data() + kPadDataAddr + 128)).find("BUSY") != std::string::npos,
|
|
"req state 1 should map to BUSY");
|
|
});
|
|
tc.Run("scePadGetFrameCount increments", [](TestCase &t)
|
|
{
|
|
R5900Context ctx;
|
|
ps2_stubs::scePadGetFrameCount(nullptr, &ctx, nullptr);
|
|
const uint32_t first = getRegU32(&ctx, 2);
|
|
ps2_stubs::scePadGetFrameCount(nullptr, &ctx, nullptr);
|
|
const uint32_t second = getRegU32(&ctx, 2);
|
|
t.Equals(second, first + 1, "frame count should increment");
|
|
});
|
|
|
|
tc.Run("scePadStateIntToStr and scePadReqIntToStr write strings", [](TestCase &t)
|
|
{
|
|
std::vector<uint8_t> rdram(PS2_RAM_SIZE, 0);
|
|
R5900Context ctx;
|
|
|
|
setRegU32(ctx, 4, 6);
|
|
setRegU32(ctx, 5, kPadDataAddr);
|
|
ps2_stubs::scePadStateIntToStr(rdram.data(), &ctx, nullptr);
|
|
const char *stateStr = reinterpret_cast<const char *>(rdram.data() + kPadDataAddr);
|
|
t.IsTrue(std::string(stateStr).find("STABLE") != std::string::npos, "state string should include STABLE");
|
|
|
|
setRegU32(ctx, 4, 0);
|
|
setRegU32(ctx, 5, kPadDataAddr + 64);
|
|
ps2_stubs::scePadReqIntToStr(rdram.data(), &ctx, nullptr);
|
|
const char *reqStr = reinterpret_cast<const char *>(rdram.data() + kPadDataAddr + 64);
|
|
t.IsTrue(std::string(reqStr).find("COMPLETE") != std::string::npos, "req string should include COMPLETE");
|
|
});
|
|
});
|
|
}
|