mirror of
https://github.com/holub/mame
synced 2025-04-19 15:11:37 +03:00
luaengine: debugger_manager support [Carl]
This commit is contained in:
parent
90abd22229
commit
81079946a4
34
3rdparty/linenoise/linenoise.c
vendored
34
3rdparty/linenoise/linenoise.c
vendored
@ -160,6 +160,7 @@ static int history_len = 0;
|
||||
static char **history = NULL;
|
||||
static char preload_buf[LINENOISE_MAX_LINE];
|
||||
static int preload = 0;
|
||||
static int refresh = 0;
|
||||
|
||||
/* Structure to contain the status of the current (being edited) line */
|
||||
struct current {
|
||||
@ -184,6 +185,7 @@ struct current {
|
||||
|
||||
static int fd_read(struct current *current);
|
||||
static int getWindowSize(struct current *current);
|
||||
static void refreshLine(const char *prompt, struct current *current);
|
||||
|
||||
void linenoiseHistoryFree(void) {
|
||||
if (history) {
|
||||
@ -408,6 +410,23 @@ static int fd_read_char(int fd, int timeout)
|
||||
*/
|
||||
static int fd_read(struct current *current)
|
||||
{
|
||||
struct pollfd p;
|
||||
int ret;
|
||||
p.fd = current->fd;
|
||||
p.events = POLLIN;
|
||||
while(1) {
|
||||
ret = poll(&p, 1, 100);
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
else if (!ret) {
|
||||
if (!refresh)
|
||||
continue;
|
||||
refresh = 0;
|
||||
refreshLine(current->prompt, current);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
#ifdef USE_UTF8
|
||||
char buf[4];
|
||||
int n;
|
||||
@ -799,7 +818,15 @@ static int fd_read(struct current *current)
|
||||
while (1) {
|
||||
INPUT_RECORD irec;
|
||||
DWORD n;
|
||||
if (WaitForSingleObject(current->inh, INFINITE) != WAIT_OBJECT_0) {
|
||||
DWORD ret = WaitForSingleObject(current->inh, 100);
|
||||
if (ret == WAIT_TIMEOUT) {
|
||||
if (!refresh)
|
||||
continue;
|
||||
refresh = 0;
|
||||
refreshLine(current->prompt, current);
|
||||
continue;
|
||||
}
|
||||
else if (ret != WAIT_OBJECT_0) {
|
||||
break;
|
||||
}
|
||||
if (!ReadConsoleInput (current->inh, &irec, 1, &n)) {
|
||||
@ -1580,6 +1607,11 @@ void linenoisePreloadBuffer(const char* preloadText)
|
||||
strcpy(preload_buf, preloadText);
|
||||
}
|
||||
|
||||
void linenoiseRefresh(void)
|
||||
{
|
||||
refresh = 1;
|
||||
}
|
||||
|
||||
char *linenoise(const char *prompt)
|
||||
{
|
||||
int count;
|
||||
|
2
3rdparty/linenoise/linenoise.h
vendored
2
3rdparty/linenoise/linenoise.h
vendored
@ -125,4 +125,6 @@ int linenoiseColumns(void);
|
||||
|
||||
void linenoisePreloadBuffer(const char* preloadText);
|
||||
|
||||
void linenoiseRefresh(void);
|
||||
|
||||
#endif /* __LINENOISE_H */
|
||||
|
7
3rdparty/lua-linenoise/linenoise.c
vendored
7
3rdparty/lua-linenoise/linenoise.c
vendored
@ -169,6 +169,12 @@ static int l_addcompletion(lua_State *L)
|
||||
return handle_ln_ok(L);
|
||||
}
|
||||
|
||||
static int l_refresh(lua_State *L)
|
||||
{
|
||||
linenoiseRefresh();
|
||||
return handle_ln_ok(L);
|
||||
}
|
||||
|
||||
luaL_Reg linenoise_funcs[] = {
|
||||
{ "linenoise", l_linenoise },
|
||||
{ "historyadd", l_historyadd },
|
||||
@ -179,6 +185,7 @@ luaL_Reg linenoise_funcs[] = {
|
||||
{ "setcompletion", l_setcompletion},
|
||||
{ "addcompletion", l_addcompletion },
|
||||
{ "preload", l_preloadbuffer },
|
||||
{ "refresh", l_refresh },
|
||||
|
||||
/* Aliases for more consistent function names */
|
||||
{ "addhistory", l_historyadd },
|
||||
|
@ -16,6 +16,8 @@ function console.startplugin()
|
||||
local ln = require("linenoise")
|
||||
local preload = false
|
||||
local matches = {}
|
||||
local lastindex = 0
|
||||
local consolebuf
|
||||
print(" _/ _/ _/_/ _/ _/ _/_/_/_/");
|
||||
print(" _/_/ _/_/ _/ _/ _/_/ _/_/ _/ ");
|
||||
print(" _/ _/ _/ _/_/_/_/ _/ _/ _/ _/_/_/ ");
|
||||
@ -197,7 +199,25 @@ return ln.linenoise('\x1b[1;36m[MAME]\x1b[0m> ')
|
||||
return "\x01" .. "-1"
|
||||
end
|
||||
|
||||
emu.register_start(function()
|
||||
if not consolebuf and manager:machine():debugger() then
|
||||
consolebuf = manager:machine():debugger().consolelog
|
||||
lastindex = 0
|
||||
end
|
||||
end)
|
||||
|
||||
emu.register_stop(function() consolebuf = nil end)
|
||||
|
||||
emu.register_periodic(function()
|
||||
if consolebuf and (#consolebuf > lastindex) then
|
||||
local last = #consolebuf
|
||||
print("\n")
|
||||
while lastindex < last do
|
||||
lastindex = lastindex + 1
|
||||
print(consolebuf[lastindex])
|
||||
end
|
||||
ln.refresh()
|
||||
end
|
||||
if conth.yield then
|
||||
conth:continue(get_completions(conth.result:match("([^\x01]*)\x01(.*)")))
|
||||
return
|
||||
|
@ -12,6 +12,10 @@
|
||||
#include <lua.hpp>
|
||||
#include "emu.h"
|
||||
#include "mame.h"
|
||||
#include "debugger.h"
|
||||
#include "debug/debugcon.h"
|
||||
#include "debug/debugcpu.h"
|
||||
#include "debug/textbuf.h"
|
||||
#include "drivenum.h"
|
||||
#include "emuopts.h"
|
||||
#include "ui/ui.h"
|
||||
@ -1133,9 +1137,9 @@ void lua_engine::initialize()
|
||||
* machine:input() - get input_manager
|
||||
* machine:uiinput() - get ui_input_manager
|
||||
* machine.paused - get paused state
|
||||
* machine.devices - get device table
|
||||
* machine.screens - get screens table
|
||||
* machine.images - get available image devices
|
||||
* machine.devices[] - get device table
|
||||
* machine.screens[] - get screens table
|
||||
* machine.images[] - get available image devices
|
||||
* machine:popmessage(str) - print str as popup
|
||||
* machine:logerror(str) - print str to log
|
||||
*/
|
||||
@ -1156,6 +1160,11 @@ void lua_engine::initialize()
|
||||
"outputs", &running_machine::output,
|
||||
"input", &running_machine::input,
|
||||
"uiinput", &running_machine::ui_input,
|
||||
"debugger", [this](running_machine &m) -> sol::object {
|
||||
if(!(m.debug_flags & DEBUG_FLAG_ENABLED))
|
||||
return sol::make_object(sol(), sol::nil);
|
||||
return sol::make_object(sol(), &m.debugger());
|
||||
},
|
||||
"paused", sol::property(&running_machine::paused),
|
||||
"devices", sol::property([this](running_machine &m) {
|
||||
std::function<void(device_t &, sol::table)> tree;
|
||||
@ -1209,11 +1218,124 @@ void lua_engine::initialize()
|
||||
"compatible_with", sol::readonly(&game_driver::compatible_with),
|
||||
"default_layout", sol::readonly(&game_driver::default_layout));
|
||||
|
||||
/* machine:debugger()
|
||||
* debug:command(cmd) - run cmd in debugger console
|
||||
* debug.consolelog[] - get consolelog
|
||||
* debug.errorlog[] - get errorlog
|
||||
* debug.visible_cpu - accessor for debugger active cpu for commands, affects debug views
|
||||
* debug.execution_state - accessor for active cpu run state
|
||||
*/
|
||||
|
||||
struct wrap_textbuf { wrap_textbuf(text_buffer *buf) { textbuf = buf; }; text_buffer *textbuf; };
|
||||
|
||||
sol().registry().new_usertype<debugger_manager>("debugger", "new", sol::no_constructor,
|
||||
"command", [](debugger_manager &debug, const std::string &cmd) { debug.console().execute_command(cmd, false); },
|
||||
"consolelog", sol::property([](debugger_manager &debug) { return wrap_textbuf(debug.console().get_console_textbuf()); }),
|
||||
"errorlog", sol::property([](debugger_manager &debug) { return wrap_textbuf(debug.console().get_errorlog_textbuf()); }),
|
||||
"visible_cpu", sol::property([](debugger_manager &debug) { debug.cpu().get_visible_cpu(); },
|
||||
[](debugger_manager &debug, device_t &dev) { debug.cpu().set_visible_cpu(&dev); }),
|
||||
"execution_state", sol::property([](debugger_manager &debug) {
|
||||
int execstate = debug.cpu().execution_state();
|
||||
if(execstate == 0)
|
||||
return "stop";
|
||||
return "running";
|
||||
},
|
||||
[](debugger_manager &debug, const std::string &state) {
|
||||
int execstate = 1;
|
||||
if(state == "stop")
|
||||
execstate = 0;
|
||||
debug.cpu().set_execution_state(execstate);
|
||||
}));
|
||||
|
||||
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()
|
||||
* debug:step([opt] steps) - run cpu steps, default 1
|
||||
* debug:go() - run cpu
|
||||
* debug:bpset(addr, cond, act) - set break, cond and act are debugger expressions
|
||||
* debug:bpclr(idx) - clear break
|
||||
* debug:bplist()[] - table of breakpoints
|
||||
* debug:wpset(space, type, addr, len, cond, act) - set watch, cond and act are debugger expressions
|
||||
* debug:wpclr(idx) - clear watch
|
||||
* debug:wplist(space)[] - table of watchpoints
|
||||
*/
|
||||
sol().registry().new_usertype<device_debug>("device_debug", "new", sol::no_constructor,
|
||||
"step", [this](device_debug &dev, sol::object num) {
|
||||
int steps = 1;
|
||||
if(num.is<int>())
|
||||
steps = num.as<int>();
|
||||
dev.single_step(steps);
|
||||
},
|
||||
"go", &device_debug::go,
|
||||
"bpset", [](device_debug &dev, offs_t addr, const char *cond, const char *act) { return dev.breakpoint_set(addr, cond, act); },
|
||||
"bpclr", &device_debug::breakpoint_clear,
|
||||
"bplist", [this](device_debug &dev) {
|
||||
sol::table table = sol().create_table();
|
||||
device_debug::breakpoint *list = dev.breakpoint_first();
|
||||
while(list)
|
||||
{
|
||||
sol::table bp = sol().create_table();
|
||||
bp["enabled"] = list->enabled();
|
||||
bp["address"] = list->address();
|
||||
bp["condition"] = list->condition();
|
||||
bp["action"] = list->action();
|
||||
table[list->index()] = bp;
|
||||
list = list->next();
|
||||
}
|
||||
return table;
|
||||
},
|
||||
"wpset", [](device_debug &dev, addr_space &sp, const std::string &type, offs_t addr, offs_t len, const char *cond, const char *act) {
|
||||
int wptype = WATCHPOINT_READ;
|
||||
if(type == "w")
|
||||
wptype = WATCHPOINT_WRITE;
|
||||
else if((type == "rw") || (type == "wr"))
|
||||
wptype = WATCHPOINT_READ | WATCHPOINT_WRITE;
|
||||
return dev.watchpoint_set(sp.space, wptype, addr, len, cond, act);
|
||||
},
|
||||
"wpclr", &device_debug::watchpoint_clear,
|
||||
"wplist", [this](device_debug &dev, addr_space &sp) {
|
||||
sol::table table = sol().create_table();
|
||||
device_debug::watchpoint *list = dev.watchpoint_first(sp.space.spacenum());
|
||||
while(list)
|
||||
{
|
||||
sol::table wp = sol().create_table();
|
||||
wp["enabled"] = list->enabled();
|
||||
wp["address"] = list->address();
|
||||
wp["length"] = list->length();
|
||||
switch(list->type())
|
||||
{
|
||||
case WATCHPOINT_READ:
|
||||
wp["type"] = "r";
|
||||
break;
|
||||
case WATCHPOINT_WRITE:
|
||||
wp["type"] = "w";
|
||||
break;
|
||||
case WATCHPOINT_READ | WATCHPOINT_WRITE:
|
||||
wp["type"] = "rw";
|
||||
break;
|
||||
default: // huh?
|
||||
wp["type"] = "";
|
||||
break;
|
||||
}
|
||||
wp["condition"] = list->condition();
|
||||
wp["action"] = list->action();
|
||||
table[list->index()] = wp;
|
||||
list = list->next();
|
||||
}
|
||||
return table;
|
||||
});
|
||||
|
||||
|
||||
/* 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.spaces[] - device address spaces table
|
||||
* device.state[] - device state entries table
|
||||
* device.items[] - device save state items table
|
||||
@ -1224,6 +1346,11 @@ void lua_engine::initialize()
|
||||
"shortname", &device_t::shortname,
|
||||
"tag", &device_t::tag,
|
||||
"owner", &device_t::owner,
|
||||
"debug", [this](device_t &dev) -> sol::object {
|
||||
if(!(dev.machine().debug_flags & DEBUG_FLAG_ENABLED) || !dynamic_cast<cpu_device *>(&dev)) // debugger not enabled or not cpu
|
||||
return sol::make_object(sol(), sol::nil);
|
||||
return sol::make_object(sol(), dev.debug());
|
||||
},
|
||||
"spaces", sol::property([this](device_t &dev) {
|
||||
device_memory_interface *memdev = dynamic_cast<device_memory_interface *>(&dev);
|
||||
sol::table sp_table = sol().create_table();
|
||||
|
Loading…
Reference in New Issue
Block a user