summaryrefslogtreecommitdiffstats
path: root/src/frontend/mame/luaengine_mem.cpp
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2022-02-10 02:06:42 +1100
committer Vas Crabb <vas@vastheman.com>2022-02-10 02:06:42 +1100
commite1a6a41234684ad5244605d417356d2c6c22ca61 (patch)
tree58f21eb2be70682b25fd4a455bf4b660157a0ee7 /src/frontend/mame/luaengine_mem.cpp
parent53bfaabe4ccfed1626e8dba3de7a95699105cf24 (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.cpp342
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);