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"
14 uint64_t get_vmabase(lua_state
& L
, const std::string
& vma
)
16 for(auto i
: lsnes_memory
.get_regions())
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
26 lua_read_memory(const std::string
& name
) : lua_function(lua_func_misc
, name
) {}
27 int invoke(lua_state
& L
)
31 if(L
.type(1) == LUA_TSTRING
) {
32 vmabase
= get_vmabase(L
, L
.get_string(1, "lua_read_memory"));
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
)));
41 template<typename T
, bool (memory_space::*wfun
)(uint64_t addr
, T value
)>
42 class lua_write_memory
: public lua_function
45 lua_write_memory(const std::string
& name
) : lua_function(lua_func_misc
, name
) {}
46 int invoke(lua_state
& L
)
50 if(L
.type(1) == LUA_TSTRING
) {
51 vmabase
= get_vmabase(L
, L
.get_string(1, "lua_read_memory"));
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
);
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
,
72 class lua_mmap_memory_helper
: public mmap_base
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
);
92 lua_mmap_struct(lua_state
& L
);
98 int index(lua_state
& L
, const std::string
& fname
)
100 const char* c
= L
.tostring(2);
106 if(!mappings
.count(c2
)) {
110 auto& x
= mappings
[c2
];
111 x
.first
->read(L
, x
.second
);
114 int newindex(lua_state
& L
, const std::string
& fname
)
116 const char* c
= L
.tostring(2);
120 if(!mappings
.count(c2
))
122 auto& x
= mappings
[c2
];
123 x
.first
->write(L
, x
.second
);
126 int map(lua_state
& L
, const std::string
& fname
);
129 size_t s
= mappings
.size();
130 return (stringfmt() << s
<< " " << ((s
!= 1) ? "mappings" : "mapping")).str();
133 std::map
<std::string
, std::pair
<mmap_base
*, uint64_t>> mappings
;
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
) {
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
)
172 void aperture_make_fun(lua_state
& L
, uint64_t base
, uint64_t size
, mmap_base
& type
)
176 L
.pushstring( "__index");
182 L
.pushlightuserdata(&type
);
183 L
.pushlightuserdata(&L
);
184 L
.pushcclosure(aperture_read_fun
, 4);
186 L
.pushstring("__newindex");
192 L
.pushlightuserdata(&type
);
193 L
.pushlightuserdata(&L
);
194 L
.pushcclosure(aperture_write_fun
, 4);
199 class lua_mmap_memory
: public lua_function
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
);
210 uint64_t vmabase
= 0;
211 if(L
.type(1) == LUA_TSTRING
) {
212 vmabase
= get_vmabase(L
, L
.get_string(1, "lua_mmap_memory"));
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());
218 throw std::runtime_error("Aperture with zero size is not valid");
219 aperture_make_fun(L
, addr
, size
- 1, h
);
225 function_ptr_luafun
vmacount(lua_func_misc
, "memory.vma_count", [](lua_state
& L
, const std::string
& fname
)
227 L
.pushnumber(lsnes_memory
.get_regions().size());
231 int handle_push_vma(lua_state
& L
, memory_region
& r
)
234 L
.pushstring("region_name");
235 L
.pushlstring(r
.name
.c_str(), r
.name
.size());
237 L
.pushstring("baseaddr");
238 L
.pushnumber(r
.base
);
240 L
.pushstring("size");
241 L
.pushnumber(r
.size
);
243 L
.pushstring("lastaddr");
244 L
.pushnumber(r
.last_address());
246 L
.pushstring("readonly");
247 L
.pushboolean(r
.readonly
);
249 L
.pushstring("iospace");
250 L
.pushboolean(r
.special
);
252 L
.pushstring("native_endian");
253 L
.pushboolean(r
.endian
== 0);
255 L
.pushstring("endian");
256 L
.pushnumber(r
.endian
);
261 function_ptr_luafun
readvma(lua_func_misc
, "memory.read_vma", [](lua_state
& L
, const std::string
& fname
)
263 std::list
<memory_region
*> regions
= lsnes_memory
.get_regions();
264 uint32_t num
= L
.get_numeric_argument
<uint32_t>(1, fname
.c_str());
266 for(auto i
= regions
.begin(); i
!= regions
.end(); i
++, j
++)
268 return handle_push_vma(L
, **i
);
273 function_ptr_luafun
findvma(lua_func_misc
, "memory.find_vma", [](lua_state
& L
, const std::string
& fname
)
275 uint64_t addr
= L
.get_numeric_argument
<uint64_t>(1, fname
.c_str());
276 auto r
= lsnes_memory
.lookup(addr
);
278 return handle_push_vma(L
, *r
.first
);
283 const char* hexes
= "0123456789ABCDEF";
285 function_ptr_luafun
hashstate(lua_func_misc
, "memory.hash_state", [](lua_state
& L
, const std::string
& fname
)
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);
298 #define BLOCKSIZE 256
300 function_ptr_luafun
hashmemory(lua_func_misc
, "memory.hash_region", [](lua_state
& L
, const std::string
& fname
)
304 uint64_t vmabase
= 0;
305 if(L
.type(1) == LUA_TSTRING
) {
306 vmabase
= get_vmabase(L
, L
.get_string(1, fname
.c_str()));
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
];
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
);
320 for(size_t i
= 0; i
< size
; i
++)
321 buffer
[i
] = lsnes_memory
.read
<uint8_t>(addr
+ i
);
322 h
.write(buffer
, size
);
324 L
.pushlstring(hash
.c_str(), 64);
328 function_ptr_luafun
readmemoryr(lua_func_misc
, "memory.readregion", [](lua_state
& L
, const std::string
& fname
)
332 uint64_t vmabase
= 0;
333 if(L
.type(1) == LUA_TSTRING
) {
334 vmabase
= get_vmabase(L
, L
.get_string(1, fname
.c_str()));
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());
340 char buffer
[BLOCKSIZE
];
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
++) {
347 L
.pushnumber(static_cast<unsigned char>(buffer
[i
]));
356 function_ptr_luafun
writememoryr(lua_func_misc
, "memory.writeregion", [](lua_state
& L
,
357 const std::string
& fname
) -> int {
360 uint64_t vmabase
= 0;
361 if(L
.type(1) == LUA_TSTRING
) {
362 vmabase
= get_vmabase(L
, L
.get_string(1, fname
.c_str()));
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
];
370 size_t rsize
= min(size
, static_cast<uint64_t>(BLOCKSIZE
));
371 for(size_t i
= 0; i
< rsize
; i
++) {
374 buffer
[i
] = L
.tointeger(-1);
377 lsnes_memory
.write_range(addr
, buffer
, rsize
);
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
);
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());
397 template<bool write
, bool sign
> int memory_scattergather(lua_state
& L
, const std::string
& fname
)
403 uint64_t vmabase
= 0;
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
++))
412 } else if(L
.type(ptr
) == LUA_TSTRING
) {
413 vmabase
= get_vmabase(L
, L
.get_string(ptr
++, fname
.c_str()));
416 addr
= L
.get_numeric_argument
<uint64_t>(ptr
++, fname
.c_str());
418 lsnes_memory
.write
<uint8_t>(addr
+ vmabase
, val
>> shift
);
420 val
= val
+ ((uint64_t)lsnes_memory
.read
<uint8_t>(addr
+ vmabase
) << shift
);
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
)
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);
495 uint64_t vmabase
= 0;
496 if(L
.type(3) == LUA_TSTRING
) {
497 vmabase
= get_vmabase(L
, L
.get_string(3, fname
.c_str()));
500 uint64_t addr
= L
.get_numeric_argument
<uint64_t>(base
+ 3, fname
.c_str());
501 const char* type
= L
.tostring(base
+ 4);
503 (stringfmt() << fname
<< ": Bad name").throwex();
505 (stringfmt() << fname
<< ": Bad type").throwex();
506 std::string
name2(name
);
507 std::string
type2(type
);
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
);
533 (stringfmt() << fname
<< ": Bad type").throwex();
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
},