mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-26 08:51:05 -04:00
Add IOP, audio, pad, fio changes, VAG handling, and call-stack logger (#76)
- Add IOP with RPC handling (handleRPC, LibSd SID) and init/reset using RDRAM - Add IOP audio layer for LibSd RPC (handleLibSdRpc) - Add PS2AudioBackend with VAG decode, onVagTransfer/onSoundCommand, raylib playback - Add PSPadBackend with readState and raylib input - Add IOP RAM mapping in Memory (getIOPRAM) for EE↔IOP access - Add fio syscalls: fioOpen, fioRead, fioWrite, fioClose, fioLseek, fioMkdir - Add VAG accumulation for fio reads (multi-chunk VagAccumEntry) - Add ps2_log.h call-stack logger (tab-indented, Debug only, ps2_log.txt next to exe) - Code generator: emit ps2_log include and PS_LOG_ENTRY for full functions - Recompiler: emit ps2_log include and PS_LOG_ENTRY for stubs - Runtime: print "[PS2 LOG] Logs saved at <path>" on exit (Debug only)
This commit is contained in:
@@ -821,6 +821,9 @@ namespace ps2recomp
|
||||
ss << "#include \"ps2_recompiled_stubs.h\"\n\n";
|
||||
ss << "#include \"ps2_syscalls.h\"\n";
|
||||
ss << "#include \"ps2_stubs.h\"\n\n";
|
||||
ss << "#ifdef _DEBUG\n";
|
||||
ss << "#include \"ps2_log.h\"\n";
|
||||
ss << "#endif\n\n";
|
||||
}
|
||||
|
||||
AnalysisResult analysisResult = collectInternalBranchTargets(function, instructions);
|
||||
@@ -836,7 +839,11 @@ namespace ps2recomp
|
||||
sanitizedName = nameBuilder.str();
|
||||
}
|
||||
|
||||
ss << "void " << sanitizedName << "(uint8_t* rdram, R5900Context* ctx, PS2Runtime *runtime) {\n\n";
|
||||
ss << "void " << sanitizedName << "(uint8_t* rdram, R5900Context* ctx, PS2Runtime *runtime) {\n";
|
||||
ss << "#ifdef _DEBUG\n";
|
||||
ss << " PS_LOG_ENTRY(\"" << sanitizedName << "\");\n";
|
||||
ss << "#endif\n";
|
||||
ss << "\n";
|
||||
ss << " ctx->pc = 0x" << std::hex << function.start << "u;\n"
|
||||
<< std::dec;
|
||||
ss << "\n";
|
||||
|
||||
@@ -984,8 +984,11 @@ namespace ps2recomp
|
||||
std::string generatedName = m_codeGenerator->getFunctionName(function.start);
|
||||
std::stringstream stub;
|
||||
stub << "void " << generatedName
|
||||
<< "(uint8_t* rdram, R5900Context* ctx, PS2Runtime *runtime) {\n"
|
||||
<< " const uint32_t __entryPc = ctx->pc;\n"
|
||||
<< "(uint8_t* rdram, R5900Context* ctx, PS2Runtime *runtime) {\n";
|
||||
stub << "#ifdef _DEBUG\n";
|
||||
stub << " PS_LOG_ENTRY(\"" << generatedName << "\");\n";
|
||||
stub << "#endif\n";
|
||||
stub << " const uint32_t __entryPc = ctx->pc;\n"
|
||||
<< " ";
|
||||
|
||||
if (function.isSkipped)
|
||||
@@ -1044,6 +1047,9 @@ namespace ps2recomp
|
||||
combinedOutput << "#include \"ps2_recompiled_stubs.h\"\n";
|
||||
combinedOutput << "#include \"ps2_syscalls.h\"\n";
|
||||
combinedOutput << "#include \"ps2_stubs.h\"\n";
|
||||
combinedOutput << "#ifdef _DEBUG\n";
|
||||
combinedOutput << "#include \"ps2_log.h\"\n";
|
||||
combinedOutput << "#endif\n";
|
||||
combinedOutput << "\n";
|
||||
|
||||
for (const auto &function : m_functions)
|
||||
@@ -1100,7 +1106,11 @@ namespace ps2recomp
|
||||
std::stringstream stubFile;
|
||||
stubFile << "#include \"ps2_runtime.h\"\n";
|
||||
stubFile << "#include \"ps2_syscalls.h\"\n";
|
||||
stubFile << "#include \"ps2_stubs.h\"\n\n";
|
||||
stubFile << "#include \"ps2_stubs.h\"\n";
|
||||
stubFile << "#ifdef _DEBUG\n";
|
||||
stubFile << "#include \"ps2_log.h\"\n";
|
||||
stubFile << "#endif\n";
|
||||
stubFile << "\n";
|
||||
stubFile << m_generatedStubs.at(function.start) << "\n";
|
||||
code = stubFile.str();
|
||||
}
|
||||
|
||||
@@ -20,9 +20,14 @@ FetchContent_MakeAvailable(raylib)
|
||||
|
||||
add_library(ps2_runtime STATIC
|
||||
src/lib/game_overrides.cpp
|
||||
src/lib/ps2_audio.cpp
|
||||
src/lib/ps2_audio_vag.cpp
|
||||
src/lib/ps2_gs_gpu.cpp
|
||||
src/lib/ps2_gs_rasterizer.cpp
|
||||
src/lib/ps2_iop.cpp
|
||||
src/lib/ps2_iop_audio.cpp
|
||||
src/lib/ps2_memory.cpp
|
||||
src/lib/ps2_pad.cpp
|
||||
src/lib/ps2_runtime.cpp
|
||||
src/lib/ps2_stubs.cpp
|
||||
src/lib/ps2_syscalls.cpp
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef PS2_AUDIO_H
|
||||
#define PS2_AUDIO_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class PS2AudioBackend
|
||||
{
|
||||
public:
|
||||
PS2AudioBackend();
|
||||
~PS2AudioBackend();
|
||||
|
||||
void onVagTransfer(const uint8_t *rdram, uint32_t srcAddr, uint32_t sizeBytes);
|
||||
void onVagTransferFromBuffer(const uint8_t *data, uint32_t sizeBytes, uint32_t keyAddr);
|
||||
void onSoundCommand(uint32_t sid, uint32_t rpcNum,
|
||||
const uint8_t *sendBuf, uint32_t sendSize,
|
||||
uint8_t *recvBuf, uint32_t recvSize);
|
||||
|
||||
void play(uint32_t sampleAddr, float pitch = 1.0f, float volume = 1.0f,
|
||||
uint32_t voiceIndex = 0xFFFFFFFFu);
|
||||
void stop(uint32_t voiceId);
|
||||
void stopAll();
|
||||
void setAudioReady(bool ready) { m_audioReady = ready; }
|
||||
|
||||
private:
|
||||
struct DecodedSample
|
||||
{
|
||||
std::vector<int16_t> pcm;
|
||||
uint32_t sampleRate = 44100;
|
||||
};
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
bool m_audioReady = false;
|
||||
uint32_t m_mostRecentSampleKey = 0;
|
||||
std::vector<DecodedSample> m_loadOrderSamples;
|
||||
std::unordered_map<uint32_t, DecodedSample> m_sampleBank;
|
||||
std::mutex m_mutex;
|
||||
|
||||
void playDecodedSample(uint32_t sampleKey, DecodedSample &sample, float pitch, float volume,
|
||||
bool isBgm = false);
|
||||
void pruneFinishedSounds();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef PS2_IOP_H
|
||||
#define PS2_IOP_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
constexpr uint32_t IOP_SID_LIBSD = 0x80000701u;
|
||||
|
||||
class IOP
|
||||
{
|
||||
public:
|
||||
IOP();
|
||||
~IOP() = default;
|
||||
|
||||
void init(uint8_t *rdram);
|
||||
void reset();
|
||||
|
||||
bool handleRPC(uint32_t sid, uint32_t rpcNum,
|
||||
uint32_t sendBufAddr, uint32_t sendSize,
|
||||
uint32_t recvBufAddr, uint32_t recvSize);
|
||||
|
||||
private:
|
||||
uint8_t *m_rdram = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef PS2_IOP_AUDIO_H
|
||||
#define PS2_IOP_AUDIO_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class PS2Runtime;
|
||||
|
||||
namespace ps2_iop_audio
|
||||
{
|
||||
void handleLibSdRpc(PS2Runtime *runtime, uint32_t sid, uint32_t rpcNum,
|
||||
const uint8_t *sendBuf, uint32_t sendSize,
|
||||
uint8_t *recvBuf, uint32_t recvSize);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,77 @@
|
||||
#ifndef PS2_LOG_H
|
||||
#define PS2_LOG_H
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
namespace ps2_log
|
||||
{
|
||||
inline std::string log_path()
|
||||
{
|
||||
static std::string path;
|
||||
if (path.empty())
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
char buf[MAX_PATH];
|
||||
if (GetModuleFileNameA(nullptr, buf, sizeof(buf)))
|
||||
path = (std::filesystem::path(buf).parent_path() / "ps2_log.txt").string();
|
||||
#endif
|
||||
if (path.empty())
|
||||
path = (std::filesystem::current_path() / "ps2_log.txt").string();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
inline std::ostream &log_stream()
|
||||
{
|
||||
static std::ofstream f(log_path(), std::ios::out);
|
||||
return f.is_open() ? f : std::cerr;
|
||||
}
|
||||
inline int &depth()
|
||||
{
|
||||
static thread_local int d = 0;
|
||||
return d;
|
||||
}
|
||||
inline void log_entry(const char *name)
|
||||
{
|
||||
for (int i = 0; i < depth(); ++i)
|
||||
log_stream() << '\t';
|
||||
log_stream() << ">> " << name << " enter\n";
|
||||
log_stream().flush();
|
||||
depth()++;
|
||||
}
|
||||
inline void log_exit(const char *name)
|
||||
{
|
||||
depth()--;
|
||||
for (int i = 0; i < depth(); ++i)
|
||||
log_stream() << '\t';
|
||||
log_stream() << "<< " << name << " exit\n";
|
||||
log_stream().flush();
|
||||
}
|
||||
inline void print_saved_location()
|
||||
{
|
||||
std::cout << "[PS2 LOG] Logs saved at " << log_path() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
#define PS_LOG_ENTRY(name) \
|
||||
ps2_log::log_entry(name); \
|
||||
struct _ps2_log_guard_ { const char *_n; _ps2_log_guard_(const char *n) : _n(n) {} \
|
||||
~_ps2_log_guard_() { ps2_log::log_exit(_n); } } _ps2_log_guard_(name)
|
||||
|
||||
#else
|
||||
|
||||
namespace ps2_log
|
||||
{
|
||||
inline void print_saved_location() {}
|
||||
}
|
||||
#define PS_LOG_ENTRY(name) ((void)0)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef PS2_PAD_H
|
||||
#define PS2_PAD_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
class PSPadBackend
|
||||
{
|
||||
public:
|
||||
PSPadBackend() = default;
|
||||
~PSPadBackend() = default;
|
||||
|
||||
bool readState(int port, int slot, uint8_t *data, size_t size);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -22,6 +22,9 @@
|
||||
#include <iomanip>
|
||||
|
||||
#include "ps2_memory.h"
|
||||
#include "ps2_iop.h"
|
||||
#include "ps2_audio.h"
|
||||
#include "ps2_pad.h"
|
||||
|
||||
enum PS2Exception
|
||||
{
|
||||
@@ -457,6 +460,13 @@ public:
|
||||
inline PS2Memory &memory() { return m_memory; }
|
||||
inline const PS2Memory &memory() const { return m_memory; }
|
||||
|
||||
inline IOP &iop() { return m_iop; }
|
||||
inline const IOP &iop() const { return m_iop; }
|
||||
inline PS2AudioBackend &audioBackend() { return m_audioBackend; }
|
||||
inline const PS2AudioBackend &audioBackend() const { return m_audioBackend; }
|
||||
inline PSPadBackend &padBackend() { return m_padBackend; }
|
||||
inline const PSPadBackend &padBackend() const { return m_padBackend; }
|
||||
|
||||
private:
|
||||
struct GuestHeapBlock
|
||||
{
|
||||
@@ -481,6 +491,9 @@ private:
|
||||
|
||||
private:
|
||||
PS2Memory m_memory;
|
||||
IOP m_iop;
|
||||
PS2AudioBackend m_audioBackend;
|
||||
PSPadBackend m_padBackend;
|
||||
R5900Context m_cpuContext;
|
||||
mutable std::mutex m_guestHeapMutex;
|
||||
std::vector<GuestHeapBlock> m_guestHeapBlocks;
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
#include "ps2_audio.h"
|
||||
#include "ps2_memory.h"
|
||||
#include "raylib.h"
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::vector<uint8_t> buildWavFromPcm(const int16_t *pcm, size_t sampleCount, uint32_t sampleRate)
|
||||
{
|
||||
const uint32_t dataSize = static_cast<uint32_t>(sampleCount * 2);
|
||||
const uint32_t fileSize = 36 + dataSize;
|
||||
std::vector<uint8_t> wav(8 + fileSize);
|
||||
|
||||
uint8_t *p = wav.data();
|
||||
p[0] = 'R'; p[1] = 'I'; p[2] = 'F'; p[3] = 'F';
|
||||
p[4] = static_cast<uint8_t>(fileSize);
|
||||
p[5] = static_cast<uint8_t>(fileSize >> 8);
|
||||
p[6] = static_cast<uint8_t>(fileSize >> 16);
|
||||
p[7] = static_cast<uint8_t>(fileSize >> 24);
|
||||
p[8] = 'W'; p[9] = 'A'; p[10] = 'V'; p[11] = 'E';
|
||||
p[12] = 'f'; p[13] = 'm'; p[14] = 't'; p[15] = ' ';
|
||||
p[16] = 16; p[17] = 0; p[18] = 0; p[19] = 0;
|
||||
p[20] = 1; p[21] = 0;
|
||||
p[22] = 1; p[23] = 0;
|
||||
p[24] = static_cast<uint8_t>(sampleRate);
|
||||
p[25] = static_cast<uint8_t>(sampleRate >> 8);
|
||||
p[26] = static_cast<uint8_t>(sampleRate >> 16);
|
||||
p[27] = static_cast<uint8_t>(sampleRate >> 24);
|
||||
const uint32_t byteRate = sampleRate * 2;
|
||||
p[28] = static_cast<uint8_t>(byteRate);
|
||||
p[29] = static_cast<uint8_t>(byteRate >> 8);
|
||||
p[30] = static_cast<uint8_t>(byteRate >> 16);
|
||||
p[31] = static_cast<uint8_t>(byteRate >> 24);
|
||||
p[32] = 2; p[33] = 0;
|
||||
p[34] = 16; p[35] = 0;
|
||||
p[36] = 'd'; p[37] = 'a'; p[38] = 't'; p[39] = 'a';
|
||||
p[40] = static_cast<uint8_t>(dataSize);
|
||||
p[41] = static_cast<uint8_t>(dataSize >> 8);
|
||||
p[42] = static_cast<uint8_t>(dataSize >> 16);
|
||||
p[43] = static_cast<uint8_t>(dataSize >> 24);
|
||||
std::memcpy(p + 44, pcm, dataSize);
|
||||
return wav;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ps2_vag
|
||||
{
|
||||
bool decode(const uint8_t *data, uint32_t sizeBytes,
|
||||
std::vector<int16_t> &outPcm, uint32_t &outSampleRate);
|
||||
}
|
||||
|
||||
struct PS2AudioBackend::Impl
|
||||
{
|
||||
struct TrackedSound { Sound snd; uint32_t sampleKey; };
|
||||
std::vector<TrackedSound> activeSounds;
|
||||
};
|
||||
|
||||
PS2AudioBackend::PS2AudioBackend() : m_impl(std::make_unique<Impl>())
|
||||
{
|
||||
}
|
||||
|
||||
PS2AudioBackend::~PS2AudioBackend()
|
||||
{
|
||||
if (m_impl)
|
||||
stopAll();
|
||||
}
|
||||
|
||||
void PS2AudioBackend::onVagTransfer(const uint8_t *rdram, uint32_t srcAddr, uint32_t sizeBytes)
|
||||
{
|
||||
if (!rdram || sizeBytes < 48)
|
||||
return;
|
||||
|
||||
const uint32_t physAddr = srcAddr & PS2_RAM_MASK;
|
||||
if (physAddr + sizeBytes > PS2_RAM_SIZE)
|
||||
return;
|
||||
|
||||
std::vector<int16_t> pcm;
|
||||
uint32_t sampleRate = 44100;
|
||||
if (!ps2_vag::decode(rdram + physAddr, sizeBytes, pcm, sampleRate))
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
DecodedSample sample;
|
||||
sample.pcm = std::move(pcm);
|
||||
sample.sampleRate = sampleRate;
|
||||
m_sampleBank[physAddr] = std::move(sample);
|
||||
m_mostRecentSampleKey = physAddr;
|
||||
}
|
||||
|
||||
void PS2AudioBackend::onVagTransferFromBuffer(const uint8_t *data, uint32_t sizeBytes, uint32_t keyAddr)
|
||||
{
|
||||
if (!data || sizeBytes < 48)
|
||||
return;
|
||||
|
||||
std::vector<int16_t> pcm;
|
||||
uint32_t sampleRate = 44100;
|
||||
if (!ps2_vag::decode(data, sizeBytes, pcm, sampleRate))
|
||||
return;
|
||||
|
||||
const uint32_t physAddr = keyAddr & PS2_RAM_MASK;
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
DecodedSample sample;
|
||||
sample.pcm = std::move(pcm);
|
||||
sample.sampleRate = sampleRate;
|
||||
m_sampleBank[physAddr] = sample;
|
||||
m_mostRecentSampleKey = physAddr;
|
||||
m_loadOrderSamples.push_back(std::move(sample));
|
||||
constexpr size_t kMaxLoadOrderSamples = 32;
|
||||
if (m_loadOrderSamples.size() > kMaxLoadOrderSamples)
|
||||
m_loadOrderSamples.erase(m_loadOrderSamples.begin());
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr uint32_t LIBSD_CMD_SET_VOICE = 0x8010u;
|
||||
}
|
||||
|
||||
void PS2AudioBackend::onSoundCommand(uint32_t sid, uint32_t rpcNum,
|
||||
const uint8_t *sendBuf, uint32_t sendSize,
|
||||
uint8_t *recvBuf, uint32_t recvSize)
|
||||
{
|
||||
if (sid != 0x80000701u)
|
||||
return;
|
||||
|
||||
if ((rpcNum == LIBSD_CMD_SET_VOICE || (rpcNum & 0xFF00u) == 0x8100u) &&
|
||||
sendBuf && sendSize >= 20)
|
||||
{
|
||||
uint32_t sampleAddr = 0;
|
||||
uint32_t voiceIndex = 0xFFFFFFFFu;
|
||||
for (int vo = 4; vo >= 0 && voiceIndex == 0xFFFFFFFFu; vo -= 4)
|
||||
{
|
||||
if (vo < static_cast<int>(sendSize))
|
||||
{
|
||||
uint32_t v = 0;
|
||||
std::memcpy(&v, sendBuf + vo, sizeof(v));
|
||||
if (v < 24u)
|
||||
voiceIndex = v;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr uint32_t kMinPlausibleAddr = 0x1000u;
|
||||
for (int off = 12; off <= 24 && sampleAddr == 0; off += 4)
|
||||
{
|
||||
if (sendSize >= static_cast<uint32_t>(off + 4))
|
||||
{
|
||||
uint32_t cand = 0;
|
||||
std::memcpy(&cand, sendBuf + off, sizeof(cand));
|
||||
if (cand >= kMinPlausibleAddr && (cand <= PS2_RAM_MASK || (cand & ~PS2_RAM_MASK) == 0))
|
||||
sampleAddr = cand;
|
||||
}
|
||||
}
|
||||
if (sampleAddr == 0)
|
||||
sampleAddr = m_mostRecentSampleKey;
|
||||
|
||||
float pitch = 1.0f;
|
||||
if (sendSize >= 12)
|
||||
{
|
||||
uint16_t pitchHalf = 0;
|
||||
std::memcpy(&pitchHalf, sendBuf + 8, sizeof(pitchHalf));
|
||||
if (pitchHalf != 0)
|
||||
pitch = 4096.0f / static_cast<float>(pitchHalf);
|
||||
}
|
||||
play(sampleAddr, pitch, 1.0f, voiceIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void PS2AudioBackend::play(uint32_t sampleAddr, float pitch, float volume, uint32_t voiceIndex)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
DecodedSample *sampleToPlay = nullptr;
|
||||
uint32_t sampleKey = 0;
|
||||
|
||||
auto it = m_sampleBank.find(sampleAddr & PS2_RAM_MASK);
|
||||
if (it != m_sampleBank.end())
|
||||
{
|
||||
sampleToPlay = &it->second;
|
||||
sampleKey = it->first;
|
||||
}
|
||||
else if (voiceIndex != 0xFFFFFFFFu && voiceIndex < m_loadOrderSamples.size())
|
||||
{
|
||||
sampleToPlay = &m_loadOrderSamples[voiceIndex];
|
||||
sampleKey = 0x1719740u + voiceIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
it = m_sampleBank.find(m_mostRecentSampleKey);
|
||||
if (it == m_sampleBank.end())
|
||||
return;
|
||||
sampleToPlay = &it->second;
|
||||
sampleKey = it->first;
|
||||
}
|
||||
if (!sampleToPlay || sampleToPlay->pcm.empty())
|
||||
return;
|
||||
|
||||
const bool isBgm = (sampleToPlay->pcm.size() > static_cast<size_t>(sampleToPlay->sampleRate * 5));
|
||||
playDecodedSample(sampleKey, *sampleToPlay, pitch, volume, isBgm);
|
||||
}
|
||||
|
||||
void PS2AudioBackend::pruneFinishedSounds()
|
||||
{
|
||||
auto &sounds = m_impl->activeSounds;
|
||||
auto it = sounds.begin();
|
||||
while (it != sounds.end())
|
||||
{
|
||||
if (!IsSoundPlaying(it->snd))
|
||||
{
|
||||
UnloadSound(it->snd);
|
||||
it = sounds.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PS2AudioBackend::playDecodedSample(uint32_t sampleKey, DecodedSample &sample, float pitch, float volume,
|
||||
bool isBgm)
|
||||
{
|
||||
if (!m_audioReady || sample.pcm.empty())
|
||||
return;
|
||||
|
||||
pruneFinishedSounds();
|
||||
|
||||
for (const auto &t : m_impl->activeSounds)
|
||||
{
|
||||
if (t.sampleKey == sampleKey && IsSoundPlaying(t.snd))
|
||||
return;
|
||||
}
|
||||
|
||||
auto &sounds = m_impl->activeSounds;
|
||||
if (isBgm)
|
||||
{
|
||||
for (auto it = sounds.begin(); it != sounds.end();)
|
||||
{
|
||||
if (IsSoundPlaying(it->snd))
|
||||
{
|
||||
StopSound(it->snd);
|
||||
UnloadSound(it->snd);
|
||||
it = sounds.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr int kMaxConcurrentSounds = 4;
|
||||
while (static_cast<int>(sounds.size()) >= kMaxConcurrentSounds)
|
||||
{
|
||||
StopSound(sounds.front().snd);
|
||||
UnloadSound(sounds.front().snd);
|
||||
sounds.erase(sounds.begin());
|
||||
}
|
||||
|
||||
std::vector<uint8_t> wav = buildWavFromPcm(sample.pcm.data(), sample.pcm.size(), sample.sampleRate);
|
||||
Wave wave = LoadWaveFromMemory(".wav", wav.data(), static_cast<int>(wav.size()));
|
||||
if (wave.frameCount <= 0)
|
||||
return;
|
||||
Sound snd = LoadSoundFromWave(wave);
|
||||
UnloadWave(wave);
|
||||
SetSoundPitch(snd, pitch);
|
||||
SetSoundVolume(snd, volume);
|
||||
m_impl->activeSounds.push_back({snd, sampleKey});
|
||||
PlaySound(snd);
|
||||
}
|
||||
|
||||
void PS2AudioBackend::stop(uint32_t voiceId)
|
||||
{
|
||||
(void)voiceId;
|
||||
}
|
||||
|
||||
void PS2AudioBackend::stopAll()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
for (auto &t : m_impl->activeSounds)
|
||||
{
|
||||
StopSound(t.snd);
|
||||
UnloadSound(t.snd);
|
||||
}
|
||||
m_impl->activeSounds.clear();
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
#include "ps2_memory.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
namespace
|
||||
{
|
||||
inline int16_t clamp16(int32_t v)
|
||||
{
|
||||
if (v < -32768) return -32768;
|
||||
if (v > 32767) return 32767;
|
||||
return static_cast<int16_t>(v);
|
||||
}
|
||||
|
||||
inline int8_t signExtend4(uint8_t nibble)
|
||||
{
|
||||
uint8_t s = nibble & 0x0F;
|
||||
return static_cast<int8_t>((s & 8) ? static_cast<int8_t>(s | 0xF0) : static_cast<int8_t>(s));
|
||||
}
|
||||
}
|
||||
|
||||
namespace ps2_vag
|
||||
{
|
||||
bool decode(const uint8_t *data, uint32_t sizeBytes,
|
||||
std::vector<int16_t> &outPcm, uint32_t &outSampleRate)
|
||||
{
|
||||
if (!data || sizeBytes < 48)
|
||||
return false;
|
||||
|
||||
const uint32_t magic = (static_cast<uint32_t>(data[0]) << 24) |
|
||||
(static_cast<uint32_t>(data[1]) << 16) |
|
||||
(static_cast<uint32_t>(data[2]) << 8) |
|
||||
static_cast<uint32_t>(data[3]);
|
||||
if (magic != 0x56414770u)
|
||||
{
|
||||
const uint32_t magicLE = (static_cast<uint32_t>(data[3]) << 24) |
|
||||
(static_cast<uint32_t>(data[2]) << 16) |
|
||||
(static_cast<uint32_t>(data[1]) << 8) |
|
||||
static_cast<uint32_t>(data[0]);
|
||||
if (magicLE != 0x56414770u)
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t dataSize = (static_cast<uint32_t>(data[0x0c]) << 24) |
|
||||
(static_cast<uint32_t>(data[0x0d]) << 16) |
|
||||
(static_cast<uint32_t>(data[0x0e]) << 8) |
|
||||
static_cast<uint32_t>(data[0x0f]);
|
||||
outSampleRate = (static_cast<uint32_t>(data[0x10]) << 24) |
|
||||
(static_cast<uint32_t>(data[0x11]) << 16) |
|
||||
(static_cast<uint32_t>(data[0x12]) << 8) |
|
||||
static_cast<uint32_t>(data[0x13]);
|
||||
if (outSampleRate == 0)
|
||||
outSampleRate = 44100;
|
||||
|
||||
const uint32_t numBlocks = (dataSize + 15) / 16;
|
||||
outPcm.clear();
|
||||
outPcm.reserve(numBlocks * 28);
|
||||
|
||||
int16_t s1 = 0, s2 = 0;
|
||||
const uint8_t *block = data + 48;
|
||||
|
||||
for (uint32_t b = 0; b < numBlocks && (block + 16) <= data + sizeBytes; ++b, block += 16)
|
||||
{
|
||||
uint8_t shift = block[0] & 0x0F;
|
||||
if (shift > 12)
|
||||
shift = 9;
|
||||
uint8_t filter = (block[0] >> 4) & 0x07;
|
||||
if (filter > 4)
|
||||
filter = 0;
|
||||
|
||||
for (int sampleIdx = 0; sampleIdx < 28; ++sampleIdx)
|
||||
{
|
||||
const uint8_t byte = block[2 + sampleIdx / 2];
|
||||
const uint8_t nibble = (sampleIdx & 1) ? (byte >> 4) : (byte & 0x0F);
|
||||
const int8_t rawSample = signExtend4(nibble);
|
||||
const int32_t shiftedSample = rawSample << (12 - shift);
|
||||
|
||||
int32_t filteredSample;
|
||||
const int32_t old = s1;
|
||||
const int32_t older = s2;
|
||||
switch (filter)
|
||||
{
|
||||
case 0:
|
||||
filteredSample = shiftedSample;
|
||||
break;
|
||||
case 1:
|
||||
filteredSample = shiftedSample + (60 * old + 32) / 64;
|
||||
break;
|
||||
case 2:
|
||||
filteredSample = shiftedSample + (115 * old - 52 * older + 32) / 64;
|
||||
break;
|
||||
case 3:
|
||||
filteredSample = shiftedSample + (98 * old - 55 * older + 32) / 64;
|
||||
break;
|
||||
case 4:
|
||||
filteredSample = shiftedSample + (122 * old - 60 * older + 32) / 64;
|
||||
break;
|
||||
default:
|
||||
filteredSample = shiftedSample;
|
||||
break;
|
||||
}
|
||||
|
||||
const int16_t clamped = clamp16(filteredSample);
|
||||
s2 = s1;
|
||||
s1 = clamped;
|
||||
outPcm.push_back(clamped);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "ps2_iop.h"
|
||||
|
||||
IOP::IOP()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void IOP::init(uint8_t *rdram)
|
||||
{
|
||||
m_rdram = rdram;
|
||||
}
|
||||
|
||||
void IOP::reset()
|
||||
{
|
||||
}
|
||||
|
||||
bool IOP::handleRPC(uint32_t /*sid*/, uint32_t /*rpcNum*/,
|
||||
uint32_t /*sendBufAddr*/, uint32_t /*sendSize*/,
|
||||
uint32_t /*recvBufAddr*/, uint32_t /*recvSize*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "ps2_iop_audio.h"
|
||||
#include "ps2_runtime.h"
|
||||
|
||||
namespace ps2_iop_audio
|
||||
{
|
||||
void handleLibSdRpc(PS2Runtime *runtime, uint32_t sid, uint32_t rpcNum,
|
||||
const uint8_t *sendBuf, uint32_t sendSize,
|
||||
uint8_t *recvBuf, uint32_t recvSize)
|
||||
{
|
||||
if (!runtime)
|
||||
return;
|
||||
runtime->audioBackend().onSoundCommand(sid, rpcNum, sendBuf, sendSize, recvBuf, recvSize);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "ps2_pad.h"
|
||||
#include "raylib.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr uint8_t kPadAnalogMarker = 0x73;
|
||||
constexpr uint8_t kPadStickCenter = 0x80;
|
||||
|
||||
constexpr uint16_t PAD_LEFT = 0x0080u;
|
||||
constexpr uint16_t PAD_DOWN = 0x0040u;
|
||||
constexpr uint16_t PAD_RIGHT = 0x0020u;
|
||||
constexpr uint16_t PAD_UP = 0x0010u;
|
||||
constexpr uint16_t PAD_START = 0x0008u;
|
||||
constexpr uint16_t PAD_R3 = 0x0004u;
|
||||
constexpr uint16_t PAD_L3 = 0x0002u;
|
||||
constexpr uint16_t PAD_SELECT = 0x0001u;
|
||||
constexpr uint16_t PAD_SQUARE = 0x8000u;
|
||||
constexpr uint16_t PAD_CROSS = 0x4000u;
|
||||
constexpr uint16_t PAD_CIRCLE = 0x2000u;
|
||||
constexpr uint16_t PAD_TRIANGLE = 0x1000u;
|
||||
constexpr uint16_t PAD_R1 = 0x0800u;
|
||||
constexpr uint16_t PAD_L1 = 0x0400u;
|
||||
constexpr uint16_t PAD_R2 = 0x0200u;
|
||||
constexpr uint16_t PAD_L2 = 0x0100u;
|
||||
}
|
||||
|
||||
bool PSPadBackend::readState(int /*port*/, int /*slot*/, uint8_t *data, size_t size)
|
||||
{
|
||||
if (!data || size < 32)
|
||||
return false;
|
||||
|
||||
std::memset(data, 0, 32);
|
||||
data[0] = 0x01;
|
||||
data[1] = kPadAnalogMarker;
|
||||
data[2] = 0xFF;
|
||||
data[3] = 0xFF;
|
||||
data[4] = data[5] = data[6] = data[7] = kPadStickCenter;
|
||||
|
||||
uint16_t btns = 0xFFFFu;
|
||||
constexpr int kGamepad = 0;
|
||||
const bool useGamepad = IsGamepadAvailable(kGamepad);
|
||||
auto clearBit = [&btns](uint16_t mask) { btns &= ~mask; };
|
||||
|
||||
if (useGamepad)
|
||||
{
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_LEFT_FACE_UP)) clearBit(PAD_UP);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_LEFT_FACE_DOWN)) clearBit(PAD_DOWN);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_LEFT_FACE_LEFT)) clearBit(PAD_LEFT);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_LEFT_FACE_RIGHT)) clearBit(PAD_RIGHT);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) clearBit(PAD_CROSS);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_RIGHT_FACE_RIGHT)) clearBit(PAD_CIRCLE);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_RIGHT_FACE_LEFT)) clearBit(PAD_SQUARE);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_RIGHT_FACE_UP)) clearBit(PAD_TRIANGLE);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_LEFT_TRIGGER_1)) clearBit(PAD_L1);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_RIGHT_TRIGGER_1)) clearBit(PAD_R1);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_LEFT_TRIGGER_2)) clearBit(PAD_L2);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_RIGHT_TRIGGER_2)) clearBit(PAD_R2);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_MIDDLE_RIGHT)) clearBit(PAD_START);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_MIDDLE_LEFT)) clearBit(PAD_SELECT);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_LEFT_THUMB)) clearBit(PAD_L3);
|
||||
if (IsGamepadButtonDown(kGamepad, GAMEPAD_BUTTON_RIGHT_THUMB)) clearBit(PAD_R3);
|
||||
|
||||
float lx = GetGamepadAxisMovement(kGamepad, GAMEPAD_AXIS_LEFT_X);
|
||||
float ly = GetGamepadAxisMovement(kGamepad, GAMEPAD_AXIS_LEFT_Y);
|
||||
float rx = GetGamepadAxisMovement(kGamepad, GAMEPAD_AXIS_RIGHT_X);
|
||||
float ry = GetGamepadAxisMovement(kGamepad, GAMEPAD_AXIS_RIGHT_Y);
|
||||
data[6] = static_cast<uint8_t>(128 + lx * 127);
|
||||
data[7] = static_cast<uint8_t>(128 + ly * 127);
|
||||
data[4] = static_cast<uint8_t>(128 + rx * 127);
|
||||
data[5] = static_cast<uint8_t>(128 + ry * 127);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)) clearBit(PAD_UP);
|
||||
if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) clearBit(PAD_DOWN);
|
||||
if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) clearBit(PAD_LEFT);
|
||||
if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) clearBit(PAD_RIGHT);
|
||||
if (IsKeyDown(KEY_ENTER) || IsKeyDown(KEY_SPACE)) clearBit(PAD_CROSS);
|
||||
if (IsKeyDown(KEY_ESCAPE)) clearBit(PAD_CIRCLE);
|
||||
if (IsKeyDown(KEY_KP_0) || IsKeyDown(KEY_Z)) clearBit(PAD_SQUARE);
|
||||
if (IsKeyDown(KEY_KP_1) || IsKeyDown(KEY_X)) clearBit(PAD_TRIANGLE);
|
||||
if (IsKeyDown(KEY_Q)) clearBit(PAD_L1);
|
||||
if (IsKeyDown(KEY_E)) clearBit(PAD_R1);
|
||||
if (IsKeyDown(KEY_LEFT_SHIFT)) clearBit(PAD_L2);
|
||||
if (IsKeyDown(KEY_RIGHT_SHIFT)) clearBit(PAD_R2);
|
||||
if (IsKeyDown(KEY_ENTER)) clearBit(PAD_START);
|
||||
if (IsKeyDown(KEY_TAB)) clearBit(PAD_SELECT);
|
||||
}
|
||||
|
||||
data[2] = static_cast<uint8_t>(btns & 0xFF);
|
||||
data[3] = static_cast<uint8_t>(btns >> 8);
|
||||
return true;
|
||||
}
|
||||
@@ -296,8 +296,13 @@ bool PS2Runtime::initialize(const char *title)
|
||||
return false;
|
||||
}
|
||||
|
||||
m_iop.init(m_memory.getRDRAM());
|
||||
m_iop.reset();
|
||||
|
||||
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
||||
InitWindow(FB_WIDTH, FB_HEIGHT, title);
|
||||
InitAudioDevice();
|
||||
m_audioBackend.setAudioReady(IsAudioDeviceReady());
|
||||
SetTargetFPS(60);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "ps2_syscalls.h"
|
||||
#include "ps2_runtime.h"
|
||||
#include "ps2_iop_audio.h"
|
||||
#include "ps2_runtime_macros.h"
|
||||
#include "ps2_stubs.h"
|
||||
#include <iostream>
|
||||
|
||||
@@ -1500,26 +1500,24 @@ void scePadPortOpen(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
|
||||
|
||||
void scePadRead(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
|
||||
{
|
||||
(void)runtime;
|
||||
|
||||
const uint32_t dataAddr = getRegU32(ctx, 6); // a2
|
||||
const int port = static_cast<int>(getRegU32(ctx, 4));
|
||||
const int slot = static_cast<int>(getRegU32(ctx, 5));
|
||||
const uint32_t dataAddr = getRegU32(ctx, 6);
|
||||
uint8_t *data = getMemPtr(rdram, dataAddr);
|
||||
if (!data)
|
||||
{
|
||||
setReturnS32(ctx, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// struct padButtonStatus (32 bytes): neutral state, no buttons pressed.
|
||||
if (runtime && runtime->padBackend().readState(port, slot, data, 32))
|
||||
{
|
||||
setReturnS32(ctx, 1);
|
||||
return;
|
||||
}
|
||||
std::memset(data, 0, 32);
|
||||
data[1] = 0x73; // analog/dualshock mode marker
|
||||
data[2] = 0xFF; // btns low (active-low)
|
||||
data[3] = 0xFF; // btns high
|
||||
data[4] = 0x80; // rjoy_h
|
||||
data[5] = 0x80; // rjoy_v
|
||||
data[6] = 0x80; // ljoy_h
|
||||
data[7] = 0x80; // ljoy_v
|
||||
|
||||
data[1] = 0x73;
|
||||
data[2] = data[3] = 0xFF;
|
||||
data[4] = data[5] = data[6] = data[7] = 0x80;
|
||||
setReturnS32(ctx, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,15 @@ static void releasePs2Fd(int ps2Fd)
|
||||
g_fileDescriptors.erase(ps2Fd);
|
||||
}
|
||||
|
||||
struct VagAccumEntry
|
||||
{
|
||||
std::vector<uint8_t> data;
|
||||
uint32_t firstBufAddr = 0;
|
||||
};
|
||||
static std::unordered_map<int, VagAccumEntry> g_vagAccum;
|
||||
static std::mutex g_vagAccumMutex;
|
||||
static constexpr size_t kVagAccumMaxBytes = 16 * 1024 * 1024;
|
||||
|
||||
static const char *translateFioMode(int ps2Flags)
|
||||
{
|
||||
bool read = (ps2Flags & PS2_FIO_O_RDONLY) || (ps2Flags & PS2_FIO_O_RDWR);
|
||||
@@ -106,21 +115,47 @@ void fioOpen(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
|
||||
|
||||
void fioClose(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
|
||||
{
|
||||
int ps2Fd = (int)getRegU32(ctx, 4); // $a0
|
||||
std::cout << "fioClose: fd=" << ps2Fd << std::endl;
|
||||
int ps2Fd = (int)getRegU32(ctx, 4);
|
||||
|
||||
FILE *fp = getHostFile(ps2Fd);
|
||||
if (!fp)
|
||||
{
|
||||
std::cerr << "fioClose warning: Invalid PS2 file descriptor " << ps2Fd << std::endl;
|
||||
setReturnS32(ctx, -1); // e.g., -EBADF
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
int ret = ::fclose(fp);
|
||||
releasePs2Fd(ps2Fd);
|
||||
|
||||
// returns 0 on success, -1 on error
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_vagAccumMutex);
|
||||
auto it = g_vagAccum.find(ps2Fd);
|
||||
if (it != g_vagAccum.end())
|
||||
{
|
||||
VagAccumEntry &e = it->second;
|
||||
if (e.data.size() >= 48)
|
||||
{
|
||||
const uint32_t magic = (static_cast<uint32_t>(e.data[0]) << 24) |
|
||||
(static_cast<uint32_t>(e.data[1]) << 16) |
|
||||
(static_cast<uint32_t>(e.data[2]) << 8) |
|
||||
static_cast<uint32_t>(e.data[3]);
|
||||
const uint32_t magicLE = (static_cast<uint32_t>(e.data[3]) << 24) |
|
||||
(static_cast<uint32_t>(e.data[2]) << 16) |
|
||||
(static_cast<uint32_t>(e.data[1]) << 8) |
|
||||
static_cast<uint32_t>(e.data[0]);
|
||||
if (magic == 0x56414770u || magicLE == 0x56414770u)
|
||||
{
|
||||
if (runtime)
|
||||
runtime->audioBackend().onVagTransferFromBuffer(
|
||||
e.data.data(), static_cast<uint32_t>(e.data.size()),
|
||||
e.firstBufAddr ? e.firstBufAddr : 0u);
|
||||
}
|
||||
}
|
||||
g_vagAccum.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
setReturnS32(ctx, ret == 0 ? 0 : -1);
|
||||
}
|
||||
|
||||
@@ -161,11 +196,39 @@ void fioRead(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
|
||||
{
|
||||
std::cerr << "fioRead error: fread failed for fd " << ps2Fd << ": " << strerror(errno) << std::endl;
|
||||
clearerr(fp);
|
||||
setReturnS32(ctx, -1); // -EIO or other appropriate error
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
// returns number of bytes read (can be 0 for EOF)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_vagAccumMutex);
|
||||
auto it = g_vagAccum.find(ps2Fd);
|
||||
if (it != g_vagAccum.end())
|
||||
{
|
||||
VagAccumEntry &e = it->second;
|
||||
if (e.data.size() + bytesRead <= kVagAccumMaxBytes)
|
||||
e.data.insert(e.data.end(), hostBuf, hostBuf + bytesRead);
|
||||
}
|
||||
else if (bytesRead >= 4)
|
||||
{
|
||||
const uint32_t magic = (static_cast<uint32_t>(hostBuf[0]) << 24) |
|
||||
(static_cast<uint32_t>(hostBuf[1]) << 16) |
|
||||
(static_cast<uint32_t>(hostBuf[2]) << 8) |
|
||||
static_cast<uint32_t>(hostBuf[3]);
|
||||
const uint32_t magicLE = (static_cast<uint32_t>(hostBuf[3]) << 24) |
|
||||
(static_cast<uint32_t>(hostBuf[2]) << 16) |
|
||||
(static_cast<uint32_t>(hostBuf[1]) << 8) |
|
||||
static_cast<uint32_t>(hostBuf[0]);
|
||||
if (magic == 0x56414770u || magicLE == 0x56414770u)
|
||||
{
|
||||
VagAccumEntry &e = g_vagAccum[ps2Fd];
|
||||
e.firstBufAddr = bufAddr;
|
||||
if (bytesRead <= kVagAccumMaxBytes)
|
||||
e.data.assign(hostBuf, hostBuf + bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setReturnS32(ctx, (int32_t)bytesRead);
|
||||
}
|
||||
|
||||
|
||||
@@ -321,6 +321,19 @@ void SifCallRpc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!handled && sid != 0 && runtime)
|
||||
{
|
||||
if (!runtime->iop().handleRPC(sid, rpcNum, sendBuf, sendSize, recvBuf, recvSize) &&
|
||||
sid == IOP_SID_LIBSD)
|
||||
{
|
||||
const uint8_t *sendPtr = sendBuf ? getConstMemPtr(rdram, sendBuf) : nullptr;
|
||||
uint8_t *recvPtr = recvBuf ? getMemPtr(rdram, recvBuf) : nullptr;
|
||||
ps2_iop_audio::handleLibSdRpc(runtime, sid, rpcNum, sendPtr, sendSize, recvPtr, recvSize);
|
||||
handled = true;
|
||||
resultPtr = recvBuf;
|
||||
}
|
||||
}
|
||||
|
||||
const bool isDtxUrpc = (sid == kDtxRpcSid) && (rpcNum >= 0x400u) && (rpcNum < 0x500u);
|
||||
uint32_t dtxUrpcCommand = isDtxUrpc ? (rpcNum & 0xFFu) : 0u;
|
||||
uint32_t dtxUrpcFn = 0;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "ps2_runtime.h"
|
||||
#include "register_functions.h"
|
||||
#include "games_database.h"
|
||||
#ifdef _DEBUG
|
||||
#include "ps2_log.h"
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
@@ -63,5 +66,8 @@ int main(int argc, char* argv[])
|
||||
|
||||
runtime.run();
|
||||
|
||||
#ifdef _DEBUG
|
||||
ps2_log::print_saved_location();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user