Lua: COMPARE_OBJ: Check strided memory block for modifications

This commit is contained in:
Ilari Liusvaara 2014-02-14 22:22:37 +02:00
parent b53979bcd1
commit ef1f61a6e7
6 changed files with 173 additions and 23 deletions

View file

@ -38,4 +38,6 @@ extern uint64_t lua_timer_hook_time;
extern void* synchronous_paint_ctx;
void lua_renderq_run(lua_render_context* ctx, void* synchronous_paint_ctx);
void lua_accessed_range(uint64_t base, uint64_t size, uint64_t rows, uint64_t stride, uint64_t& m, uint64_t& M);
#endif

28
lua.lyx
View file

@ -6788,6 +6788,34 @@ Set the global execute hook mask to <mask>.
CPU.
\end_layout
\begin_layout Subsection
memory.compare_new: Create memory compare object.
\end_layout
\begin_layout Itemize
Syntax: COMPARE_OBJ memory.compare_new([string marea], number size, [number
rows, number stride])
\end_layout
\begin_layout Standard
Create memory compare object of <rows> blocks of <size> bytes starting from
address <base> (relative to <marea>).
The blocks are offset by <stride> from one another.
\end_layout
\begin_layout Subsection
COMPARE_OBJ(): Region changed?
\end_layout
\begin_layout Itemize
Syntax: bool COMPARE_OBJ()
\end_layout
\begin_layout Standard
Returns true if region has changed, false if it is still is way it is during
last call (creation counts).
\end_layout
\begin_layout Subsection
memory.mmap: Class MMAP_STRUCT
\end_layout

BIN
lua.pdf

Binary file not shown.

119
src/lua/memory-compare.cpp Normal file
View file

@ -0,0 +1,119 @@
#include "lua/internal.hpp"
#include "core/memorymanip.hpp"
#include "library/minmax.hpp"
namespace
{
uint64_t get_vmabase(const std::string& vma)
{
for(auto i : lsnes_memory.get_regions())
if(i->name == vma)
return i->base;
throw std::runtime_error("No such VMA");
}
uint64_t get_read_address(lua::parameters& P)
{
uint64_t vmabase = 0;
if(P.is_string())
vmabase = get_vmabase(P.arg<std::string>());
auto addr = P.arg<uint64_t>();
return addr + vmabase;
}
class compare_obj
{
public:
compare_obj(lua::state& L, uint64_t addr, uint64_t size, uint64_t rows, uint64_t stride);
static int create(lua::state& L, lua::parameters& P);
int call(lua::state& L, lua::parameters& P);
private:
std::vector<uint8_t> prev;
bool try_map;
uint64_t addr;
uint64_t minaddr;
uint64_t maxaddr;
uint64_t rows;
uint64_t size;
uint64_t stride;
};
compare_obj::compare_obj(lua::state& L, uint64_t _addr, uint64_t _size, uint64_t _rows, uint64_t _stride)
{
if(!_size || !_rows) {
//Empty.
try_map = false;
addr = 0;
minaddr = 0;
maxaddr = 0;
rows = 0;
size = 1;
stride = 0;
return;
} else {
addr = _addr;
size = _size;
rows = _rows;
stride = _stride;
lua_accessed_range(addr, size, rows, stride, minaddr, maxaddr);
try_map = (minaddr <= maxaddr && (maxaddr - minaddr + 1));
if((size_t)(size * rows) / rows != size)
throw std::runtime_error("Size to monitor too large");
prev.resize(size * rows);
}
}
int compare_obj::create(lua::state& L, lua::parameters& P)
{
uint64_t addr, daddr, size;
uint64_t stride = 0, rows = 1;
addr = get_read_address(P);
P(daddr, size, P.optional(rows, 1));
if(rows > 1)
P(stride);
compare_obj* o = lua::_class<compare_obj>::create(L, addr, size, rows, stride);
o->call(L, P);
L.pop(1);
return 1;
}
int compare_obj::call(lua::state& L, lua::parameters& P)
{
bool equals = true;
char* pbuffer = try_map ? lsnes_memory.get_physical_mapping(minaddr, maxaddr - minaddr + 1) : NULL;
if(pbuffer) {
//Mapable.
uint64_t offset = addr - minaddr;
for(uint64_t i = 0; i < rows; i++) {
bool eq = !memcmp(&prev[i * size], pbuffer + offset, size);
if(!eq)
memcpy(&prev[i * size], pbuffer + offset, size);
equals &= eq;
offset += stride;
}
} else {
//Not mapable.
for(uint64_t i = 0; i < rows; i++) {
uint64_t addr1 = addr + i * stride;
uint64_t addr2 = i * size;
for(uint64_t j = 0; j < size; j++) {
uint8_t byte = lsnes_memory.read<uint8_t>(addr1 + j);
bool eq = prev[addr2 + j] == (char)byte;
if(!eq)
prev[addr2 + j] = byte;
equals &= eq;
}
}
}
L.pushboolean(!equals);
return 1;
}
lua::_class<compare_obj> class_vmalist(lua_class_memory, "COMPARE_OBJ", {
{"new", compare_obj::create},
}, {
{"__call", &compare_obj::call},
});
}

