JSON-based controller descriptions
[lsnes.git] / src / lua / memory.cpp
blob17e901cc50c59fa2ed0745f486dff69a302d7081
1 #include "lua/internal.hpp"
2 #include "core/memorymanip.hpp"
3 #include "core/memorywatch.hpp"
4 #include "core/moviedata.hpp"
5 #include "core/moviefile.hpp"
6 #include "core/rom.hpp"
7 #include "library/sha256.hpp"
8 #include "library/string.hpp"
9 #include "library/minmax.hpp"
10 #include "library/int24.hpp"
12 namespace
14 uint64_t get_vmabase(lua_state& L, const std::string& vma)
16 for(auto i : lsnes_memory.get_regions())
17 if(i->name == vma)
18 return i->base;
19 throw std::runtime_error("No such VMA");
22 template<typename T, T (memory_space::*rfun)(uint64_t addr)>
23 class lua_read_memory : public lua_function
25 public:
26 lua_read_memory(const std::string& name) : lua_function(lua_func_misc, name) {}
27 int invoke(lua_state& L)
29 int base = 0;
30 uint64_t vmabase = 0;
31 if(L.type(1) == LUA_TSTRING) {
32 vmabase = get_vmabase(L, L.get_string(1, "lua_read_memory"));
33 base = 1;
35 uint64_t addr = L.get_numeric_argument<uint64_t>(base + 1, fname.c_str()) + vmabase;
36 L.pushnumber(static_cast<T>((lsnes_memory.*rfun)(addr)));
37 return 1;
41 template<typename T, bool (memory_space::*wfun)(uint64_t addr, T value)>
42 class lua_write_memory : public lua_function
44 public:
45 lua_write_memory(const std::string& name) : lua_function(lua_func_misc, name) {}
46 int invoke(lua_state& L)
48 int base = 0;
49 uint64_t vmabase = 0;
50 if(L.type(1) == LUA_TSTRING) {
51 vmabase = get_vmabase(L, L.get_string(1, "lua_read_memory"));
52 base = 1;
54 uint64_t addr = L.get_numeric_argument<uint64_t>(base + 1, fname.c_str()) + vmabase;
55 T value = L.get_numeric_argument<T>(base + 2, fname.c_str());
56 (lsnes_memory.*wfun)(addr, value);
57 return 0;
61 class mmap_base
63 public:
64 ~mmap_base() {}
65 virtual void read(lua_state& L, uint64_t addr) = 0;
66 virtual void write(lua_state& L, uint64_t addr) = 0;
70 template<typename T, T (memory_space::*rfun)(uint64_t addr), bool (memory_space::*wfun)(uint64_t addr,
71 T value)>
72 class lua_mmap_memory_helper : public mmap_base
74 public:
75 ~lua_mmap_memory_helper() {}
76 void read(lua_state& L, uint64_t addr)
78 L.pushnumber(static_cast<T>((lsnes_memory.*rfun)(addr)));
81 void write(lua_state& L, uint64_t addr)
83 T value = L.get_numeric_argument<T>(3, "aperture(write)");
84 (lsnes_memory.*wfun)(addr, value);
89 class lua_mmap_struct
91 public:
92 lua_mmap_struct(lua_state& L);
94 ~lua_mmap_struct()
98 int index(lua_state& L, const std::string& fname)
100 const char* c = L.tostring(2);
101 if(!c) {
102 L.pushnil();
103 return 1;
105 std::string c2(c);
106 if(!mappings.count(c2)) {
107 L.pushnil();
108 return 1;
110 auto& x = mappings[c2];
111 x.first->read(L, x.second);
112 return 1;
114 int newindex(lua_state& L, const std::string& fname)
116 const char* c = L.tostring(2);
117 if(!c)
118 return 0;
119 std::string c2(c);
120 if(!mappings.count(c2))
121 return 0;
122 auto& x = mappings[c2];
123 x.first->write(L, x.second);
124 return 0;
126 int map(lua_state& L, const std::string& fname);
127 std::string print()
129 size_t s = mappings.size();
130 return (stringfmt() << s << " " << ((s != 1) ? "mappings" : "mapping")).str();
132 private:
133 std::map<std::string, std::pair<mmap_base*, uint64_t>> mappings;
136 namespace
138 int aperture_read_fun(lua_State* _L)
140 lua_state& L = *reinterpret_cast<lua_state*>(lua_touserdata(_L, lua_upvalueindex(4)));
141 uint64_t base = L.tonumber(lua_upvalueindex(1));
142 uint64_t size = 0xFFFFFFFFFFFFFFFFULL;
143 if(L.type(lua_upvalueindex(2)) == LUA_TNUMBER)
144 size = L.tonumber(lua_upvalueindex(2));
145 mmap_base* fn = reinterpret_cast<mmap_base*>(L.touserdata(lua_upvalueindex(3)));
146 uint64_t addr = L.get_numeric_argument<uint64_t>(2, "aperture(read)");
147 if(addr > size || addr + base < addr) {
148 L.pushnumber(0);
149 return 1;
151 addr += base;
152 fn->read(L, addr);
153 return 1;
156 int aperture_write_fun(lua_State* _L)
158 lua_state& L = *reinterpret_cast<lua_state*>(lua_touserdata(_L, lua_upvalueindex(4)));
159 uint64_t base = L.tonumber(lua_upvalueindex(1));
160 uint64_t size = 0xFFFFFFFFFFFFFFFFULL;
161 if(L.type(lua_upvalueindex(2)) == LUA_TNUMBER)
162 size = L.tonumber(lua_upvalueindex(2));
163 mmap_base* fn = reinterpret_cast<mmap_base*>(L.touserdata(lua_upvalueindex(3)));
164 uint64_t addr = L.get_numeric_argument<uint64_t>(2, "aperture(write)");
165 if(addr > size || addr + base < addr)
166 return 0;
167 addr += base;
168 fn->write(L, addr);
169 return 0;
172 void aperture_make_fun(lua_state& L, uint64_t base, uint64_t size, mmap_base& type)
174 L.newtable();
175 L.newtable();
176 L.pushstring( "__index");
177 L.pushnumber(base);
178 if(!(size + 1))
179 L.pushnil();
180 else
181 L.pushnumber(size);
182 L.pushlightuserdata(&type);
183 L.pushlightuserdata(&L);
184 L.pushcclosure(aperture_read_fun, 4);
185 L.settable(-3);
186 L.pushstring("__newindex");
187 L.pushnumber(base);
188 if(!(size + 1))
189 L.pushnil();
190 else
191 L.pushnumber(size);
192 L.pushlightuserdata(&type);
193 L.pushlightuserdata(&L);
194 L.pushcclosure(aperture_write_fun, 4);
195 L.settable(-3);
196 L.setmetatable(-2);
199 class lua_mmap_memory : public lua_function
201 public:
202 lua_mmap_memory(const std::string& name, mmap_base& _h) : lua_function(lua_func_misc, name), h(_h) {}
203 int invoke(lua_state& L)
205 if(L.isnoneornil(1)) {
206 aperture_make_fun(L, 0, 0xFFFFFFFFFFFFFFFFULL, h);
207 return 1;
209 int base = 0;
210 uint64_t vmabase = 0;
211 if(L.type(1) == LUA_TSTRING) {
212 vmabase = get_vmabase(L, L.get_string(1, "lua_mmap_memory"));
213 base = 1;
215 uint64_t addr = L.get_numeric_argument<uint64_t>(base + 1, fname.c_str()) + vmabase;
216 uint64_t size = L.get_numeric_argument<uint64_t>(base + 2, fname.c_str());
217 if(!size)
218 throw std::runtime_error("Aperture with zero size is not valid");
219 aperture_make_fun(L, addr, size - 1, h);
220 return 1;
222 mmap_base& h;
225 function_ptr_luafun vmacount(lua_func_misc, "memory.vma_count", [](lua_state& L, const std::string& fname)
226 -> int {
227 L.pushnumber(lsnes_memory.get_regions().size());
228 return 1;
231 int handle_push_vma(lua_state& L, memory_region& r)
233 L.newtable();
234 L.pushstring("region_name");
235 L.pushlstring(r.name.c_str(), r.name.size());
236 L.settable(-3);
237 L.pushstring("baseaddr");
238 L.pushnumber(r.base);
239 L.settable(-3);
240 L.pushstring("size");
241 L.pushnumber(r.size);
242 L.settable(-3);
243 L.pushstring("lastaddr");
244 L.pushnumber(r.last_address());
245 L.settable(-3);
246 L.pushstring("readonly");
247 L.pushboolean(r.readonly);
248 L.settable(-3);
249 L.pushstring("iospace");
250 L.pushboolean(r.special);
251 L.settable(-3);
252 L.pushstring("native_endian");
253 L.pushboolean(r.endian == 0);
254 L.settable(-3);
255 L.pushstring("endian");
256 L.pushnumber(r.endian);
257 L.settable(-3);
258 return 1;
261 function_ptr_luafun readvma(lua_func_misc, "memory.read_vma", [](lua_state& L, const std::string& fname)
262 -> int {
263 std::list<memory_region*> regions = lsnes_memory.get_regions();
264 uint32_t num = L.get_numeric_argument<uint32_t>(1, fname.c_str());
265 uint32_t j = 0;
266 for(auto i = regions.begin(); i != regions.end(); i++, j++)
267 if(j == num)
268 return handle_push_vma(L, **i);
269 L.pushnil();
270 return 1;
273 function_ptr_luafun findvma(lua_func_misc, "memory.find_vma", [](lua_state& L, const std::string& fname)
274 -> int {
275 uint64_t addr = L.get_numeric_argument<uint64_t>(1, fname.c_str());
276 auto r = lsnes_memory.lookup(addr);
277 if(r.first)
278 return handle_push_vma(L, *r.first);
279 L.pushnil();
280 return 1;
283 const char* hexes = "0123456789ABCDEF";
285 function_ptr_luafun hashstate(lua_func_misc, "memory.hash_state", [](lua_state& L, const std::string& fname)
286 -> int {
287 char hash[64];
288 auto x = our_rom.save_core_state();
289 size_t offset = x.size() - 32;
290 for(unsigned i = 0; i < 32; i++) {
291 hash[2 * i + 0] = hexes[static_cast<unsigned char>(x[offset + i]) >> 4];
292 hash[2 * i + 1] = hexes[static_cast<unsigned char>(x[offset + i]) & 0xF];
294 L.pushlstring(hash, 64);
295 return 1;
298 #define BLOCKSIZE 256
300 function_ptr_luafun hashmemory(lua_func_misc, "memory.hash_region", [](lua_state& L, const std::string& fname)
301 -> int {
302 std::string hash;
303 int base = 0;
304 uint64_t vmabase = 0;
305 if(L.type(1) == LUA_TSTRING) {
306 vmabase = get_vmabase(L, L.get_string(1, fname.c_str()));
307 base = 1;
309 uint64_t addr = L.get_numeric_argument<uint64_t>(base + 1, fname.c_str()) + vmabase;
310 uint64_t size = L.get_numeric_argument<uint64_t>(base + 2, fname.c_str());
311 char buffer[BLOCKSIZE];
312 sha256 h;
313 while(size > BLOCKSIZE) {
314 for(size_t i = 0; i < BLOCKSIZE; i++)
315 buffer[i] = lsnes_memory.read<uint8_t>(addr + i);
316 h.write(buffer, BLOCKSIZE);
317 addr += BLOCKSIZE;
318 size -= BLOCKSIZE;
320 for(size_t i = 0; i < size; i++)
321 buffer[i] = lsnes_memory.read<uint8_t>(addr + i);
322 h.write(buffer, size);
323 hash = h.read();
324 L.pushlstring(hash.c_str(), 64);
325 return 1;
328 function_ptr_luafun readmemoryr(lua_func_misc, "memory.readregion", [](lua_state& L, const std::string& fname)
329 -> int {
330 std::string hash;
331 int base = 0;
332 uint64_t vmabase = 0;
333 if(L.type(1) == LUA_TSTRING) {
334 vmabase = get_vmabase(L, L.get_string(1, fname.c_str()));
335 base = 1;
337 uint64_t addr = L.get_numeric_argument<uint64_t>(base + 1, fname.c_str()) + vmabase;
338 uint64_t size = L.get_numeric_argument<uint64_t>(base + 2, fname.c_str());
339 L.newtable();
340 char buffer[BLOCKSIZE];
341 uint64_t ctr = 0;
342 while(size > 0) {
343 size_t rsize = min(size, static_cast<uint64_t>(BLOCKSIZE));
344 lsnes_memory.read_range(addr, buffer, rsize);
345 for(size_t i = 0; i < rsize; i++) {
346 L.pushnumber(ctr++);
347 L.pushnumber(static_cast<unsigned char>(buffer[i]));
348 L.settable(-3);
350 addr += rsize;
351 size -= rsize;
353 return 1;
356 function_ptr_luafun writememoryr(lua_func_misc, "memory.writeregion", [](lua_state& L,
357 const std::string& fname) -> int {
358 std::string hash;
359 int base = 0;
360 uint64_t vmabase = 0;
361 if(L.type(1) == LUA_TSTRING) {
362 vmabase = get_vmabase(L, L.get_string(1, fname.c_str()));
363 base = 1;
365 uint64_t addr = L.get_numeric_argument<uint64_t>(base + 1, fname.c_str()) + vmabase;
366 uint64_t size = L.get_numeric_argument<uint64_t>(base + 2, fname.c_str());
367 char buffer[BLOCKSIZE];
368 uint64_t ctr = 0;
369 while(size > 0) {
370 size_t rsize = min(size, static_cast<uint64_t>(BLOCKSIZE));
371 for(size_t i = 0; i < rsize; i++) {
372 L.pushnumber(ctr++);
373 L.gettable(3);
374 buffer[i] = L.tointeger(-1);
375 L.pop(1);
377 lsnes_memory.write_range(addr, buffer, rsize);
378 addr += rsize;
379 size -= rsize;
381 return 1;
384 function_ptr_luafun gui_cbitmap(lua_func_misc, "memory.map_structure", [](lua_state& L,
385 const std::string& fname) -> int {
386 lua_class<lua_mmap_struct>::create(L);
387 return 1;
390 function_ptr_luafun memory_watchexpr(lua_func_misc, "memory.read_expr", [](lua_state& L,
391 const std::string& fname) -> int {
392 std::string val = evaluate_watch(L.get_string(1, fname.c_str()));
393 L.pushstring(val.c_str());
394 return 1;
397 template<bool write, bool sign> int memory_scattergather(lua_state& L, const std::string& fname)
399 uint64_t val = 0;
400 int ptr = 1;
401 unsigned shift = 0;
402 uint64_t addr = 0;
403 uint64_t vmabase = 0;
404 if(write)
405 val = L.get_numeric_argument<uint64_t>(ptr++, fname.c_str());
406 while(L.type(ptr) != LUA_TNIL && L.type(ptr) != LUA_TNONE) {
407 if(L.type(ptr) == LUA_TBOOLEAN) {
408 if(L.toboolean(ptr++))
409 addr++;
410 else
411 addr--;
412 } else if(L.type(ptr) == LUA_TSTRING) {
413 vmabase = get_vmabase(L, L.get_string(ptr++, fname.c_str()));
414 continue;
415 } else
416 addr = L.get_numeric_argument<uint64_t>(ptr++, fname.c_str());
417 if(write)
418 lsnes_memory.write<uint8_t>(addr + vmabase, val >> shift);
419 else
420 val = val + ((uint64_t)lsnes_memory.read<uint8_t>(addr + vmabase) << shift);
421 shift += 8;
423 if(!write) {
424 int64_t sval = val;
425 if(val >= (1ULL << (shift - 1))) sval -= (1ULL << shift);
426 if(sign) L.pushnumber(sval); else L.pushnumber(val);
428 return write ? 0 : 1;
431 function_ptr_luafun scattergather1(lua_func_misc, "memory.read_sg", [](lua_state& L, const std::string& fname)
432 -> int {
433 return memory_scattergather<false, false>(L, fname);
436 function_ptr_luafun scattergather2(lua_func_misc, "memory.sread_sg", [](lua_state& L,
437 const std::string& fname) -> int {
438 return memory_scattergather<false, true>(L, fname);
441 function_ptr_luafun scattergather3(lua_func_misc, "memory.write_sg", [](lua_state& L,
442 const std::string& fname) -> int {
443 return memory_scattergather<true, false>(L, fname);
446 lua_read_memory<uint8_t, &memory_space::read<uint8_t>> rub("memory.readbyte");
447 lua_read_memory<int8_t, &memory_space::read<int8_t>> rsb("memory.readsbyte");
448 lua_read_memory<uint16_t, &memory_space::read<uint16_t>> ruw("memory.readword");
449 lua_read_memory<int16_t, &memory_space::read<int16_t>> rsw("memory.readsword");
450 lua_read_memory<ss_uint24_t, &memory_space::read<ss_uint24_t>> ruh("memory.readhword");
451 lua_read_memory<ss_int24_t, &memory_space::read<ss_int24_t>> rsh("memory.readshword");
452 lua_read_memory<uint32_t, &memory_space::read<uint32_t>> rud("memory.readdword");
453 lua_read_memory<int32_t, &memory_space::read<int32_t>> rsd("memory.readsdword");
454 lua_read_memory<uint64_t, &memory_space::read<uint64_t>> ruq("memory.readqword");
455 lua_read_memory<int64_t, &memory_space::read<int64_t>> rsq("memory.readsqword");
456 lua_read_memory<float, &memory_space::read<float>> rf4("memory.readfloat");
457 lua_read_memory<double, &memory_space::read<double>> rf8("memory.readdouble");
458 lua_write_memory<uint8_t, &memory_space::write<uint8_t>> wb("memory.writebyte");
459 lua_write_memory<uint16_t, &memory_space::write<uint16_t>> ww("memory.writeword");
460 lua_write_memory<ss_uint24_t, &memory_space::write<ss_uint24_t>> wh("memory.writehword");
461 lua_write_memory<uint32_t, &memory_space::write<uint32_t>> wd("memory.writedword");
462 lua_write_memory<uint64_t, &memory_space::write<uint64_t>> wq("memory.writeqword");
463 lua_write_memory<float, &memory_space::write<float>> wf4("memory.writefloat");
464 lua_write_memory<double, &memory_space::write<double>> wf8("memory.writedouble");
465 lua_mmap_memory_helper<uint8_t, &memory_space::read<uint8_t>, &memory_space::write<uint8_t>> mhub;
466 lua_mmap_memory_helper<int8_t, &memory_space::read<int8_t>, &memory_space::write<int8_t>> mhsb;
467 lua_mmap_memory_helper<uint16_t, &memory_space::read<uint16_t>, &memory_space::write<uint16_t>> mhuw;
468 lua_mmap_memory_helper<int16_t, &memory_space::read<int16_t>, &memory_space::write<int16_t>> mhsw;
469 lua_mmap_memory_helper<ss_uint24_t, &memory_space::read<ss_uint24_t>, &memory_space::write<ss_uint24_t>> mhuh;
470 lua_mmap_memory_helper<ss_int24_t, &memory_space::read<ss_int24_t>, &memory_space::write<ss_int24_t>> mhsh;
471 lua_mmap_memory_helper<uint32_t, &memory_space::read<uint32_t>, &memory_space::write<uint32_t>> mhud;
472 lua_mmap_memory_helper<int32_t, &memory_space::read<int32_t>, &memory_space::write<int32_t>> mhsd;
473 lua_mmap_memory_helper<uint64_t, &memory_space::read<uint64_t>, &memory_space::write<uint64_t>> mhuq;
474 lua_mmap_memory_helper<int64_t, &memory_space::read<int64_t>, &memory_space::write<int64_t>> mhsq;
475 lua_mmap_memory_helper<float, &memory_space::read<float>, &memory_space::write<float>> mhf4;
476 lua_mmap_memory_helper<double, &memory_space::read<double>, &memory_space::write<double>> mhf8;
477 lua_mmap_memory mub("memory.mapbyte", mhub);
478 lua_mmap_memory msb("memory.mapsbyte", mhsb);
479 lua_mmap_memory muw("memory.mapword", mhuw);
480 lua_mmap_memory msw("memory.mapsword", mhsw);
481 lua_mmap_memory muh("memory.maphword", mhuh);
482 lua_mmap_memory msh("memory.mapshword", mhsh);
483 lua_mmap_memory mud("memory.mapdword", mhud);
484 lua_mmap_memory msd("memory.mapsdword", mhsd);
485 lua_mmap_memory muq("memory.mapqword", mhuq);
486 lua_mmap_memory msq("memory.mapsqword", mhsq);
487 lua_mmap_memory mf4("memory.mapfloat", mhf4);
488 lua_mmap_memory mf8("memory.mapdouble", mhf8);
491 int lua_mmap_struct::map(lua_state& L, const std::string& fname)
493 const char* name = L.tostring(2);
494 int base = 0;
495 uint64_t vmabase = 0;
496 if(L.type(3) == LUA_TSTRING) {
497 vmabase = get_vmabase(L, L.get_string(3, fname.c_str()));
498 base = 1;
500 uint64_t addr = L.get_numeric_argument<uint64_t>(base + 3, fname.c_str());
501 const char* type = L.tostring(base + 4);
502 if(!name)
503 (stringfmt() << fname << ": Bad name").throwex();
504 if(!type)
505 (stringfmt() << fname << ": Bad type").throwex();
506 std::string name2(name);
507 std::string type2(type);
508 if(type2 == "byte")
509 mappings[name2] = std::make_pair(&mhub, addr);
510 else if(type2 == "sbyte")
511 mappings[name2] = std::make_pair(&mhsb, addr);
512 else if(type2 == "word")
513 mappings[name2] = std::make_pair(&mhuw, addr);
514 else if(type2 == "sword")
515 mappings[name2] = std::make_pair(&mhsw, addr);
516 else if(type2 == "hword")
517 mappings[name2] = std::make_pair(&mhuh, addr);
518 else if(type2 == "shword")
519 mappings[name2] = std::make_pair(&mhsh, addr);
520 else if(type2 == "dword")
521 mappings[name2] = std::make_pair(&mhud, addr);
522 else if(type2 == "sdword")
523 mappings[name2] = std::make_pair(&mhsd, addr);
524 else if(type2 == "qword")
525 mappings[name2] = std::make_pair(&mhuq, addr);
526 else if(type2 == "sqword")
527 mappings[name2] = std::make_pair(&mhsq, addr);
528 else if(type2 == "float")
529 mappings[name2] = std::make_pair(&mhf4, addr);
530 else if(type2 == "double")
531 mappings[name2] = std::make_pair(&mhf8, addr);
532 else
533 (stringfmt() << fname << ": Bad type").throwex();
534 return 0;
537 DECLARE_LUACLASS(lua_mmap_struct, "MMAP_STRUCT");
539 lua_mmap_struct::lua_mmap_struct(lua_state& L)
541 objclass<lua_mmap_struct>().bind_multi(L, {
542 {"__index", &lua_mmap_struct::index},
543 {"__newindex", &lua_mmap_struct::newindex},
544 {"__call", &lua_mmap_struct::map},