diff options
-rw-r--r-- | plugins/cheatfind/init.lua | 4 | ||||
-rw-r--r-- | plugins/gdbstub/init.lua | 8 | ||||
-rw-r--r-- | scripts/src/mame/frontend.lua | 1 | ||||
-rw-r--r-- | src/emu/debug/debugcpu.cpp | 3 | ||||
-rw-r--r-- | src/emu/debug/points.h | 2 | ||||
-rw-r--r-- | src/frontend/mame/luaengine.cpp | 299 | ||||
-rw-r--r-- | src/frontend/mame/luaengine.h | 1 | ||||
-rw-r--r-- | src/frontend/mame/luaengine_debug.cpp | 314 |
8 files changed, 416 insertions, 216 deletions
diff --git a/plugins/cheatfind/init.lua b/plugins/cheatfind/init.lua index 729aed26cb0..83e00e4d51a 100644 --- a/plugins/cheatfind/init.lua +++ b/plugins/cheatfind/init.lua @@ -31,7 +31,7 @@ function cheatfind.startplugin() function cheat.getram() local ram = {} for tag, device in pairs(manager:machine().devices) do - if device:shortname() == "ram" then + if device.shortname == "ram" then ram[tag] = {} ram[tag].dev = device ram[tag].size = emu.item(device.items["0/m_size"]):read(0) @@ -56,7 +56,7 @@ function cheatfind.startplugin() data.shift = space.shift end if getmetatable(space).__name:match("device_t") then - if space:shortname() == "ram" then + if space.shortname == "ram" then data.block = emu.item(space.items["0/m_pointer"]):read_block(start, size) if not data.block then return nil diff --git a/plugins/gdbstub/init.lua b/plugins/gdbstub/init.lua index e34b0dcfb5d..f2292bc0027 100644 --- a/plugins/gdbstub/init.lua +++ b/plugins/gdbstub/init.lua @@ -45,8 +45,8 @@ function gdbstub.startplugin() if not cpu then print("gdbstub: maincpu not found") end - if not regmaps[cpu:shortname()] then - print("gdbstub: no register map for cpu " .. cpu:shortname()) + if not regmaps[cpu.shortname] then + print("gdbstub: no register map for cpu " .. cpu.shortname) cpu = nil end consolelog = debugger.consolelog @@ -98,7 +98,7 @@ function gdbstub.startplugin() consolelast = #consolelog if #consolelog > last and msg:find("Stopped at", 1, true) then local point = tonumber(msg:match("Stopped at breakpoint ([0-9]+)")) - local map = regmaps[cpu:shortname()] + local map = regmaps[cpu.shortname] running = false if not point then point = tonumber(msg:match("Stopped at watchpoint ([0-9]+")) @@ -152,7 +152,7 @@ function gdbstub.startplugin() if packet then packet:gsub("}(.)", function(s) return string.char(string.byte(s) ~ 0x20) end) local cmd = packet:sub(1, 1) - local map = regmaps[cpu:shortname()] + local map = regmaps[cpu.shortname] if cmd == "g" then local regs = {} for reg, idx in pairs(map.togdb) do diff --git a/scripts/src/mame/frontend.lua b/scripts/src/mame/frontend.lua index 3fe8911b9e2..766909efc56 100644 --- a/scripts/src/mame/frontend.lua +++ b/scripts/src/mame/frontend.lua @@ -73,6 +73,7 @@ files { MAME_DIR .. "src/frontend/mame/luaengine.cpp", MAME_DIR .. "src/frontend/mame/luaengine.h", MAME_DIR .. "src/frontend/mame/luaengine.ipp", + MAME_DIR .. "src/frontend/mame/luaengine_debug.cpp", MAME_DIR .. "src/frontend/mame/luaengine_input.cpp", MAME_DIR .. "src/frontend/mame/luaengine_mem.cpp", MAME_DIR .. "src/frontend/mame/luaengine_render.cpp", diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp index 3c325d3a841..e91a7801b3c 100644 --- a/src/emu/debug/debugcpu.cpp +++ b/src/emu/debug/debugcpu.cpp @@ -1669,7 +1669,7 @@ void device_debug::breakpoint_update_flags() break; } - if ( ! ( m_flags & DEBUG_FLAG_LIVE_BP ) ) + if (!(m_flags & DEBUG_FLAG_LIVE_BP)) { // see if there are any enabled registerpoints for (debug_registerpoint &rp : *m_rplist) @@ -1677,6 +1677,7 @@ void device_debug::breakpoint_update_flags() if (rp.m_enabled) { m_flags |= DEBUG_FLAG_LIVE_BP; + break; } } } diff --git a/src/emu/debug/points.h b/src/emu/debug/points.h index 220b75728ce..84cdad7720b 100644 --- a/src/emu/debug/points.h +++ b/src/emu/debug/points.h @@ -47,7 +47,7 @@ public: const char *action() const { return m_action.c_str(); } // setters - void setEnabled(bool value) { m_enabled = value; } + void setEnabled(bool value) { m_enabled = value; } // FIXME: need to update breakpoint flags but it's a private method private: // internals diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index 48ebc897899..dd03ca08cc5 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -16,10 +16,6 @@ #include "ui/pluginopt.h" #include "ui/ui.h" -#include "debug/debugcon.h" -#include "debug/debugcpu.h" -#include "debug/points.h" -#include "debug/textbuf.h" #include "debugger.h" #include "drivenum.h" #include "emuopts.h" @@ -525,15 +521,6 @@ void lua_engine::initialize() }; - static const enum_parser<read_or_write, 4> s_read_or_write_parser = - { - { "r", read_or_write::READ }, - { "w", read_or_write::WRITE }, - { "rw", read_or_write::READWRITE }, - { "wr", read_or_write::READWRITE } - }; - - static const enum_parser<ui::text_layout::text_justify, 3> s_text_justify_parser = { { "left", ui::text_layout::LEFT }, @@ -1165,7 +1152,7 @@ void lua_engine::initialize() machine_type["logerror"] = [] (running_machine &m, const char *str) { m.logerror("[luaengine] %s\n", str); }; -/* game_driver library +/* game_driver library * * emu.driver_find(driver_name) * @@ -1191,203 +1178,90 @@ void lua_engine::initialize() * driver.is_incomplete - official system with blatantly incomplete hardware/software */ - auto game_driver_type = sol().registry().new_usertype<game_driver>("game_driver", "new", sol::no_constructor); - game_driver_type.set("source_file", sol::property([] (game_driver const &driver) { return &driver.type.source()[0]; })); - game_driver_type.set("parent", sol::readonly(&game_driver::parent)); - game_driver_type.set("name", sol::property([] (game_driver const &driver) { return &driver.name[0]; })); - game_driver_type.set("description", sol::property([] (game_driver const &driver) { return &driver.type.fullname()[0]; })); - game_driver_type.set("year", sol::readonly(&game_driver::year)); - game_driver_type.set("manufacturer", sol::readonly(&game_driver::manufacturer)); - game_driver_type.set("compatible_with", sol::readonly(&game_driver::compatible_with)); - game_driver_type.set("default_layout", sol::readonly(&game_driver::default_layout)); - game_driver_type.set("orientation", sol::property([](game_driver const &driver) { - std::string rot; - switch (driver.flags & machine_flags::MASK_ORIENTATION) - { - case machine_flags::ROT0: - rot = "rot0"; - break; - case machine_flags::ROT90: - rot = "rot90"; - break; - case machine_flags::ROT180: - rot = "rot180"; - break; - case machine_flags::ROT270: - rot = "rot270"; - break; - default: - rot = "undefined"; - break; - } - return rot; - })); - game_driver_type.set("type", sol::property([](game_driver const &driver) { - std::string type; - switch (driver.flags & machine_flags::MASK_TYPE) - { - case machine_flags::TYPE_ARCADE: - type = "arcade"; - break; - case machine_flags::TYPE_CONSOLE: - type = "console"; - break; - case machine_flags::TYPE_COMPUTER: - type = "computer"; - break; - default: - type = "other"; - break; - } - return type; - })); - game_driver_type.set("not_working", sol::property([](game_driver const &driver) { return (driver.flags & machine_flags::NOT_WORKING) > 0; })); - game_driver_type.set("supports_save", sol::property([](game_driver const &driver) { return (driver.flags & machine_flags::SUPPORTS_SAVE) > 0; })); - game_driver_type.set("no_cocktail", sol::property([](game_driver const &driver) { return (driver.flags & machine_flags::NO_COCKTAIL) > 0; })); - game_driver_type.set("is_bios_root", sol::property([](game_driver const &driver) { return (driver.flags & machine_flags::IS_BIOS_ROOT) > 0; })); - game_driver_type.set("requires_artwork", sol::property([](game_driver const &driver) { return (driver.flags & machine_flags::REQUIRES_ARTWORK) > 0; })); - game_driver_type.set("clickable_artwork", sol::property([](game_driver const &driver) { return (driver.flags & machine_flags::CLICKABLE_ARTWORK) > 0; })); - game_driver_type.set("unofficial", sol::property([](game_driver const &driver) { return (driver.flags & machine_flags::UNOFFICIAL) > 0; })); - game_driver_type.set("no_sound_hw", sol::property([](game_driver const &driver) { return (driver.flags & machine_flags::NO_SOUND_HW) > 0; })); - game_driver_type.set("mechanical", sol::property([](game_driver const &driver) { return (driver.flags & machine_flags::MECHANICAL) > 0; })); - game_driver_type.set("is_incomplete", sol::property([](game_driver const &driver) { return (driver.flags & machine_flags::IS_INCOMPLETE) > 0; } )); - - -/* debugger_manager library (requires debugger to be active) - * - * manager:machine():debugger() - * - * debugger:command(command_string) - run command_string in debugger console - * - * debugger.consolelog[] - get consolelog text buffer (wrap_textbuf) - * debugger.errorlog[] - get errorlog text buffer (wrap_textbuf) - * debugger.visible_cpu - accessor for debugger active cpu for commands, affects debug views - * debugger.execution_state - accessor for active cpu run state - */ - - struct wrap_textbuf { wrap_textbuf(const text_buffer &buf) : textbuf(buf) { } std::reference_wrapper<const text_buffer> textbuf; }; - - auto debugger_type = sol().registry().new_usertype<debugger_manager>("debugger", "new", sol::no_constructor); - debugger_type.set("command", [](debugger_manager &debug, const std::string &cmd) { debug.console().execute_command(cmd, false); }); - debugger_type.set("consolelog", sol::property([](debugger_manager &debug) { return wrap_textbuf(debug.console().get_console_textbuf()); })); - debugger_type.set("errorlog", sol::property([](debugger_manager &debug) { return wrap_textbuf(debug.console().get_errorlog_textbuf()); })); - debugger_type.set("visible_cpu", sol::property( - [](debugger_manager &debug) { debug.console().get_visible_cpu(); }, - [](debugger_manager &debug, device_t &dev) { debug.console().set_visible_cpu(&dev); })); - debugger_type.set("execution_state", sol::property( - [](debugger_manager &debug) { - return debug.cpu().is_stopped() ? "stop" : "run"; - }, - [](debugger_manager &debug, const std::string &state) { - if(state == "stop") - debug.cpu().set_execution_stopped(); - else - debug.cpu().set_execution_running(); - })); - - -/* wrap_textbuf library (requires debugger to be active) - * - * manager:machine():debugger().consolelog - * manager:machine():debugger().errorlog - * - * log[index] - get log entry - * #log - entry count - */ - - sol().registry().new_usertype<wrap_textbuf>("text_buffer", "new", sol::no_constructor, - "__metatable", [](){}, - "__newindex", [](){}, - "__index", [](wrap_textbuf &buf, int index) { return text_buffer_get_seqnum_line(buf.textbuf, index - 1); }, - "__len", [](wrap_textbuf &buf) { return text_buffer_num_lines(buf.textbuf) + text_buffer_line_index_to_seqnum(buf.textbuf, 0) - 1; }); - -/* device_debug library (requires debugger to be active) - * - * manager:machine().devices[device_tag]:debug() - * - * debug:step([opt] steps) - run cpu steps, default 1 - * debug:go() - run cpu - * debug:bpset(addr, [opt] cond, [opt] act) - set breakpoint on addr, cond and act are debugger - * expressions. returns breakpoint index - * debug:bpclr(idx) - clear break - * debug:bplist()[] - table of breakpoints (k=index, v=debug_breakpoint) - * debug:wpset(space, type, addr, len, [opt] cond, [opt] act) - set watchpoint, cond and act - * are debugger expressions. - * returns watchpoint index - * debug:wpclr(idx) - clear watch - * debug:wplist(space)[] - table of watchpoints (k=index, v=watchpoint) - */ - - auto device_debug_type = sol().registry().new_usertype<device_debug>("device_debug", "new", sol::no_constructor); - device_debug_type.set("step", [](device_debug &dev, sol::object num) { - int steps = 1; - if(num.is<int>()) - steps = num.as<int>(); - dev.single_step(steps); - }); - device_debug_type.set("go", &device_debug::go); - device_debug_type.set("bpset", [](device_debug &dev, offs_t addr, const char *cond, const char *act) { return dev.breakpoint_set(addr, cond, act); }); - device_debug_type.set("bpclr", &device_debug::breakpoint_clear); - device_debug_type.set("bplist", [this](device_debug &dev) { - sol::table table = sol().create_table(); - for(const auto &bpp : dev.breakpoint_list()) + auto game_driver_type = sol().registry().new_usertype<game_driver>("game_driver", sol::no_constructor); + game_driver_type["source_file"] = sol::property([] (game_driver const &driver) { return &driver.type.source()[0]; }); + game_driver_type["parent"] = sol::readonly(&game_driver::parent); + game_driver_type["name"] = sol::property([] (game_driver const &driver) { return &driver.name[0]; }); + game_driver_type["description"] = sol::property([] (game_driver const &driver) { return &driver.type.fullname()[0]; }); + game_driver_type["year"] = sol::readonly(&game_driver::year); + game_driver_type["manufacturer"] = sol::readonly(&game_driver::manufacturer); + game_driver_type["compatible_with"] = sol::readonly(&game_driver::compatible_with); + game_driver_type["default_layout"] = sol::readonly(&game_driver::default_layout); + game_driver_type["orientation"] = sol::property( + [] (game_driver const &driver) { - const debug_breakpoint &bpt = *bpp.second; - sol::table bp = sol().create_table(); - bp["enabled"] = bpt.enabled(); - bp["address"] = bpt.address(); - bp["condition"] = bpt.condition(); - bp["action"] = bpt.action(); - table[bpt.index()] = bp; - } - return table; - }); - device_debug_type.set("wpset", [](device_debug &dev, addr_space &sp, const std::string &type, offs_t addr, offs_t len, const char *cond, const char *act) { - read_or_write wptype = s_read_or_write_parser(type); - return dev.watchpoint_set(sp.space, wptype, addr, len, cond, act); - }); - device_debug_type.set("wpclr", &device_debug::watchpoint_clear); - device_debug_type.set("wplist", [this](device_debug &dev, addr_space &sp) { - sol::table table = sol().create_table(); - for(auto &wpp : dev.watchpoint_vector(sp.space.spacenum())) + std::string rot; + switch (driver.flags & machine_flags::MASK_ORIENTATION) + { + case machine_flags::ROT0: + rot = "rot0"; + break; + case machine_flags::ROT90: + rot = "rot90"; + break; + case machine_flags::ROT180: + rot = "rot180"; + break; + case machine_flags::ROT270: + rot = "rot270"; + break; + default: + rot = "undefined"; + break; + } + return rot; + }); + game_driver_type["type"] = sol::property( + [](game_driver const &driver) { - sol::table wp = sol().create_table(); - wp["enabled"] = wpp->enabled(); - wp["address"] = wpp->address(); - wp["length"] = wpp->length(); - switch(wpp->type()) + std::string type; + switch (driver.flags & machine_flags::MASK_TYPE) { - case read_or_write::READ: - wp["type"] = "r"; - break; - case read_or_write::WRITE: - wp["type"] = "w"; - break; - case read_or_write::READWRITE: - wp["type"] = "rw"; - break; - default: // huh? - wp["type"] = ""; - break; + case machine_flags::TYPE_ARCADE: + type = "arcade"; + break; + case machine_flags::TYPE_CONSOLE: + type = "console"; + break; + case machine_flags::TYPE_COMPUTER: + type = "computer"; + break; + default: + type = "other"; + break; } - wp["condition"] = wpp->condition(); - wp["action"] = wpp->action(); - table[wpp->index()] = wp; - } - return table; - }); - - -/* device_t library + return type; + }); + game_driver_type["not_working"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::NOT_WORKING) != 0; }); + game_driver_type["supports_save"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::SUPPORTS_SAVE) != 0; }); + game_driver_type["no_cocktail"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::NO_COCKTAIL) != 0; }); + game_driver_type["is_bios_root"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::IS_BIOS_ROOT) != 0; }); + game_driver_type["requires_artwork"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::REQUIRES_ARTWORK) != 0; }); + game_driver_type["clickable_artwork"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::CLICKABLE_ARTWORK) != 0; }); + game_driver_type["unofficial"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::UNOFFICIAL) != 0; }); + game_driver_type["no_sound_hw"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::NO_SOUND_HW) != 0; }); + game_driver_type["mechanical"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::MECHANICAL) != 0; }); + game_driver_type["is_incomplete"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::IS_INCOMPLETE) != 0; }); + + +/* device_t library * * manager:machine().devices[device_tag] * - * device:name() - device long name - * device:shortname() - device short name - * device:tag() - device tree tag - * device:owner() - device parent tag - * device:debug() - debug interface, cpus only + * device:subtag(tag) - get absolute tag relative to this device + * device:siblingtag(tag) - get absolute tag relative to this device + * device:memregion(tag) - get memory region + * device:memshare(tag) - get memory share + * device:membank(tag) - get memory bank + * device:subdevice(tag) - get subdevice + * device:siblingdevice(tag) - get sibling device + * device:debug() - debug interface, CPUs only * + * device.tag - device tree tag + * device.basetag - last component of tag ("root" for root device) + * device.name - device type full name + * device.shortname - device type short name + * device.owner - parent device (nil for root device) * device.configured - whether configuration is complete * device.started - whether the device has been started * device.spaces[] - device address spaces table (k=name, v=addr_space) @@ -1396,11 +1270,14 @@ void lua_engine::initialize() * device.roms[] - device rom entry table (k=name, v=rom_entry) */ - auto device_type = sol().registry().new_usertype<device_t>("device", "new", sol::no_constructor); - device_type["name"] = &device_t::name; - device_type["shortname"] = &device_t::shortname; - device_type["tag"] = &device_t::tag; - device_type["owner"] = &device_t::owner; + auto device_type = sol().registry().new_usertype<device_t>("device", sol::no_constructor); + device_type["subtag"] = &device_t::subtag; + device_type["siblingtag"] = &device_t::siblingtag; + device_type["memregion"] = &device_t::memregion; + device_type["memshare"] = &device_t::memshare; + device_type["membank"] = &device_t::membank; + device_type["subdevice"] = static_cast<device_t *(device_t::*)(char const *) const>(&device_t::subdevice); + device_type["siblingdevice"] = static_cast<device_t *(device_t::*)(char const *) const>(&device_t::siblingdevice); device_type["debug"] = [this] (device_t &dev) -> sol::object { @@ -1408,6 +1285,11 @@ void lua_engine::initialize() return sol::make_object(sol(), sol::lua_nil); return sol::make_object(sol(), dev.debug()); }; + device_type["tag"] = sol::property(&device_t::tag); + device_type["basetag"] = sol::property(&device_t::basetag); + device_type["name"] = sol::property(&device_t::name); + device_type["shortname"] = sol::property(&device_t::shortname); + device_type["owner"] = sol::property(&device_t::owner); device_type["configured"] = sol::property(&device_t::configured); device_type["started"] = sol::property(&device_t::started); device_type["spaces"] = sol::property( @@ -1939,6 +1821,7 @@ void lua_engine::initialize() // set up other user types + initialize_debug(); initialize_input(); initialize_memory(); initialize_render(); diff --git a/src/frontend/mame/luaengine.h b/src/frontend/mame/luaengine.h index 3053de34b7d..e479ba60646 100644 --- a/src/frontend/mame/luaengine.h +++ b/src/frontend/mame/luaengine.h @@ -169,6 +169,7 @@ private: template<typename TFunc, typename... TArgs> sol::protected_function_result invoke(TFunc &&func, TArgs&&... args); + void initialize_debug(); void initialize_input(); void initialize_memory(); void initialize_render(); diff --git a/src/frontend/mame/luaengine_debug.cpp b/src/frontend/mame/luaengine_debug.cpp new file mode 100644 index 00000000000..8fa89e23754 --- /dev/null +++ b/src/frontend/mame/luaengine_debug.cpp @@ -0,0 +1,314 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic,Luca Bruno +/*************************************************************************** + + luaengine.cpp + + Controls execution of the core MAME system. + +***************************************************************************/ + +#include "emu.h" +#include "luaengine.ipp" + +#include "debug/debugcon.h" +#include "debug/debugcpu.h" +#include "debug/debugvw.h" +#include "debug/points.h" +#include "debug/textbuf.h" +#include "debugger.h" + + +namespace { + +struct wrap_textbuf +{ + wrap_textbuf(text_buffer const &buf) : textbuf(buf) { } + + std::reference_wrapper<const text_buffer> textbuf; +}; + + +sol::object do_breakpoint_enable(lua_State *L, device_debug &dev, sol::object &index, bool enable) +{ + if (index == sol::lua_nil) + { + dev.breakpoint_enable_all(enable); + dev.device().machine().debug_view().update_all(DVT_DISASSEMBLY); + dev.device().machine().debug_view().update_all(DVT_BREAK_POINTS); + return sol::lua_nil; + } + else if (index.is<int>()) + { + bool result(dev.breakpoint_enable(index.as<int>(), enable)); + if (result) + { + dev.device().machine().debug_view().update_all(DVT_DISASSEMBLY); + dev.device().machine().debug_view().update_all(DVT_BREAK_POINTS); + } + return sol::make_object(L, result); + } + else + { + osd_printf_error("[LUA ERROR] must call bpenable with integer or nil\n"); + return sol::lua_nil; + } +} + + +sol::object do_watchpoint_enable(lua_State *L, device_debug &dev, sol::object &index, bool enable) +{ + if (index == sol::lua_nil) + { + dev.watchpoint_enable_all(enable); + dev.device().machine().debug_view().update_all(DVT_WATCH_POINTS); + return sol::lua_nil; + } + else if (index.is<int>()) + { + bool result(dev.watchpoint_enable(index.as<int>(), enable)); + if (result) + dev.device().machine().debug_view().update_all(DVT_WATCH_POINTS); + return sol::make_object(L, result); + } + else + { + osd_printf_error("[LUA ERROR] must call wpenable with integer or nil"); + return sol::lua_nil; + } +} + +} // anonymous namespace + + +void lua_engine::initialize_debug() +{ + + static const enum_parser<read_or_write, 4> s_read_or_write_parser = + { + { "r", read_or_write::READ }, + { "w", read_or_write::WRITE }, + { "rw", read_or_write::READWRITE }, + { "wr", read_or_write::READWRITE } + }; + + +/* debugger_manager library (requires debugger to be active) + * + * manager:machine():debugger() + * + * debugger:command(command_string) - run command_string in debugger console + * + * debugger.consolelog[] - get consolelog text buffer (wrap_textbuf) + * debugger.errorlog[] - get errorlog text buffer (wrap_textbuf) + * debugger.visible_cpu - accessor for debugger active cpu for commands, affects debug views + * debugger.execution_state - accessor for active cpu run state + */ + + auto debugger_type = sol().registry().new_usertype<debugger_manager>("debugger", sol::no_constructor); + debugger_type["command"] = [] (debugger_manager &debug, std::string const &cmd) { debug.console().execute_command(cmd, false); }; + debugger_type["consolelog"] = sol::property([] (debugger_manager &debug) { return wrap_textbuf(debug.console().get_console_textbuf()); }); + debugger_type["errorlog"] = sol::property([](debugger_manager &debug) { return wrap_textbuf(debug.console().get_errorlog_textbuf()); }); + debugger_type["visible_cpu"] = sol::property( + [](debugger_manager &debug) { debug.console().get_visible_cpu(); }, + [](debugger_manager &debug, device_t &dev) { debug.console().set_visible_cpu(&dev); }); + debugger_type["execution_state"] = sol::property( + [] (debugger_manager &debug) { return debug.cpu().is_stopped() ? "stop" : "run"; }, + [] (debugger_manager &debug, std::string const &state) + { + if(state == "stop") + debug.cpu().set_execution_stopped(); + else + debug.cpu().set_execution_running(); + }); + + +/* wrap_textbuf library (requires debugger to be active) + * + * manager:machine():debugger().consolelog + * manager:machine():debugger().errorlog + * + * log[index] - get log entry + * #log - entry count + */ + + sol().registry().new_usertype<wrap_textbuf>("text_buffer", "new", sol::no_constructor, + "__metatable", [](){}, + "__newindex", [](){}, + "__index", [](wrap_textbuf &buf, int index) { return text_buffer_get_seqnum_line(buf.textbuf, index - 1); }, + "__len", [](wrap_textbuf &buf) { return text_buffer_num_lines(buf.textbuf) + text_buffer_line_index_to_seqnum(buf.textbuf, 0) - 1; }); + + +/* device_debug library (requires debugger to be active) + * + * manager:machine().devices[device_tag]:debug() + * + * debug:step([opt] steps) - run cpu steps, default 1 + * debug:go() - run cpu + * debug:bpset(addr, [opt] cond, [opt] act) - set breakpoint on addr, cond and act are debugger + * expressions. returns breakpoint index + * debug:bpclr(idx) - clear breakpoint + * debug:bpenable(idx) - enable breakpoint + * debug:bpdisable(idx) - disable breakpoint + * debug:bplist()[] - table of breakpoints (k=index, v=debug_breakpoint) + * debug:wpset(space, type, addr, len, [opt] cond, [opt] act) - set watchpoint, cond and act + * are debugger expressions. + * returns watchpoint index + * debug:wpclr(idx) - clear watchpoint + * debug:wpenable(idx) - enable watchpoint + * debug:wpdisable(idx) - disable watchpoint + * debug:wplist(space)[] - table of watchpoints (k=index, v=debug_watchpoint) + */ + + auto device_debug_type = sol().registry().new_usertype<device_debug>("device_debug", sol::no_constructor); + device_debug_type["step"] = + [] (device_debug &dev, sol::object num) + { + int steps = 1; + if (num.is<int>()) + steps = num.as<int>(); + dev.single_step(steps); + }; + device_debug_type["go"] = &device_debug::go; + device_debug_type["bpset"] = + [this] (device_debug &dev, offs_t address, char const *cond, char const *act) + { + int result(dev.breakpoint_set(address, cond, act)); + dev.device().machine().debug_view().update_all(DVT_DISASSEMBLY); + dev.device().machine().debug_view().update_all(DVT_BREAK_POINTS); + return result; + }; + device_debug_type["bpclear"] = + [this] (device_debug &dev, sol::object index) -> sol::object + { + if (index == sol::lua_nil) + { + dev.breakpoint_clear_all(); + dev.device().machine().debug_view().update_all(DVT_DISASSEMBLY); + dev.device().machine().debug_view().update_all(DVT_BREAK_POINTS); + return sol::lua_nil; + } + else if (index.is<int>()) + { + bool result(dev.breakpoint_clear(index.as<int>())); + if (result) + { + dev.device().machine().debug_view().update_all(DVT_DISASSEMBLY); + dev.device().machine().debug_view().update_all(DVT_BREAK_POINTS); + } + return sol::make_object(sol(), result); + } + else + { + osd_printf_error("[LUA ERROR] must call bpclear with integer or nil"); + return sol::lua_nil; + } + }; + device_debug_type["bpenable"] = [this] (device_debug &dev, sol::object index) { return do_breakpoint_enable(sol(), dev, index, true); }; + device_debug_type["bpdisable"] = [this] (device_debug &dev, sol::object index) { return do_breakpoint_enable(sol(), dev, index, false); }; + device_debug_type["bplist"] = + [this] (device_debug &dev) + { + sol::table table = sol().create_table(); + for (auto const &bpp : dev.breakpoint_list()) + table[bpp.second->index()] = sol::make_reference(sol(), *bpp.second); + return table; + }; + device_debug_type["wpset"] = + [] (device_debug &dev, addr_space &sp, std::string const &type, offs_t addr, offs_t len, char const *cond, char const *act) + { + read_or_write wptype = s_read_or_write_parser(type); + int result(dev.watchpoint_set(sp.space, wptype, addr, len, cond, act)); + dev.device().machine().debug_view().update_all(DVT_WATCH_POINTS); + return result; + }; + device_debug_type["wpclear"] = + [this] (device_debug &dev, sol::object index) -> sol::object + { + if (index == sol::lua_nil) + { + dev.watchpoint_clear_all(); + dev.device().machine().debug_view().update_all(DVT_WATCH_POINTS); + return sol::lua_nil; + } + else if (index.is<int>()) + { + bool result(dev.watchpoint_clear(index.as<int>())); + if (result) + dev.device().machine().debug_view().update_all(DVT_WATCH_POINTS); + return sol::make_object(sol(), result); + } + else + { + osd_printf_error("[LUA ERROR] must call wpclear with integer or nil"); + return sol::lua_nil; + } + }; + device_debug_type["wpenable"] = [this] (device_debug &dev, sol::object index) { return do_watchpoint_enable(sol(), dev, index, true); }; + device_debug_type["wpdisable"] = [this] (device_debug &dev, sol::object index) { return do_watchpoint_enable(sol(), dev, index, false); }; + device_debug_type["wplist"] = + [this] (device_debug &dev, addr_space &sp) + { + sol::table table = sol().create_table(); + for (auto &wpp : dev.watchpoint_vector(sp.space.spacenum())) + table[wpp->index()] = sol::make_reference(sol(), *wpp); + return table; + }; + + +/* debug_breakpoint library (requires debugger to be active) + * + * manager:machine().devices[device_tag]:debug():bplist()[index] + * + * breakpoint.index - stable index of breakpoint + * breakpoint.enabled - whether breakpoint is enabled + * breakpoint.address - + * breakpoint.condition - + * breakpoint.action - + */ + + auto breakpoint_type = sol().registry().new_usertype<debug_breakpoint>("breakpoint", sol::no_constructor); + breakpoint_type["index"] = sol::property(&debug_breakpoint::index); + breakpoint_type["enabled"] = sol::property(&debug_breakpoint::enabled); + breakpoint_type["address"] = sol::property(&debug_breakpoint::address); + breakpoint_type["condition"] = sol::property(&debug_breakpoint::condition); + breakpoint_type["action"] = sol::property(&debug_breakpoint::action); + + +/* debug_watchpoint library (requires debugger to be active) + * + * manager:machine().devices[device_tag]:debug():wplist()[index] + * + * watchpoint.index - stable index of watchpoint + * watchpoint.enabled - whether breakpoint is enabled + * watchpoint.type - type of access to watch ("r", "w" or "rw") + * watchpoint.address - start of address range to watch + * watchpoint.length - lenght of address range to watch + * watchpoint.condition - + * watchpoint.action - + */ + + auto watchpoint_type = sol().registry().new_usertype<debug_watchpoint>("watchpoint", sol::no_constructor); + watchpoint_type["index"] = sol::property(&debug_watchpoint::index); + watchpoint_type["enabled"] = sol::property(&debug_watchpoint::enabled); + watchpoint_type["type"] = sol::property( + [] (debug_watchpoint &wp) -> char const * + { + switch (wp.type()) + { + case read_or_write::READ: + return "r"; + case read_or_write::WRITE: + return "w"; + case read_or_write::READWRITE: + return "rw"; + default: // huh? + return ""; + } + }); + watchpoint_type["address"] = sol::property(&debug_watchpoint::address); + watchpoint_type["length"] = sol::property(&debug_watchpoint::length); + watchpoint_type["condition"] = sol::property(&debug_watchpoint::condition); + watchpoint_type["action"] = sol::property(&debug_watchpoint::action); + +} |