project64/Source/Project64/UserInterface/Debugger/ScriptAPI/ScriptAPI_events.cpp

827 lines
25 KiB
C++

#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, (int)((UINT_PTR)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, (int)((UINT_PTR)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, (int)((UINT_PTR)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, (int)((UINT_PTR)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, (int)((UINT_PTR)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, (int)((UINT_PTR)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, (int)((UINT_PTR)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, (int)((UINT_PTR)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, (int)((UINT_PTR)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, (int)((UINT_PTR)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, (int)((UINT_PTR)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, (int)((UINT_PTR)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((int)((UINT_PTR)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((int)((UINT_PTR)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((int)((UINT_PTR)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((int)((UINT_PTR)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((int)((UINT_PTR)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);
break;
}
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);
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)(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((int)((UINT_PTR)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((int)((UINT_PTR)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((int)((UINT_PTR)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((int)((UINT_PTR)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((int)((UINT_PTR)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;
}