diff options
author | 2022-02-10 02:06:42 +1100 | |
---|---|---|
committer | 2022-02-10 02:06:42 +1100 | |
commit | e1a6a41234684ad5244605d417356d2c6c22ca61 (patch) | |
tree | 58f21eb2be70682b25fd4a455bf4b660157a0ee7 /src/frontend/mame/luaengine_mem.cpp | |
parent | 53bfaabe4ccfed1626e8dba3de7a95699105cf24 (diff) |
frontend: Exposed memory pass-through handlers (address space taps) to Lua.
Diffstat (limited to 'src/frontend/mame/luaengine_mem.cpp')
-rw-r--r-- | src/frontend/mame/luaengine_mem.cpp | 342 |
1 files changed, 291 insertions, 51 deletions
diff --git a/src/frontend/mame/luaengine_mem.cpp b/src/frontend/mame/luaengine_mem.cpp index f95ebdb37c2..26518931e9e 100644 --- a/src/frontend/mame/luaengine_mem.cpp +++ b/src/frontend/mame/luaengine_mem.cpp @@ -184,6 +184,220 @@ int sol_lua_push(sol::types<endianness_t>, lua_State *L, endianness_t &&value) //------------------------------------------------- +// tap_helper - class for managing address space +// taps +//------------------------------------------------- + +class lua_engine::tap_helper +{ +public: + tap_helper(tap_helper const &) = delete; + tap_helper(tap_helper &&) = delete; + + tap_helper( + lua_engine &engine, + address_space &space, + read_or_write mode, + offs_t start, + offs_t end, + std::string &&name, + sol::protected_function &&callback) + : m_callback(std::move(callback)) + , m_engine(engine) + , m_space(space) + , m_handler(nullptr) + , m_name(std::move(name)) + , m_start(start) + , m_end(end) + , m_mode(mode) + , m_installing(false) + , m_installed(false) + { + reinstall(); + } + + ~tap_helper() + { + if (m_handler && m_installed) + m_handler->remove(); + } + + offs_t start() const noexcept { return m_start; } + offs_t end() const noexcept { return m_end; } + std::string const &name() const noexcept { return m_name; } + + void reinstall() + { + switch (m_space.data_width()) + { + case 8: do_install<u8>(); break; + case 16: do_install<u16>(); break; + case 32: do_install<u32>(); break; + case 64: do_install<u64>(); break; + } + } + + void remove() + { + if (m_handler) + { + m_handler->remove(); + m_installed = false; + } + } + +private: + template <typename T> + void do_install() + { + if (m_installing) + return; + m_installing = true; + if (m_handler) + m_handler->remove(); + + switch (m_mode) + { + case read_or_write::READ: + m_handler = m_space.install_read_tap( + m_start, + m_end, + m_name, + [this] (offs_t offset, T &data, T mem_mask) + { + auto result = m_engine.invoke(m_callback, offset, data, mem_mask).template get<sol::optional<T> >(); + if (result) + data = *result; + }, + m_handler); + break; + case read_or_write::WRITE: + m_handler = m_space.install_write_tap( + m_start, + m_end, + m_name, + [this] (offs_t offset, T &data, T mem_mask) + { + auto result = m_engine.invoke(m_callback, offset, data, mem_mask).template get<sol::optional<T> >(); + if (result) + data = *result; + }, + m_handler); + break; + case read_or_write::READWRITE: + // won't ever get here, but compilers complain about unhandled enum value + break; + } + + m_installed = true; + m_installing = false; + }; + + sol::protected_function m_callback; + lua_engine &m_engine; + address_space &m_space; + memory_passthrough_handler *m_handler; + std::string m_name; + offs_t const m_start; + offs_t const m_end; + read_or_write const m_mode; + bool m_installing; + bool m_installed; +}; + + +//------------------------------------------------- +// addr_space_change_notif - helper for hanging +// on to an address space change notification +// subscription +//------------------------------------------------- + +class lua_engine::addr_space_change_notif +{ +public: + addr_space_change_notif(addr_space_change_notif const &) = delete; + + addr_space_change_notif(addr_space_change_notif &&that) + : m_callback(std::move(that.m_callback)) + , m_engine(that.m_engine) + , m_space(that.m_space) + , m_id(-1) + { + that.remove(); + install(); + } + + addr_space_change_notif &operator=(addr_space_change_notif &&that) + { + if (&that != this) + { + remove(); + m_callback = std::move(that.m_callback); + m_engine = that.m_engine; + m_space = that.m_space; + that.remove(); + install(); + } + return *this; + } + + addr_space_change_notif(lua_engine &engine, address_space &space, sol::protected_function &&callback) + : m_callback(std::move(callback)) + , m_engine(&engine) + , m_space(&space) + , m_id(-1) + { + install(); + } + + ~addr_space_change_notif() + { + if (m_space) + m_space->remove_change_notifier(m_id); + } + + void remove() + { + if (m_space) + { + m_space->remove_change_notifier(m_id); + m_space = nullptr; + m_id = -1; + } + } + +private: + void install() + { + if (m_space) + { + m_id = m_space->add_change_notifier( + [this] (read_or_write mode) + { + char const *modestr = ""; + switch (mode) + { + case read_or_write::READ: modestr = "r"; break; + case read_or_write::WRITE: modestr = "w"; break; + case read_or_write::READWRITE: modestr = "rw"; break; + } + m_engine->invoke(m_callback, modestr); + }); + } + else + { + m_id = -1; + } + } + + sol::protected_function m_callback; + lua_engine *m_engine; + address_space *m_space; + int m_id; +}; + + +//------------------------------------------------- // mem_read - templated memory readers for <sign>,<size> // -> manager:machine().devices[":maincpu"].spaces["program"]:read_i8(0xC000) //------------------------------------------------- @@ -449,64 +663,79 @@ void lua_engine::initialize_memory(sol::table &emu) addr_space_type["write_direct_i64"] = &addr_space::direct_mem_write<s64>; addr_space_type["write_direct_u64"] = &addr_space::direct_mem_write<u64>; addr_space_type["read_range"] = - [] (addr_space &sp, sol::this_state s, u64 first, u64 last, int width, sol::object opt_step) -> sol::object - { - lua_State *L = s; - luaL_Buffer buff; - offs_t space_size = sp.space.addrmask(); - u64 step = 1; - if (opt_step.is<u64>()) - { - step = opt_step.as<u64>(); - if (step < 1 || step > last - first) - { - luaL_error(L, "Invalid step"); - return sol::lua_nil; - } - } - if (first > space_size || last > space_size || last < first) + [] (addr_space &sp, sol::this_state s, u64 first, u64 last, int width, sol::object opt_step) -> sol::object { - luaL_error(L, "Invalid offset"); - return sol::lua_nil; - } - int byte_count = width / 8 * (last - first + 1) / step; - switch (width) - { - case 8: + lua_State *L = s; + luaL_Buffer buff; + offs_t space_size = sp.space.addrmask(); + u64 step = 1; + if (opt_step.is<u64>()) { - u8 *dest = (u8 *)luaL_buffinitsize(L, &buff, byte_count); - for ( ; first <= last; first += step) - *dest++ = sp.mem_read<u8>(first); - break; + step = opt_step.as<u64>(); + if (step < 1 || step > last - first) + { + luaL_error(L, "Invalid step"); + return sol::lua_nil; + } } - case 16: + if (first > space_size || last > space_size || last < first) { - u16 *dest = (u16 *)luaL_buffinitsize(L, &buff, byte_count); - for ( ; first <= last; first += step) - *dest++ = sp.mem_read<u16>(first); - break; - } - case 32: - { - u32 *dest = (u32 *)luaL_buffinitsize(L, &buff, byte_count); - for(; first <= last; first += step) - *dest++ = sp.mem_read<u32>(first); - break; + luaL_error(L, "Invalid offset"); + return sol::lua_nil; } - case 64: + int byte_count = width / 8 * (last - first + 1) / step; + switch (width) { - u64 *dest = (u64 *)luaL_buffinitsize(L, &buff, byte_count); - for(; first <= last; first += step) - *dest++ = sp.mem_read<u64>(first); - break; + case 8: + { + u8 *dest = (u8 *)luaL_buffinitsize(L, &buff, byte_count); + for ( ; first <= last; first += step) + *dest++ = sp.mem_read<u8>(first); + break; + } + case 16: + { + u16 *dest = (u16 *)luaL_buffinitsize(L, &buff, byte_count); + for ( ; first <= last; first += step) + *dest++ = sp.mem_read<u16>(first); + break; + } + case 32: + { + u32 *dest = (u32 *)luaL_buffinitsize(L, &buff, byte_count); + for( ; first <= last; first += step) + *dest++ = sp.mem_read<u32>(first); + break; + } + case 64: + { + u64 *dest = (u64 *)luaL_buffinitsize(L, &buff, byte_count); + for( ; first <= last; first += step) + *dest++ = sp.mem_read<u64>(first); + break; + } + default: + luaL_error(L, "Invalid width. Must be 8/16/32/64"); + return sol::lua_nil; } - default: - luaL_error(L, "Invalid width. Must be 8/16/32/64"); - return sol::lua_nil; - } - luaL_pushresultsize(&buff, byte_count); - return sol::make_reference(L, sol::stack_reference(L, -1)); - }; + luaL_pushresultsize(&buff, byte_count); + return sol::make_reference(L, sol::stack_reference(L, -1)); + }; + addr_space_type["add_change_notifier"] = + [this] (addr_space &sp, sol::protected_function &&cb) + { + return addr_space_change_notif(*this, sp.space, std::move(cb)); + }; + addr_space_type["install_read_tap"] = + [this] (addr_space &sp, offs_t start, offs_t end, std::string &&name, sol::protected_function &&cb) + { + return std::make_unique<tap_helper>(*this, sp.space, read_or_write::READ, start, end, std::move(name), std::move(cb)); + }; + addr_space_type["install_write_tap"] = + [this] (addr_space &sp, offs_t start, offs_t end, std::string &&name, sol::protected_function &&cb) + { + return std::make_unique<tap_helper>(*this, sp.space, read_or_write::WRITE, start, end, std::move(name), std::move(cb)); + }; addr_space_type["name"] = sol::property([] (addr_space &sp) { return sp.space.name(); }); addr_space_type["shift"] = sol::property([] (addr_space &sp) { return sp.space.addr_shift(); }); addr_space_type["index"] = sol::property([] (addr_space &sp) { return sp.space.spacenum(); }); @@ -516,6 +745,17 @@ void lua_engine::initialize_memory(sol::table &emu) addr_space_type["map"] = sol::property([] (addr_space &sp) { return sp.space.map(); }); + auto change_notif_type = sol().registry().new_usertype<addr_space_change_notif>("addr_space_change", sol::no_constructor); + change_notif_type["remove"] = &addr_space_change_notif::remove; + + auto tap_type = sol().registry().new_usertype<tap_helper>("mempassthrough", sol::no_constructor); + tap_type["reinstall"] = &tap_helper::reinstall; + tap_type["remove"] = &tap_helper::remove; + tap_type["addrstart"] = sol::property(&tap_helper::start); + tap_type["addrend"] = sol::property(&tap_helper::end); + tap_type["name"] = sol::property(&tap_helper::name); + + auto addrmap_type = sol().registry().new_usertype<address_map>("addrmap", sol::no_constructor); addrmap_type["spacenum"] = sol::readonly(&address_map::m_spacenum); addrmap_type["device"] = sol::readonly(&address_map::m_device); |