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

830 lines
25 KiB
C++
Raw Normal View History

#include <stdafx.h>
#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;
}