refactor: from guest threads to EE scheduler

This commit is contained in:
Ran-j
2026-07-25 21:23:24 -03:00
parent f3687c5ae6
commit cc941d2f4f
41 changed files with 5018 additions and 7410 deletions
+71 -646
View File
@@ -1,538 +1,103 @@
#include "Common.h"
#include "Interrupt.h"
#include "ps2_log.h"
#include "Stubs/GS.h"
namespace ps2_syscalls
{
namespace interrupt_state
namespace
{
constexpr uint32_t kIntcVblankStart = 2u;
constexpr uint32_t kIntcVblankEnd = 3u;
constexpr auto kVblankPeriod = std::chrono::microseconds(16667);
constexpr int kMaxCatchupTicks = 4;
constexpr uint32_t kMaxIrqHandlerSteps = 4096u;
std::mutex g_irq_handler_mutex;
std::mutex g_irq_worker_mutex;
std::condition_variable g_irq_worker_cv;
std::mutex g_vsync_flag_mutex;
std::condition_variable g_vsync_cv;
std::atomic<bool> g_irq_worker_stop{false};
std::atomic<bool> g_irq_worker_running{false};
uint32_t g_enabled_intc_mask = 0xFFFFFFFFu;
uint32_t g_enabled_dmac_mask = 0xFFFFFFFFu;
uint64_t g_vsync_tick_counter = 0u;
VSyncFlagRegistration g_vsync_registration{};
}
using namespace interrupt_state;
static void writeGuestU32NoThrow(uint8_t *rdram, uint32_t addr, uint32_t value)
{
if (addr == 0u)
EeScheduler &scheduler(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
{
return;
EeScheduler &result = runtime->eeScheduler();
result.bindMainContextForSyscall(*ctx, rdram);
return result;
}
uint8_t *dst = getMemPtr(rdram, addr);
if (!dst)
void setCauseEnabled(uint8_t *rdram,
R5900Context *ctx,
PS2Runtime *runtime,
bool dmac,
bool enabled)
{
return;
}
std::memcpy(dst, &value, sizeof(value));
}
static void writeGuestU64NoThrow(uint8_t *rdram, uint32_t addr, uint64_t value)
{
if (addr == 0u)
{
return;
setReturnS32(ctx,
scheduler(rdram, ctx, runtime)
.setIrqCauseEnabled(dmac, getRegU32(ctx, 4), enabled));
}
uint8_t *dst = getMemPtr(rdram, addr);
if (!dst)
void addHandler(uint8_t *rdram,
R5900Context *ctx,
PS2Runtime *runtime,
bool dmac)
{
return;
}
std::memcpy(dst, &value, sizeof(value));
}
static uint32_t readGuestU32NoThrow(uint8_t *rdram, uint32_t addr)
{
if (addr == 0u)
{
return 0u;
const int id = scheduler(rdram, ctx, runtime)
.addIrqHandler(dmac,
getRegU32(ctx, 4),
getRegU32(ctx, 5),
getRegU32(ctx, 6) != 0u,
getRegU32(ctx, 7),
getRegU32(ctx, 28),
getRegU32(ctx, 29));
setReturnS32(ctx, id);
}
uint8_t *src = getMemPtr(rdram, addr);
if (!src)
void removeHandler(uint8_t *rdram,
R5900Context *ctx,
PS2Runtime *runtime,
bool dmac)
{
return 0u;
setReturnS32(ctx,
scheduler(rdram, ctx, runtime)
.removeIrqHandler(dmac,
getRegU32(ctx, 4),
static_cast<int>(getRegU32(ctx, 5))));
}
uint32_t value = 0u;
std::memcpy(&value, src, sizeof(value));
return value;
}
static uint32_t getAsyncHandlerStackTop(PS2Runtime *runtime)
{
constexpr uint32_t kAsyncHandlerStackSize = 0x4000u;
thread_local PS2Runtime *s_cachedRuntime = nullptr;
thread_local uint32_t s_cachedStackTop = 0u;
if (runtime == nullptr)
void setHandlerEnabled(uint8_t *rdram,
R5900Context *ctx,
PS2Runtime *runtime,
bool dmac,
bool enabled)
{
return PS2_RAM_SIZE - 0x10u;
}
if (s_cachedRuntime != runtime || s_cachedStackTop == 0u)
{
s_cachedRuntime = runtime;
s_cachedStackTop = runtime->reserveAsyncCallbackStack(kAsyncHandlerStackSize, 16u);
}
return (s_cachedStackTop != 0u) ? s_cachedStackTop : (PS2_RAM_SIZE - 0x10u);
}
static void dispatchIntcHandlersForCause(uint8_t *rdram, PS2Runtime *runtime, uint32_t cause)
{
if (!rdram || !runtime)
{
return;
}
std::vector<IrqHandlerInfo> handlers;
{
std::lock_guard<std::mutex> lock(g_irq_handler_mutex);
if (cause < 32u && (g_enabled_intc_mask & (1u << cause)) == 0u)
{
return;
}
handlers.reserve(g_intcHandlers.size());
for (const auto &[id, info] : g_intcHandlers)
{
(void)id;
if (!info.enabled)
{
continue;
}
if (info.cause != cause)
{
continue;
}
if (info.handler == 0u)
{
continue;
}
handlers.push_back(info);
}
std::sort(handlers.begin(), handlers.end(), [](const IrqHandlerInfo &a, const IrqHandlerInfo &b)
{ return a.order < b.order; });
}
for (const IrqHandlerInfo &info : handlers)
{
if (!runtime->hasFunction(info.handler))
{
if (cause == kIntcVblankStart)
{
PS2_IF_AGRESSIVE_LOGS({
static std::atomic<uint32_t> s_missingHandlerLogCount{0u};
const uint32_t logIndex = s_missingHandlerLogCount.fetch_add(1u, std::memory_order_relaxed);
if (logIndex < 32u)
{
auto flags = std::cout.flags();
std::cout << "[INTC:missing] cause=" << cause
<< " handler=0x" << std::hex << info.handler
<< std::dec
<< " id=" << info.id
<< std::endl;
std::cout.flags(flags);
}
});
}
continue;
}
try
{
R5900Context irqCtx{};
SET_GPR_U32(&irqCtx, 28, info.gp);
SET_GPR_U32(&irqCtx, 29, getAsyncHandlerStackTop(runtime));
SET_GPR_U32(&irqCtx, 31, 0u);
SET_GPR_U32(&irqCtx, 4, cause);
SET_GPR_U32(&irqCtx, 5, info.arg);
SET_GPR_U32(&irqCtx, 6, 0u);
SET_GPR_U32(&irqCtx, 7, 0u);
irqCtx.pc = info.handler;
bool reschedulePending = false;
uint64_t handoffBaseline = 0u;
uint32_t steps = 0u;
{
PS2Runtime::GuestExecutionScope guestExecution(runtime);
PS2Runtime::DeferredGuestYieldScope deferYield(reschedulePending);
while (irqCtx.pc != 0u && runtime && !runtime->isStopRequested() && steps < kMaxIrqHandlerSteps)
{
PS2Runtime::RecompiledFunction step = runtime->lookupFunction(irqCtx.pc);
if (!step)
{
break;
}
step(rdram, &irqCtx, runtime);
++steps;
}
handoffBaseline = runtime->guestExecutionHandoffEpochSnapshot();
}
if (steps >= kMaxIrqHandlerSteps)
{
static uint32_t s_stepLimitLogCount = 0u;
if (s_stepLimitLogCount < 16u)
{
std::cerr << "[INTC:step-limit] handler=0x" << std::hex << info.handler << " pc=0x" << irqCtx.pc << std::dec << std::endl;
++s_stepLimitLogCount;
}
}
if (reschedulePending && !runtime->isStopRequested())
{
runtime->waitForGuestExecutionHandoff(handoffBaseline);
}
}
catch (const ThreadExitException &)
{
}
catch (const std::exception &e)
{
static uint32_t warnCount = 0;
if (warnCount < 8u)
{
std::cerr << "[INTC] handler 0x" << std::hex << info.handler
<< " threw exception: " << e.what() << std::dec << std::endl;
++warnCount;
}
}
setReturnS32(ctx,
scheduler(rdram, ctx, runtime)
.setIrqHandlerEnabled(dmac,
static_cast<int>(getRegU32(ctx, 5)),
enabled));
}
}
void dispatchDmacHandlersForCause(uint8_t *rdram, PS2Runtime *runtime, uint32_t cause)
void dispatchDmacHandlersForCause(uint8_t *, PS2Runtime *runtime, uint32_t cause)
{
if (!rdram || !runtime)
{
return;
}
std::vector<IrqHandlerInfo> handlers;
{
std::lock_guard<std::mutex> lock(g_irq_handler_mutex);
if (cause < 32u && (g_enabled_dmac_mask & (1u << cause)) == 0u)
{
return;
}
handlers.reserve(g_dmacHandlers.size());
for (const auto &[id, info] : g_dmacHandlers)
{
(void)id;
if (!info.enabled)
{
continue;
}
if (info.cause != cause)
{
continue;
}
if (info.handler == 0u)
{
continue;
}
handlers.push_back(info);
}
std::sort(handlers.begin(), handlers.end(), [](const IrqHandlerInfo &a, const IrqHandlerInfo &b)
{ return a.order < b.order; });
}
for (const IrqHandlerInfo &info : handlers)
{
if (!runtime->hasFunction(info.handler))
{
continue;
}
try
{
R5900Context irqCtx{};
SET_GPR_U32(&irqCtx, 28, info.gp);
SET_GPR_U32(&irqCtx, 29, getAsyncHandlerStackTop(runtime));
SET_GPR_U32(&irqCtx, 31, 0u);
SET_GPR_U32(&irqCtx, 4, cause);
SET_GPR_U32(&irqCtx, 5, info.arg);
SET_GPR_U32(&irqCtx, 6, 0u);
SET_GPR_U32(&irqCtx, 7, 0u);
irqCtx.pc = info.handler;
bool reschedulePending = false;
uint64_t handoffBaseline = 0u;
uint32_t steps = 0u;
{
PS2Runtime::GuestExecutionScope guestExecution(runtime);
PS2Runtime::DeferredGuestYieldScope deferYield(reschedulePending);
while (irqCtx.pc != 0u && runtime && !runtime->isStopRequested() &&
steps < kMaxIrqHandlerSteps)
{
PS2Runtime::RecompiledFunction step = runtime->lookupFunction(irqCtx.pc);
if (!step)
{
break;
}
step(rdram, &irqCtx, runtime);
++steps;
}
handoffBaseline = runtime->guestExecutionHandoffEpochSnapshot();
}
if (steps >= kMaxIrqHandlerSteps)
{
static uint32_t s_stepLimitLogCount = 0u;
if (s_stepLimitLogCount < 16u)
{
std::cerr << "[DMAC:step-limit] handler=0x" << std::hex << info.handler
<< " pc=0x" << irqCtx.pc << std::dec << std::endl;
++s_stepLimitLogCount;
}
}
if (reschedulePending && !runtime->isStopRequested())
{
runtime->waitForGuestExecutionHandoff(handoffBaseline);
}
}
catch (const ThreadExitException &)
{
}
catch (const std::exception &e)
{
static uint32_t warnCount = 0;
if (warnCount < 8u)
{
std::cerr << "[DMAC] handler 0x" << std::hex << info.handler
<< " threw exception: " << e.what() << std::dec << std::endl;
++warnCount;
}
}
}
runtime->eeScheduler().dispatchIrq(true, cause);
}
static void updateGsCsrFieldForVSync(PS2Runtime *runtime, uint64_t tickValue)
uint64_t GetCurrentVSyncTick(PS2Runtime *runtime)
{
if (!runtime)
{
return;
}
constexpr uint64_t kGsCsrFieldMask = 0x2000ull;
std::atomic<uint64_t> &csr = runtime->memory().gs().csr;
if (tickValue & 1ull)
{
csr.fetch_or(kGsCsrFieldMask);
}
else
{
csr.fetch_and(~kGsCsrFieldMask);
}
return runtime->eeScheduler().currentVSyncTick();
}
static uint64_t signalVSyncFlag(uint8_t *rdram, PS2Runtime *runtime)
void WaitVSyncTick(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime, int fixedResult)
{
VSyncFlagRegistration reg{};
uint64_t tickValue = 0u;
{
std::lock_guard<std::mutex> lock(g_vsync_flag_mutex);
reg = g_vsync_registration;
g_vsync_registration = {};
tickValue = ++g_vsync_tick_counter;
}
g_vsync_cv.notify_all();
updateGsCsrFieldForVSync(runtime, tickValue);
if (reg.flagAddr != 0u)
{
writeGuestU32NoThrow(rdram, reg.flagAddr, 1u);
}
if (reg.tickAddr != 0u)
{
writeGuestU64NoThrow(rdram, reg.tickAddr, tickValue);
}
return tickValue;
}
static void interruptWorkerMain(uint8_t *rdram, PS2Runtime *runtime)
{
g_currentThreadId = -1;
using clock = std::chrono::steady_clock;
auto nextTick = clock::now() + kVblankPeriod;
while (runtime != nullptr && !runtime->isStopRequested())
{
{
std::unique_lock<std::mutex> lock(g_irq_worker_mutex);
if (g_irq_worker_cv.wait_until(lock, nextTick, []()
{ return g_irq_worker_stop.load(std::memory_order_acquire); }))
{
break;
}
}
const auto now = clock::now();
int ticksToProcess = 0;
while (now >= nextTick && ticksToProcess < kMaxCatchupTicks)
{
++ticksToProcess;
nextTick += kVblankPeriod;
}
if (ticksToProcess == 0)
{
continue;
}
for (int i = 0; i < ticksToProcess; ++i)
{
bool reschedulePending = false;
uint64_t handoffBaseline = 0u;
{
PS2Runtime::GuestExecutionScope guestExecution(runtime);
PS2Runtime::DeferredGuestYieldScope deferYield(reschedulePending);
const uint64_t tickValue = signalVSyncFlag(rdram, runtime);
ps2_stubs::dispatchGsSyncVCallback(rdram, runtime, tickValue);
dispatchIntcHandlersForCause(rdram, runtime, kIntcVblankStart);
handoffBaseline = runtime->guestExecutionHandoffEpochSnapshot();
}
if (reschedulePending && !runtime->isStopRequested())
{
runtime->waitForGuestExecutionHandoff(handoffBaseline);
}
std::this_thread::sleep_for(std::chrono::microseconds(500));
dispatchIntcHandlersForCause(rdram, runtime, kIntcVblankEnd);
}
}
g_irq_worker_running.store(false, std::memory_order_release);
g_irq_worker_cv.notify_all();
}
static void ensureInterruptWorkerRunning(uint8_t *rdram, PS2Runtime *runtime)
{
if (!rdram || !runtime)
{
return;
}
std::lock_guard<std::mutex> lock(g_irq_worker_mutex);
if (g_irq_worker_running.load(std::memory_order_acquire))
{
return;
}
g_irq_worker_stop.store(false, std::memory_order_release);
g_irq_worker_running.store(true, std::memory_order_release);
try
{
std::thread(interruptWorkerMain, rdram, runtime).detach();
}
catch (...)
{
g_irq_worker_running.store(false, std::memory_order_release);
}
}
void EnsureVSyncWorkerRunning(uint8_t *rdram, PS2Runtime *runtime)
{
ensureInterruptWorkerRunning(rdram, runtime);
}
uint64_t GetCurrentVSyncTick()
{
std::lock_guard<std::mutex> lock(g_vsync_flag_mutex);
return g_vsync_tick_counter;
}
void stopInterruptWorker()
{
g_irq_worker_stop.store(true, std::memory_order_release);
g_irq_worker_cv.notify_all();
std::unique_lock<std::mutex> lock(g_irq_worker_mutex);
g_irq_worker_cv.wait_for(lock, std::chrono::milliseconds(500), []()
{ return !g_irq_worker_running.load(std::memory_order_acquire); });
g_vsync_cv.notify_all();
}
uint64_t WaitForNextVSyncTick(uint8_t *rdram, PS2Runtime *runtime)
{
ensureInterruptWorkerRunning(rdram, runtime);
std::unique_lock<std::mutex> lock(g_vsync_flag_mutex);
uint64_t current = g_vsync_tick_counter;
uint64_t result = current;
waitWithGuestExecutionReleasedUntilUnlocked(
runtime,
lock,
[&]()
{
g_vsync_cv.wait(lock, [current, runtime]()
{ return g_vsync_tick_counter > current || (runtime != nullptr && runtime->isStopRequested()); });
},
[&]()
{
result = g_vsync_tick_counter;
});
return result;
}
void WaitVSyncTick(uint8_t *rdram, PS2Runtime *runtime)
{
(void)WaitForNextVSyncTick(rdram, runtime);
EeScheduler &ee = scheduler(rdram, ctx, runtime);
ee.waitVSync(ee.currentVSyncTick(), fixedResult);
}
void SetVSyncFlag(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
{
const uint32_t flagAddr = getRegU32(ctx, 4);
const uint32_t tickAddr = getRegU32(ctx, 5);
const uint32_t flagAddress = getRegU32(ctx, 4);
const uint32_t tickAddress = getRegU32(ctx, 5);
if ((flagAddress != 0u && !getEeGuestStruct<uint32_t>(rdram, flagAddress)) ||
(tickAddress != 0u && !getEeGuestStruct<uint64_t>(rdram, tickAddress)))
{
std::lock_guard<std::mutex> lock(g_vsync_flag_mutex);
g_vsync_registration.flagAddr = flagAddr;
g_vsync_registration.tickAddr = tickAddr;
setReturnS32(ctx, KE_ERROR);
return;
}
writeGuestU32NoThrow(rdram, flagAddr, 0u);
writeGuestU64NoThrow(rdram, tickAddr, 0u);
ensureInterruptWorkerRunning(rdram, runtime);
scheduler(rdram, ctx, runtime).setVSyncFlag(flagAddress, tickAddress);
setReturnS32(ctx, KE_OK);
}
void EnableIntc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
{
const uint32_t cause = getRegU32(ctx, 4);
if (cause < 32u)
{
std::lock_guard<std::mutex> lock(g_irq_handler_mutex);
g_enabled_intc_mask |= (1u << cause);
}
if (cause == kIntcVblankStart || cause == kIntcVblankEnd)
{
PS2_IF_AGRESSIVE_LOGS({
static std::atomic<uint32_t> s_enableLogCount{0u};
const uint32_t logIndex = s_enableLogCount.fetch_add(1u, std::memory_order_relaxed);
if (logIndex < 32u)
{
RUNTIME_LOG("[EnableIntc] cause=" << cause);
}
});
}
setReturnS32(ctx, KE_OK);
setCauseEnabled(rdram, ctx, runtime, false, true);
}
void iEnableIntc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
@@ -542,24 +107,7 @@ namespace ps2_syscalls
void DisableIntc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
{
const uint32_t cause = getRegU32(ctx, 4);
if (cause < 32u)
{
std::lock_guard<std::mutex> lock(g_irq_handler_mutex);
g_enabled_intc_mask &= ~(1u << cause);
}
if (cause == kIntcVblankStart || cause == kIntcVblankEnd)
{
PS2_IF_AGRESSIVE_LOGS({
static std::atomic<uint32_t> s_disableLogCount{0u};
const uint32_t logIndex = s_disableLogCount.fetch_add(1u, std::memory_order_relaxed);
if (logIndex < 32u)
{
RUNTIME_LOG("[DisableIntc] cause=" << cause);
}
});
}
setReturnS32(ctx, KE_OK);
setCauseEnabled(rdram, ctx, runtime, false, false);
}
void iDisableIntc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
@@ -569,47 +117,7 @@ namespace ps2_syscalls
void AddIntcHandler(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
{
IrqHandlerInfo info{};
info.cause = getRegU32(ctx, 4);
info.handler = getRegU32(ctx, 5);
uint32_t next = getRegU32(ctx, 6);
info.arg = getRegU32(ctx, 7);
info.gp = getRegU32(ctx, 28);
info.sp = getRegU32(ctx, 29);
info.enabled = true;
int handlerId = 0;
{
std::lock_guard<std::mutex> lock(g_irq_handler_mutex);
info.order = (next == 0) ? --g_intc_head_order : ++g_intc_tail_order;
handlerId = g_nextIntcHandlerId++;
info.id = handlerId;
g_intcHandlers[handlerId] = info;
}
if (info.cause == kIntcVblankStart)
{
PS2_IF_AGRESSIVE_LOGS({
static std::atomic<uint32_t> s_addHandlerLogCount{0u};
const uint32_t logIndex = s_addHandlerLogCount.fetch_add(1u, std::memory_order_relaxed);
if (logIndex < 32u)
{
auto flags = std::cout.flags();
std::cout << "[AddIntcHandler] cause=" << info.cause
<< " handler=0x" << std::hex << info.handler
<< " arg=0x" << info.arg
<< " gp=0x" << info.gp
<< " sp=0x" << info.sp
<< std::dec
<< " id=" << handlerId
<< std::endl;
std::cout.flags(flags);
}
});
}
ensureInterruptWorkerRunning(rdram, runtime);
setReturnS32(ctx, handlerId);
addHandler(rdram, ctx, runtime, false);
}
void AddIntcHandler2(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
@@ -619,40 +127,12 @@ namespace ps2_syscalls
void RemoveIntcHandler(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
{
const uint32_t cause = getRegU32(ctx, 4);
const int handlerId = static_cast<int>(getRegU32(ctx, 5));
if (handlerId > 0)
{
std::lock_guard<std::mutex> lock(g_irq_handler_mutex);
auto it = g_intcHandlers.find(handlerId);
if (it != g_intcHandlers.end() && it->second.cause == cause)
{
g_intcHandlers.erase(it);
}
}
setReturnS32(ctx, KE_OK);
removeHandler(rdram, ctx, runtime, false);
}
void AddDmacHandler(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
{
IrqHandlerInfo info{};
info.cause = getRegU32(ctx, 4);
info.handler = getRegU32(ctx, 5);
uint32_t next = getRegU32(ctx, 6);
info.arg = getRegU32(ctx, 7);
info.gp = getRegU32(ctx, 28);
info.sp = getRegU32(ctx, 29);
info.enabled = true;
int handlerId = 0;
{
std::lock_guard<std::mutex> lock(g_irq_handler_mutex);
info.order = (next == 0) ? --g_dmac_head_order : ++g_dmac_tail_order;
handlerId = g_nextDmacHandlerId++;
info.id = handlerId;
g_dmacHandlers[handlerId] = info;
}
setReturnS32(ctx, handlerId);
addHandler(rdram, ctx, runtime, true);
}
void AddDmacHandler2(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
@@ -662,81 +142,32 @@ namespace ps2_syscalls
void RemoveDmacHandler(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
{
const uint32_t cause = getRegU32(ctx, 4);
const int handlerId = static_cast<int>(getRegU32(ctx, 5));
if (handlerId > 0)
{
std::lock_guard<std::mutex> lock(g_irq_handler_mutex);
auto it = g_dmacHandlers.find(handlerId);
if (it != g_dmacHandlers.end() && it->second.cause == cause)
{
g_dmacHandlers.erase(it);
}
}
setReturnS32(ctx, KE_OK);
removeHandler(rdram, ctx, runtime, true);
}
void EnableIntcHandler(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
{
const int handlerId = static_cast<int>(getRegU32(ctx, 5));
{
std::lock_guard<std::mutex> lock(g_irq_handler_mutex);
if (auto it = g_intcHandlers.find(handlerId); it != g_intcHandlers.end())
{
it->second.enabled = true;
}
}
setReturnS32(ctx, KE_OK);
setHandlerEnabled(rdram, ctx, runtime, false, true);
}
void DisableIntcHandler(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
{
const int handlerId = static_cast<int>(getRegU32(ctx, 5));
{
std::lock_guard<std::mutex> lock(g_irq_handler_mutex);
if (auto it = g_intcHandlers.find(handlerId); it != g_intcHandlers.end())
{
it->second.enabled = false;
}
}
setReturnS32(ctx, KE_OK);
setHandlerEnabled(rdram, ctx, runtime, false, false);
}
void EnableDmacHandler(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
{
const int handlerId = static_cast<int>(getRegU32(ctx, 5));
{
std::lock_guard<std::mutex> lock(g_irq_handler_mutex);
if (auto it = g_dmacHandlers.find(handlerId); it != g_dmacHandlers.end())
{
it->second.enabled = true;
}
}
setReturnS32(ctx, KE_OK);
setHandlerEnabled(rdram, ctx, runtime, true, true);
}
void DisableDmacHandler(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
{
const int handlerId = static_cast<int>(getRegU32(ctx, 5));
{
std::lock_guard<std::mutex> lock(g_irq_handler_mutex);
if (auto it = g_dmacHandlers.find(handlerId); it != g_dmacHandlers.end())
{
it->second.enabled = false;
}
}
setReturnS32(ctx, KE_OK);
setHandlerEnabled(rdram, ctx, runtime, true, false);
}
void EnableDmac(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
{
const uint32_t cause = getRegU32(ctx, 4);
if (cause < 32u)
{
std::lock_guard<std::mutex> lock(g_irq_handler_mutex);
g_enabled_dmac_mask |= (1u << cause);
}
setReturnS32(ctx, KE_OK);
setCauseEnabled(rdram, ctx, runtime, true, true);
}
void iEnableDmac(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
@@ -746,13 +177,7 @@ namespace ps2_syscalls
void DisableDmac(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
{
const uint32_t cause = getRegU32(ctx, 4);
if (cause < 32u)
{
std::lock_guard<std::mutex> lock(g_irq_handler_mutex);
g_enabled_dmac_mask &= ~(1u << cause);
}
setReturnS32(ctx, KE_OK);
setCauseEnabled(rdram, ctx, runtime, true, false);
}
void iDisableDmac(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)