lsnes rr2-β24
[lsnes.git] / src / lua / memory-compare.cpp
blobc6edeca621892fd60be322b4be47d41425603c42
1 #include "lua/internal.hpp"
2 #include "core/instance.hpp"
3 #include "core/memorymanip.hpp"
4 #include "library/memoryspace.hpp"
5 #include "library/minmax.hpp"
7 namespace
9 class compare_obj
11 public:
12 compare_obj(lua::state& L, uint64_t addr, uint64_t size, uint64_t rows, uint64_t stride);
13 static size_t overcommit(uint64_t addr, uint64_t size, uint64_t rows, uint64_t stride)
15 return lua::overcommit_std_align + (size_t)size * rows;
17 static int create(lua::state& L, lua::parameters& P);
18 int call(lua::state& L, lua::parameters& P);
19 std::string print()
21 std::ostringstream x;
22 x << "addr=0x" << std::hex << addr << " rows=" << rows << " size=0x" << std::hex << size
23 << " stride=0x" << std::hex << stride;
24 return x.str();
26 private:
27 uint8_t* prev;
28 bool try_map;
29 uint64_t addr;
30 uint64_t minaddr;
31 uint64_t maxaddr;
32 uint64_t rows;
33 uint64_t size;
34 uint64_t stride;
37 compare_obj::compare_obj(lua::state& L, uint64_t _addr, uint64_t _size, uint64_t _rows, uint64_t _stride)
39 if(!_size || !_rows) {
40 //Empty.
41 try_map = false;
42 addr = 0;
43 minaddr = 0;
44 maxaddr = 0;
45 rows = 0;
46 size = 1;
47 stride = 0;
48 prev = NULL;
49 return;
50 } else {
51 addr = _addr;
52 size = _size;
53 rows = _rows;
54 stride = _stride;
55 rpair(minaddr, maxaddr) = memoryspace_row_bounds(addr, size, rows, stride);
56 try_map = (minaddr <= maxaddr && (maxaddr - minaddr + 1));
57 if((((size_t)size * rows) + lua::overcommit_std_align) / rows < size)
58 throw std::runtime_error("Size to monitor too large");
59 prev = lua::align_overcommit<compare_obj, uint8_t>(this);
60 memset(prev, 0, (size_t)size * rows);
64 int compare_obj::create(lua::state& L, lua::parameters& P)
66 uint64_t addr, size;
67 uint64_t stride = 0, rows = 1;
69 addr = lua_get_read_address(P);
70 P(size, P.optional(rows, 1));
71 if(rows > 1)
72 P(stride);
74 compare_obj* o = lua::_class<compare_obj>::create(L, addr, size, rows, stride);
75 o->call(L, P);
76 L.pop(1);
77 return 1;
80 int compare_obj::call(lua::state& L, lua::parameters& P)
82 auto& core = CORE();
83 bool equals = true;
84 char* pbuffer = try_map ? core.memory->get_physical_mapping(minaddr, maxaddr - minaddr + 1) :
85 NULL;
86 if(pbuffer) {
87 //Mapable.
88 uint64_t offset = addr - minaddr;
89 for(uint64_t i = 0; i < rows; i++) {
90 bool eq = !memcmp(&prev[i * size], pbuffer + offset, size);
91 if(!eq)
92 memcpy(&prev[i * size], pbuffer + offset, size);
93 equals &= eq;
94 offset += stride;
96 } else {
97 //Not mapable.
98 for(uint64_t i = 0; i < rows; i++) {
99 uint64_t addr1 = addr + i * stride;
100 uint64_t addr2 = i * size;
101 for(uint64_t j = 0; j < size; j++) {
102 uint8_t byte = core.memory->read<uint8_t>(addr1 + j);
103 bool eq = prev[addr2 + j] == (char)byte;
104 if(!eq)
105 prev[addr2 + j] = byte;
106 equals &= eq;
110 L.pushboolean(!equals);
111 return 1;
114 lua::_class<compare_obj> LUA_class_vmalist(lua_class_memory, "COMPARE_OBJ", {
115 {"new", compare_obj::create},
116 }, {
117 {"__call", &compare_obj::call},
118 }, &compare_obj::print);