summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--docs/source/techspecs/luareference.rst45
-rw-r--r--src/emu/distate.h6
-rw-r--r--src/frontend/mame/luaengine.cpp127
-rw-r--r--src/frontend/mame/luaengine.ipp15
4 files changed, 142 insertions, 51 deletions
diff --git a/docs/source/techspecs/luareference.rst b/docs/source/techspecs/luareference.rst
index 28ee0c08c75..4c3c5098004 100644
--- a/docs/source/techspecs/luareference.rst
+++ b/docs/source/techspecs/luareference.rst
@@ -852,6 +852,11 @@ device.debug (read-only)
The :ref:`debugger interface <luareference-debug-devdebug>` to the device if
it is a CPU device, or ``nil`` if it is not a CPU device or the debugger is
not enabled.
+device.state[] (read-only)
+ The :ref:`state entries <luareference-dev-stateentry>` for devices that
+ expose the register state interface, indexed by symbol, or ``nil`` for other
+ devices. The index operator and ``index_of`` methods have O(n) complexity;
+ all other supported operations have O(1) complexity.
device.spaces[] (read-only)
A table of the device’s :ref:`address spaces <luareference-mem-space>`,
indexed by name. Only valid for devices that implement the memory
@@ -1311,6 +1316,46 @@ slot.options[] (read-only)
slot.device (read-only)
The underlying :ref:`device <luareference-dev-device>`.
+.. _luareference-dev-stateentry:
+
+Device state entry
+~~~~~~~~~~~~~~~~~~
+
+Wraps MAME’s ``device_state_entry`` class, which allows access to named
+registers exposed by a :ref:`device <luareference-dev-device>`. Supports
+conversion to string for display.
+
+Instantiation
+^^^^^^^^^^^^^
+
+manager.machine.devices[tag].state[symbol]
+ Gets a state entry for a given device by symbol.
+
+Properties
+^^^^^^^^^^
+
+entry.value (read/write)
+ The numeric value of the state entry, as either an integer or floating-point
+ number. Attempting to set the value of a read-only state entry raises an
+ error.
+entry.symbol (read-only)
+ The state entry’s symbolic name.
+entry.visible (read-only)
+ A Boolean indicating whether the state entry should be displayed in the
+ debugger register view.
+entry.writeable (read-only)
+ A Boolean indicating whether it is possible to modify the state entry’s
+ value.
+entry.is_float (read-only)
+ A Boolean indicating whether the state entry’s value is a floating-point
+ number.
+entry.datamask (read-only)
+ A bit mask of the valid bits of the value for integer state entries.
+entry.datasize (read-only)
+ The size of the underlying value in bytes for integer state entries.
+entry.max_length (read-only)
+ The maximum display string length for the state entry.
+
.. _luareference-dev-imagefmt:
Media image format
diff --git a/src/emu/distate.h b/src/emu/distate.h
index 182010c8142..b4727c259f4 100644
--- a/src/emu/distate.h
+++ b/src/emu/distate.h
@@ -286,12 +286,14 @@ class device_state_interface : public device_interface
friend class device_state_entry;
public:
+ using entrylist_type = std::vector<std::unique_ptr<device_state_entry> >;
+
// construction/destruction
device_state_interface(const machine_config &mconfig, device_t &device);
virtual ~device_state_interface();
// configuration access
- const std::vector<std::unique_ptr<device_state_entry>> &state_entries() const { return m_state_list; }
+ const entrylist_type &state_entries() const { return m_state_list; }
// state getters
u64 state_int(int index) const { const device_state_entry *entry = state_find_entry(index); return (entry == nullptr) ? 0 : entry->value(); }
@@ -361,7 +363,7 @@ protected:
static constexpr int FAST_STATE_MAX = 256; // lookups
// state
- std::vector<std::unique_ptr<device_state_entry>> m_state_list; // head of state list
+ entrylist_type m_state_list; // head of state list
device_state_entry *m_fast_state[FAST_STATE_MAX + 1 - FAST_STATE_MIN]; // fast access to common entries
};
diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp
index 063f01dc5c9..cca0a7fc972 100644
--- a/src/frontend/mame/luaengine.cpp
+++ b/src/frontend/mame/luaengine.cpp
@@ -158,6 +158,19 @@ public:
}
};
+
+struct device_state_entries
+{
+ device_state_entries(device_state_interface const &s) : state(s) { }
+ device_state_interface::entrylist_type const &items() { return state.state_entries(); }
+
+ static device_state_entry const &unwrap(device_state_interface::entrylist_type::const_iterator const &it) { return **it; }
+ static int push_key(lua_State *L, device_state_interface::entrylist_type::const_iterator const &it, std::size_t ix) { return sol::stack::push_reference(L, (*it)->symbol()); }
+
+ device_state_interface const &state;
+};
+
+
struct image_interface_formats
{
image_interface_formats(device_image_interface &i) : image(i) { }
@@ -184,9 +197,9 @@ struct plugin_options_plugins
} // anonymous namespace
-namespace sol
-{
+namespace sol {
+template <> struct is_container<device_state_entries> : std::true_type { };
template <> struct is_container<image_interface_formats> : std::true_type { };
template <> struct is_container<plugin_options_plugins> : std::true_type { };
@@ -295,6 +308,34 @@ public:
template <>
+struct usertype_container<device_state_entries> : lua_engine::immutable_sequence_helper<device_state_entries, device_state_interface::entrylist_type const, device_state_interface::entrylist_type::const_iterator>
+{
+private:
+ using entrylist_type = device_state_interface::entrylist_type;
+
+public:
+ static int get(lua_State *L)
+ {
+ device_state_entries &self(get_self(L));
+ char const *const symbol(stack::unqualified_get<char const *>(L));
+ auto const found(std::find_if(
+ self.state.state_entries().begin(),
+ self.state.state_entries().end(),
+ [&symbol] (std::unique_ptr<device_state_entry> const &v) { return !std::strcmp(v->symbol(), symbol); }));
+ if (self.state.state_entries().end() != found)
+ return stack::push_reference(L, **found);
+ else
+ return stack::push(L, lua_nil);
+ }
+
+ static int index_get(lua_State *L)
+ {
+ return get(L);
+ }
+};
+
+
+template <>
struct usertype_container<image_interface_formats> : lua_engine::immutable_sequence_helper<image_interface_formats, device_image_interface::formatlist_type const, device_image_interface::formatlist_type::const_iterator>
{
private:
@@ -1406,18 +1447,13 @@ void lua_engine::initialize()
}
return sp_table;
});
- // FIXME: improve this
device_type["state"] = sol::property(
- [this] (device_t &dev)
+ [] (device_t &dev, sol::this_state s) -> sol::object
{
- sol::table st_table = sol().create_table();
- const device_state_interface *state;
- if(!dev.interface(state))
- return st_table;
- // XXX: refrain from exporting non-visible entries?
- for(auto &s : state->state_entries())
- st_table[s->symbol()] = s.get();
- return st_table;
+ device_state_interface const *state;
+ if (!dev.interface(state))
+ return sol::lua_nil;
+ return sol::make_object(s, device_state_entries(*state));
});
// FIXME: turn into a wrapper - it's stupid slow to walk on every property access
// also, this mixes up things like RAM areas with stuff saved by the device itself, so there's potential for key conflicts
@@ -1740,6 +1776,38 @@ void lua_engine::initialize()
image_type["device"] = sol::property(static_cast<device_t & (device_image_interface::*)()>(&device_image_interface::device));
+ auto state_entry_type = sol().registry().new_usertype<device_state_entry>("state_entry", sol::no_constructor);
+ state_entry_type["value"] = sol::property(
+ [] (device_state_entry const &entry, sol::this_state s) -> sol::object
+ {
+ if (entry.is_float())
+ return sol::make_object(s, entry.dvalue());
+ else
+ return sol::make_object(s, entry.value());
+ },
+ [] (device_state_entry const &entry, sol::this_state s, sol::object value)
+ {
+ if (!entry.writeable())
+ luaL_error(s, "cannot set value of read-only device state entry");
+ else if (entry.is_float())
+ entry.set_dvalue(value.as<double>());
+ else
+ entry.set_value(value.as<u64>());
+ });
+ state_entry_type["symbol"] = sol::property(&device_state_entry::symbol);
+ state_entry_type["visible"] = sol::property(&device_state_entry::visible);
+ state_entry_type["writeable"] = sol::property(&device_state_entry::writeable);
+ state_entry_type["is_float"] = sol::property(&device_state_entry::is_float);
+ state_entry_type["datamask"] = sol::property(
+ [] (device_state_entry const &entry)
+ {
+ return entry.is_float() ? std::optional<u64>() : std::optional<u64>(entry.datamask());
+ });
+ state_entry_type["datasize"] = sol::property(&device_state_entry::datasize);
+ state_entry_type["max_length"] = sol::property(&device_state_entry::max_length);
+ state_entry_type[sol::meta_function::to_string] = &device_state_entry::to_string;
+
+
auto format_type = sol().registry().new_usertype<image_device_format>("image_format", sol::no_constructor);
format_type["name"] = sol::property(&image_device_format::name);
format_type["description"] = sol::property(&image_device_format::description);
@@ -1876,41 +1944,6 @@ void lua_engine::initialize()
ui_type["image_display_enabled"] = sol::property(&mame_ui_manager::image_display_enabled, &mame_ui_manager::set_image_display_enabled);
-/* device_state_entry library
- *
- * manager:machine().devices[device_tag].state[state_name]
- *
- * state:name() - get device state name
- * state:is_visible() - is state visible in debugger
- * state:is_divider() - is state a divider
- *
- * state.value - get device state value
- */
-
- auto dev_state_type = sol().registry().new_usertype<device_state_entry>("dev_state", "new", sol::no_constructor);
- dev_state_type.set("name", &device_state_entry::symbol);
- dev_state_type.set("value", sol::property(
- [this](device_state_entry &entry) -> uint64_t {
- device_state_interface *state = entry.parent_state();
- if(state)
- {
- machine().save().dispatch_presave();
- return state->state_int(entry.index());
- }
- return 0;
- },
- [this](device_state_entry &entry, uint64_t val) {
- device_state_interface *state = entry.parent_state();
- if(state)
- {
- state->set_state_int(entry.index(), val);
- machine().save().dispatch_presave();
- }
- }));
- dev_state_type.set("is_visible", &device_state_entry::visible);
- dev_state_type.set("is_divider", &device_state_entry::divider);
-
-
/* rom_entry library
*
* manager:machine().devices[device_tag].roms[rom]
diff --git a/src/frontend/mame/luaengine.ipp b/src/frontend/mame/luaengine.ipp
index f575f6a8ffb..79c22c3b71d 100644
--- a/src/frontend/mame/luaengine.ipp
+++ b/src/frontend/mame/luaengine.ipp
@@ -20,6 +20,7 @@
#include <cassert>
#include <system_error>
+#include <type_traits>
@@ -460,7 +461,10 @@ protected:
result = sol::stack::push(L, i.ix + 1);
else
result = T::push_key(L, i.it, i.ix);
- result += sol::stack::push_reference(L, T::unwrap(i.it));
+ if constexpr (std::is_reference_v<decltype(T::unwrap(i.it))>)
+ result += sol::stack::push_reference(L, std::ref(T::unwrap(i.it)));
+ else
+ result += sol::stack::push_reference(L, T::unwrap(i.it));
++i;
return result;
}
@@ -481,9 +485,16 @@ public:
T &self(immutable_sequence_helper::get_self(L));
std::ptrdiff_t const index(sol::stack::unqualified_get<std::ptrdiff_t>(L, 2));
if ((0 >= index) || (self.items().size() < index))
+ {
return sol::stack::push(L, sol::lua_nil);
+ }
else
- return sol::stack::push_reference(L, T::unwrap(std::next(self.items().begin(), index - 1)));
+ {
+ if constexpr (std::is_reference_v<decltype(T::unwrap(std::next(self.items().begin(), index - 1)))>)
+ return sol::stack::push_reference(L, std::ref(T::unwrap(std::next(self.items().begin(), index - 1))));
+ else
+ return sol::stack::push_reference(L, T::unwrap(std::next(self.items().begin(), index - 1)));
+ }
}
static int index_of(lua_State *L)