Get rid of DECLARE_LUACLASS
[lsnes.git] / src / lua / memory2.cpp
blob6330a9baaab11a631623adf5b2a386f075bcec63
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, const std::string& fname);
54 template<class T, bool _bswap> int rw(lua_state& L, const std::string& fname);
55 template<bool write, bool sign> int scattergather(lua_state& L, const std::string& fname);
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 int index(lua_state& L, const std::string& fname);
72 int newindex(lua_state& L, const std::string& fname);
73 int call(lua_state& L, const std::string& fname);
74 std::string print()
76 return "";
80 lua_class<lua_vma> class_vma("VMA");
81 lua_class<lua_vma_list> class_vmalist("VMALIST");
83 lua_vma::lua_vma(lua_state& L, memory_region* r)
85 objclass<lua_vma>().bind_multi(L, {
86 {"info", &lua_vma::info},
87 {"read", &lua_vma::scattergather<false, false>},
88 {"sread", &lua_vma::scattergather<false, true>},
89 {"write", &lua_vma::scattergather<true, false>},
90 {"sbyte", &lua_vma::rw<int8_t, false>},
91 {"byte", &lua_vma::rw<uint8_t, false>},
92 {"sword", &lua_vma::rw<int16_t, false>},
93 {"word", &lua_vma::rw<uint16_t, false>},
94 {"shword", &lua_vma::rw<ss_int24_t, false>},
95 {"hword", &lua_vma::rw<ss_uint24_t, false>},
96 {"sdword", &lua_vma::rw<int32_t, false>},
97 {"dword", &lua_vma::rw<uint32_t, false>},
98 {"sqword", &lua_vma::rw<int64_t, false>},
99 {"qword", &lua_vma::rw<uint64_t, false>},
100 {"float", &lua_vma::rw<float, false>},
101 {"double", &lua_vma::rw<double, false>},
102 {"isbyte", &lua_vma::rw<int8_t, true>},
103 {"ibyte", &lua_vma::rw<uint8_t, true>},
104 {"isword", &lua_vma::rw<int16_t, true>},
105 {"iword", &lua_vma::rw<uint16_t, true>},
106 {"ishword", &lua_vma::rw<ss_int24_t, true>},
107 {"ihword", &lua_vma::rw<ss_uint24_t, true>},
108 {"isdword", &lua_vma::rw<int32_t, true>},
109 {"idword", &lua_vma::rw<uint32_t, true>},
110 {"isqword", &lua_vma::rw<int64_t, true>},
111 {"iqword", &lua_vma::rw<uint64_t, true>},
112 {"ifloat", &lua_vma::rw<float, true>},
113 {"idouble", &lua_vma::rw<double, true>},
115 vmabase = r->base;
116 vmasize = r->size;
117 vma = r->name;
118 ro = r->readonly;
121 int lua_vma::info(lua_state& L, const std::string& fname)
123 for(auto i : lsnes_memory.get_regions())
124 if(i->name == vma)
125 return handle_push_vma(L, *i);
126 (stringfmt() << fname << ": Stale region").throwex();
129 template<class T, bool _bswap> int lua_vma::rw(lua_state& L, const std::string& fname)
131 uint64_t addr = L.get_numeric_argument<uint64_t>(2, fname.c_str());
132 if(addr > vmasize || addr > vmasize - sizeof(T))
133 throw std::runtime_error("VMA::rw<T>: Address outside VMA bounds");
134 if(L.type(3) == LUA_TNIL || L.type(3) == LUA_TNONE) {
135 //Read.
136 T val = lsnes_memory.read<T>(addr + vmabase);
137 if(_bswap) val = bswap(val);
138 L.pushnumber(val);
139 return 1;
140 } else if(L.type(3) == LUA_TNUMBER) {
141 //Write.
142 if(ro)
143 (stringfmt() << fname << ": VMA is read-only").throwex();
144 T val = L.get_numeric_argument<T>(3, "VMA::rw<T>");
145 if(_bswap) val = bswap(val);
146 lsnes_memory.write<T>(addr + vmabase, val);
147 return 0;
148 } else
149 (stringfmt() << fname << ": Parameter #3 must be integer if present").throwex();
152 template<bool write, bool sign> int lua_vma::scattergather(lua_state& L, const std::string& fname)
154 uint64_t val = 0;
155 int ptr = 2;
156 unsigned shift = 0;
157 uint64_t addr = 0;
158 if(write)
159 val = L.get_numeric_argument<uint64_t>(ptr++, fname.c_str());
160 while(L.type(ptr) != LUA_TNIL && L.type(ptr) != LUA_TNONE) {
161 if(L.type(ptr) == LUA_TBOOLEAN) {
162 if(L.toboolean(ptr++))
163 addr++;
164 else
165 addr--;
166 } else
167 addr = L.get_numeric_argument<uint64_t>(ptr++, fname.c_str());
168 if(write)
169 lsnes_memory.write<uint8_t>(addr + vmabase, val >> shift);
170 else
171 val = val + ((uint64_t)lsnes_memory.read<uint8_t>(addr + vmabase) << shift);
172 shift += 8;
174 if(!write) {
175 int64_t sval = val;
176 if(val >= (1ULL << (shift - 1))) sval -= (1ULL << shift);
177 if(sign) L.pushnumber(sval); else L.pushnumber(val);
179 return write ? 0 : 1;
182 lua_vma_list::lua_vma_list(lua_state& L)
184 objclass<lua_vma_list>().bind_multi(L, {
185 {"__index", &lua_vma_list::index},
186 {"__newindex", &lua_vma_list::newindex},
187 {"__call", &lua_vma_list::call},
191 int lua_vma_list::call(lua_state& L, const std::string& fname)
193 L.newtable();
194 size_t key = 1;
195 for(auto i : lsnes_memory.get_regions()) {
196 L.pushnumber(key++);
197 L.pushlstring(i->name);
198 L.rawset(-3);
200 return 1;
203 int lua_vma_list::index(lua_state& L, const std::string& fname)
205 std::string vma = L.get_string(2, fname.c_str());
206 auto l = lsnes_memory.get_regions();
207 size_t j;
208 std::list<memory_region*>::iterator i;
209 for(i = l.begin(), j = 0; i != l.end(); i++, j++)
210 if((*i)->name == vma) {
211 lua_class<lua_vma>::create(L, *i);
212 return 1;
214 (stringfmt() << fname << ": No such VMA").throwex();
217 int lua_vma_list::newindex(lua_state& L, const std::string& fname)
219 throw std::runtime_error("Writing is not allowed");
222 function_ptr_luafun memory2(lua_func_misc, "memory2", [](lua_state& L, const std::string& fname) ->
223 int {
224 lua_class<lua_vma_list>::create(L);
225 return 1;