Binary interface: Memory and register access & hooks

This commit is contained in:
Parakoopa 2020-04-06 12:00:37 +02:00
parent b18e2058cb
commit 651cb53fbe
5 changed files with 373 additions and 31 deletions

View File

@ -30,6 +30,10 @@
#include "lua-engine.h" #include "lua-engine.h"
#endif #endif
#ifdef TARGET_INTERFACE
#include "frontend/interface/interface.h"
#endif
#ifdef HAVE_JIT #ifdef HAVE_JIT
#include "arm_jit.h" #include "arm_jit.h"
#endif #endif
@ -699,6 +703,9 @@ FORCEINLINE u8 _MMU_read08(const int PROCNUM, const MMU_ACCESS_TYPE AT, const u3
#ifdef HAVE_LUA #ifdef HAVE_LUA
CallRegisteredLuaMemHook(addr, 1, /*FIXME*/ 0, LUAMEMHOOK_READ); CallRegisteredLuaMemHook(addr, 1, /*FIXME*/ 0, LUAMEMHOOK_READ);
#endif #endif
#ifdef TARGET_INTERFACE
call_registered_interface_mem_hook(addr, 1, HOOK_READ);
#endif
// break points, wheee // break points, wheee
for (size_t i = 0; i < memReadBreakPoints.size(); ++i) for (size_t i = 0; i < memReadBreakPoints.size(); ++i)
@ -744,6 +751,9 @@ FORCEINLINE u16 _MMU_read16(const int PROCNUM, const MMU_ACCESS_TYPE AT, const u
#ifdef HAVE_LUA #ifdef HAVE_LUA
CallRegisteredLuaMemHook(addr, 2, /*FIXME*/ 0, LUAMEMHOOK_READ); CallRegisteredLuaMemHook(addr, 2, /*FIXME*/ 0, LUAMEMHOOK_READ);
#endif #endif
#ifdef TARGET_INTERFACE
call_registered_interface_mem_hook(addr, 2, HOOK_READ);
#endif
// break points, wheee // break points, wheee
for (size_t i = 0; i < memReadBreakPoints.size(); ++i) for (size_t i = 0; i < memReadBreakPoints.size(); ++i)
@ -801,6 +811,9 @@ FORCEINLINE u32 _MMU_read32(const int PROCNUM, const MMU_ACCESS_TYPE AT, const u
#ifdef HAVE_LUA #ifdef HAVE_LUA
CallRegisteredLuaMemHook(addr, 4, /*FIXME*/ 0, LUAMEMHOOK_READ); CallRegisteredLuaMemHook(addr, 4, /*FIXME*/ 0, LUAMEMHOOK_READ);
#endif
#ifdef TARGET_INTERFACE
call_registered_interface_mem_hook(addr, 4, HOOK_READ);
#endif #endif
// break points, wheee // break points, wheee
for (size_t i = 0; i < memReadBreakPoints.size(); ++i) for (size_t i = 0; i < memReadBreakPoints.size(); ++i)
@ -883,6 +896,9 @@ FORCEINLINE void _MMU_write08(const int PROCNUM, const MMU_ACCESS_TYPE AT, const
T1WriteByte(MMU.ARM9_DTCM, addr & 0x3FFF, val); T1WriteByte(MMU.ARM9_DTCM, addr & 0x3FFF, val);
#ifdef HAVE_LUA #ifdef HAVE_LUA
CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE); CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE);
#endif
#ifdef TARGET_INTERFACE
call_registered_interface_mem_hook(addr, 1, HOOK_READ);
#endif #endif
return; return;
} }
@ -894,6 +910,9 @@ FORCEINLINE void _MMU_write08(const int PROCNUM, const MMU_ACCESS_TYPE AT, const
T1WriteByte( MMU.MAIN_MEM, addr & _MMU_MAIN_MEM_MASK, val); T1WriteByte( MMU.MAIN_MEM, addr & _MMU_MAIN_MEM_MASK, val);
#ifdef HAVE_LUA #ifdef HAVE_LUA
CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE); CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE);
#endif
#ifdef TARGET_INTERFACE
call_registered_interface_mem_hook(addr, 1, HOOK_WRITE);
#endif #endif
return; return;
} }
@ -903,6 +922,9 @@ FORCEINLINE void _MMU_write08(const int PROCNUM, const MMU_ACCESS_TYPE AT, const
#ifdef HAVE_LUA #ifdef HAVE_LUA
CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE); CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE);
#endif #endif
#ifdef TARGET_INTERFACE
call_registered_interface_mem_hook(addr, 1, HOOK_WRITE);
#endif
} }
FORCEINLINE void _MMU_write16(const int PROCNUM, const MMU_ACCESS_TYPE AT, const u32 addr, u16 val) FORCEINLINE void _MMU_write16(const int PROCNUM, const MMU_ACCESS_TYPE AT, const u32 addr, u16 val)
@ -932,6 +954,9 @@ FORCEINLINE void _MMU_write16(const int PROCNUM, const MMU_ACCESS_TYPE AT, const
T1WriteWord(MMU.ARM9_DTCM, addr & 0x3FFE, val); T1WriteWord(MMU.ARM9_DTCM, addr & 0x3FFE, val);
#ifdef HAVE_LUA #ifdef HAVE_LUA
CallRegisteredLuaMemHook(addr, 2, val, LUAMEMHOOK_WRITE); CallRegisteredLuaMemHook(addr, 2, val, LUAMEMHOOK_WRITE);
#endif
#ifdef TARGET_INTERFACE
call_registered_interface_mem_hook(addr, 2, HOOK_WRITE);
#endif #endif
return; return;
} }
@ -952,6 +977,9 @@ FORCEINLINE void _MMU_write16(const int PROCNUM, const MMU_ACCESS_TYPE AT, const
#ifdef HAVE_LUA #ifdef HAVE_LUA
CallRegisteredLuaMemHook(addr, 2, val, LUAMEMHOOK_WRITE); CallRegisteredLuaMemHook(addr, 2, val, LUAMEMHOOK_WRITE);
#endif #endif
#ifdef TARGET_INTERFACE
call_registered_interface_mem_hook(addr, 2, HOOK_WRITE);
#endif
} }
FORCEINLINE void _MMU_write32(const int PROCNUM, const MMU_ACCESS_TYPE AT, const u32 addr, u32 val) FORCEINLINE void _MMU_write32(const int PROCNUM, const MMU_ACCESS_TYPE AT, const u32 addr, u32 val)
@ -981,6 +1009,9 @@ FORCEINLINE void _MMU_write32(const int PROCNUM, const MMU_ACCESS_TYPE AT, const
T1WriteLong(MMU.ARM9_DTCM, addr & 0x3FFC, val); T1WriteLong(MMU.ARM9_DTCM, addr & 0x3FFC, val);
#ifdef HAVE_LUA #ifdef HAVE_LUA
CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE); CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE);
#endif
#ifdef TARGET_INTERFACE
call_registered_interface_mem_hook(addr, 4, HOOK_WRITE);
#endif #endif
return; return;
} }
@ -993,6 +1024,9 @@ FORCEINLINE void _MMU_write32(const int PROCNUM, const MMU_ACCESS_TYPE AT, const
T1WriteLong( MMU.MAIN_MEM, addr & _MMU_MAIN_MEM_MASK32, val); T1WriteLong( MMU.MAIN_MEM, addr & _MMU_MAIN_MEM_MASK32, val);
#ifdef HAVE_LUA #ifdef HAVE_LUA
CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE); CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE);
#endif
#ifdef TARGET_INTERFACE
call_registered_interface_mem_hook(addr, 4, HOOK_WRITE);
#endif #endif
return; return;
} }
@ -1002,6 +1036,9 @@ FORCEINLINE void _MMU_write32(const int PROCNUM, const MMU_ACCESS_TYPE AT, const
#ifdef HAVE_LUA #ifdef HAVE_LUA
CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE); CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE);
#endif #endif
#ifdef TARGET_INTERFACE
call_registered_interface_mem_hook(addr, 4, HOOK_WRITE);
#endif
} }

