#include #include "ScriptAPI.h" #include "../OpInfo.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; }