1 #include "lua/internal.hpp"
2 #include "lua/debug.hpp"
3 #include "core/memorymanip.hpp"
4 #include "core/memorywatch.hpp"
5 #include "core/moviedata.hpp"
6 #include "core/moviefile.hpp"
7 #include "core/rom.hpp"
8 #include "library/sha256.hpp"
9 #include "library/skein.hpp"
10 #include "library/string.hpp"
11 #include "library/serialization.hpp"
12 #include "library/minmax.hpp"
13 #include "library/int24.hpp"
17 int handle_push_vma(lua::state
& L
, memory_region
& r
)
21 L
.pushlstring(r
.name
.c_str(), r
.name
.size());
23 L
.pushstring("address");
30 L
.pushnumber(r
.last_address());
32 L
.pushstring("readonly");
33 L
.pushboolean(r
.readonly
);
35 L
.pushstring("special");
36 L
.pushboolean(r
.special
);
38 L
.pushstring("endian");
39 L
.pushnumber(r
.endian
);
44 template<typename T
> T
bswap(T val
)
47 serialization::swap_endian(val2
);
54 lua_vma(lua::state
& L
, memory_region
* r
);
55 int info(lua::state
& L
, lua::parameters
& P
);
56 template<class T
, bool _bswap
> int rw(lua::state
& L
, lua::parameters
& P
);
57 template<bool write
, bool sign
> int scattergather(lua::state
& L
, lua::parameters
& P
);
58 template<class T
> int hash(lua::state
& L
, lua::parameters
& P
);
59 template<bool cmp
> int storecmp(lua::state
& L
, lua::parameters
& P
);
60 int readregion(lua::state
& L
, lua::parameters
& P
);
61 int writeregion(lua::state
& L
, lua::parameters
& P
);
62 int cheat(lua::state
& L
, lua::parameters
& P
);
63 template<debug_type type
, bool reg
> int registerX(lua::state
& L
, lua::parameters
& P
);
78 lua_vma_list(lua::state
& L
);
79 static int create(lua::state
& L
, lua::parameters
& P
);
80 int index(lua::state
& L
, lua::parameters
& P
);
81 int newindex(lua::state
& L
, lua::parameters
& P
);
82 int call(lua::state
& L
, lua::parameters
& P
);
91 static sha256
create()
95 static void write(sha256
& h
, void* b
, size_t s
)
97 h
.write(reinterpret_cast<uint8_t*>(b
), s
);
99 static std::string
read(sha256
& h
)
107 static skein::hash
create()
109 return skein::hash(skein::hash::PIPE_512
, 256);
111 static void write(skein::hash
& h
, void* b
, size_t s
)
113 h
.write(reinterpret_cast<uint8_t*>(b
), s
);
115 static std::string
read(skein::hash
& h
)
119 return hex::b_to(buf
, 32);
123 lua::_class
<lua_vma
> class_vma(lua_class_memory
, "VMA", {}, {
124 {"info", &lua_vma::info
},
125 {"read", &lua_vma::scattergather
<false, false>},
126 {"sread", &lua_vma::scattergather
<false, true>},
127 {"write", &lua_vma::scattergather
<true, false>},
128 {"sbyte", &lua_vma::rw
<int8_t, false>},
129 {"byte", &lua_vma::rw
<uint8_t, false>},
130 {"sword", &lua_vma::rw
<int16_t, false>},
131 {"word", &lua_vma::rw
<uint16_t, false>},
132 {"shword", &lua_vma::rw
<ss_int24_t
, false>},
133 {"hword", &lua_vma::rw
<ss_uint24_t
, false>},
134 {"sdword", &lua_vma::rw
<int32_t, false>},
135 {"dword", &lua_vma::rw
<uint32_t, false>},
136 {"sqword", &lua_vma::rw
<int64_t, false>},
137 {"qword", &lua_vma::rw
<uint64_t, false>},
138 {"float", &lua_vma::rw
<float, false>},
139 {"double", &lua_vma::rw
<double, false>},
140 {"isbyte", &lua_vma::rw
<int8_t, true>},
141 {"ibyte", &lua_vma::rw
<uint8_t, true>},
142 {"isword", &lua_vma::rw
<int16_t, true>},
143 {"iword", &lua_vma::rw
<uint16_t, true>},
144 {"ishword", &lua_vma::rw
<ss_int24_t
, true>},
145 {"ihword", &lua_vma::rw
<ss_uint24_t
, true>},
146 {"isdword", &lua_vma::rw
<int32_t, true>},
147 {"idword", &lua_vma::rw
<uint32_t, true>},
148 {"isqword", &lua_vma::rw
<int64_t, true>},
149 {"iqword", &lua_vma::rw
<uint64_t, true>},
150 {"ifloat", &lua_vma::rw
<float, true>},
151 {"idouble", &lua_vma::rw
<double, true>},
152 {"cheat", &lua_vma::cheat
},
153 {"sha256", &lua_vma::hash
<l_sha256_h
>},
154 {"skein", &lua_vma::hash
<l_skein_h
>},
155 {"store", &lua_vma::storecmp
<false>},
156 {"storecmp", &lua_vma::storecmp
<true>},
157 {"readregion", &lua_vma::readregion
},
158 {"writeregion", &lua_vma::writeregion
},
159 {"registerread", &lua_vma::registerX
<DEBUG_READ
, true>},
160 {"unregisterread", &lua_vma::registerX
<DEBUG_READ
, false>},
161 {"registerwrite", &lua_vma::registerX
<DEBUG_WRITE
, true>},
162 {"unregisterwrite", &lua_vma::registerX
<DEBUG_WRITE
, false>},
163 {"registerexec", &lua_vma::registerX
<DEBUG_EXEC
, true>},
164 {"unregisterexec", &lua_vma::registerX
<DEBUG_EXEC
, false>},
167 lua::_class
<lua_vma_list
> class_vmalist(lua_class_memory
, "VMALIST", {
168 {"new", lua_vma_list::create
},
170 {"__index", &lua_vma_list::index
},
171 {"__newindex", &lua_vma_list::newindex
},
172 {"__call", &lua_vma_list::call
},
175 lua_vma::lua_vma(lua::state
& L
, memory_region
* r
)
183 int lua_vma::info(lua::state
& L
, lua::parameters
& P
)
185 for(auto i
: lsnes_memory
.get_regions())
187 return handle_push_vma(L
, *i
);
188 (stringfmt() << P
.get_fname() << ": Stale region").throwex();
191 template<class T
, bool _bswap
> int lua_vma::rw(lua::state
& L
, lua::parameters
& P
)
196 P(P
.skipped(), addr
);
198 if(addr
> vmasize
|| addr
> vmasize
- sizeof(T
))
199 throw std::runtime_error("VMA::rw<T>: Address outside VMA bounds");
202 T val
= lsnes_memory
.read
<T
>(addr
+ vmabase
);
203 if(_bswap
) val
= bswap(val
);
206 } else if(P
.is_number()) {
209 (stringfmt() << P
.get_fname() << ": VMA is read-only").throwex();
211 if(_bswap
) val
= bswap(val
);
212 lsnes_memory
.write
<T
>(addr
+ vmabase
, val
);
215 P
.expected("number or nil");
218 template<bool write
, bool sign
> int lua_vma::scattergather(lua::state
& L
, lua::parameters
& P
)
228 while(!P
.is_novalue()) {
235 addr
= P
.arg
<uint64_t>();
237 lsnes_memory
.write
<uint8_t>(addr
+ vmabase
, val
>> shift
);
239 val
= val
+ ((uint64_t)lsnes_memory
.read
<uint8_t>(addr
+ vmabase
) << shift
);
244 if(val
>= (1ULL << (shift
- 1))) sval
-= (1ULL << shift
);
245 if(sign
) L
.pushnumber(sval
); else L
.pushnumber(val
);
247 return write
? 0 : 1;
250 template<class T
> int lua_vma::hash(lua::state
& L
, lua::parameters
& P
)
252 uint64_t addr
, size
, rows
, stride
= 0;
255 P(P
.skipped(), addr
, size
, P
.optional(rows
, 1));
256 if(rows
> 1) P(stride
);
258 //First verify that all reads are to the region.
260 if(size
> vmasize
&& rows
)
261 throw std::runtime_error("Region out of range");
262 for(uint64_t i
= 0; i
< rows
; i
++) {
263 if(tmp
>= vmasize
|| tmp
+ size
> vmasize
)
264 throw std::runtime_error("Region out of range");
268 auto hstate
= T::create();
269 //Try to map the VMA.
270 char* vmabuf
= lsnes_memory
.get_physical_mapping(vmabase
, vmasize
);
272 for(uint64_t i
= 0; i
< rows
; i
++) {
273 T::write(hstate
, vmabuf
+ addr
, size
);
277 uint8_t buf
[512]; //Must be power of 2.
279 for(uint64_t i
= 0; i
< rows
; i
++) {
280 for(uint64_t j
= 0; j
< size
; j
++) {
281 buf
[bf
] = lsnes_memory
.read
<uint8_t>(vmabase
+ addr
+ j
);
282 bf
= (bf
+ 1) & (sizeof(buf
) - 1);
284 T::write(hstate
, buf
, sizeof(buf
));
289 T::write(hstate
, buf
, bf
);
291 L
.pushlstring(T::read(hstate
));
295 int lua_vma::readregion(lua::state
& L
, lua::parameters
& P
)
299 P(P
.skipped(), addr
, size
);
301 if(addr
>= vmasize
|| size
> vmasize
|| addr
+ size
> vmasize
)
302 throw std::runtime_error("Read out of range");
305 char* vmabuf
= lsnes_memory
.get_physical_mapping(vmabase
, vmasize
);
308 for(size_t i
= 0; i
< size
; i
++) {
310 L
.pushnumber(static_cast<unsigned char>(vmabuf
[addr
+ i
]));
315 for(size_t i
= 0; i
< size
; i
++) {
317 L
.pushnumber(lsnes_memory
.read
<uint8_t>(addr
+ i
));
324 int lua_vma::writeregion(lua::state
& L
, lua::parameters
& P
)
329 P(P
.skipped(), addr
, P
.table(ltbl
));
331 auto g
= lsnes_memory
.lookup(vmabase
);
332 if(!g
.first
|| g
.first
->readonly
)
333 throw std::runtime_error("Memory address is read-only");
335 throw std::runtime_error("Write out of range");
338 char* vmabuf
= lsnes_memory
.get_physical_mapping(vmabase
, vmasize
);
340 for(size_t i
= 0;; i
++) {
343 if(L
.type(-1) == LUA_TNIL
)
345 if(addr
+ i
>= vmasize
)
346 throw std::runtime_error("Write out of range");
347 vmabuf
[addr
+ i
] = L
.tointeger(-1);
351 for(size_t i
= 0;; i
++) {
354 if(L
.type(-1) == LUA_TNIL
)
356 if(addr
+ i
>= vmasize
)
357 throw std::runtime_error("Write out of range");
358 lsnes_memory
.write
<uint8_t>(vmabase
+ addr
+ i
, L
.tointeger(-1));
364 template<bool cmp
> int lua_vma::storecmp(lua::state
& L
, lua::parameters
& P
)
366 uint64_t addr
, daddr
, size
, rows
, stride
= 0;
369 P(P
.skipped(), addr
, daddr
, size
, P
.optional(rows
, 1));
370 if(rows
> 1) P(stride
);
372 //First verify that all reads are to the region.
374 if(size
> vmasize
&& rows
)
375 throw std::runtime_error("Source out of range");
376 for(uint64_t i
= 0; i
< rows
; i
++) {
377 if(tmp
>= vmasize
|| tmp
+ size
> vmasize
)
378 throw std::runtime_error("Source out of range");
381 //Calculate new size of target.
382 auto& h
= movb
.get_mfile().host_memory
;
383 size_t rsize
= size
* rows
;
384 if(size
&& rsize
/ size
!= rows
)
385 throw std::runtime_error("Copy size out of range");
386 if((size_t)daddr
+ rsize
< rsize
)
387 throw std::runtime_error("Target out of range");
388 if(daddr
+ rsize
> h
.size()) {
389 h
.resize(daddr
+ rsize
);
393 //Try to map the VMA.
394 char* vmabuf
= lsnes_memory
.get_physical_mapping(vmabase
, vmasize
);
396 for(uint64_t i
= 0; i
< rows
; i
++) {
397 bool eq
= (cmp
&& !memcmp(&h
[daddr
], vmabuf
+ addr
, size
));
399 memcpy(&h
[daddr
], vmabuf
+ addr
, size
);
405 for(uint64_t i
= 0; i
< rows
; i
++) {
406 for(uint64_t j
= 0; j
< size
; j
++) {
407 uint8_t byte
= lsnes_memory
.read
<uint8_t>(vmabase
+ addr
+ j
);
408 bool eq
= (cmp
&& ((uint8_t)h
[daddr
+ j
] == byte
));
416 if(cmp
) L
.pushboolean(equals
);
420 template<debug_type type
, bool reg
> int lua_vma::registerX(lua::state
& L
, lua::parameters
& P
)
424 P(P
.skipped(), addr
, P
.function(lfn
));
427 handle_registerX
<type
>(L
, vmabase
+ addr
, lfn
);
431 handle_unregisterX
<type
>(L
, vmabase
+ addr
, lfn
);
436 int lua_vma::cheat(lua::state
& L
, lua::parameters
& P
)
438 uint64_t addr
, value
;
440 P(P
.skipped(), addr
);
442 throw std::runtime_error("Address out of range");
444 debug_clear_cheat(vmabase
+ addr
);
447 debug_set_cheat(vmabase
+ addr
, value
);
452 lua_vma_list::lua_vma_list(lua::state
& L
)
456 int lua_vma_list::create(lua::state
& L
, lua::parameters
& P
)
458 lua::_class
<lua_vma_list
>::create(L
);
462 int lua_vma_list::call(lua::state
& L
, lua::parameters
& P
)
466 for(auto i
: lsnes_memory
.get_regions()) {
468 L
.pushlstring(i
->name
);
474 int lua_vma_list::index(lua::state
& L
, lua::parameters
& P
)
480 auto l
= lsnes_memory
.get_regions();
482 std::list
<memory_region
*>::iterator i
;
483 for(i
= l
.begin(), j
= 0; i
!= l
.end(); i
++, j
++)
484 if((*i
)->name
== vma
) {
485 lua::_class
<lua_vma
>::create(L
, *i
);
488 (stringfmt() << P
.get_fname() << ": No such VMA").throwex();
491 int lua_vma_list::newindex(lua::state
& L
, lua::parameters
& P
)
493 throw std::runtime_error("Writing is not allowed");