Refactor Lua support
[lsnes.git] / src / lua / memory.cpp
blobbee8a812821bb90fae74507c8561eb42a26cb216
1 #include "lua/internal.hpp"
2 #include "core/memorymanip.hpp"
3 #include "core/memorywatch.hpp"
4 #include "core/rom.hpp"
5 #include "library/sha256.hpp"
6 #include "library/string.hpp"
7 #include "library/minmax.hpp"
9 namespace
11 template<typename T, typename U, U (*rfun)(uint64_t addr)>
12 class lua_read_memory : public lua_function
14 public:
15 lua_read_memory(const std::string& name) : lua_function(LS, name) {}
16 int invoke(lua_state& L)
18 uint64_t addr = L.get_numeric_argument<uint64_t>(1, fname.c_str());
19 L.pushnumber(static_cast<T>(rfun(addr)));
20 return 1;
24 template<typename T, bool (*wfun)(uint64_t addr, T value)>
25 class lua_write_memory : public lua_function
27 public:
28 lua_write_memory(const std::string& name) : lua_function(LS, name) {}
29 int invoke(lua_state& L)
31 uint64_t addr = L.get_numeric_argument<uint64_t>(1, fname.c_str());
32 T value = L.get_numeric_argument<T>(2, fname.c_str());
33 wfun(addr, value);
34 return 0;
38 class mmap_base
40 public:
41 ~mmap_base() {}
42 virtual void read(lua_state& L, uint64_t addr) = 0;
43 virtual void write(lua_state& L, uint64_t addr) = 0;
47 template<typename T, typename U, U (*rfun)(uint64_t addr), bool (*wfun)(uint64_t addr, U value)>
48 class lua_mmap_memory_helper : public mmap_base
50 public:
51 ~lua_mmap_memory_helper() {}
52 void read(lua_state& L, uint64_t addr)
54 L.pushnumber(static_cast<T>(rfun(addr)));
57 void write(lua_state& L, uint64_t addr)
59 T value = L.get_numeric_argument<T>(3, "aperture(write)");
60 wfun(addr, value);
65 class lua_mmap_struct
67 public:
68 lua_mmap_struct(lua_state* L);
70 ~lua_mmap_struct()
74 int index(lua_state& L)
76 const char* c = L.tostring(2);
77 if(!c) {
78 L.pushnil();
79 return 1;
81 std::string c2(c);
82 if(!mappings.count(c2)) {
83 L.pushnil();
84 return 1;
86 auto& x = mappings[c2];
87 x.first->read(L, x.second);
88 return 1;
90 int newindex(lua_state& L)
92 const char* c = L.tostring(2);
93 if(!c)
94 return 0;
95 std::string c2(c);
96 if(!mappings.count(c2))
97 return 0;
98 auto& x = mappings[c2];
99 x.first->write(L, x.second);
100 return 0;
103 int map(lua_state& L);
104 private:
105 std::map<std::string, std::pair<mmap_base*, uint64_t>> mappings;
108 namespace
110 int aperture_read_fun(lua_State* _L)
112 lua_state& L = *reinterpret_cast<lua_state*>(lua_touserdata(_L, lua_upvalueindex(4)));
113 uint64_t base = L.tonumber(lua_upvalueindex(1));
114 uint64_t size = 0xFFFFFFFFFFFFFFFFULL;
115 if(L.type(lua_upvalueindex(2)) == LUA_TNUMBER)
116 size = L.tonumber(lua_upvalueindex(2));
117 mmap_base* fn = reinterpret_cast<mmap_base*>(L.touserdata(lua_upvalueindex(3)));
118 uint64_t addr = L.get_numeric_argument<uint64_t>(2, "aperture(read)");
119 if(addr > size || addr + base < addr) {
120 L.pushnumber(0);
121 return 1;
123 addr += base;
124 fn->read(L, addr);
125 return 1;
128 int aperture_write_fun(lua_State* _L)
130 lua_state& L = *reinterpret_cast<lua_state*>(lua_touserdata(_L, lua_upvalueindex(4)));
131 uint64_t base = L.tonumber(lua_upvalueindex(1));
132 uint64_t size = 0xFFFFFFFFFFFFFFFFULL;
133 if(L.type(lua_upvalueindex(2)) == LUA_TNUMBER)
134 size = L.tonumber(lua_upvalueindex(2));
135 mmap_base* fn = reinterpret_cast<mmap_base*>(L.touserdata(lua_upvalueindex(3)));
136 uint64_t addr = L.get_numeric_argument<uint64_t>(2, "aperture(write)");
137 if(addr > size || addr + base < addr)
138 return 0;
139 addr += base;
140 fn->write(L, addr);
141 return 0;
144 void aperture_make_fun(lua_state& L, uint64_t base, uint64_t size, mmap_base& type)
146 L.newtable();
147 L.newtable();
148 L.pushstring( "__index");
149 L.pushnumber(base);
150 if(!(size + 1))
151 L.pushnil();
152 else
153 L.pushnumber(size);
154 L.pushlightuserdata(&type);
155 L.pushlightuserdata(&L);
156 L.pushcclosure(aperture_read_fun, 4);
157 L.settable(-3);
158 L.pushstring("__newindex");
159 L.pushnumber(base);
160 if(!(size + 1))
161 L.pushnil();
162 else
163 L.pushnumber(size);
164 L.pushlightuserdata(&type);
165 L.pushlightuserdata(&L);
166 L.pushcclosure(aperture_write_fun, 4);
167 L.settable(-3);
168 L.setmetatable(-2);
171 class lua_mmap_memory : public lua_function
173 public:
174 lua_mmap_memory(const std::string& name, mmap_base& _h) : lua_function(LS, name), h(_h) {}
175 int invoke(lua_state& L)
177 if(L.isnoneornil(1)) {
178 aperture_make_fun(L, 0, 0xFFFFFFFFFFFFFFFFULL, h);
179 return 1;
181 uint64_t addr = L.get_numeric_argument<uint64_t>(1, fname.c_str());
182 uint64_t size = L.get_numeric_argument<uint64_t>(2, fname.c_str());
183 if(!size) {
184 L.pushstring("Aperture with zero size is not valid");
185 L.error();
186 return 0;
188 aperture_make_fun(L, addr, size - 1, h);
189 return 1;
191 mmap_base& h;
194 function_ptr_luafun vmacount(LS, "memory.vma_count", [](lua_state& L, const std::string& fname) -> int {
195 L.pushnumber(get_regions().size());
196 return 1;
199 int handle_push_vma(lua_state& L, std::vector<memory_region>& regions, size_t idx)
201 if(idx >= regions.size()) {
202 L.pushnil();
203 return 1;
205 memory_region& r = regions[idx];
206 L.newtable();
207 L.pushstring("region_name");
208 L.pushlstring(r.region_name.c_str(), r.region_name.size());
209 L.settable(-3);
210 L.pushstring("baseaddr");
211 L.pushnumber(r.baseaddr);
212 L.settable(-3);
213 L.pushstring("size");
214 L.pushnumber(r.size);
215 L.settable(-3);
216 L.pushstring("lastaddr");
217 L.pushnumber(r.lastaddr);
218 L.settable(-3);
219 L.pushstring("readonly");
220 L.pushboolean(r.readonly);
221 L.settable(-3);
222 L.pushstring("iospace");
223 L.pushboolean(r.iospace);
224 L.settable(-3);
225 L.pushstring("native_endian");
226 L.pushboolean(r.native_endian);
227 L.settable(-3);
228 return 1;
231 function_ptr_luafun readvma(LS, "memory.read_vma", [](lua_state& L, const std::string& fname) -> int {
232 std::vector<memory_region> regions = get_regions();
233 uint32_t num = L.get_numeric_argument<uint32_t>(1, fname.c_str());
234 return handle_push_vma(L, regions, num);
237 function_ptr_luafun findvma(LS, "memory.find_vma", [](lua_state& L, const std::string& fname) -> int {
238 std::vector<memory_region> regions = get_regions();
239 uint64_t addr = L.get_numeric_argument<uint64_t>(1, fname.c_str());
240 size_t i;
241 for(i = 0; i < regions.size(); i++)
242 if(addr >= regions[i].baseaddr && addr <= regions[i].lastaddr)
243 break;
244 return handle_push_vma(L, regions, i);
247 const char* hexes = "0123456789ABCDEF";
249 function_ptr_luafun hashstate(LS, "memory.hash_state", [](lua_state& L, const std::string& fname) -> int {
250 char hash[64];
251 auto x = save_core_state();
252 size_t offset = x.size() - 32;
253 for(unsigned i = 0; i < 32; i++) {
254 hash[2 * i + 0] = hexes[static_cast<unsigned char>(x[offset + i]) >> 4];
255 hash[2 * i + 1] = hexes[static_cast<unsigned char>(x[offset + i]) & 0xF];
257 L.pushlstring(hash, 64);
258 return 1;
261 #define BLOCKSIZE 256
263 function_ptr_luafun hashmemory(LS, "memory.hash_region", [](lua_state& L, const std::string& fname) -> int {
264 std::string hash;
265 uint64_t addr = L.get_numeric_argument<uint64_t>(1, fname.c_str());
266 uint64_t size = L.get_numeric_argument<uint64_t>(2, fname.c_str());
267 char buffer[BLOCKSIZE];
268 sha256 h;
269 while(size > BLOCKSIZE) {
270 for(size_t i = 0; i < BLOCKSIZE; i++)
271 buffer[i] = memory_read_byte(addr + i);
272 h.write(buffer, BLOCKSIZE);
273 addr += BLOCKSIZE;
274 size -= BLOCKSIZE;
276 for(size_t i = 0; i < size; i++)
277 buffer[i] = memory_read_byte(addr + i);
278 h.write(buffer, size);
279 hash = h.read();
280 L.pushlstring(hash.c_str(), 64);
281 return 1;
284 function_ptr_luafun readmemoryr(LS, "memory.readregion", [](lua_state& L, const std::string& fname) -> int {
285 std::string hash;
286 uint64_t addr = L.get_numeric_argument<uint64_t>(1, fname.c_str());
287 uint64_t size = L.get_numeric_argument<uint64_t>(2, fname.c_str());
288 L.newtable();
289 char buffer[BLOCKSIZE];
290 uint64_t ctr = 0;
291 while(size > 0) {
292 size_t rsize = min(size, static_cast<uint64_t>(BLOCKSIZE));
293 memory_read_bytes(addr, rsize, buffer);
294 for(size_t i = 0; i < rsize; i++) {
295 L.pushnumber(ctr++);
296 L.pushnumber(static_cast<unsigned char>(buffer[i]));
297 L.settable(-3);
299 addr += rsize;
300 size -= rsize;
302 return 1;
305 function_ptr_luafun writememoryr(LS, "memory.writeregion", [](lua_state& L, const std::string& fname) -> int {
306 std::string hash;
307 uint64_t addr = L.get_numeric_argument<uint64_t>(1, fname.c_str());
308 uint64_t size = L.get_numeric_argument<uint64_t>(2, fname.c_str());
309 char buffer[BLOCKSIZE];
310 uint64_t ctr = 0;
311 while(size > 0) {
312 size_t rsize = min(size, static_cast<uint64_t>(BLOCKSIZE));
313 for(size_t i = 0; i < rsize; i++) {
314 L.pushnumber(ctr++);
315 L.gettable(3);
316 buffer[i] = L.tointeger(-1);
317 L.pop(1);
319 memory_write_bytes(addr, rsize, buffer);
320 addr += rsize;
321 size -= rsize;
323 return 1;
326 function_ptr_luafun gui_cbitmap(LS, "memory.map_structure", [](lua_state& L, const std::string& fname) ->
327 int {
328 lua_mmap_struct* b = lua_class<lua_mmap_struct>::create(L, &L);
329 return 1;
332 function_ptr_luafun memory_watchexpr(LS, "memory.read_expr", [](lua_state& L, const std::string& fname) ->
333 int {
334 std::string val = evaluate_watch(L.get_string(1, fname.c_str()));
335 L.pushstring(val.c_str());
336 return 1;
339 lua_read_memory<uint8_t, uint8_t, memory_read_byte> rub("memory.readbyte");
340 lua_read_memory<int8_t, uint8_t, memory_read_byte> rsb("memory.readsbyte");
341 lua_read_memory<uint16_t, uint16_t, memory_read_word> ruw("memory.readword");
342 lua_read_memory<int16_t, uint16_t, memory_read_word> rsw("memory.readsword");
343 lua_read_memory<uint32_t, uint32_t, memory_read_dword> rud("memory.readdword");
344 lua_read_memory<int32_t, uint32_t, memory_read_dword> rsd("memory.readsdword");
345 lua_read_memory<uint64_t, uint64_t, memory_read_qword> ruq("memory.readqword");
346 lua_read_memory<int64_t, uint64_t, memory_read_qword> rsq("memory.readsqword");
347 lua_write_memory<uint8_t, memory_write_byte> wb("memory.writebyte");
348 lua_write_memory<uint16_t, memory_write_word> ww("memory.writeword");
349 lua_write_memory<uint32_t, memory_write_dword> wd("memory.writedword");
350 lua_write_memory<uint64_t, memory_write_qword> wq("memory.writeqword");
351 lua_mmap_memory_helper<uint8_t, uint8_t, memory_read_byte, memory_write_byte> mhub;
352 lua_mmap_memory_helper<int8_t, uint8_t, memory_read_byte, memory_write_byte> mhsb;
353 lua_mmap_memory_helper<uint16_t, uint16_t, memory_read_word, memory_write_word> mhuw;
354 lua_mmap_memory_helper<int16_t, uint16_t, memory_read_word, memory_write_word> mhsw;
355 lua_mmap_memory_helper<uint32_t, uint32_t, memory_read_dword, memory_write_dword> mhud;
356 lua_mmap_memory_helper<int32_t, uint32_t, memory_read_dword, memory_write_dword> mhsd;
357 lua_mmap_memory_helper<uint64_t, uint64_t, memory_read_qword, memory_write_qword> mhuq;
358 lua_mmap_memory_helper<int64_t, uint64_t, memory_read_qword, memory_write_qword> mhsq;
359 lua_mmap_memory mub("memory.mapbyte", mhub);
360 lua_mmap_memory msb("memory.mapsbyte", mhsb);
361 lua_mmap_memory muw("memory.mapword", mhuw);
362 lua_mmap_memory msw("memory.mapsword", mhsw);
363 lua_mmap_memory mud("memory.mapdword", mhud);
364 lua_mmap_memory msd("memory.mapsdword", mhsd);
365 lua_mmap_memory muq("memory.mapqword", mhuq);
366 lua_mmap_memory msq("memory.mapsqword", mhsq);
370 int lua_mmap_struct::map(lua_state& L)
372 const char* name = L.tostring(2);
373 uint64_t addr = L.get_numeric_argument<uint64_t>(3, "lua_mmap_struct::map");
374 const char* type = L.tostring(4);
375 if(!name) {
376 L.pushstring("lua_mmap_struct::map: Bad name");
377 L.error();
378 return 0;
380 if(!type) {
381 L.pushstring("lua_mmap_struct::map: Bad type");
382 L.error();
383 return 0;
385 std::string name2(name);
386 std::string type2(type);
387 if(type2 == "byte")
388 mappings[name2] = std::make_pair(&mhub, addr);
389 else if(type2 == "sbyte")
390 mappings[name2] = std::make_pair(&mhsb, addr);
391 else if(type2 == "word")
392 mappings[name2] = std::make_pair(&mhuw, addr);
393 else if(type2 == "sword")
394 mappings[name2] = std::make_pair(&mhsw, addr);
395 else if(type2 == "dword")
396 mappings[name2] = std::make_pair(&mhud, addr);
397 else if(type2 == "sdword")
398 mappings[name2] = std::make_pair(&mhsd, addr);
399 else if(type2 == "qword")
400 mappings[name2] = std::make_pair(&mhuq, addr);
401 else if(type2 == "sqword")
402 mappings[name2] = std::make_pair(&mhsq, addr);
403 else {
404 L.pushstring("lua_mmap_struct::map: Bad type");
405 L.error();
406 return 0;
408 return 0;
411 DECLARE_LUACLASS(lua_mmap_struct, "MMAP_STRUCT");
413 lua_mmap_struct::lua_mmap_struct(lua_state* L)
415 static char key;
416 L->pushlightuserdata(&key);
417 L->rawget(LUA_REGISTRYINDEX);
418 if(L->type(-1) == LUA_TNIL) {
419 L->pop(1);
420 L->pushlightuserdata(&key);
421 L->pushboolean(true);
422 L->rawset(LUA_REGISTRYINDEX);
423 objclass<lua_mmap_struct>().bind(*L, "__index", &lua_mmap_struct::index, true);
424 objclass<lua_mmap_struct>().bind(*L, "__newindex", &lua_mmap_struct::newindex, true);
425 objclass<lua_mmap_struct>().bind(*L, "__call", &lua_mmap_struct::map);
426 } else
427 L->pop(1);