View File

@ -32,6 +32,9 @@
#ifdef HAVE_LUA #ifdef HAVE_LUA
#include "lua-engine.h" #include "lua-engine.h"
#endif #endif
#ifdef TARGET_INTERFACE
#include "frontend/interface/interface.h"
#endif
#ifdef HAVE_JIT #ifdef HAVE_JIT
#include "arm_jit.h" #include "arm_jit.h"
#endif #endif
@ -674,6 +677,9 @@ u32 armcpu_exec()
{ {
#ifdef HAVE_LUA #ifdef HAVE_LUA
CallRegisteredLuaMemHook(ARMPROC.instruct_adr, 4, ARMPROC.instruction, LUAMEMHOOK_EXEC); // should report even if condition=false? CallRegisteredLuaMemHook(ARMPROC.instruct_adr, 4, ARMPROC.instruction, LUAMEMHOOK_EXEC); // should report even if condition=false?
#endif
#ifdef TARGET_INTERFACE
call_registered_interface_mem_hook(ARMPROC.instruct_adr, 4, HOOK_EXEC);
#endif #endif
#ifdef DEVELOPER #ifdef DEVELOPER
DEBUG_statistics.instructionHits[PROCNUM].arm[INSTRUCTION_INDEX(ARMPROC.instruction)]++; DEBUG_statistics.instructionHits[PROCNUM].arm[INSTRUCTION_INDEX(ARMPROC.instruction)]++;
@ -695,6 +701,9 @@ u32 armcpu_exec()
#ifdef HAVE_LUA #ifdef HAVE_LUA
CallRegisteredLuaMemHook(ARMPROC.instruct_adr, 2, ARMPROC.instruction, LUAMEMHOOK_EXEC); CallRegisteredLuaMemHook(ARMPROC.instruct_adr, 2, ARMPROC.instruction, LUAMEMHOOK_EXEC);
#endif
#ifdef TARGET_INTERFACE
call_registered_interface_mem_hook(ARMPROC.instruct_adr, 2, HOOK_EXEC);
#endif #endif
#ifdef DEVELOPER #ifdef DEVELOPER
DEBUG_statistics.instructionHits[PROCNUM].thumb[ARMPROC.instruction>>6]++; DEBUG_statistics.instructionHits[PROCNUM].thumb[ARMPROC.instruction>>6]++;

View File

@ -32,6 +32,8 @@ if ( test -d ../../../../.git; ) && test "x${GIT}" != "x" -a -x "${GIT}" ; then
fi fi
AC_DEFINE_UNQUOTED([GIT_COMMIT], ["$COMMIT"], [git commit hash]) AC_DEFINE_UNQUOTED([GIT_COMMIT], ["$COMMIT"], [git commit hash])
AC_DEFINE([TARGET_INTERFACE])
dnl - Check for zlib dnl - Check for zlib
AC_CHECK_LIB(z, gzopen, [], [AC_MSG_ERROR([zlib was not found, we can't go further. Please install it or specify the location where it's installed.])]) AC_CHECK_LIB(z, gzopen, [], [AC_MSG_ERROR([zlib was not found, we can't go further. Please install it or specify the location where it's installed.])])

View File

@ -25,11 +25,13 @@
// TODO: OSD Support isn't really done yet! Test! // TODO: OSD Support isn't really done yet! Test!
#include "../modules/osd/agg/agg_osd.h" #include "../modules/osd/agg/agg_osd.h"
#include "../../SPU.h" #include "../../SPU.h"
#include "../../MMU.h"
#include "../../rasterize.h" #include "../../rasterize.h"
#include "../../saves.h" #include "../../saves.h"
#include "../../movie.h" #include "../../movie.h"
#include "../../mc.h" #include "../../mc.h"
#include "../../firmware.h" #include "../../firmware.h"
#include "../../armcpu.h"
#include "../posix/shared/sndsdl.h" #include "../posix/shared/sndsdl.h"
#include "../posix/shared/ctrlssdl.h" #include "../posix/shared/ctrlssdl.h"
#include <locale> #include <locale>
@ -38,6 +40,8 @@
#define SCREENS_PIXEL_SIZE 98304 #define SCREENS_PIXEL_SIZE 98304
volatile bool execute = false; volatile bool execute = false;
TieredRegion hooked_regions [HOOK_COUNT];
std::map<unsigned int, memory_cb_fnc> hooks[HOOK_COUNT];
SoundInterface_struct *SNDCoreList[] = { SoundInterface_struct *SNDCoreList[] = {
@ -311,29 +315,198 @@ EXPORTED void desmume_volume_set(int volume)
SNDSDLSetAudioVolume(volume); SNDSDLSetAudioVolume(volume);
} }
// EXPORTED unsigned char desmume_memory_read_byte(int address)
//EXPORTED unsigned char desmume_memory_read_byte(int address); {
//EXPORTED signed char desmume_memory_read_byte_signed(int address); return (unsigned char)(_MMU_read08<ARMCPU_ARM9>(address) & 0xFF);
//EXPORTED unsigned short desmume_memory_read_short(int address); }
//EXPORTED signed short desmume_memory_read_short_signed(int address);
//EXPORTED unsigned long desmume_memory_read_long(int address); EXPORTED signed char desmume_memory_read_byte_signed(int address)
//EXPORTED signed long desmume_memory_read_long_signed(int address); {
//EXPORTED unsigned char *desmume_memory_read_byterange(int address, int length); return (signed char)(_MMU_read08<ARMCPU_ARM9>(address) & 0xFF);
// }
//EXPORTED void desmume_memory_write_byte(int address, unsigned char value);
//EXPORTED void desmume_memory_write_byte_signed(int address, signed char value); EXPORTED unsigned short desmume_memory_read_short(int address)
//EXPORTED void desmume_memory_write_short(int address, unsigned short value); {
//EXPORTED void desmume_memory_write_short_signed(int address, signed short value); return (unsigned short)(_MMU_read16<ARMCPU_ARM9>(address) & 0xFFFF);
//EXPORTED void desmume_memory_write_long(int address, unsigned long value); }
//EXPORTED void desmume_memory_write_long_signed(int address, signed long value);
//EXPORTED void desmume_memory_write_byterange(int address, const unsigned char *bytes); EXPORTED signed short desmume_memory_read_short_signed(int address)
// {
//EXPORTED long desmume_memory_read_register(char* register_name); return (signed short)(_MMU_read16<ARMCPU_ARM9>(address) & 0xFFFF);
//EXPORTED void desmume_memory_write_register(char* register_name, long value); }
//
//EXPORTED void desmume_memory_register_write(int address, int size, memory_cb_fnc cb); EXPORTED unsigned long desmume_memory_read_long(int address)
//EXPORTED void desmume_memory_register_read(int address, int size, memory_cb_fnc cb); {
//EXPORTED void desmume_memory_register_exec(int address, int size, memory_cb_fnc cb); return (unsigned long)(_MMU_read32<ARMCPU_ARM9>(address));
}
EXPORTED signed long desmume_memory_read_long_signed(int address)
{
return (signed long)(_MMU_read32<ARMCPU_ARM9>(address));
}
EXPORTED void desmume_memory_write_byte(int address, unsigned char value)
{
_MMU_write08<ARMCPU_ARM9>(address, value);
}
EXPORTED void desmume_memory_write_short(int address, unsigned short value)
{
_MMU_write16<ARMCPU_ARM9>(address, value);
}
EXPORTED void desmume_memory_write_long(int address, unsigned long value)
{
_MMU_write32<ARMCPU_ARM9>(address, value);
}
struct registerPointerMap
{
const char* registerName;
unsigned int* pointer;
int dataSize;
};
#define RPM_ENTRY(name,var) {name, (unsigned int*)&var, sizeof(var)},
registerPointerMap arm9PointerMap [] = {
RPM_ENTRY("r0", NDS_ARM9.R[0])
RPM_ENTRY("r1", NDS_ARM9.R[1])
RPM_ENTRY("r2", NDS_ARM9.R[2])
RPM_ENTRY("r3", NDS_ARM9.R[3])
RPM_ENTRY("r4", NDS_ARM9.R[4])
RPM_ENTRY("r5", NDS_ARM9.R[5])
RPM_ENTRY("r6", NDS_ARM9.R[6])
RPM_ENTRY("r7", NDS_ARM9.R[7])
RPM_ENTRY("r8", NDS_ARM9.R[8])
RPM_ENTRY("r9", NDS_ARM9.R[9])
RPM_ENTRY("r10", NDS_ARM9.R[10])
RPM_ENTRY("r11", NDS_ARM9.R[11])
RPM_ENTRY("r12", NDS_ARM9.R[12])
RPM_ENTRY("r13", NDS_ARM9.R[13])
RPM_ENTRY("r14", NDS_ARM9.R[14])
RPM_ENTRY("r15", NDS_ARM9.R[15])
RPM_ENTRY("cpsr", NDS_ARM9.CPSR.val)
RPM_ENTRY("spsr", NDS_ARM9.SPSR.val)
{}
};
registerPointerMap arm7PointerMap [] = {
RPM_ENTRY("r0", NDS_ARM7.R[0])
RPM_ENTRY("r1", NDS_ARM7.R[1])
RPM_ENTRY("r2", NDS_ARM7.R[2])
RPM_ENTRY("r3", NDS_ARM7.R[3])
RPM_ENTRY("r4", NDS_ARM7.R[4])
RPM_ENTRY("r5", NDS_ARM7.R[5])
RPM_ENTRY("r6", NDS_ARM7.R[6])
RPM_ENTRY("r7", NDS_ARM7.R[7])
RPM_ENTRY("r8", NDS_ARM7.R[8])
RPM_ENTRY("r9", NDS_ARM7.R[9])
RPM_ENTRY("r10", NDS_ARM7.R[10])
RPM_ENTRY("r11", NDS_ARM7.R[11])
RPM_ENTRY("r12", NDS_ARM7.R[12])
RPM_ENTRY("r13", NDS_ARM7.R[13])
RPM_ENTRY("r14", NDS_ARM7.R[14])
RPM_ENTRY("r15", NDS_ARM7.R[15])
RPM_ENTRY("cpsr", NDS_ARM7.CPSR.val)
RPM_ENTRY("spsr", NDS_ARM7.SPSR.val)
{}
};
struct cpuToRegisterMap
{
const char* cpuName;
registerPointerMap* rpmap;
}
cpuToRegisterMaps [] =
{
{"arm9.", arm9PointerMap},
{"main.", arm9PointerMap},
{"arm7.", arm7PointerMap},
{"sub.", arm7PointerMap},
{"", arm9PointerMap},
};
EXPORTED int desmume_memory_read_register(char* register_name)
{
for(int cpu = 0; cpu < sizeof(cpuToRegisterMaps)/sizeof(*cpuToRegisterMaps); cpu++)
{
cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu];
int cpuNameLen = strlen(ctrm.cpuName);
if(!strncasecmp(register_name, ctrm.cpuName, cpuNameLen))
{
register_name += cpuNameLen;
for(int reg = 0; ctrm.rpmap[reg].dataSize; reg++)
{
registerPointerMap rpm = ctrm.rpmap[reg];
if(!strcasecmp(register_name, rpm.registerName))
{
switch(rpm.dataSize)
{ default:
case 1: return *(unsigned char*)rpm.pointer;
case 2: return *(unsigned short*)rpm.pointer;
case 4: return *(unsigned long*)rpm.pointer;
}
}
}
return 0;
}
}
return 0;
}
EXPORTED void desmume_memory_write_register(char* register_name, long value)
{
for(int cpu = 0; cpu < sizeof(cpuToRegisterMaps)/sizeof(*cpuToRegisterMaps); cpu++)
{
cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu];
int cpuNameLen = strlen(ctrm.cpuName);
if(!strncasecmp(register_name, ctrm.cpuName, cpuNameLen))
{
register_name += cpuNameLen;
for(int reg = 0; ctrm.rpmap[reg].dataSize; reg++)
{
registerPointerMap rpm = ctrm.rpmap[reg];
if(!strcasecmp(register_name, rpm.registerName))
{
switch(rpm.dataSize)
{ default:
case 1: *(unsigned char*)rpm.pointer = (unsigned char)(value & 0xFF); break;
case 2: *(unsigned short*)rpm.pointer = (unsigned short)(value & 0xFFFF); break;
case 4: *(unsigned long*)rpm.pointer = value; break;
}
}
}
}
}
}
INLINE void memory_register_hook(int addr, MemHookType hook_type, int size, memory_cb_fnc cb)
{
for(unsigned int i = addr; i != addr+size; i++)
{
hooks[hook_type][i] = cb;
}
std::vector<unsigned int> hooked_bytes;
for(std::map<unsigned int, memory_cb_fnc>::iterator it = hooks[hook_type].begin(); it != hooks[hook_type].end(); ++it) {
hooked_bytes.push_back(it->first);
}
hooked_regions[hook_type].Calculate(hooked_bytes);
}
EXPORTED void desmume_memory_register_write(int address, int size, memory_cb_fnc cb)
{
memory_register_hook(address, HOOK_WRITE, size, cb);
}
EXPORTED void desmume_memory_register_read(int address, int size, memory_cb_fnc cb)
{
memory_register_hook(address, HOOK_READ, size, cb);
}
EXPORTED void desmume_memory_register_exec(int address, int size, memory_cb_fnc cb)
{
memory_register_hook(address, HOOK_EXEC, size, cb);
}
EXPORTED void desmume_screenshot(char *screenshot_buffer) EXPORTED void desmume_screenshot(char *screenshot_buffer)
{ {

View File

@ -44,9 +44,18 @@
# define EXPORTED # define EXPORTED
#endif #endif
enum MemHookType
{
HOOK_WRITE,
HOOK_READ,
HOOK_EXEC,
HOOK_COUNT
};
extern "C" { extern "C" {
// callback for memory hooks: if it returns false, remove it. // callback for memory hooks (get's two values: address and size of operation that triggered the hook)
typedef BOOL (*memory_cb_fnc)(void); typedef BOOL (*memory_cb_fnc)(unsigned int, int);
struct SimpleDate { struct SimpleDate {
int year; int year;
@ -68,6 +77,7 @@ EXPORTED void desmume_set_savetype(int type);
EXPORTED void desmume_pause(void); EXPORTED void desmume_pause(void);
EXPORTED void desmume_resume(void); EXPORTED void desmume_resume(void);
EXPORTED void desmume_reset(void); EXPORTED void desmume_reset(void);
EXPORTED void desmume_stop(void);
EXPORTED BOOL desmume_running(void); EXPORTED BOOL desmume_running(void);
EXPORTED void desmume_skip_next_frame(void); EXPORTED void desmume_skip_next_frame(void);
EXPORTED void desmume_cycle(void); EXPORTED void desmume_cycle(void);
@ -115,17 +125,14 @@ EXPORTED unsigned short desmume_memory_read_short(int address);
EXPORTED signed short desmume_memory_read_short_signed(int address); EXPORTED signed short desmume_memory_read_short_signed(int address);
EXPORTED unsigned long desmume_memory_read_long(int address); EXPORTED unsigned long desmume_memory_read_long(int address);
EXPORTED signed long desmume_memory_read_long_signed(int address); EXPORTED signed long desmume_memory_read_long_signed(int address);
EXPORTED unsigned char *desmume_memory_read_byterange(int address, int length); //EXPORTED unsigned char *desmume_memory_read_byterange(int address, int length);
EXPORTED void desmume_memory_write_byte(int address, unsigned char value); EXPORTED void desmume_memory_write_byte(int address, unsigned char value);
EXPORTED void desmume_memory_write_byte_signed(int address, signed char value);
EXPORTED void desmume_memory_write_short(int address, unsigned short value); EXPORTED void desmume_memory_write_short(int address, unsigned short value);
EXPORTED void desmume_memory_write_short_signed(int address, signed short value);
EXPORTED void desmume_memory_write_long(int address, unsigned long value); EXPORTED void desmume_memory_write_long(int address, unsigned long value);
EXPORTED void desmume_memory_write_long_signed(int address, signed long value); //EXPORTED void desmume_memory_write_byterange(int address, int length, const unsigned char *bytes);
EXPORTED void desmume_memory_write_byterange(int address, const unsigned char *bytes);
EXPORTED long desmume_memory_read_register(char* register_name); EXPORTED int desmume_memory_read_register(char* register_name);
EXPORTED void desmume_memory_write_register(char* register_name, long value); EXPORTED void desmume_memory_write_register(char* register_name, long value);
EXPORTED void desmume_memory_register_write(int address, int size, memory_cb_fnc cb); EXPORTED void desmume_memory_register_write(int address, int size, memory_cb_fnc cb);
@ -168,4 +175,118 @@ EXPORTED void desmume_movie_replay();
EXPORTED void desmume_movie_stop(); EXPORTED void desmume_movie_stop();
}; };
// TODO: Below is mostly just from lua-engine.h, might think about how to get rid of the code duplication.
#include <vector>
#include <algorithm>
// the purpose of this structure is to provide a way of
// QUICKLY determining whether a memory address range has a hook associated with it,
// with a bias toward fast rejection because the majority of addresses will not be hooked.
// (it must not use any part of Lua or perform any per-script operations,
// otherwise it would definitely be too slow.)
// calculating the regions when a hook is added/removed may be slow,
// but this is an intentional tradeoff to obtain a high speed of checking during later execution
struct TieredRegion
{
template<unsigned int maxGap>
struct Region
{
struct Island
{
unsigned int start;
unsigned int end;
FORCEINLINE bool Contains(unsigned int address, int size) const { return address < end && address+size > start; }
};
std::vector<Island> islands;
void Calculate(const std::vector<unsigned int>& bytes)
{
islands.clear();
unsigned int lastEnd = ~0;
std::vector<unsigned int>::const_iterator iter = bytes.begin();
std::vector<unsigned int>::const_iterator end = bytes.end();
for(; iter != end; ++iter)
{
unsigned int addr = *iter;
if(addr < lastEnd || addr > lastEnd + (long long)maxGap)
{
islands.push_back(Island());
islands.back().start = addr;
}
islands.back().end = addr+1;
lastEnd = addr+1;
}
}
bool Contains(unsigned int address, int size) const
{
typename std::vector<Island>::const_iterator iter = islands.begin();
typename std::vector<Island>::const_iterator end = islands.end();
for(; iter != end; ++iter)
if(iter->Contains(address, size))
return true;
return false;
}
};
Region<0xFFFFFFFF> broad;
Region<0x1000> mid;
Region<0> narrow;
void Calculate(std::vector<unsigned int>& bytes)
{
std::sort(bytes.begin(), bytes.end());
broad.Calculate(bytes);
mid.Calculate(bytes);
narrow.Calculate(bytes);
}
TieredRegion()
{
std::vector<unsigned int> somevector;
Calculate(somevector);
}
FORCEINLINE int NotEmpty()
{
return broad.islands.size();
}
// note: it is illegal to call this if NotEmpty() returns 0
FORCEINLINE bool Contains(unsigned int address, int size)
{
return broad.islands[0].Contains(address,size) &&
mid.Contains(address,size) &&
narrow.Contains(address,size);
}
};
extern TieredRegion hooked_regions [HOOK_COUNT];
extern std::map<unsigned int, memory_cb_fnc> hooks[HOOK_COUNT];
FORCEINLINE void call_registered_interface_mem_hook(unsigned int address, int size, MemHookType hook_type)
{
// See notes for CallRegisteredLuaMemHook!
if(hooked_regions[hook_type].NotEmpty())
{
if(hooked_regions[hook_type].Contains(address, size))
{
for(int i = address; i != address+size; i++)
{
memory_cb_fnc hook = hooks[hook_type][i];
if(hook != 0)
{
(*hook)(address, size);
break;
}
}
}
}
}
#endif //DESMUME_INTERFACE_H #endif //DESMUME_INTERFACE_H