Lua: COMPARE_OBJ: Check strided memory block for modifications
This commit is contained in:
parent
b53979bcd1
commit
ef1f61a6e7
6 changed files with 173 additions and 23 deletions
|
@ -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
28
lua.lyx
|
@ -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
BIN
lua.pdf
Binary file not shown.
119
src/lua/memory-compare.cpp
Normal file
119
src/lua/memory-compare.cpp
Normal 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},
|
||||
});
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue