mirror of
https://github.com/holub/mame
synced 2025-07-02 08:39:21 +03:00
Lua engine improvements (#9453)
Made auto-boot script errors and plugin bootstrap errors fatal. Run auto-boot scripts in a sandbox. Globals can be accessed, but not set. The sandbox is cleared on hard reset, but not on soft reset. Added (hopefully) useful to string metafunctions to device_t and address space that show short names and tags. Fixed issues in plugins that surface when strict type checking is enabled, as this means numbers and nil are not automatically converted to strings. Plugins should be tested with debug builds to check for this. Made save item read_block raise an error on invalid arguments rather than returning an empty string, and made it use luaL_buffer directly rather than using the helper wrapper. Changed some more function bindings to use set_function to avoid issues related to ThePhD/sol2#608, and got rid of some unnecessary lambda captures.
This commit is contained in:
parent
bb3f3e5abd
commit
e6588480c4
@ -157,8 +157,8 @@ local function populate_configure_menu(menu)
|
|||||||
configure_selection_save = #menu
|
configure_selection_save = #menu
|
||||||
end
|
end
|
||||||
table.insert(menu, {_p('plugin-autofire', 'Hotkey'), key_name, hotkey_poller and 'lr' or ''})
|
table.insert(menu, {_p('plugin-autofire', 'Hotkey'), key_name, hotkey_poller and 'lr' or ''})
|
||||||
table.insert(menu, {_p('plugin-autofire', 'On frames'), current_button.on_frames, current_button.on_frames > 1 and 'lr' or 'r'})
|
table.insert(menu, {_p('plugin-autofire', 'On frames'), tostring(current_button.on_frames), current_button.on_frames > 1 and 'lr' or 'r'})
|
||||||
table.insert(menu, {_p('plugin-autofire', 'Off frames'), current_button.off_frames, current_button.off_frames > 1 and 'lr' or 'r'})
|
table.insert(menu, {_p('plugin-autofire', 'Off frames'), tostring(current_button.off_frames), current_button.off_frames > 1 and 'lr' or 'r'})
|
||||||
configure_menu_active = true
|
configure_menu_active = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -351,7 +351,7 @@ function cheatfind.startplugin()
|
|||||||
for num, func in ipairs(menu) do
|
for num, func in ipairs(menu) do
|
||||||
local item, f = func()
|
local item, f = func()
|
||||||
if item then
|
if item then
|
||||||
menu_list[#menu_list + 1] = item
|
table.insert(menu_list, item)
|
||||||
menu_func[#menu_list] = f
|
menu_func[#menu_list] = f
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -715,9 +715,9 @@ function cheatfind.startplugin()
|
|||||||
end
|
end
|
||||||
local m
|
local m
|
||||||
if optable[opsel] == "ltv" or optable[opsel] == "gtv" or optable[opsel] == "eqv" or optable[opsel] == "nev" then
|
if optable[opsel] == "ltv" or optable[opsel] == "gtv" or optable[opsel] == "eqv" or optable[opsel] == "nev" then
|
||||||
m = { _("Value"), value, "" }
|
m = { _("Value"), tostring(value), "" }
|
||||||
else
|
else
|
||||||
m = { _("Difference"), value, "" }
|
m = { _("Difference"), tostring(value), "" }
|
||||||
end
|
end
|
||||||
local max = 100 -- max value?
|
local max = 100 -- max value?
|
||||||
menu_lim(value, 0, max, m)
|
menu_lim(value, 0, max, m)
|
||||||
@ -792,7 +792,7 @@ function cheatfind.startplugin()
|
|||||||
end
|
end
|
||||||
menu[#menu + 1] = function() return { "---", "", "off" }, nil end
|
menu[#menu + 1] = function() return { "---", "", "off" }, nil end
|
||||||
menu[#menu + 1] = function()
|
menu[#menu + 1] = function()
|
||||||
local m = { _("Match block"), matchsel, "" }
|
local m = { _("Match block"), tostring(matchsel), "" }
|
||||||
menu_lim(matchsel, 0, #matches[#matches], m)
|
menu_lim(matchsel, 0, #matches[#matches], m)
|
||||||
if matchsel == 0 then
|
if matchsel == 0 then
|
||||||
m[2] = _("All")
|
m[2] = _("All")
|
||||||
@ -1017,7 +1017,7 @@ function cheatfind.startplugin()
|
|||||||
end
|
end
|
||||||
if matches[#matches].count > 100 then
|
if matches[#matches].count > 100 then
|
||||||
menu[#menu + 1] = function()
|
menu[#menu + 1] = function()
|
||||||
local m = { _("Page"), matchpg, "on" }
|
local m = { _("Page"), tostring(matchpg), "on" }
|
||||||
local max
|
local max
|
||||||
if matchsel == 0 then
|
if matchsel == 0 then
|
||||||
max = math.ceil(matches[#matches].count / 100) - 1
|
max = math.ceil(matches[#matches].count / 100) - 1
|
||||||
|
@ -347,7 +347,7 @@ local function add_edit_items(items)
|
|||||||
local input = manager.machine.input
|
local input = manager.machine.input
|
||||||
local arrows
|
local arrows
|
||||||
|
|
||||||
items[#items + 1] = { _p('plugin-inputmacro', 'Name'), edit_name_buffer and (edit_name_buffer .. '_') or edit_current_macro.name, '' }
|
table.insert(items, { _p('plugin-inputmacro', 'Name'), edit_name_buffer and (edit_name_buffer .. '_') or edit_current_macro.name, '' })
|
||||||
edit_items[#items] = { action = 'name' }
|
edit_items[#items] = { action = 'name' }
|
||||||
if not (edit_start_selection or edit_start_step or edit_menu_active) then
|
if not (edit_start_selection or edit_start_step or edit_menu_active) then
|
||||||
edit_start_selection = #items
|
edit_start_selection = #items
|
||||||
@ -356,11 +356,11 @@ local function add_edit_items(items)
|
|||||||
|
|
||||||
local binding = edit_current_macro.binding
|
local binding = edit_current_macro.binding
|
||||||
local activation = binding and input:seq_name(binding) or _p('plugin-inputmacro', '[not set]')
|
local activation = binding and input:seq_name(binding) or _p('plugin-inputmacro', '[not set]')
|
||||||
items[#items + 1] = { _p('plugin-inputmacro', 'Activation sequence'), activation, edit_switch_poller and 'lr' or '' }
|
table.insert(items, { _p('plugin-inputmacro', 'Activation sequence'), activation, edit_switch_poller and 'lr' or '' })
|
||||||
edit_items[#items] = { action = 'binding' }
|
edit_items[#items] = { action = 'binding' }
|
||||||
|
|
||||||
local releaseaction = edit_current_macro.earlycancel and _p('plugin-inputmacro', 'Stop immediately') or _p('plugin-inputmacro', 'Complete macro')
|
local releaseaction = edit_current_macro.earlycancel and _p('plugin-inputmacro', 'Stop immediately') or _p('plugin-inputmacro', 'Complete macro')
|
||||||
items[#items + 1] = { _p('plugin-inputmacro', 'On release'), releaseaction, edit_current_macro.earlycancel and 'r' or 'l' }
|
table.insert(items, { _p('plugin-inputmacro', 'On release'), releaseaction, edit_current_macro.earlycancel and 'r' or 'l' })
|
||||||
edit_items[#items] = { action = 'releaseaction' }
|
edit_items[#items] = { action = 'releaseaction' }
|
||||||
|
|
||||||
local holdaction
|
local holdaction
|
||||||
@ -376,18 +376,18 @@ local function add_edit_items(items)
|
|||||||
else
|
else
|
||||||
holdaction = string.format(_p('plugin-inputmacro', 'Prolong step %d'), #edit_current_macro.steps)
|
holdaction = string.format(_p('plugin-inputmacro', 'Prolong step %d'), #edit_current_macro.steps)
|
||||||
end
|
end
|
||||||
items[#items + 1] = { _p('plugin-inputmacro', 'When held'), holdaction, arrows }
|
table.insert(items, { _p('plugin-inputmacro', 'When held'), holdaction, arrows })
|
||||||
edit_items[#items] = { action = 'holdaction' }
|
edit_items[#items] = { action = 'holdaction' }
|
||||||
|
|
||||||
for i, step in ipairs(edit_current_macro.steps) do
|
for i, step in ipairs(edit_current_macro.steps) do
|
||||||
items[#items + 1] = { string.format(_p('plugin-inputmacro', 'Step %d'), i), '', 'heading' }
|
table.insert(items, { string.format(_p('plugin-inputmacro', 'Step %d'), i), '', 'heading' })
|
||||||
items[#items + 1] = { _p('plugin-inputmacro', 'Delay (frames)'), step.delay, (step.delay > 0) and 'lr' or 'r' }
|
table.insert(items, { _p('plugin-inputmacro', 'Delay (frames)'), tostring(step.delay), (step.delay > 0) and 'lr' or 'r' })
|
||||||
edit_items[#items] = { action = 'delay', step = i }
|
edit_items[#items] = { action = 'delay', step = i }
|
||||||
if edit_start_step == i then
|
if edit_start_step == i then
|
||||||
edit_start_selection = #items
|
edit_start_selection = #items
|
||||||
end
|
end
|
||||||
|
|
||||||
items[#items + 1] = { _p('plugin-inputmacro', 'Duration (frames)'), step.duration, (step.duration > 1) and 'lr' or 'r' }
|
table.insert(items, { _p('plugin-inputmacro', 'Duration (frames)'), tostring(step.duration), (step.duration > 1) and 'lr' or 'r' })
|
||||||
edit_items[#items] = { action = 'duration', step = i }
|
edit_items[#items] = { action = 'duration', step = i }
|
||||||
|
|
||||||
for j, input in ipairs(step.inputs) do
|
for j, input in ipairs(step.inputs) do
|
||||||
@ -399,17 +399,17 @@ local function add_edit_items(items)
|
|||||||
else
|
else
|
||||||
inputname = _p('plugin-inputmacro', '[not set]')
|
inputname = _p('plugin-inputmacro', '[not set]')
|
||||||
end
|
end
|
||||||
items[#items + 1] = { string.format(_p('plugin-inputmacro', 'Input %d'), j), inputname, '' }
|
table.insert(items, { string.format(_p('plugin-inputmacro', 'Input %d'), j), inputname, '' })
|
||||||
edit_items[#items] = { action = 'input', step = i, input = j }
|
edit_items[#items] = { action = 'input', step = i, input = j }
|
||||||
end
|
end
|
||||||
|
|
||||||
if step.inputs[#step.inputs].field then
|
if step.inputs[#step.inputs].field then
|
||||||
items[#items + 1] = { _p('plugin-inputmacro', 'Add input'), '', '' }
|
table.insert(items, { _p('plugin-inputmacro', 'Add input'), '', '' })
|
||||||
edit_items[#items] = { action = 'addinput', step = i }
|
edit_items[#items] = { action = 'addinput', step = i }
|
||||||
end
|
end
|
||||||
|
|
||||||
if #edit_current_macro.steps > 1 then
|
if #edit_current_macro.steps > 1 then
|
||||||
items[#items + 1] = { _p('plugin-inputmacro', 'Delete step'), '', '' }
|
table.insert(items, { _p('plugin-inputmacro', 'Delete step'), '', '' })
|
||||||
edit_items[#items] = { action = 'deletestep', step = i }
|
edit_items[#items] = { action = 'deletestep', step = i }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -417,7 +417,7 @@ local function add_edit_items(items)
|
|||||||
|
|
||||||
local laststep = edit_current_macro.steps[#edit_current_macro.steps]
|
local laststep = edit_current_macro.steps[#edit_current_macro.steps]
|
||||||
if laststep.inputs[#laststep.inputs].field then
|
if laststep.inputs[#laststep.inputs].field then
|
||||||
items[#items + 1] = { '---', '', '' }
|
table.insert(items, { '---', '', '' })
|
||||||
|
|
||||||
arrows = 'lr'
|
arrows = 'lr'
|
||||||
if edit_insert_position > #edit_current_macro.steps then
|
if edit_insert_position > #edit_current_macro.steps then
|
||||||
@ -425,7 +425,7 @@ local function add_edit_items(items)
|
|||||||
elseif edit_insert_position < 2 then
|
elseif edit_insert_position < 2 then
|
||||||
arrows = 'r'
|
arrows = 'r'
|
||||||
end
|
end
|
||||||
items[#items + 1] = { _p('plugin-inputmacro', 'Add step at position'), edit_insert_position, arrows }
|
table.insert(items, { _p('plugin-inputmacro', 'Add step at position'), tostring(edit_insert_position), arrows })
|
||||||
edit_items[#items] = { action = 'addstep', step = i }
|
edit_items[#items] = { action = 'addstep', step = i }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -38,7 +38,7 @@ function timer.startplugin()
|
|||||||
{ '---', '', '' },
|
{ '---', '', '' },
|
||||||
{ _p("plugin-timer", "Current time"), sectohms(time), "off" },
|
{ _p("plugin-timer", "Current time"), sectohms(time), "off" },
|
||||||
{ _p("plugin-timer", "Total time"), sectohms(total), "off" },
|
{ _p("plugin-timer", "Total time"), sectohms(total), "off" },
|
||||||
{ _p("plugin-timer", "Play Count"), play_count, "off" } },
|
{ _p("plugin-timer", "Play Count"), tostring(play_count), "off" } },
|
||||||
highlight,
|
highlight,
|
||||||
"idle"
|
"idle"
|
||||||
end
|
end
|
||||||
|
@ -352,16 +352,18 @@ sol::object lua_engine::call_plugin(const std::string &name, sol::object in)
|
|||||||
{
|
{
|
||||||
std::string field = "cb_" + name;
|
std::string field = "cb_" + name;
|
||||||
sol::object obj = sol().registry()[field];
|
sol::object obj = sol().registry()[field];
|
||||||
if(obj.is<sol::protected_function>())
|
if (obj.is<sol::protected_function>())
|
||||||
{
|
{
|
||||||
auto res = invoke(obj.as<sol::protected_function>(), in);
|
auto res = invoke(obj.as<sol::protected_function>(), in);
|
||||||
if(!res.valid())
|
if (!res.valid())
|
||||||
{
|
{
|
||||||
sol::error err = res;
|
sol::error err = res;
|
||||||
osd_printf_error("[LUA ERROR] in call_plugin: %s\n", err.what());
|
osd_printf_error("[LUA ERROR] in call_plugin: %s\n", err.what());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return res.get<sol::object>();
|
return res.get<sol::object>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sol::lua_nil;
|
return sol::lua_nil;
|
||||||
}
|
}
|
||||||
@ -380,7 +382,7 @@ std::optional<long> lua_engine::menu_populate(const std::string &menu, std::vect
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::tuple<sol::table, std::optional<long>, std::string> table = res;
|
std::tuple<sol::table, std::optional<long>, std::optional<std::string> > table = res;
|
||||||
for (auto &entry : std::get<0>(table))
|
for (auto &entry : std::get<0>(table))
|
||||||
{
|
{
|
||||||
if (entry.second.is<sol::table>())
|
if (entry.second.is<sol::table>())
|
||||||
@ -389,7 +391,10 @@ std::optional<long> lua_engine::menu_populate(const std::string &menu, std::vect
|
|||||||
menu_list.emplace_back(enttable.get<std::string, std::string, std::string>(1, 2, 3));
|
menu_list.emplace_back(enttable.get<std::string, std::string, std::string>(1, 2, 3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flags = std::get<2>(table);
|
if (std::get<2>(table))
|
||||||
|
flags = *std::get<2>(table);
|
||||||
|
else
|
||||||
|
flags.clear();
|
||||||
return std::get<1>(table);
|
return std::get<1>(table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -400,7 +405,7 @@ std::optional<long> lua_engine::menu_populate(const std::string &menu, std::vect
|
|||||||
std::pair<bool, std::optional<long> > lua_engine::menu_callback(const std::string &menu, int index, const std::string &event)
|
std::pair<bool, std::optional<long> > lua_engine::menu_callback(const std::string &menu, int index, const std::string &event)
|
||||||
{
|
{
|
||||||
std::string field = "menu_cb_" + menu;
|
std::string field = "menu_cb_" + menu;
|
||||||
std::pair<bool, std::optional<long> > ret(false, std::nullopt);
|
std::pair<std::optional<bool>, std::optional<long> > ret(false, std::nullopt);
|
||||||
sol::object obj = sol().registry()[field];
|
sol::object obj = sol().registry()[field];
|
||||||
if (obj.is<sol::protected_function>())
|
if (obj.is<sol::protected_function>())
|
||||||
{
|
{
|
||||||
@ -415,7 +420,7 @@ std::pair<bool, std::optional<long> > lua_engine::menu_callback(const std::strin
|
|||||||
ret = res;
|
ret = res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return std::make_pair(std::get<0>(ret) && *std::get<0>(ret), std::get<1>(ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_engine::set_machine(running_machine *machine)
|
void lua_engine::set_machine(running_machine *machine)
|
||||||
@ -423,9 +428,10 @@ void lua_engine::set_machine(running_machine *machine)
|
|||||||
m_machine = machine;
|
m_machine = machine;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_engine::enumerate_functions(const char *id, std::function<bool(const sol::protected_function &func)> &&callback)
|
template <typename T>
|
||||||
|
size_t lua_engine::enumerate_functions(const char *id, T &&callback)
|
||||||
{
|
{
|
||||||
int count = 0;
|
size_t count = 0;
|
||||||
sol::object functable = sol().registry()[id];
|
sol::object functable = sol().registry()[id];
|
||||||
if (functable.is<sol::table>())
|
if (functable.is<sol::table>())
|
||||||
{
|
{
|
||||||
@ -439,23 +445,24 @@ int lua_engine::enumerate_functions(const char *id, std::function<bool(const sol
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lua_engine::execute_function(const char *id)
|
bool lua_engine::execute_function(const char *id)
|
||||||
{
|
{
|
||||||
int count = enumerate_functions(id, [this](const sol::protected_function &func)
|
size_t count = enumerate_functions(
|
||||||
{
|
id,
|
||||||
auto ret = invoke(func);
|
[] (const sol::protected_function &func)
|
||||||
if(!ret.valid())
|
{
|
||||||
{
|
auto ret = invoke(func);
|
||||||
sol::error err = ret;
|
if (!ret.valid())
|
||||||
osd_printf_error("[LUA ERROR] in execute_function: %s\n", err.what());
|
{
|
||||||
}
|
sol::error err = ret;
|
||||||
return true;
|
osd_printf_error("[LUA ERROR] in execute_function: %s\n", err.what());
|
||||||
});
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
return count > 0;
|
return count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,21 +528,23 @@ void lua_engine::on_periodic()
|
|||||||
bool lua_engine::on_missing_mandatory_image(const std::string &instance_name)
|
bool lua_engine::on_missing_mandatory_image(const std::string &instance_name)
|
||||||
{
|
{
|
||||||
bool handled = false;
|
bool handled = false;
|
||||||
enumerate_functions("LUA_ON_MANDATORY_FILE_MANAGER_OVERRIDE", [this, &instance_name, &handled](const sol::protected_function &func)
|
enumerate_functions(
|
||||||
{
|
"LUA_ON_MANDATORY_FILE_MANAGER_OVERRIDE",
|
||||||
auto ret = invoke(func, instance_name);
|
[&instance_name, &handled] (const sol::protected_function &func)
|
||||||
|
{
|
||||||
|
auto ret = invoke(func, instance_name);
|
||||||
|
|
||||||
if(!ret.valid())
|
if (!ret.valid())
|
||||||
{
|
{
|
||||||
sol::error err = ret;
|
sol::error err = ret;
|
||||||
osd_printf_error("[LUA ERROR] in on_missing_mandatory_image: %s\n", err.what());
|
osd_printf_error("[LUA ERROR] in on_missing_mandatory_image: %s\n", err.what());
|
||||||
}
|
}
|
||||||
else if (ret.get<bool>())
|
else if (ret.get<bool>())
|
||||||
{
|
{
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
return !handled;
|
return !handled;
|
||||||
});
|
});
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -829,7 +838,7 @@ void lua_engine::initialize()
|
|||||||
auto space = buf.prepare(len);
|
auto space = buf.prepare(len);
|
||||||
space.add(file.read(space.get(), len));
|
space.add(file.read(space.get(), len));
|
||||||
buf.push();
|
buf.push();
|
||||||
return sol::stack::pop<sol::object>(s);
|
return sol::make_reference(s, sol::stack_reference(s, -1));
|
||||||
});
|
});
|
||||||
file_type.set("write", [](emu_file &file, const std::string &data) { return file.write(data.data(), data.size()); });
|
file_type.set("write", [](emu_file &file, const std::string &data) { return file.write(data.data(), data.size()); });
|
||||||
file_type.set("puts", &emu_file::puts);
|
file_type.set("puts", &emu_file::puts);
|
||||||
@ -974,12 +983,14 @@ void lua_engine::initialize()
|
|||||||
}));
|
}));
|
||||||
item_type.set("size", sol::readonly(&save_item::size));
|
item_type.set("size", sol::readonly(&save_item::size));
|
||||||
item_type.set("count", sol::readonly(&save_item::count));
|
item_type.set("count", sol::readonly(&save_item::count));
|
||||||
item_type.set("read", [this](save_item &item, int offset) -> sol::object {
|
item_type.set("read",
|
||||||
if(!item.base || (offset >= item.count))
|
[this] (save_item &item, int offset) -> sol::object
|
||||||
|
{
|
||||||
|
if (!item.base || (offset >= item.count))
|
||||||
return sol::lua_nil;
|
return sol::lua_nil;
|
||||||
const void *const data = reinterpret_cast<const uint8_t *>(item.base) + (item.stride * (offset / item.valcount));
|
const void *const data = reinterpret_cast<const uint8_t *>(item.base) + (item.stride * (offset / item.valcount));
|
||||||
uint64_t ret = 0;
|
uint64_t ret = 0;
|
||||||
switch(item.size)
|
switch (item.size)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
default:
|
default:
|
||||||
@ -997,33 +1008,38 @@ void lua_engine::initialize()
|
|||||||
}
|
}
|
||||||
return sol::make_object(sol(), ret);
|
return sol::make_object(sol(), ret);
|
||||||
});
|
});
|
||||||
item_type.set("read_block", [](save_item &item, sol::this_state s, int offset, size_t len) {
|
item_type.set("read_block",
|
||||||
buffer_helper buf(s);
|
[] (save_item &item, sol::this_state s, uint32_t offset, size_t len) -> sol::object
|
||||||
auto space = buf.prepare(len);
|
{
|
||||||
if(!item.base || ((offset + len) > (item.size * item.count)))
|
if (!item.base)
|
||||||
{
|
{
|
||||||
space.add(0);
|
luaL_error(s, "Invalid save item");
|
||||||
|
return sol::lua_nil;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if ((offset + len) > (item.size * item.count))
|
||||||
{
|
{
|
||||||
const uint32_t blocksize = item.size * item.valcount;
|
luaL_error(s, "Range extends beyond end of save item");
|
||||||
size_t remaining = len;
|
return sol::lua_nil;
|
||||||
uint8_t *dest = reinterpret_cast<uint8_t *>(space.get());
|
|
||||||
while(remaining)
|
|
||||||
{
|
|
||||||
const uint32_t blockno = offset / blocksize;
|
|
||||||
const uint32_t available = blocksize - (offset % blocksize);
|
|
||||||
const uint32_t chunk = (available < remaining) ? available : remaining;
|
|
||||||
const void *const source = reinterpret_cast<const uint8_t *>(item.base) + (blockno * item.stride) + (offset % blocksize);
|
|
||||||
std::memcpy(dest, source, chunk);
|
|
||||||
offset += chunk;
|
|
||||||
remaining -= chunk;
|
|
||||||
dest += chunk;
|
|
||||||
}
|
|
||||||
space.add(len);
|
|
||||||
}
|
}
|
||||||
buf.push();
|
|
||||||
return sol::stack::pop<sol::object>(s);
|
luaL_Buffer buff;
|
||||||
|
uint8_t *dest = reinterpret_cast<uint8_t *>(luaL_buffinitsize(s, &buff, len));
|
||||||
|
const uint32_t blocksize = item.size * item.valcount;
|
||||||
|
size_t remaining = len;
|
||||||
|
while (remaining)
|
||||||
|
{
|
||||||
|
const uint32_t blockno = offset / blocksize;
|
||||||
|
const uint32_t available = blocksize - (offset % blocksize);
|
||||||
|
const uint32_t chunk = (available < remaining) ? available : remaining;
|
||||||
|
const void *const source = reinterpret_cast<const uint8_t *>(item.base) + (blockno * item.stride) + (offset % blocksize);
|
||||||
|
std::memcpy(dest, source, chunk);
|
||||||
|
offset += chunk;
|
||||||
|
remaining -= chunk;
|
||||||
|
dest += chunk;
|
||||||
|
}
|
||||||
|
luaL_pushresultsize(&buff, len);
|
||||||
|
return sol::make_reference(s, sol::stack_reference(s, -1));
|
||||||
});
|
});
|
||||||
item_type.set("write", [](save_item &item, int offset, uint64_t value) {
|
item_type.set("write", [](save_item &item, int offset, uint64_t value) {
|
||||||
if(!item.base || (offset >= item.count))
|
if(!item.base || (offset >= item.count))
|
||||||
@ -1187,54 +1203,54 @@ void lua_engine::initialize()
|
|||||||
|
|
||||||
|
|
||||||
auto machine_type = sol().registry().new_usertype<running_machine>("machine", sol::no_constructor);
|
auto machine_type = sol().registry().new_usertype<running_machine>("machine", sol::no_constructor);
|
||||||
machine_type["exit"] = &running_machine::schedule_exit;
|
machine_type.set_function("exit", &running_machine::schedule_exit);
|
||||||
machine_type["hard_reset"] = &running_machine::schedule_hard_reset;
|
machine_type.set_function("hard_reset", &running_machine::schedule_hard_reset);
|
||||||
machine_type["soft_reset"] = &running_machine::schedule_soft_reset;
|
machine_type.set_function("soft_reset", &running_machine::schedule_soft_reset);
|
||||||
machine_type["save"] = &running_machine::schedule_save; // TODO: some kind of completion notification?
|
machine_type.set_function("save", &running_machine::schedule_save); // TODO: some kind of completion notification?
|
||||||
machine_type["load"] = &running_machine::schedule_load; // TODO: some kind of completion notification?
|
machine_type.set_function("load", &running_machine::schedule_load); // TODO: some kind of completion notification?
|
||||||
machine_type["buffer_save"] =
|
machine_type.set_function("buffer_save",
|
||||||
[] (running_machine &m, sol::this_state s)
|
[] (running_machine &m, sol::this_state s)
|
||||||
{
|
|
||||||
// FIXME: this needs to schedule saving to a buffer and return asynchronously somehow
|
|
||||||
// right now it's broken by anonymous timers, synchronize, etc.
|
|
||||||
lua_State *L = s;
|
|
||||||
luaL_Buffer buff;
|
|
||||||
int size = ram_state::get_size(m.save());
|
|
||||||
u8 *ptr = (u8 *)luaL_buffinitsize(L, &buff, size);
|
|
||||||
save_error error = m.save().write_buffer(ptr, size);
|
|
||||||
if (error == STATERR_NONE)
|
|
||||||
{
|
{
|
||||||
luaL_pushresultsize(&buff, size);
|
// FIXME: this needs to schedule saving to a buffer and return asynchronously somehow
|
||||||
return sol::make_reference(L, sol::stack_reference(L, -1));
|
// right now it's broken by anonymous timers, synchronize, etc.
|
||||||
}
|
lua_State *L = s;
|
||||||
luaL_error(L, "State save error.");
|
luaL_Buffer buff;
|
||||||
return sol::make_reference(L, nullptr);
|
int size = ram_state::get_size(m.save());
|
||||||
};
|
u8 *ptr = (u8 *)luaL_buffinitsize(L, &buff, size);
|
||||||
machine_type["buffer_load"] =
|
save_error error = m.save().write_buffer(ptr, size);
|
||||||
[] (running_machine &m, sol::this_state s, std::string str)
|
if (error == STATERR_NONE)
|
||||||
{
|
{
|
||||||
// FIXME: this needs to schedule loading from the buffer and return asynchronously somehow
|
luaL_pushresultsize(&buff, size);
|
||||||
// right now it's broken by anonymous timers, synchronize, etc.
|
return sol::make_reference(L, sol::stack_reference(L, -1));
|
||||||
save_error error = m.save().read_buffer((u8 *)str.data(), str.size());
|
}
|
||||||
if (error == STATERR_NONE)
|
luaL_error(L, "State save error.");
|
||||||
|
return sol::make_reference(L, nullptr);
|
||||||
|
});
|
||||||
|
machine_type.set_function("buffer_load",
|
||||||
|
[] (running_machine &m, sol::this_state s, std::string str)
|
||||||
{
|
{
|
||||||
return true;
|
// FIXME: this needs to schedule loading from the buffer and return asynchronously somehow
|
||||||
}
|
// right now it's broken by anonymous timers, synchronize, etc.
|
||||||
else
|
save_error error = m.save().read_buffer((u8 *)str.data(), str.size());
|
||||||
|
if (error == STATERR_NONE)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
luaL_error(s,"State load error.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
machine_type.set_function("popmessage",
|
||||||
|
[] (running_machine &m, std::optional<const char *> str)
|
||||||
{
|
{
|
||||||
luaL_error(s,"State load error.");
|
if (str)
|
||||||
return false;
|
m.popmessage("%s", *str);
|
||||||
}
|
else
|
||||||
};
|
m.popmessage();
|
||||||
machine_type["popmessage"] =
|
});
|
||||||
[] (running_machine &m, const char *str)
|
machine_type.set_function("logerror", [] (running_machine &m, char const *str) { m.logerror("[luaengine] %s\n", str); });
|
||||||
{
|
|
||||||
if (str)
|
|
||||||
m.popmessage("%s", str);
|
|
||||||
else
|
|
||||||
m.popmessage();
|
|
||||||
};
|
|
||||||
machine_type["logerror"] = [] (running_machine &m, std::string const *str) { m.logerror("[luaengine] %s\n", str); };
|
|
||||||
machine_type["time"] = sol::property(&running_machine::time);
|
machine_type["time"] = sol::property(&running_machine::time);
|
||||||
machine_type["system"] = sol::property(&running_machine::system);
|
machine_type["system"] = sol::property(&running_machine::system);
|
||||||
machine_type["parameters"] = sol::property(&running_machine::parameters);
|
machine_type["parameters"] = sol::property(&running_machine::parameters);
|
||||||
@ -1337,15 +1353,16 @@ void lua_engine::initialize()
|
|||||||
|
|
||||||
|
|
||||||
auto device_type = sol().registry().new_usertype<device_t>("device", sol::no_constructor);
|
auto device_type = sol().registry().new_usertype<device_t>("device", sol::no_constructor);
|
||||||
device_type["subtag"] = &device_t::subtag;
|
device_type.set_function(sol::meta_function::to_string, [] (device_t &d) { return util::string_format("%s(%s)", d.shortname(), d.tag()); });
|
||||||
device_type["siblingtag"] = &device_t::siblingtag;
|
device_type.set_function("subtag", &device_t::subtag);
|
||||||
device_type["memregion"] = &device_t::memregion;
|
device_type.set_function("siblingtag", &device_t::siblingtag);
|
||||||
device_type["memshare"] = &device_t::memshare;
|
device_type.set_function("memregion", &device_t::memregion);
|
||||||
device_type["membank"] = &device_t::membank;
|
device_type.set_function("memshare", &device_t::memshare);
|
||||||
device_type["ioport"] = &device_t::ioport;
|
device_type.set_function("membank", &device_t::membank);
|
||||||
device_type["subdevice"] = static_cast<device_t *(device_t::*)(std::string_view) const>(&device_t::subdevice);
|
device_type.set_function("ioport", &device_t::ioport);
|
||||||
device_type["siblingdevice"] = static_cast<device_t *(device_t::*)(std::string_view) const>(&device_t::siblingdevice);
|
device_type.set_function("subdevice", static_cast<device_t *(device_t::*)(std::string_view) const>(&device_t::subdevice));
|
||||||
device_type["parameter"] = &device_t::parameter;
|
device_type.set_function("siblingdevice", static_cast<device_t *(device_t::*)(std::string_view) const>(&device_t::siblingdevice));
|
||||||
|
device_type.set_function("parameter", &device_t::parameter);
|
||||||
device_type["tag"] = sol::property(&device_t::tag);
|
device_type["tag"] = sol::property(&device_t::tag);
|
||||||
device_type["basetag"] = sol::property(&device_t::basetag);
|
device_type["basetag"] = sol::property(&device_t::basetag);
|
||||||
device_type["name"] = sol::property(&device_t::name);
|
device_type["name"] = sol::property(&device_t::name);
|
||||||
@ -1914,35 +1931,29 @@ void lua_engine::resume(int nparam)
|
|||||||
luaL_unref(m_lua_state, LUA_REGISTRYINDEX, nparam);
|
luaL_unref(m_lua_state, LUA_REGISTRYINDEX, nparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_engine::run(sol::load_result res)
|
//-------------------------------------------------
|
||||||
|
// load_script - load script from file path
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
sol::load_result lua_engine::load_script(std::string const &filename)
|
||||||
{
|
{
|
||||||
if(res.valid())
|
return sol().load_file(filename);
|
||||||
{
|
|
||||||
auto ret = invoke(res.get<sol::protected_function>());
|
|
||||||
if(!ret.valid())
|
|
||||||
{
|
|
||||||
sol::error err = ret;
|
|
||||||
osd_printf_error("[LUA ERROR] in run: %s\n", err.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
osd_printf_error("[LUA ERROR] %d loading Lua script\n", (int)res.status());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
// execute - load and execute script
|
// load_string - load script from string
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
void lua_engine::load_script(const char *filename)
|
sol::load_result lua_engine::load_string(std::string const &value)
|
||||||
{
|
{
|
||||||
run(sol().load_file(filename));
|
return sol().load(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
// execute_string - execute script from string
|
// make_environment - make a sandbox
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
void lua_engine::load_string(const char *value)
|
sol::environment lua_engine::make_environment()
|
||||||
{
|
{
|
||||||
run(sol().load(value));
|
return sol::environment(sol(), sol::create, sol().globals());
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ class lua_engine
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// helper structures
|
// helper structures
|
||||||
class buffer_helper;
|
|
||||||
template <typename T> struct devenum;
|
template <typename T> struct devenum;
|
||||||
template <typename T> struct simple_list_wrapper;
|
template <typename T> struct simple_list_wrapper;
|
||||||
template <typename T> struct tag_object_ptr_map;
|
template <typename T> struct tag_object_ptr_map;
|
||||||
@ -48,8 +47,9 @@ public:
|
|||||||
~lua_engine();
|
~lua_engine();
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
void load_script(const char *filename);
|
sol::load_result load_script(std::string const &filename);
|
||||||
void load_string(const char *value);
|
sol::load_result load_string(std::string const &value);
|
||||||
|
sol::environment make_environment();
|
||||||
|
|
||||||
bool frame_hook();
|
bool frame_hook();
|
||||||
|
|
||||||
@ -122,9 +122,27 @@ public:
|
|||||||
|
|
||||||
sol::state_view &sol() const { return *m_sol_state; }
|
sol::state_view &sol() const { return *m_sol_state; }
|
||||||
|
|
||||||
private:
|
template <typename Func, typename... Params>
|
||||||
template<typename T, size_t SIZE> class enum_parser;
|
static std::decay_t<std::invoke_result_t<Func, Params...> > invoke(Func &&func, Params&&... args)
|
||||||
|
{
|
||||||
|
g_profiler.start(PROFILER_LUA);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto result = func(std::forward<Params>(args)...);
|
||||||
|
g_profiler.stop();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
g_profiler.stop();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename T, size_t Size> class enum_parser;
|
||||||
|
|
||||||
|
class buffer_helper;
|
||||||
struct addr_space;
|
struct addr_space;
|
||||||
class tap_helper;
|
class tap_helper;
|
||||||
class addr_space_change_notif;
|
class addr_space_change_notif;
|
||||||
@ -170,17 +188,12 @@ private:
|
|||||||
|
|
||||||
void resume(int nparam);
|
void resume(int nparam);
|
||||||
void register_function(sol::function func, const char *id);
|
void register_function(sol::function func, const char *id);
|
||||||
int enumerate_functions(const char *id, std::function<bool(const sol::protected_function &func)> &&callback);
|
template <typename T> size_t enumerate_functions(const char *id, T &&callback);
|
||||||
bool execute_function(const char *id);
|
bool execute_function(const char *id);
|
||||||
sol::object call_plugin(const std::string &name, sol::object in);
|
sol::object call_plugin(const std::string &name, sol::object in);
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
void run(sol::load_result res);
|
|
||||||
|
|
||||||
template <typename TFunc, typename... TArgs>
|
|
||||||
sol::protected_function_result invoke(TFunc &&func, TArgs&&... args);
|
|
||||||
|
|
||||||
void initialize_debug(sol::table &emu);
|
void initialize_debug(sol::table &emu);
|
||||||
void initialize_input(sol::table &emu);
|
void initialize_input(sol::table &emu);
|
||||||
void initialize_memory(sol::table &emu);
|
void initialize_memory(sol::table &emu);
|
||||||
|
@ -21,6 +21,24 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct lua_engine::simple_list_wrapper
|
||||||
|
{
|
||||||
|
simple_list_wrapper(simple_list<T> const &l) : list(l) { }
|
||||||
|
|
||||||
|
simple_list<T> const &list;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct lua_engine::tag_object_ptr_map
|
||||||
|
{
|
||||||
|
tag_object_ptr_map(T const &m) : map(m) { }
|
||||||
|
|
||||||
|
T const ↦
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class lua_engine::buffer_helper
|
class lua_engine::buffer_helper
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@ -110,24 +128,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct lua_engine::simple_list_wrapper
|
|
||||||
{
|
|
||||||
simple_list_wrapper(simple_list<T> const &l) : list(l) { }
|
|
||||||
|
|
||||||
simple_list<T> const &list;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct lua_engine::tag_object_ptr_map
|
|
||||||
{
|
|
||||||
tag_object_ptr_map(T const &m) : map(m) { }
|
|
||||||
|
|
||||||
T const ↦
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
|
|
||||||
// don't convert core_options to a table directly
|
// don't convert core_options to a table directly
|
||||||
@ -491,13 +491,13 @@ struct lua_engine::addr_space
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename T, size_t SIZE>
|
template <typename T, size_t Size>
|
||||||
class lua_engine::enum_parser
|
class lua_engine::enum_parser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
constexpr enum_parser(std::initializer_list<std::pair<std::string_view, T> > values)
|
constexpr enum_parser(std::initializer_list<std::pair<std::string_view, T> > values)
|
||||||
{
|
{
|
||||||
if (values.size() != SIZE)
|
if (values.size() != Size)
|
||||||
throw false && "size template argument incorrectly specified";
|
throw false && "size template argument incorrectly specified";
|
||||||
std::copy(values.begin(), values.end(), m_map.begin());
|
std::copy(values.begin(), values.end(), m_map.begin());
|
||||||
}
|
}
|
||||||
@ -514,7 +514,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<std::pair<std::string_view, T>, SIZE> m_map;
|
std::array<std::pair<std::string_view, T>, Size> m_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -527,7 +527,7 @@ template <typename R, typename T, typename D>
|
|||||||
auto lua_engine::make_simple_callback_setter(void (T::*setter)(delegate<R ()> &&), D &&dflt, const char *name, const char *desc)
|
auto lua_engine::make_simple_callback_setter(void (T::*setter)(delegate<R ()> &&), D &&dflt, const char *name, const char *desc)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
[this, setter, dflt, name, desc] (T &self, sol::object cb)
|
[setter, dflt, name, desc] (T &self, sol::object cb)
|
||||||
{
|
{
|
||||||
if (cb == sol::lua_nil)
|
if (cb == sol::lua_nil)
|
||||||
{
|
{
|
||||||
@ -536,7 +536,7 @@ auto lua_engine::make_simple_callback_setter(void (T::*setter)(delegate<R ()> &&
|
|||||||
else if (cb.is<sol::protected_function>())
|
else if (cb.is<sol::protected_function>())
|
||||||
{
|
{
|
||||||
(self.*setter)(delegate<R ()>(
|
(self.*setter)(delegate<R ()>(
|
||||||
[this, dflt, desc, cbfunc = cb.as<sol::protected_function>()] () -> R
|
[dflt, desc, cbfunc = cb.as<sol::protected_function>()] () -> R
|
||||||
{
|
{
|
||||||
if constexpr (std::is_same_v<R, void>)
|
if constexpr (std::is_same_v<R, void>)
|
||||||
{
|
{
|
||||||
@ -566,18 +566,4 @@ auto lua_engine::make_simple_callback_setter(void (T::*setter)(delegate<R ()> &&
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
|
||||||
// invoke - invokes a function, wrapping profiler
|
|
||||||
//-------------------------------------------------
|
|
||||||
|
|
||||||
template <typename TFunc, typename... TArgs>
|
|
||||||
inline sol::protected_function_result lua_engine::invoke(TFunc &&func, TArgs &&... args)
|
|
||||||
{
|
|
||||||
g_profiler.start(PROFILER_LUA);
|
|
||||||
sol::protected_function_result result = func(std::forward<TArgs>(args)...);
|
|
||||||
g_profiler.stop();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // MAME_FRONTEND_MAME_LUAENGINE_IPP
|
#endif // MAME_FRONTEND_MAME_LUAENGINE_IPP
|
||||||
|
@ -181,14 +181,14 @@ void lua_engine::initialize_debug(sol::table &emu)
|
|||||||
{ "m", EXPSPACE_REGION }
|
{ "m", EXPSPACE_REGION }
|
||||||
};
|
};
|
||||||
|
|
||||||
auto const do_add_symbol = [this] (symbol_table_wrapper &st, char const *name, sol::protected_function getter, std::optional<sol::protected_function> setter, std::optional<char const *> format) -> symbol_entry &
|
auto const do_add_symbol = [] (symbol_table_wrapper &st, char const *name, sol::protected_function getter, std::optional<sol::protected_function> setter, std::optional<char const *> format) -> symbol_entry &
|
||||||
{
|
{
|
||||||
symbol_table::setter_func setfun;
|
symbol_table::setter_func setfun;
|
||||||
if (setter)
|
if (setter)
|
||||||
setfun = [this, cbfunc = std::move(*setter)] (u64 value) { invoke(cbfunc, value); };
|
setfun = [cbfunc = std::move(*setter)] (u64 value) { invoke(cbfunc, value); };
|
||||||
return st.table().add(
|
return st.table().add(
|
||||||
name,
|
name,
|
||||||
[this, cbfunc = std::move(getter)] () -> u64
|
[cbfunc = std::move(getter)] () -> u64
|
||||||
{
|
{
|
||||||
auto result = invoke(cbfunc).get<sol::optional<u64> >();
|
auto result = invoke(cbfunc).get<sol::optional<u64> >();
|
||||||
if (result)
|
if (result)
|
||||||
@ -217,12 +217,12 @@ void lua_engine::initialize_debug(sol::table &emu)
|
|||||||
[] (device_t &device)
|
[] (device_t &device)
|
||||||
{ return std::make_shared<symbol_table_wrapper>(device.machine(), nullptr, &device); }));
|
{ return std::make_shared<symbol_table_wrapper>(device.machine(), nullptr, &device); }));
|
||||||
symbol_table_type.set_function("set_memory_modified_func",
|
symbol_table_type.set_function("set_memory_modified_func",
|
||||||
[this] (symbol_table_wrapper &st, sol::object cb)
|
[] (symbol_table_wrapper &st, sol::object cb)
|
||||||
{
|
{
|
||||||
if (cb == sol::lua_nil)
|
if (cb == sol::lua_nil)
|
||||||
st.table().set_memory_modified_func(nullptr);
|
st.table().set_memory_modified_func(nullptr);
|
||||||
else if (cb.is<sol::protected_function>())
|
else if (cb.is<sol::protected_function>())
|
||||||
st.table().set_memory_modified_func([this, cbfunc = cb.as<sol::protected_function>()] () { invoke(cbfunc); });
|
st.table().set_memory_modified_func([cbfunc = cb.as<sol::protected_function>()] () { invoke(cbfunc); });
|
||||||
else
|
else
|
||||||
osd_printf_error("[LUA ERROR] must call set_memory_modified_func with function or nil\n");
|
osd_printf_error("[LUA ERROR] must call set_memory_modified_func with function or nil\n");
|
||||||
});
|
});
|
||||||
@ -246,19 +246,19 @@ void lua_engine::initialize_debug(sol::table &emu)
|
|||||||
{
|
{
|
||||||
return do_add_symbol(st, name, getter, std::nullopt, nullptr);
|
return do_add_symbol(st, name, getter, std::nullopt, nullptr);
|
||||||
},
|
},
|
||||||
[this] (symbol_table_wrapper &st, char const *name, int minparams, int maxparams, sol::protected_function execute) -> symbol_entry &
|
[] (symbol_table_wrapper &st, sol::this_state s, char const *name, int minparams, int maxparams, sol::protected_function execute) -> symbol_entry &
|
||||||
{
|
{
|
||||||
return st.table().add(
|
return st.table().add(
|
||||||
name,
|
name,
|
||||||
minparams,
|
minparams,
|
||||||
maxparams,
|
maxparams,
|
||||||
[this, cbref = sol::reference(execute)] (int numparams, u64 const *paramlist) -> u64
|
[L = s.L, cbref = sol::reference(execute)] (int numparams, u64 const *paramlist) -> u64
|
||||||
{
|
{
|
||||||
sol::stack_reference traceback(m_lua_state, -sol::stack::push(m_lua_state, sol::default_traceback_error_handler));
|
sol::stack_reference traceback(L, -sol::stack::push(L, sol::default_traceback_error_handler));
|
||||||
cbref.push();
|
cbref.push();
|
||||||
sol::stack_aligned_stack_handler_function func(m_lua_state, -1, traceback);
|
sol::stack_aligned_stack_handler_function func(L, -1, traceback);
|
||||||
for (int i = 0; numparams > i; ++i)
|
for (int i = 0; numparams > i; ++i)
|
||||||
lua_pushinteger(m_lua_state, paramlist[i]);
|
lua_pushinteger(L, paramlist[i]);
|
||||||
auto result = func(sol::stack_count(numparams)).get<sol::optional<u64> >();
|
auto result = func(sol::stack_count(numparams)).get<sol::optional<u64> >();
|
||||||
traceback.pop();
|
traceback.pop();
|
||||||
return result ? *result : 0;
|
return result ? *result : 0;
|
||||||
|
@ -195,7 +195,6 @@ public:
|
|||||||
tap_helper(tap_helper &&) = delete;
|
tap_helper(tap_helper &&) = delete;
|
||||||
|
|
||||||
tap_helper(
|
tap_helper(
|
||||||
lua_engine &engine,
|
|
||||||
address_space &space,
|
address_space &space,
|
||||||
read_or_write mode,
|
read_or_write mode,
|
||||||
offs_t start,
|
offs_t start,
|
||||||
@ -203,7 +202,6 @@ public:
|
|||||||
std::string &&name,
|
std::string &&name,
|
||||||
sol::protected_function &&callback)
|
sol::protected_function &&callback)
|
||||||
: m_callback(std::move(callback))
|
: m_callback(std::move(callback))
|
||||||
, m_engine(engine)
|
|
||||||
, m_space(space)
|
, m_space(space)
|
||||||
, m_handler()
|
, m_handler()
|
||||||
, m_name(std::move(name))
|
, m_name(std::move(name))
|
||||||
@ -270,7 +268,7 @@ private:
|
|||||||
m_name,
|
m_name,
|
||||||
[this] (offs_t offset, T &data, T mem_mask)
|
[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> >();
|
auto result = invoke(m_callback, offset, data, mem_mask).template get<sol::optional<T> >();
|
||||||
if (result)
|
if (result)
|
||||||
data = *result;
|
data = *result;
|
||||||
},
|
},
|
||||||
@ -283,7 +281,7 @@ private:
|
|||||||
m_name,
|
m_name,
|
||||||
[this] (offs_t offset, T &data, T mem_mask)
|
[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> >();
|
auto result = invoke(m_callback, offset, data, mem_mask).template get<sol::optional<T> >();
|
||||||
if (result)
|
if (result)
|
||||||
data = *result;
|
data = *result;
|
||||||
},
|
},
|
||||||
@ -303,7 +301,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
sol::protected_function m_callback;
|
sol::protected_function m_callback;
|
||||||
lua_engine &m_engine;
|
|
||||||
address_space &m_space;
|
address_space &m_space;
|
||||||
memory_passthrough_handler m_handler;
|
memory_passthrough_handler m_handler;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
@ -531,118 +528,125 @@ void lua_engine::initialize_memory(sol::table &emu)
|
|||||||
{
|
{
|
||||||
|
|
||||||
auto addr_space_type = sol().registry().new_usertype<addr_space>("addr_space", sol::no_constructor);
|
auto addr_space_type = sol().registry().new_usertype<addr_space>("addr_space", sol::no_constructor);
|
||||||
addr_space_type["read_i8"] = &addr_space::mem_read<s8>;
|
addr_space_type.set_function(sol::meta_function::to_string,
|
||||||
addr_space_type["read_u8"] = &addr_space::mem_read<u8>;
|
[] (addr_space const &sp)
|
||||||
addr_space_type["read_i16"] = &addr_space::mem_read<s16>;
|
{
|
||||||
addr_space_type["read_u16"] = &addr_space::mem_read<u16>;
|
device_t &d(sp.dev.device());
|
||||||
addr_space_type["read_i32"] = &addr_space::mem_read<s32>;
|
return util::string_format("%s(%s):%s", d.shortname(), d.tag(), sp.space.name());
|
||||||
addr_space_type["read_u32"] = &addr_space::mem_read<u32>;
|
});
|
||||||
addr_space_type["read_i64"] = &addr_space::mem_read<s64>;
|
addr_space_type.set_function("read_i8", &addr_space::mem_read<s8>);
|
||||||
addr_space_type["read_u64"] = &addr_space::mem_read<u64>;
|
addr_space_type.set_function("read_u8", &addr_space::mem_read<u8>);
|
||||||
addr_space_type["write_i8"] = &addr_space::mem_write<s8>;
|
addr_space_type.set_function("read_i16", &addr_space::mem_read<s16>);
|
||||||
addr_space_type["write_u8"] = &addr_space::mem_write<u8>;
|
addr_space_type.set_function("read_u16", &addr_space::mem_read<u16>);
|
||||||
addr_space_type["write_i16"] = &addr_space::mem_write<s16>;
|
addr_space_type.set_function("read_i32", &addr_space::mem_read<s32>);
|
||||||
addr_space_type["write_u16"] = &addr_space::mem_write<u16>;
|
addr_space_type.set_function("read_u32", &addr_space::mem_read<u32>);
|
||||||
addr_space_type["write_i32"] = &addr_space::mem_write<s32>;
|
addr_space_type.set_function("read_i64", &addr_space::mem_read<s64>);
|
||||||
addr_space_type["write_u32"] = &addr_space::mem_write<u32>;
|
addr_space_type.set_function("read_u64", &addr_space::mem_read<u64>);
|
||||||
addr_space_type["write_i64"] = &addr_space::mem_write<s64>;
|
addr_space_type.set_function("write_i8", &addr_space::mem_write<s8>);
|
||||||
addr_space_type["write_u64"] = &addr_space::mem_write<u64>;
|
addr_space_type.set_function("write_u8", &addr_space::mem_write<u8>);
|
||||||
addr_space_type["readv_i8"] = &addr_space::log_mem_read<s8>;
|
addr_space_type.set_function("write_i16", &addr_space::mem_write<s16>);
|
||||||
addr_space_type["readv_u8"] = &addr_space::log_mem_read<u8>;
|
addr_space_type.set_function("write_u16", &addr_space::mem_write<u16>);
|
||||||
addr_space_type["readv_i16"] = &addr_space::log_mem_read<s16>;
|
addr_space_type.set_function("write_i32", &addr_space::mem_write<s32>);
|
||||||
addr_space_type["readv_u16"] = &addr_space::log_mem_read<u16>;
|
addr_space_type.set_function("write_u32", &addr_space::mem_write<u32>);
|
||||||
addr_space_type["readv_i32"] = &addr_space::log_mem_read<s32>;
|
addr_space_type.set_function("write_i64", &addr_space::mem_write<s64>);
|
||||||
addr_space_type["readv_u32"] = &addr_space::log_mem_read<u32>;
|
addr_space_type.set_function("write_u64", &addr_space::mem_write<u64>);
|
||||||
addr_space_type["readv_i64"] = &addr_space::log_mem_read<s64>;
|
addr_space_type.set_function("readv_i8", &addr_space::log_mem_read<s8>);
|
||||||
addr_space_type["readv_u64"] = &addr_space::log_mem_read<u64>;
|
addr_space_type.set_function("readv_u8", &addr_space::log_mem_read<u8>);
|
||||||
addr_space_type["writev_i8"] = &addr_space::log_mem_write<s8>;
|
addr_space_type.set_function("readv_i16", &addr_space::log_mem_read<s16>);
|
||||||
addr_space_type["writev_u8"] = &addr_space::log_mem_write<u8>;
|
addr_space_type.set_function("readv_u16", &addr_space::log_mem_read<u16>);
|
||||||
addr_space_type["writev_i16"] = &addr_space::log_mem_write<s16>;
|
addr_space_type.set_function("readv_i32", &addr_space::log_mem_read<s32>);
|
||||||
addr_space_type["writev_u16"] = &addr_space::log_mem_write<u16>;
|
addr_space_type.set_function("readv_u32", &addr_space::log_mem_read<u32>);
|
||||||
addr_space_type["writev_i32"] = &addr_space::log_mem_write<s32>;
|
addr_space_type.set_function("readv_i64", &addr_space::log_mem_read<s64>);
|
||||||
addr_space_type["writev_u32"] = &addr_space::log_mem_write<u32>;
|
addr_space_type.set_function("readv_u64", &addr_space::log_mem_read<u64>);
|
||||||
addr_space_type["writev_i64"] = &addr_space::log_mem_write<s64>;
|
addr_space_type.set_function("writev_i8", &addr_space::log_mem_write<s8>);
|
||||||
addr_space_type["writev_u64"] = &addr_space::log_mem_write<u64>;
|
addr_space_type.set_function("writev_u8", &addr_space::log_mem_write<u8>);
|
||||||
addr_space_type["read_direct_i8"] = &addr_space::direct_mem_read<s8>;
|
addr_space_type.set_function("writev_i16", &addr_space::log_mem_write<s16>);
|
||||||
addr_space_type["read_direct_u8"] = &addr_space::direct_mem_read<u8>;
|
addr_space_type.set_function("writev_u16", &addr_space::log_mem_write<u16>);
|
||||||
addr_space_type["read_direct_i16"] = &addr_space::direct_mem_read<s16>;
|
addr_space_type.set_function("writev_i32", &addr_space::log_mem_write<s32>);
|
||||||
addr_space_type["read_direct_u16"] = &addr_space::direct_mem_read<u16>;
|
addr_space_type.set_function("writev_u32", &addr_space::log_mem_write<u32>);
|
||||||
addr_space_type["read_direct_i32"] = &addr_space::direct_mem_read<s32>;
|
addr_space_type.set_function("writev_i64", &addr_space::log_mem_write<s64>);
|
||||||
addr_space_type["read_direct_u32"] = &addr_space::direct_mem_read<u32>;
|
addr_space_type.set_function("writev_u64", &addr_space::log_mem_write<u64>);
|
||||||
addr_space_type["read_direct_i64"] = &addr_space::direct_mem_read<s64>;
|
addr_space_type.set_function("read_direct_i8", &addr_space::direct_mem_read<s8>);
|
||||||
addr_space_type["read_direct_u64"] = &addr_space::direct_mem_read<u64>;
|
addr_space_type.set_function("read_direct_u8", &addr_space::direct_mem_read<u8>);
|
||||||
addr_space_type["write_direct_i8"] = &addr_space::direct_mem_write<s8>;
|
addr_space_type.set_function("read_direct_i16", &addr_space::direct_mem_read<s16>);
|
||||||
addr_space_type["write_direct_u8"] = &addr_space::direct_mem_write<u8>;
|
addr_space_type.set_function("read_direct_u16", &addr_space::direct_mem_read<u16>);
|
||||||
addr_space_type["write_direct_i16"] = &addr_space::direct_mem_write<s16>;
|
addr_space_type.set_function("read_direct_i32", &addr_space::direct_mem_read<s32>);
|
||||||
addr_space_type["write_direct_u16"] = &addr_space::direct_mem_write<u16>;
|
addr_space_type.set_function("read_direct_u32", &addr_space::direct_mem_read<u32>);
|
||||||
addr_space_type["write_direct_i32"] = &addr_space::direct_mem_write<s32>;
|
addr_space_type.set_function("read_direct_i64", &addr_space::direct_mem_read<s64>);
|
||||||
addr_space_type["write_direct_u32"] = &addr_space::direct_mem_write<u32>;
|
addr_space_type.set_function("read_direct_u64", &addr_space::direct_mem_read<u64>);
|
||||||
addr_space_type["write_direct_i64"] = &addr_space::direct_mem_write<s64>;
|
addr_space_type.set_function("write_direct_i8", &addr_space::direct_mem_write<s8>);
|
||||||
addr_space_type["write_direct_u64"] = &addr_space::direct_mem_write<u64>;
|
addr_space_type.set_function("write_direct_u8", &addr_space::direct_mem_write<u8>);
|
||||||
addr_space_type["read_range"] =
|
addr_space_type.set_function("write_direct_i16", &addr_space::direct_mem_write<s16>);
|
||||||
|
addr_space_type.set_function("write_direct_u16", &addr_space::direct_mem_write<u16>);
|
||||||
|
addr_space_type.set_function("write_direct_i32", &addr_space::direct_mem_write<s32>);
|
||||||
|
addr_space_type.set_function("write_direct_u32", &addr_space::direct_mem_write<u32>);
|
||||||
|
addr_space_type.set_function("write_direct_i64", &addr_space::direct_mem_write<s64>);
|
||||||
|
addr_space_type.set_function("write_direct_u64", &addr_space::direct_mem_write<u64>);
|
||||||
|
addr_space_type.set_function("read_range",
|
||||||
[] (addr_space &sp, sol::this_state s, u64 first, u64 last, int width, sol::object opt_step) -> sol::object
|
[] (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;
|
u64 step = 1;
|
||||||
if (opt_step.is<u64>())
|
if (opt_step.is<u64>())
|
||||||
{
|
{
|
||||||
step = opt_step.as<u64>();
|
step = opt_step.as<u64>();
|
||||||
if (step < 1 || step > last - first)
|
if ((step < 1) || (step > last - first))
|
||||||
{
|
{
|
||||||
luaL_error(L, "Invalid step");
|
luaL_error(s, "Invalid step");
|
||||||
return sol::lua_nil;
|
return sol::lua_nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (first > space_size || last > space_size || last < first)
|
|
||||||
|
offs_t space_size = sp.space.addrmask();
|
||||||
|
if ((first > space_size) || (last > space_size) || (last < first))
|
||||||
{
|
{
|
||||||
luaL_error(L, "Invalid offset");
|
luaL_error(s, "Invalid offset");
|
||||||
return sol::lua_nil;
|
return sol::lua_nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
luaL_Buffer buff;
|
||||||
int byte_count = width / 8 * (last - first + 1) / step;
|
int byte_count = width / 8 * (last - first + 1) / step;
|
||||||
switch (width)
|
switch (width)
|
||||||
{
|
{
|
||||||
case 8:
|
case 8:
|
||||||
{
|
{
|
||||||
u8 *dest = (u8 *)luaL_buffinitsize(L, &buff, byte_count);
|
u8 *dest = (u8 *)luaL_buffinitsize(s, &buff, byte_count);
|
||||||
for ( ; first <= last; first += step)
|
for ( ; first <= last; first += step)
|
||||||
*dest++ = sp.mem_read<u8>(first);
|
*dest++ = sp.mem_read<u8>(first);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 16:
|
case 16:
|
||||||
{
|
{
|
||||||
u16 *dest = (u16 *)luaL_buffinitsize(L, &buff, byte_count);
|
u16 *dest = (u16 *)luaL_buffinitsize(s, &buff, byte_count);
|
||||||
for ( ; first <= last; first += step)
|
for ( ; first <= last; first += step)
|
||||||
*dest++ = sp.mem_read<u16>(first);
|
*dest++ = sp.mem_read<u16>(first);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 32:
|
case 32:
|
||||||
{
|
{
|
||||||
u32 *dest = (u32 *)luaL_buffinitsize(L, &buff, byte_count);
|
u32 *dest = (u32 *)luaL_buffinitsize(s, &buff, byte_count);
|
||||||
for( ; first <= last; first += step)
|
for( ; first <= last; first += step)
|
||||||
*dest++ = sp.mem_read<u32>(first);
|
*dest++ = sp.mem_read<u32>(first);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 64:
|
case 64:
|
||||||
{
|
{
|
||||||
u64 *dest = (u64 *)luaL_buffinitsize(L, &buff, byte_count);
|
u64 *dest = (u64 *)luaL_buffinitsize(s, &buff, byte_count);
|
||||||
for( ; first <= last; first += step)
|
for( ; first <= last; first += step)
|
||||||
*dest++ = sp.mem_read<u64>(first);
|
*dest++ = sp.mem_read<u64>(first);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
luaL_error(L, "Invalid width. Must be 8/16/32/64");
|
luaL_error(s, "Invalid width. Must be 8/16/32/64");
|
||||||
return sol::lua_nil;
|
return sol::lua_nil;
|
||||||
}
|
}
|
||||||
luaL_pushresultsize(&buff, byte_count);
|
luaL_pushresultsize(&buff, byte_count);
|
||||||
return sol::make_reference(L, sol::stack_reference(L, -1));
|
return sol::make_reference(s, sol::stack_reference(s, -1));
|
||||||
};
|
});
|
||||||
addr_space_type["add_change_notifier"] =
|
addr_space_type.set_function("add_change_notifier",
|
||||||
[this] (addr_space &sp, sol::protected_function &&cb)
|
[] (addr_space &sp, sol::protected_function &&cb)
|
||||||
{
|
{
|
||||||
return sp.space.add_change_notifier(
|
return sp.space.add_change_notifier(
|
||||||
[this, callback = std::move(cb)] (read_or_write mode)
|
[callback = std::move(cb)] (read_or_write mode)
|
||||||
{
|
{
|
||||||
char const *modestr = "";
|
char const *modestr = "";
|
||||||
switch (mode)
|
switch (mode)
|
||||||
@ -653,17 +657,17 @@ void lua_engine::initialize_memory(sol::table &emu)
|
|||||||
}
|
}
|
||||||
invoke(callback, modestr);
|
invoke(callback, modestr);
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
addr_space_type["install_read_tap"] =
|
addr_space_type.set_function("install_read_tap",
|
||||||
[this] (addr_space &sp, offs_t start, offs_t end, std::string &&name, sol::protected_function &&cb)
|
[] (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));
|
return std::make_unique<tap_helper>(sp.space, read_or_write::READ, start, end, std::move(name), std::move(cb));
|
||||||
};
|
});
|
||||||
addr_space_type["install_write_tap"] =
|
addr_space_type.set_function("install_write_tap",
|
||||||
[this] (addr_space &sp, offs_t start, offs_t end, std::string &&name, sol::protected_function &&cb)
|
[] (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));
|
return std::make_unique<tap_helper>(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["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["shift"] = sol::property([] (addr_space &sp) { return sp.space.addr_shift(); });
|
||||||
addr_space_type["index"] = sol::property([] (addr_space &sp) { return sp.space.spacenum(); });
|
addr_space_type["index"] = sol::property([] (addr_space &sp) { return sp.space.spacenum(); });
|
||||||
@ -674,8 +678,8 @@ void lua_engine::initialize_memory(sol::table &emu)
|
|||||||
|
|
||||||
|
|
||||||
auto tap_type = sol().registry().new_usertype<tap_helper>("mempassthrough", sol::no_constructor);
|
auto tap_type = sol().registry().new_usertype<tap_helper>("mempassthrough", sol::no_constructor);
|
||||||
tap_type["reinstall"] = &tap_helper::reinstall;
|
tap_type.set_function("reinstall", &tap_helper::reinstall);
|
||||||
tap_type["remove"] = &tap_helper::remove;
|
tap_type.set_function("remove", &tap_helper::remove);
|
||||||
tap_type["addrstart"] = sol::property(&tap_helper::start);
|
tap_type["addrstart"] = sol::property(&tap_helper::start);
|
||||||
tap_type["addrend"] = sol::property(&tap_helper::end);
|
tap_type["addrend"] = sol::property(&tap_helper::end);
|
||||||
tap_type["name"] = sol::property(&tap_helper::name);
|
tap_type["name"] = sol::property(&tap_helper::name);
|
||||||
@ -722,22 +726,22 @@ void lua_engine::initialize_memory(sol::table &emu)
|
|||||||
|
|
||||||
|
|
||||||
auto region_type = sol().registry().new_usertype<memory_region>("region", sol::no_constructor);
|
auto region_type = sol().registry().new_usertype<memory_region>("region", sol::no_constructor);
|
||||||
region_type["read_i8"] = ®ion_read<s8>;
|
region_type.set_function("read_i8", ®ion_read<s8>);
|
||||||
region_type["read_u8"] = ®ion_read<u8>;
|
region_type.set_function("read_u8", ®ion_read<u8>);
|
||||||
region_type["read_i16"] = ®ion_read<s16>;
|
region_type.set_function("read_i16", ®ion_read<s16>);
|
||||||
region_type["read_u16"] = ®ion_read<u16>;
|
region_type.set_function("read_u16", ®ion_read<u16>);
|
||||||
region_type["read_i32"] = ®ion_read<s32>;
|
region_type.set_function("read_i32", ®ion_read<s32>);
|
||||||
region_type["read_u32"] = ®ion_read<u32>;
|
region_type.set_function("read_u32", ®ion_read<u32>);
|
||||||
region_type["read_i64"] = ®ion_read<s64>;
|
region_type.set_function("read_i64", ®ion_read<s64>);
|
||||||
region_type["read_u64"] = ®ion_read<u64>;
|
region_type.set_function("read_u64", ®ion_read<u64>);
|
||||||
region_type["write_i8"] = ®ion_write<s8>;
|
region_type.set_function("write_i8", ®ion_write<s8>);
|
||||||
region_type["write_u8"] = ®ion_write<u8>;
|
region_type.set_function("write_u8", ®ion_write<u8>);
|
||||||
region_type["write_i16"] = ®ion_write<s16>;
|
region_type.set_function("write_i16", ®ion_write<s16>);
|
||||||
region_type["write_u16"] = ®ion_write<u16>;
|
region_type.set_function("write_u16", ®ion_write<u16>);
|
||||||
region_type["write_i32"] = ®ion_write<s32>;
|
region_type.set_function("write_i32", ®ion_write<s32>);
|
||||||
region_type["write_u32"] = ®ion_write<u32>;
|
region_type.set_function("write_u32", ®ion_write<u32>);
|
||||||
region_type["write_i64"] = ®ion_write<s64>;
|
region_type.set_function("write_i64", ®ion_write<s64>);
|
||||||
region_type["write_u64"] = ®ion_write<u64>;
|
region_type.set_function("write_u64", ®ion_write<u64>);
|
||||||
region_type["tag"] = sol::property(&memory_region::name);
|
region_type["tag"] = sol::property(&memory_region::name);
|
||||||
region_type["size"] = sol::property(&memory_region::bytes);
|
region_type["size"] = sol::property(&memory_region::bytes);
|
||||||
region_type["length"] = sol::property([] (memory_region &r) { return r.bytes() / r.bytewidth(); });
|
region_type["length"] = sol::property([] (memory_region &r) { return r.bytes() / r.bytewidth(); });
|
||||||
@ -747,22 +751,22 @@ void lua_engine::initialize_memory(sol::table &emu)
|
|||||||
|
|
||||||
|
|
||||||
auto share_type = sol().registry().new_usertype<memory_share>("share", sol::no_constructor);
|
auto share_type = sol().registry().new_usertype<memory_share>("share", sol::no_constructor);
|
||||||
share_type["read_i8"] = &share_read<s8>;
|
share_type.set_function("read_i8", &share_read<s8>);
|
||||||
share_type["read_u8"] = &share_read<u8>;
|
share_type.set_function("read_u8", &share_read<u8>);
|
||||||
share_type["read_i16"] = &share_read<s16>;
|
share_type.set_function("read_i16", &share_read<s16>);
|
||||||
share_type["read_u16"] = &share_read<u16>;
|
share_type.set_function("read_u16", &share_read<u16>);
|
||||||
share_type["read_i32"] = &share_read<s32>;
|
share_type.set_function("read_i32", &share_read<s32>);
|
||||||
share_type["read_u32"] = &share_read<u32>;
|
share_type.set_function("read_u32", &share_read<u32>);
|
||||||
share_type["read_i64"] = &share_read<s64>;
|
share_type.set_function("read_i64", &share_read<s64>);
|
||||||
share_type["read_u64"] = &share_read<u64>;
|
share_type.set_function("read_u64", &share_read<u64>);
|
||||||
share_type["write_i8"] = &share_write<s8>;
|
share_type.set_function("write_i8", &share_write<s8>);
|
||||||
share_type["write_u8"] = &share_write<u8>;
|
share_type.set_function("write_u8", &share_write<u8>);
|
||||||
share_type["write_i16"] = &share_write<s16>;
|
share_type.set_function("write_i16", &share_write<s16>);
|
||||||
share_type["write_u16"] = &share_write<u16>;
|
share_type.set_function("write_u16", &share_write<u16>);
|
||||||
share_type["write_i32"] = &share_write<s32>;
|
share_type.set_function("write_i32", &share_write<s32>);
|
||||||
share_type["write_u32"] = &share_write<u32>;
|
share_type.set_function("write_u32", &share_write<u32>);
|
||||||
share_type["write_i64"] = &share_write<s64>;
|
share_type.set_function("write_i64", &share_write<s64>);
|
||||||
share_type["write_u64"] = &share_write<u64>;
|
share_type.set_function("write_u64", &share_write<u64>);
|
||||||
share_type["tag"] = sol::property(&memory_share::name);
|
share_type["tag"] = sol::property(&memory_share::name);
|
||||||
share_type["size"] = sol::property(&memory_share::bytes);
|
share_type["size"] = sol::property(&memory_share::bytes);
|
||||||
share_type["length"] = sol::property([] (memory_share &s) { return s.bytes() / s.bytewidth(); });
|
share_type["length"] = sol::property([] (memory_share &s) { return s.bytes() / s.bytewidth(); });
|
||||||
|
@ -203,8 +203,29 @@ void mame_machine_manager::start_luaengine()
|
|||||||
if (!filerr)
|
if (!filerr)
|
||||||
{
|
{
|
||||||
std::string exppath;
|
std::string exppath;
|
||||||
osd_subst_env(exppath, std::string(file.fullpath()));
|
osd_subst_env(exppath, file.fullpath());
|
||||||
m_lua->load_script(exppath.c_str());
|
auto &l(*lua());
|
||||||
|
auto load_result = l.load_script(exppath);
|
||||||
|
if (!load_result.valid())
|
||||||
|
{
|
||||||
|
sol::error err = load_result;
|
||||||
|
sol::load_status status = load_result.status();
|
||||||
|
fatalerror("Error plugin bootstrap script %s: %s error\n%s\n",
|
||||||
|
exppath,
|
||||||
|
sol::to_string(status),
|
||||||
|
err.what());
|
||||||
|
}
|
||||||
|
sol::protected_function func = load_result;
|
||||||
|
sol::protected_function_result call_result = l.invoke(func);
|
||||||
|
if (!call_result.valid())
|
||||||
|
{
|
||||||
|
sol::error err = call_result;
|
||||||
|
sol::call_status status = call_result.status();
|
||||||
|
fatalerror("Error running plugin bootstrap script %s: %s error\n%s\n",
|
||||||
|
options().autoboot_script(),
|
||||||
|
sol::to_string(status),
|
||||||
|
err.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,21 +316,35 @@ int mame_machine_manager::execute()
|
|||||||
|
|
||||||
TIMER_CALLBACK_MEMBER(mame_machine_manager::autoboot_callback)
|
TIMER_CALLBACK_MEMBER(mame_machine_manager::autoboot_callback)
|
||||||
{
|
{
|
||||||
if (strlen(options().autoboot_script())!=0) {
|
if (*options().autoboot_script())
|
||||||
mame_machine_manager::instance()->lua()->load_script(options().autoboot_script());
|
{
|
||||||
|
assert(m_autoboot_script);
|
||||||
|
sol::protected_function func = *m_autoboot_script;
|
||||||
|
sol::protected_function_result result = lua()->invoke(func);
|
||||||
|
if (!result.valid())
|
||||||
|
{
|
||||||
|
sol::error err = result;
|
||||||
|
sol::call_status status = result.status();
|
||||||
|
fatalerror("Error running autoboot script %s: %s error\n%s\n",
|
||||||
|
options().autoboot_script(),
|
||||||
|
sol::to_string(status),
|
||||||
|
err.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (strlen(options().autoboot_command())!=0) {
|
else if (*options().autoboot_command())
|
||||||
std::string cmd = std::string(options().autoboot_command());
|
{
|
||||||
|
std::string cmd(options().autoboot_command());
|
||||||
strreplace(cmd, "'", "\\'");
|
strreplace(cmd, "'", "\\'");
|
||||||
std::string val = std::string("emu.keypost('").append(cmd).append("')");
|
std::string val = std::string("emu.keypost('").append(cmd).append("')");
|
||||||
mame_machine_manager::instance()->lua()->load_string(val.c_str());
|
auto &l(*lua());
|
||||||
|
l.invoke(l.load_string(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mame_machine_manager::reset()
|
void mame_machine_manager::reset()
|
||||||
{
|
{
|
||||||
// setup autoboot if needed
|
// setup autoboot if needed
|
||||||
m_autoboot_timer->adjust(attotime(options().autoboot_delay(),0),0);
|
m_autoboot_timer->adjust(attotime(options().autoboot_delay(), 0), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_manager* mame_machine_manager::create_ui(running_machine& machine)
|
ui_manager* mame_machine_manager::create_ui(running_machine& machine)
|
||||||
@ -337,7 +372,7 @@ void mame_machine_manager::before_load_settings(running_machine& machine)
|
|||||||
m_lua->on_machine_before_load_settings();
|
m_lua->on_machine_before_load_settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mame_machine_manager::create_custom(running_machine& machine)
|
void mame_machine_manager::create_custom(running_machine &machine)
|
||||||
{
|
{
|
||||||
// start the inifile manager
|
// start the inifile manager
|
||||||
m_inifile = std::make_unique<inifile_manager>(m_ui->options());
|
m_inifile = std::make_unique<inifile_manager>(m_ui->options());
|
||||||
@ -347,6 +382,25 @@ void mame_machine_manager::create_custom(running_machine& machine)
|
|||||||
|
|
||||||
// start favorite manager
|
// start favorite manager
|
||||||
m_favorite = std::make_unique<favorite_manager>(m_ui->options());
|
m_favorite = std::make_unique<favorite_manager>(m_ui->options());
|
||||||
|
|
||||||
|
// attempt to load the autoboot script if configured
|
||||||
|
m_autoboot_script.reset();
|
||||||
|
if (*options().autoboot_script())
|
||||||
|
{
|
||||||
|
auto result = lua()->load_script(options().autoboot_script());
|
||||||
|
if (!result.valid())
|
||||||
|
{
|
||||||
|
sol::error err = result;
|
||||||
|
sol::load_status status = result.status();
|
||||||
|
fatalerror("Error loading autoboot script %s: %s error\n%s\n",
|
||||||
|
options().autoboot_script(),
|
||||||
|
sol::to_string(status),
|
||||||
|
err.what());
|
||||||
|
}
|
||||||
|
m_autoboot_script.reset(new sol::load_result(std::move(result)));
|
||||||
|
sol::protected_function func = *m_autoboot_script;
|
||||||
|
sol::set_environment(lua()->make_environment(), func);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mame_machine_manager::load_cheatfiles(running_machine& machine)
|
void mame_machine_manager::load_cheatfiles(running_machine& machine)
|
||||||
|
@ -12,6 +12,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
namespace sol {
|
||||||
|
|
||||||
|
struct load_result;
|
||||||
|
|
||||||
|
} // namespace sol
|
||||||
|
|
||||||
class plugin_options;
|
class plugin_options;
|
||||||
class osd_interface;
|
class osd_interface;
|
||||||
|
|
||||||
@ -71,19 +77,20 @@ private:
|
|||||||
mame_machine_manager &operator=(mame_machine_manager const &) = delete;
|
mame_machine_manager &operator=(mame_machine_manager const &) = delete;
|
||||||
mame_machine_manager &operator=(mame_machine_manager &&) = delete;
|
mame_machine_manager &operator=(mame_machine_manager &&) = delete;
|
||||||
|
|
||||||
std::unique_ptr<plugin_options> m_plugins; // pointer to plugin options
|
std::unique_ptr<plugin_options> m_plugins; // pointer to plugin options
|
||||||
std::unique_ptr<lua_engine> m_lua;
|
std::unique_ptr<lua_engine> m_lua;
|
||||||
|
|
||||||
const game_driver * m_new_driver_pending; // pointer to the next pending driver
|
const game_driver * m_new_driver_pending; // pointer to the next pending driver
|
||||||
bool m_firstrun;
|
bool m_firstrun;
|
||||||
|
|
||||||
static mame_machine_manager *s_manager;
|
emu_timer * m_autoboot_timer; // auto-boot timer
|
||||||
emu_timer *m_autoboot_timer; // autoboot timer
|
std::unique_ptr<sol::load_result> m_autoboot_script; // auto-boot script
|
||||||
std::unique_ptr<mame_ui_manager> m_ui; // internal data from ui.cpp
|
std::unique_ptr<mame_ui_manager> m_ui; // internal data from ui.cpp
|
||||||
std::unique_ptr<cheat_manager> m_cheat; // internal data from cheat.cpp
|
std::unique_ptr<cheat_manager> m_cheat; // internal data from cheat.cpp
|
||||||
std::unique_ptr<inifile_manager> m_inifile; // internal data from inifile.c for INIs
|
std::unique_ptr<inifile_manager> m_inifile; // internal data from inifile.c for INIs
|
||||||
std::unique_ptr<favorite_manager> m_favorite; // internal data from inifile.c for favorites
|
std::unique_ptr<favorite_manager> m_favorite; // internal data from inifile.c for favorites
|
||||||
|
|
||||||
|
static mame_machine_manager *s_manager;
|
||||||
};
|
};
|
||||||
|
|
||||||
//**************************************************************************
|
//**************************************************************************
|
||||||
|
Loading…
Reference in New Issue
Block a user