mirror of
https://github.com/holub/mame
synced 2025-04-17 22:13:04 +03:00
Lua engine: Better bindings for device_state_interface.
This avoids creating a table every time the state property of a device is accessed, adds proper support for getting/setting floating/point state entries from Lua, calls the state entry's formatting method to convert to a string (for flags fields, etc.) and exposes more properties. This is a breaking change as the exposed properties on state entries have changed, and the value property has different semantics for floating-point state entries.
This commit is contained in:
parent
bff2c33fee
commit
2c226a3b9f
@ -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
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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 { };
|
||||
|
||||
@ -294,6 +307,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>
|
||||
{
|
||||
@ -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]
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user