View file

@ -320,6 +320,27 @@ void handle_unregisterX(lua::state& L, uint64_t addr, int lfn)
}
}
void lua_accessed_range(uint64_t base, uint64_t size, uint64_t rows, uint64_t stride, uint64_t& m, uint64_t& M)
{
m = 0xFFFFFFFFFFFFFFFFULL;
M = 0;
if(!rows || !size)
return;
for(uint64_t i = 0; i < rows; i++) {
if(base + size > base) {
m = min(m, base);
M = max(M, base + size - 1);
} else if(base + size == 0) {
m = min(m, base);
M = 0xFFFFFFFFFFFFFFFFULL;
} else {
m = 0;
M = 0xFFFFFFFFFFFFFFFFULL;
}
base += stride;
}
}
typedef void(*dummy1_t)(lua::state& L, uint64_t addr, int lfn);
dummy1_t dummy_628963286932869328692386963[] = {
handle_registerX<DEBUG_READ>,
@ -513,27 +534,6 @@ namespace
return 1;
}
void accessed_range(uint64_t base, uint64_t size, uint64_t rows, uint64_t stride, uint64_t& m, uint64_t& M)
{
m = 0xFFFFFFFFFFFFFFFFULL;
M = 0;
if(!rows || !size)
return;
for(uint64_t i = 0; i < rows; i++) {
if(base + size > base) {
m = min(m, base);
M = max(M, base + size - 1);
} else if(base + size == 0) {
m = min(m, base);
M = 0xFFFFFFFFFFFFFFFFULL;
} else {
m = 0;
M = 0xFFFFFFFFFFFFFFFFULL;
}
base += stride;
}
}
template<typename H, void(*update)(H& state, const char* mem, size_t memsize),
std::string(*read)(H& state), bool extra>
int hash_core(H& state, lua::state& L, lua::parameters& P)
@ -552,7 +552,7 @@ namespace
P(stride);
}
accessed_range(addr, size, rows, stride, low, high);
lua_accessed_range(addr, size, rows, stride, low, high);
if(low > high || high - low + 1 == 0)
mappable = false;
@ -631,7 +631,7 @@ namespace
if(rows > 1)
P(stride);
accessed_range(addr, size, rows, stride, low, high);
lua_accessed_range(addr, size, rows, stride, low, high);
if(low > high || high - low + 1 == 0)
mappable = false;
if(rows && (size_t)(size * rows) / rows != size)

View file

@ -69,6 +69,7 @@ filereader = classes.FILEREADER;
memory2=classes.VMALIST.new();
callback=classes.CALLBACKS_LIST.new();
memory.map_structure=classes.MMAP_STRUCT.new;
memory.compare_new=classes.COMPARE_OBJ.new;
zip.create=classes.ZIPWRITER.new;
gui.tilemap=classes.TILEMAP.new;
gui.renderq_new=classes.RENDERCTX.new;