Refactor some generic reading/writing routines out of moviefile.cpp
[lsnes.git] / src / lua / memory2.cpp
blob47a6cb5338bd028b1e9e9c3208b536069e44e074
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/serialization.hpp"
10 #include "library/minmax.hpp"
11 #include "library/int24.hpp"
13 namespace
15 int handle_push_vma(lua::state& L, memory_region& r)
17 L.newtable();
18 L.pushstring("name");
19 L.pushlstring(r.name.c_str(), r.name.size());
20 L.settable(-3);
21 L.pushstring("address");
22 L.pushnumber(r.base);
23 L.settable(-3);
24 L.pushstring("size");
25 L.pushnumber(r.size);
26 L.settable(-3);
27 L.pushstring("last");
28 L.pushnumber(r.last_address());
29 L.settable(-3);
30 L.pushstring("readonly");
31 L.pushboolean(r.readonly);
32 L.settable(-3);
33 L.pushstring("special");
34 L.pushboolean(r.special);
35 L.settable(-3);
36 L.pushstring("endian");
37 L.pushnumber(r.endian);
38 L.settable(-3);
39 return 1;
42 template<typename T> T bswap(T val)
44 T val2 = val;
45 serialization::swap_endian(val2);
46 return val2;
49 class lua_vma
51 public:
52 lua_vma(lua::state& L, memory_region* r);
53 int info(lua::state& L, lua::parameters& P);
54 template<class T, bool _bswap> int rw(lua::state& L, lua::parameters& P);
55 template<bool write, bool sign> int scattergather(lua::state& L, lua::parameters& P);
56 std::string print()
58 return vma;
60 private:
61 std::string vma;
62 uint64_t vmabase;
63 uint64_t vmasize;
64 bool ro;
67 class lua_vma_list
69 public:
70 lua_vma_list(lua::state& L);
71 static int create(lua::state& L, lua::parameters& P);
72 int index(lua::state& L, lua::parameters& P);
73 int newindex(lua::state& L, lua::parameters& P);
74 int call(lua::state& L, lua::parameters& P);
75 std::string print()
77 return "";
81 lua::_class<lua_vma> class_vma(lua_class_memory, "VMA", {}, {
82 {"info", &lua_vma::info},
83 {"read", &lua_vma::scattergather<false, false>},
84 {"sread", &lua_vma::scattergather<false, true>},
85 {"write", &lua_vma::scattergather<true, false>},
86 {"sbyte", &lua_vma::rw<int8_t, false>},
87 {"byte", &lua_vma::rw<uint8_t, false>},
88 {"sword", &lua_vma::rw<int16_t, false>},
89 {"word", &lua_vma::rw<uint16_t, false>},
90 {"shword", &lua_vma::rw<ss_int24_t, false>},
91 {"hword", &lua_vma::rw<ss_uint24_t, false>},
92 {"sdword", &lua_vma::rw<int32_t, false>},
93 {"dword", &lua_vma::rw<uint32_t, false>},
94 {"sqword", &lua_vma::rw<int64_t, false>},
95 {"qword", &lua_vma::rw<uint64_t, false>},
96 {"float", &lua_vma::rw<float, false>},
97 {"double", &lua_vma::rw<double, false>},
98 {"isbyte", &lua_vma::rw<int8_t, true>},
99 {"ibyte", &lua_vma::rw<uint8_t, true>},
100 {"isword", &lua_vma::rw<int16_t, true>},
101 {"iword", &lua_vma::rw<uint16_t, true>},
102 {"ishword", &lua_vma::rw<ss_int24_t, true>},
103 {"ihword", &lua_vma::rw<ss_uint24_t, true>},
104 {"isdword", &lua_vma::rw<int32_t, true>},
105 {"idword", &lua_vma::rw<uint32_t, true>},
106 {"isqword", &lua_vma::rw<int64_t, true>},
107 {"iqword", &lua_vma::rw<uint64_t, true>},
108 {"ifloat", &lua_vma::rw<float, true>},
109 {"idouble", &lua_vma::rw<double, true>},
110 }, &lua_vma::print);
112 lua::_class<lua_vma_list> class_vmalist(lua_class_memory, "VMALIST", {
113 {"new", lua_vma_list::create},
114 }, {
115 {"__index", &lua_vma_list::index},
116 {"__newindex", &lua_vma_list::newindex},
117 {"__call", &lua_vma_list::call},
120 lua_vma::lua_vma(lua::state& L, memory_region* r)
122 vmabase = r->base;
123 vmasize = r->size;
124 vma = r->name;
125 ro = r->readonly;
128 int lua_vma::info(lua::state& L, lua::parameters& P)
130 for(auto i : lsnes_memory.get_regions())
131 if(i->name == vma)
132 return handle_push_vma(L, *i);
133 (stringfmt() << P.get_fname() << ": Stale region").throwex();
136 template<class T, bool _bswap> int lua_vma::rw(lua::state& L, lua::parameters& P)
138 uint64_t addr;
139 T val;
141 P(P.skipped(), addr);
143 if(addr > vmasize || addr > vmasize - sizeof(T))
144 throw std::runtime_error("VMA::rw<T>: Address outside VMA bounds");
145 if(P.is_novalue()) {
146 //Read.
147 T val = lsnes_memory.read<T>(addr + vmabase);
148 if(_bswap) val = bswap(val);
149 L.pushnumber(val);
150 return 1;
151 } else if(P.is_number()) {
152 //Write.
153 if(ro)
154 (stringfmt() << P.get_fname() << ": VMA is read-only").throwex();
155 P(val);
156 if(_bswap) val = bswap(val);
157 lsnes_memory.write<T>(addr + vmabase, val);
158 return 0;
159 } else
160 P.expected("number or nil");
163 template<bool write, bool sign> int lua_vma::scattergather(lua::state& L, lua::parameters& P)
165 uint64_t val = 0;
166 unsigned shift = 0;
167 uint64_t addr = 0;
169 P(P.skipped());
170 if(write)
171 P(val);
173 while(!P.is_novalue()) {
174 if(P.is_boolean()) {
175 if(P.arg<bool>())
176 addr++;
177 else
178 addr--;
179 } else
180 addr = P.arg<uint64_t>();
181 if(write)
182 lsnes_memory.write<uint8_t>(addr + vmabase, val >> shift);
183 else
184 val = val + ((uint64_t)lsnes_memory.read<uint8_t>(addr + vmabase) << shift);
185 shift += 8;
187 if(!write) {
188 int64_t sval = val;
189 if(val >= (1ULL << (shift - 1))) sval -= (1ULL << shift);
190 if(sign) L.pushnumber(sval); else L.pushnumber(val);
192 return write ? 0 : 1;
195 lua_vma_list::lua_vma_list(lua::state& L)
199 int lua_vma_list::create(lua::state& L, lua::parameters& P)
201 lua::_class<lua_vma_list>::create(L);
202 return 1;
205 int lua_vma_list::call(lua::state& L, lua::parameters& P)
207 L.newtable();
208 size_t key = 1;
209 for(auto i : lsnes_memory.get_regions()) {
210 L.pushnumber(key++);
211 L.pushlstring(i->name);
212 L.rawset(-3);
214 return 1;
217 int lua_vma_list::index(lua::state& L, lua::parameters& P)
219 std::string vma;
221 P(P.skipped(), vma);
223 auto l = lsnes_memory.get_regions();
224 size_t j;
225 std::list<memory_region*>::iterator i;
226 for(i = l.begin(), j = 0; i != l.end(); i++, j++)
227 if((*i)->name == vma) {
228 lua::_class<lua_vma>::create(L, *i);
229 return 1;
231 (stringfmt() << P.get_fname() << ": No such VMA").throwex();
234 int lua_vma_list::newindex(lua::state& L, lua::parameters& P)
236 throw std::runtime_error("Writing is not allowed");