#include "stdafx.h" #include "../OpInfo.h" #include "ScriptAPI.h" #pragma warning(disable : 4702) // disable unreachable code warning using namespace ScriptAPI; static bool CbCond_PcBetween(JSAppCallback * cb, void * env); static bool CbCond_ReadAddrBetween(JSAppCallback * cb, void * env); static bool CbCond_WriteAddrBetween(JSAppCallback * cb, void * env); static bool CbCond_PcBetween_OpcodeEquals(JSAppCallback * cb, void * env); static bool CbCond_PcBetween_GprValueEquals(JSAppCallback * cb, void * env); static duk_idx_t CbArgs_GenericEventObject(duk_context * ctx, void * env); static duk_idx_t CbArgs_EmuStateChangeEventObject(duk_context * ctx, void * env); static duk_idx_t CbArgs_ExecEventObject(duk_context * ctx, void * env); static duk_idx_t CbArgs_ReadEventObject(duk_context * ctx, void * env); static duk_idx_t CbArgs_WriteEventObject(duk_context * ctx, void * env); static duk_idx_t CbArgs_OpcodeEventObject(duk_context * ctx, void * env); static duk_idx_t CbArgs_RegValueEventObject(duk_context * ctx, void * env); static duk_idx_t CbArgs_MouseEventObject(duk_context * ctx, void * env); static duk_idx_t CbArgs_SPTaskEventObject(duk_context * ctx, void * env); static duk_idx_t CbArgs_PIEventObject(duk_context * ctx, void * env); static duk_ret_t RequireAddressOrAddressRange(duk_context * ctx, duk_idx_t idx, uint32_t * addrStart, uint32_t * addrEnd); static duk_ret_t RequireInterpreterCPU(duk_context * ctx); void ScriptAPI::Define_events(duk_context * ctx) { const DukPropListEntry props[] = { {"onstatechange", DukCFunction(js_events_onstatechange)}, {"onexec", DukCFunction(js_events_onexec)}, {"onread", DukCFunction(js_events_onread)}, {"onwrite", DukCFunction(js_events_onwrite)}, {"ongprvalue", DukCFunction(js_events_ongprvalue)}, {"onopcode", DukCFunction(js_events_onopcode)}, {"onpifread", DukCFunction(js_events_onpifread)}, {"onsptask", DukCFunction(js_events_onsptask)}, {"onpidma", DukCFunction(js_events_onpidma)}, {"onmouseup", DukCFunction(js_events_onmouseup)}, {"onmousedown", DukCFunction(js_events_onmousedown)}, {"onmousemove", DukCFunction(js_events_onmousemove)}, {"remove", DukCFunction(js_events_remove)}, { nullptr } }; DefineGlobalInterface(ctx, "events", props); DefineGlobalClass(ctx, "GenericEvent", js_DummyConstructor); DefineGlobalClass(ctx, "EmuStateChangeEvent", js_DummyConstructor); DefineGlobalClass(ctx, "CPUExecEvent", js_DummyConstructor); DefineGlobalClass(ctx, "CPUReadWriteEvent", js_DummyConstructor); DefineGlobalClass(ctx, "CPUOpcodeEvent", js_DummyConstructor); DefineGlobalClass(ctx, "CPURegValueEvent", js_DummyConstructor); DefineGlobalClass(ctx, "SPTaskEvent", js_DummyConstructor); DefineGlobalClass(ctx, "PIEvent", js_DummyConstructor); DefineGlobalClass(ctx, "DrawEvent", js_DummyConstructor); const DukPropListEntry mouseEventStaticProps[] = { {"NONE", DukNumber(-1)}, {"LEFT", DukNumber(0)}, {"MIDDLE", DukNumber(1)}, {"RIGHT", DukNumber(2)}, {nullptr} }; DefineGlobalClass(ctx, "MouseEvent", js_DummyConstructor, nullptr, mouseEventStaticProps); } duk_ret_t ScriptAPI::js_events_onstatechange(duk_context * ctx) { CheckArgs(ctx, {Arg_Function}); JSAppCallbackID callbackId = AddAppCallback(ctx, 0, JS_HOOK_EMUSTATECHANGE, CbArgs_EmuStateChangeEventObject); duk_push_uint(ctx, callbackId); return 1; } duk_ret_t ScriptAPI::js_events_onexec(duk_context * ctx) { CheckArgs(ctx, {Arg_Any, Arg_Function}); uint32_t addrStart, addrEnd; RequireAddressOrAddressRange(ctx, 0, &addrStart, &addrEnd); RequireInterpreterCPU(ctx); JSAppCallback cb(GetInstance(ctx), duk_get_heapptr(ctx, 1), CbCond_PcBetween, CbArgs_ExecEventObject); cb.m_Params.addrStart = addrStart; cb.m_Params.addrEnd = addrEnd; JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPU_EXEC, cb); duk_push_uint(ctx, callbackId); return 1; } duk_ret_t ScriptAPI::js_events_onread(duk_context * ctx) { CheckArgs(ctx, {Arg_Any, Arg_Function}); uint32_t addrStart, addrEnd; RequireAddressOrAddressRange(ctx, 0, &addrStart, &addrEnd); RequireInterpreterCPU(ctx); JSAppCallback cb(GetInstance(ctx), duk_get_heapptr(ctx, 1), CbCond_ReadAddrBetween, CbArgs_ReadEventObject); cb.m_Params.addrStart = addrStart; cb.m_Params.addrEnd = addrEnd; JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPU_READ, cb); duk_push_uint(ctx, callbackId); return 1; } duk_ret_t ScriptAPI::js_events_onwrite(duk_context * ctx) { CheckArgs(ctx, {Arg_Any, Arg_Function}); uint32_t addrStart, addrEnd; RequireAddressOrAddressRange(ctx, 0, &addrStart, &addrEnd); RequireInterpreterCPU(ctx); JSAppCallback cb(GetInstance(ctx), duk_get_heapptr(ctx, 1), CbCond_WriteAddrBetween, CbArgs_WriteEventObject); cb.m_Params.addrStart = addrStart; cb.m_Params.addrEnd = addrEnd; JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPU_WRITE, cb); duk_push_uint(ctx, callbackId); return 1; } duk_ret_t ScriptAPI::js_events_onopcode(duk_context * ctx) { CheckArgs(ctx, {Arg_Any, Arg_Number, Arg_Number, Arg_Function}); uint32_t addrStart, addrEnd; RequireAddressOrAddressRange(ctx, 0, &addrStart, &addrEnd); RequireInterpreterCPU(ctx); uint32_t opcode = duk_get_uint(ctx, 1); uint32_t mask = duk_get_uint(ctx, 2); JSAppCallback cb(GetInstance(ctx), duk_get_heapptr(ctx, 3), CbCond_PcBetween_OpcodeEquals, CbArgs_OpcodeEventObject); cb.m_Params.addrStart = addrStart; cb.m_Params.addrEnd = addrEnd; cb.m_Params.opcode = opcode; cb.m_Params.opcodeMask = mask; JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPU_EXEC, cb); duk_push_uint(ctx, callbackId); return 1; } duk_ret_t ScriptAPI::js_events_ongprvalue(duk_context * ctx) { CheckArgs(ctx, {Arg_Any, Arg_Number, Arg_Number, Arg_Function}); uint32_t addrStart, addrEnd; RequireAddressOrAddressRange(ctx, 0, &addrStart, &addrEnd); RequireInterpreterCPU(ctx); JSAppCallback cb(GetInstance(ctx), duk_get_heapptr(ctx, 3), CbCond_PcBetween_GprValueEquals, CbArgs_RegValueEventObject); cb.m_Params.addrStart = addrStart; cb.m_Params.addrEnd = addrEnd; cb.m_Params.regIndices = duk_get_uint(ctx, 1); cb.m_Params.regValue = duk_get_uint(ctx, 2); JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPU_EXEC, cb); duk_push_uint(ctx, callbackId); return 1; } duk_ret_t ScriptAPI::js_events_onpifread(duk_context * ctx) { CheckArgs(ctx, {Arg_Function}); JSAppCallbackID callbackId = AddAppCallback(ctx, 0, JS_HOOK_PIFREAD, CbArgs_GenericEventObject); duk_push_uint(ctx, callbackId); return 1; } duk_ret_t ScriptAPI::js_events_onsptask(duk_context * ctx) { CheckArgs(ctx, {Arg_Function}); JSAppCallbackID callbackId = AddAppCallback(ctx, 0, JS_HOOK_RSPTASK, CbArgs_SPTaskEventObject); duk_push_uint(ctx, callbackId); return 1; } duk_ret_t ScriptAPI::js_events_onpidma(duk_context * ctx) { CheckArgs(ctx, {Arg_Function}); JSAppCallbackID callbackId = AddAppCallback(ctx, 0, JS_HOOK_PIDMA, CbArgs_PIEventObject); duk_push_uint(ctx, callbackId); return 1; } duk_ret_t ScriptAPI::js_events_onmouseup(duk_context * ctx) { CheckArgs(ctx, {Arg_Function}); JSAppCallbackID callbackId = AddAppCallback(ctx, 0, JS_HOOK_MOUSEUP, CbArgs_MouseEventObject); duk_push_uint(ctx, callbackId); return 1; } duk_ret_t ScriptAPI::js_events_onmousedown(duk_context * ctx) { CheckArgs(ctx, {Arg_Function}); JSAppCallbackID callbackId = AddAppCallback(ctx, 0, JS_HOOK_MOUSEDOWN, CbArgs_MouseEventObject); duk_push_uint(ctx, callbackId); return 1; } duk_ret_t ScriptAPI::js_events_onmousemove(duk_context * ctx) { CheckArgs(ctx, {Arg_Function}); JSAppCallbackID callbackId = AddAppCallback(ctx, 0, JS_HOOK_MOUSEMOVE, CbArgs_MouseEventObject); duk_push_uint(ctx, callbackId); return 1; } duk_ret_t ScriptAPI::js_events_remove(duk_context * ctx) { CheckArgs(ctx, {Arg_Number}); JSAppCallbackID callbackId = (JSAppCallbackID)duk_get_uint(ctx, 0); if (!RemoveAppCallback(ctx, callbackId)) { duk_push_error_object(ctx, DUK_ERR_REFERENCE_ERROR, "invalid callback ID"); return duk_throw(ctx); } return 0; } bool CbCond_ReadAddrBetween(JSAppCallback * cb, void * _env) { JSHookCpuStepEnv * env = (JSHookCpuStepEnv *)_env; if (!env->opInfo.IsLoadCommand()) { return false; } uint32_t addr = env->opInfo.GetLoadStoreAddress(); return (addr >= cb->m_Params.addrStart && addr <= cb->m_Params.addrEnd); } bool CbCond_WriteAddrBetween(JSAppCallback * cb, void * _env) { JSHookCpuStepEnv * env = (JSHookCpuStepEnv *)_env; if (!env->opInfo.IsStoreCommand()) { return false; } uint32_t addr = env->opInfo.GetLoadStoreAddress(); return (addr >= cb->m_Params.addrStart && addr <= cb->m_Params.addrEnd); } bool CbCond_PcBetween(JSAppCallback * cb, void * _env) { JSHookCpuStepEnv * env = (JSHookCpuStepEnv *)_env; return (env->pc >= cb->m_Params.addrStart && env->pc <= cb->m_Params.addrEnd); } bool CbCond_PcBetween_OpcodeEquals(JSAppCallback * cb, void * _env) { if (!CbCond_PcBetween(cb, _env)) { return false; } JSHookCpuStepEnv * env = (JSHookCpuStepEnv *)_env; return cb->m_Params.opcode == (env->opInfo.m_OpCode.Value & cb->m_Params.opcodeMask); } static bool CbCond_PcBetween_GprValueEquals(JSAppCallback * cb, void * _env) { if (!CbCond_PcBetween(cb, _env)) { return false; } JSHookCpuStepEnv * env = (JSHookCpuStepEnv *)_env; for (int i = 0; i < 32; i++) { if (cb->m_Params.regIndices & (1 << i)) { if (g_Reg->m_GPR[i].UW[0] == cb->m_Params.regValue) { env->outAffectedRegIndex = i; return true; } } } return false; } duk_idx_t CbArgs_EmuStateChangeEventObject(duk_context * ctx, void * _env) { CScriptInstance * inst = GetInstance(ctx); JSHookEmuStateChangeEnv * env = (JSHookEmuStateChangeEnv *)_env; duk_push_object(ctx); SetDummyConstructor(ctx, -1, "EmuStateChangeEvent"); const DukPropListEntry props[] = { {"callbackId", DukUInt(inst->CallbackId())}, {"state", DukUInt(env->state)}, { nullptr } }; DukPutPropList(ctx, -1, props); duk_freeze(ctx, -1); return 1; } duk_idx_t CbArgs_GenericEventObject(duk_context * ctx, void * /*_env*/) { CScriptInstance * inst = GetInstance(ctx); duk_push_object(ctx); SetDummyConstructor(ctx, -1, "GenericEvent"); const DukPropListEntry props[] = { {"callbackId", DukUInt(inst->CallbackId())}, { nullptr } }; DukPutPropList(ctx, -1, props); duk_freeze(ctx, -1); return 1; } duk_idx_t CbArgs_ExecEventObject(duk_context * ctx, void * _env) { CScriptInstance * inst = GetInstance(ctx); JSHookCpuStepEnv * env = (JSHookCpuStepEnv *)_env; duk_push_object(ctx); SetDummyConstructor(ctx, -1, "CPUExecEvent"); const DukPropListEntry props[] = { {"callbackId", DukUInt(inst->CallbackId())}, {"pc", DukUInt(env->pc)}, { nullptr } }; DukPutPropList(ctx, -1, props); duk_freeze(ctx, -1); return 1; } duk_idx_t CbArgs_ReadEventObject(duk_context * ctx, void * _env) { CScriptInstance * inst = GetInstance(ctx); CDebuggerUI * debugger = inst->Debugger(); JSHookCpuStepEnv * env = (JSHookCpuStepEnv *)_env; uint32_t address = env->opInfo.GetLoadStoreAddress(); uint8_t op = env->opInfo.m_OpCode.op; uint8_t rt = env->opInfo.m_OpCode.rt; bool bFPU = (op == R4300i_LWC1 || op == R4300i_LDC1); duk_push_object(ctx); SetDummyConstructor(ctx, -1, "CPUReadWriteEvent"); const DukPropListEntry props[] = { {"callbackId", DukUInt(inst->CallbackId())}, {"pc", DukUInt(env->pc)}, {"address", DukUInt(address)}, {"reg", DukUInt(rt)}, {"fpu", DukBoolean(bFPU)}, { nullptr } }; DukPutPropList(ctx, -1, props); union { uint8_t u8; int8_t s8; uint16_t u16; int16_t s16; uint32_t u32; int32_t s32; float f32; double f64; uint64_t u64; } value = {0}; bool bNeedUpper32 = false; switch (env->opInfo.m_OpCode.op) { case R4300i_LB: debugger->DebugLoad_VAddr(address, value.s8); duk_push_int(ctx, value.s8); duk_push_int(ctx, S8); break; case R4300i_LBU: debugger->DebugLoad_VAddr(address, value.u8); duk_push_uint(ctx, value.u8); duk_push_int(ctx, U8); break; case R4300i_LH: debugger->DebugLoad_VAddr(address, value.s16); duk_push_int(ctx, value.s16); duk_push_int(ctx, S16); break; case R4300i_LHU: debugger->DebugLoad_VAddr(address, value.u16); duk_push_uint(ctx, value.u16); duk_push_int(ctx, U16); break; case R4300i_LL: case R4300i_LW: debugger->DebugLoad_VAddr(address, value.s32); duk_push_int(ctx, value.s32); duk_push_int(ctx, S32); break; case R4300i_LWU: debugger->DebugLoad_VAddr(address, value.u32); duk_push_uint(ctx, value.u32); duk_push_int(ctx, U32); break; case R4300i_LWC1: debugger->DebugLoad_VAddr(address, value.f32); duk_push_number(ctx, value.f32); duk_push_int(ctx, F32); break; case R4300i_LDC1: debugger->DebugLoad_VAddr(address, value.f64); duk_push_number(ctx, value.f64); duk_push_int(ctx, F64); break; case R4300i_LD: debugger->DebugLoad_VAddr(address, value.u64); duk_push_number(ctx, (duk_double_t)(value.u64 & 0xFFFFFFFF)); duk_push_int(ctx, U64); bNeedUpper32 = true; break; case R4300i_LDL: { int shift = (address & 7) * 8; uint64_t mask = ~(((uint64_t)-1) << shift); debugger->DebugLoad_VAddr(address & ~7, value.u64); value.u64 = (g_Reg->m_GPR[rt].DW & mask) + (value.u64 << shift); duk_push_number(ctx, (duk_double_t)(value.u64 & 0xFFFFFFFF)); duk_push_int(ctx, U64); bNeedUpper32 = true; } break; case R4300i_LDR: { int shift = 56 - ((address & 7) * 8); uint64_t mask = ~(((uint64_t)-1) >> shift); debugger->DebugLoad_VAddr(address & ~7, value.u64); value.u64 = (g_Reg->m_GPR[rt].DW & mask) + (value.u64 >> shift); duk_push_number(ctx, (duk_double_t)(value.u64 & 0xFFFFFFFF)); duk_push_int(ctx, U64); bNeedUpper32 = true; } break; case R4300i_LWL: { int shift = (address & 3) * 8; uint32_t mask = ~(((uint32_t)-1) << shift); debugger->DebugLoad_VAddr(address & ~3, value.s32); value.s32 = (g_Reg->m_GPR[rt].W[0] & mask) + (value.s32 << shift); duk_push_number(ctx, value.s32); duk_push_int(ctx, S32); } break; case R4300i_LWR: { int shift = 24 - ((address & 3) * 8); uint32_t mask = ~(((uint32_t)-1) >> shift); debugger->DebugLoad_VAddr(address & ~3, value.s32); value.s32 = (g_Reg->m_GPR[rt].W[0] & mask) + (value.s32 >> shift); duk_push_number(ctx, value.s32); duk_push_int(ctx, S32); } break; default: duk_push_number(ctx, 0); duk_push_number(ctx, 0); break; } duk_put_prop_string(ctx, -3, "valueType"); duk_put_prop_string(ctx, -2, "value"); if (bNeedUpper32) { duk_push_number(ctx, (duk_double_t)(value.u64 >> 32)); duk_put_prop_string(ctx, -2, "valueHi"); } duk_freeze(ctx, -1); return 1; } duk_idx_t CbArgs_WriteEventObject(duk_context * ctx, void * _env) { CScriptInstance * inst = GetInstance(ctx); CDebuggerUI * debugger = inst->Debugger(); JSHookCpuStepEnv * env = (JSHookCpuStepEnv *)_env; uint32_t address = env->opInfo.GetLoadStoreAddress(); uint8_t op = env->opInfo.m_OpCode.op; uint8_t rt = env->opInfo.m_OpCode.rt; bool bFPU = (op == R4300i_SWC1 || op == R4300i_SDC1); duk_push_object(ctx); SetDummyConstructor(ctx, -1, "CPUReadWriteEvent"); const DukPropListEntry props[] = { {"callbackId", DukUInt(inst->CallbackId())}, {"pc", DukUInt(env->pc)}, {"address", DukUInt(address)}, {"reg", DukUInt(rt)}, {"fpu", DukBoolean(bFPU)}, { nullptr } }; DukPutPropList(ctx, -1, props); bool bNeedUpper32 = false; uint64_t value64 = 0; switch (env->opInfo.m_OpCode.op) { case R4300i_SB: duk_push_int(ctx, g_Reg->m_GPR[rt].B[0]); duk_push_int(ctx, S8); break; case R4300i_SH: duk_push_int(ctx, g_Reg->m_GPR[rt].HW[0]); duk_push_int(ctx, S16); break; case R4300i_SW: duk_push_int(ctx, g_Reg->m_GPR[rt].W[0]); duk_push_int(ctx, S32); break; case R4300i_SWC1: duk_push_number(ctx, *g_Reg->m_FPR_S[rt]); duk_push_int(ctx, F32); break; case R4300i_SDC1: duk_push_number(ctx, *g_Reg->m_FPR_D[rt]); duk_push_int(ctx, F64); break; case R4300i_SD: duk_push_number(ctx, g_Reg->m_GPR[rt].UW[0]); duk_push_int(ctx, U64); bNeedUpper32 = true; break; case R4300i_SWL: { int shift = (address & 3) * 8; uint32_t mask = ~(((uint32_t)-1) >> shift); uint32_t value; debugger->DebugLoad_VAddr(address & ~3, value); value = (value & mask) + (g_Reg->m_GPR[rt].UW[0] >> shift); duk_push_number(ctx, value); duk_push_int(ctx, S32); } break; case R4300i_SWR: { int shift = 24 - ((address & 3) * 8); uint32_t mask = ~(((uint32_t)-1) << shift); uint32_t value; debugger->DebugLoad_VAddr(address & ~3, value); value = (value & mask) + (g_Reg->m_GPR[rt].UW[0] >> shift); duk_push_number(ctx, value); duk_push_int(ctx, S32); } break; case R4300i_SDL: { int shift = (address & 7) * 8; uint64_t mask = ~(((uint64_t)-1) >> shift); debugger->DebugLoad_VAddr(address & ~7, value64); value64 = (value64 & mask) + (g_Reg->m_GPR[rt].UDW >> shift); duk_push_number(ctx, (duk_double_t)(value64 & 0xFFFFFFFF)); duk_push_int(ctx, U64); } case R4300i_SDR: { int shift = 56 - ((address & 7) * 8); uint64_t mask = ~(((uint64_t)-1) << shift); debugger->DebugLoad_VAddr(address & ~7, value64); value64 = (value64 & mask) + (g_Reg->m_GPR[rt].UDW >> shift); duk_push_number(ctx, (duk_double_t)(value64 & 0xFFFFFFFF)); duk_push_int(ctx, U64); } default: duk_push_number(ctx, 0); duk_push_number(ctx, 0); break; } duk_put_prop_string(ctx, -3, "valueType"); duk_put_prop_string(ctx, -2, "value"); if (bNeedUpper32) { duk_push_number(ctx, (duk_double_t)(value64 >> 32)); duk_put_prop_string(ctx, -2, "valueHi"); } duk_freeze(ctx, -1); return 1; } duk_idx_t CbArgs_OpcodeEventObject(duk_context * ctx, void * _env) { CScriptInstance * inst = GetInstance(ctx); JSHookCpuStepEnv * env = (JSHookCpuStepEnv *)_env; duk_push_object(ctx); SetDummyConstructor(ctx, -1, "CPUOpcodeEvent"); const DukPropListEntry props[] = { {"callbackId", DukUInt(inst->CallbackId())}, {"pc", DukUInt(env->pc)}, {"opcode", DukUInt(env->opInfo.m_OpCode.Value)}, { nullptr } }; DukPutPropList(ctx, -1, props); duk_freeze(ctx, -1); return 1; } duk_idx_t CbArgs_RegValueEventObject(duk_context * ctx, void * _env) { CScriptInstance * inst = GetInstance(ctx); JSHookCpuStepEnv * env = (JSHookCpuStepEnv *)_env; duk_push_object(ctx); SetDummyConstructor(ctx, -1, "CPURegValueEvent"); const DukPropListEntry props[] = { {"callbackId", DukUInt(inst->CallbackId())}, {"pc", DukUInt(env->pc)}, {"value", DukUInt(g_Reg->m_GPR[env->outAffectedRegIndex].UW[0])}, {"reg", DukUInt(env->outAffectedRegIndex)}, { nullptr } }; DukPutPropList(ctx, -1, props); duk_freeze(ctx, -1); return 1; } static duk_idx_t CbArgs_MouseEventObject(duk_context * ctx, void * _env) { CScriptInstance * inst = GetInstance(ctx); JSHookMouseEnv * env = (JSHookMouseEnv *)_env; duk_push_object(ctx); SetDummyConstructor(ctx, -1, "MouseEvent"); const DukPropListEntry props[] = { {"callbackId", DukUInt(inst->CallbackId())}, {"button", DukInt(env->button)}, {"x", DukInt(env->x)}, {"y", DukInt(env->y)}, { nullptr } }; DukPutPropList(ctx, -1, props); duk_freeze(ctx, -1); return 1; } static duk_idx_t CbArgs_SPTaskEventObject(duk_context * ctx, void * _env) { CScriptInstance * inst = GetInstance(ctx); JSHookSpTaskEnv * env = (JSHookSpTaskEnv *)_env; duk_push_object(ctx); SetDummyConstructor(ctx, -1, "SPTaskEvent"); const DukPropListEntry props[] = { {"callbackId", DukUInt(inst->CallbackId())}, {"taskType", DukUInt(env->taskType)}, {"taskFlags", DukUInt(env->taskFlags)}, {"ucodeBootAddress", DukUInt(env->ucodeBootAddress | 0x80000000)}, {"ucodeBootSize", DukUInt(env->ucodeBootSize)}, {"ucodeAddress", DukUInt(env->ucodeAddress | 0x80000000)}, {"ucodeSize", DukUInt(env->ucodeSize)}, {"ucodeDataAddress", DukUInt(env->ucodeDataAddress | 0x80000000)}, {"ucodeDataSize", DukUInt(env->ucodeDataSize)}, {"dramStackAddress", DukUInt(env->dramStackAddress | 0x80000000)}, {"dramStackSize", DukUInt(env->dramStackSize)}, {"outputBuffAddress", DukUInt(env->outputBuffAddress | 0x80000000)}, {"outputBuffSize", DukUInt(env->outputBuffSize)}, {"dataAddress", DukUInt(env->dataAddress | 0x80000000)}, {"dataSize", DukUInt(env->dataSize)}, {"yieldDataAddress", DukUInt(env->yieldDataAddress | 0x80000000)}, {"yieldDataSize", DukUInt(env->yieldDataSize)}, { nullptr } }; DukPutPropList(ctx, -1, props); duk_freeze(ctx, -1); return 1; } static duk_idx_t CbArgs_PIEventObject(duk_context * ctx, void * _env) { CScriptInstance * inst = GetInstance(ctx); JSHookPiDmaEnv * env = (JSHookPiDmaEnv *)_env; duk_push_object(ctx); SetDummyConstructor(ctx, -1, "PIEvent"); const DukPropListEntry props[] = { {"callbackId", DukUInt(inst->CallbackId())}, {"direction", DukUInt(env->direction)}, {"dramAddress", DukUInt(env->dramAddress | 0x80000000)}, {"cartAddress", DukUInt(env->cartAddress | 0xA0000000)}, {"length", DukUInt(env->length + 1)}, { nullptr } }; DukPutPropList(ctx, -1, props); duk_freeze(ctx, -1); return 1; } duk_ret_t RequireAddressOrAddressRange(duk_context * ctx, duk_idx_t idx, uint32_t * addrStart, uint32_t * addrEnd) { if (duk_is_number(ctx, idx)) { if (abs(duk_get_number(ctx, idx)) > 0xFFFFFFFF) { duk_push_error_object(ctx, DUK_ERR_RANGE_ERROR, "address is out of range"); return duk_throw(ctx); } uint32_t addr = duk_get_uint(ctx, idx); *addrStart = addr; *addrEnd = addr; return 0; } if (duk_is_object(ctx, idx)) { if (!duk_has_prop_string(ctx, idx, "start") || !duk_has_prop_string(ctx, idx, "end")) { duk_push_error_object(ctx, DUK_ERR_REFERENCE_ERROR, "object is missing 'start' or 'end' property"); return duk_throw(ctx); } duk_get_prop_string(ctx, idx, "start"); duk_get_prop_string(ctx, idx, "end"); if (!duk_is_number(ctx, -2) || !duk_is_number(ctx, -1)) { duk_pop_n(ctx, 2); duk_push_error_object(ctx, DUK_ERR_REFERENCE_ERROR, "'start' and 'end' properties must be numbers"); return duk_throw(ctx); } if (abs(duk_get_number(ctx, -2)) > 0xFFFFFFFF || abs(duk_get_number(ctx, -1)) > 0xFFFFFFFF) { duk_push_error_object(ctx, DUK_ERR_RANGE_ERROR, "'start' or 'end' property out of range"); return duk_throw(ctx); } *addrStart = duk_get_uint(ctx, -2); *addrEnd = duk_get_uint(ctx, -1); duk_pop_n(ctx, 2); return 0; } duk_push_error_object(ctx, DUK_ERR_TYPE_ERROR, "argument %d invalid; expected number or object", idx); return duk_throw(ctx); } duk_ret_t RequireInterpreterCPU(duk_context * ctx) { if (!g_Settings->LoadBool(Setting_ForceInterpreterCPU) && (CPU_TYPE)g_Settings->LoadDword(Game_CpuType) != CPU_Interpreter) { duk_push_error_object(ctx, DUK_ERR_ERROR, "this feature requires the interpreter core"); return duk_throw(ctx); } return 0; }