Add asynchronous machine over and out to shared MCP

This commit is contained in:
Александр Петров
2026-09-17 23:32:46 +03:00
parent 259c782190
commit a8d0692eb2
15 changed files with 241 additions and 19 deletions
+5 -2
View File
@@ -168,8 +168,11 @@ function exports.startplugin()
pending={kind="step",time=now()}
cpu().debug:step(count)
elseif command=="step_over" then
local count=number(args.count or 1,64)
assert(count>=1,"over count должен быть 1..64")
pending={kind="step_over",time=now()}
machine().debugger:command("over 1")
-- В консоли MAME числа без префикса шестнадцатеричные.
machine().debugger:command("over #"..count)
elseif command=="step_out" then
pending={kind="step_out",time=now()}
machine().debugger:command("out")
@@ -210,7 +213,7 @@ function exports.startplugin()
"Дизассемблирование за пределами logical Z80")
local path=directory.."/_disasm.txt"
os.remove(path) -- Не возвращать файл от прежней команды при ошибке MAME.
machine().debugger:command(string.format("dasm %s,0x%X,%d",path,address,length))
machine().debugger:command(string.format("dasm %s,0x%X,#%d",path,address,length))
local size=lfs.attributes(path,"size")
assert(size and size>0 and size<=65536,"MAME не создал ограниченный disasm-файл")
local file=assert(io.open(path,"rb"))
+9
View File
@@ -206,6 +206,15 @@ class McpSession:
raise SessionError('Число машинных шагов должно быть 1..64')
return self.call('step', {'count': count, 'owner': self.owner})
def step_over_instruction(self, count: int = 1):
if not isinstance(count, int) or isinstance(count, bool) or count < 1 or count > 64:
raise SessionError('Число машинных шагов должно быть 1..64')
return self.call('step_over_instruction',
{'count': count, 'owner': self.owner})
def step_out_instruction(self):
return self.call('step_out_instruction', {'owner': self.owner})
def step_source(self, kind: str = 'into'):
if kind not in ('into', 'over', 'out'):
raise SessionError('kind должен быть into, over или out')
+18 -1
View File
@@ -403,6 +403,22 @@ class SessionController:
self.running = False
self._emit('stopped', {'reason': 'pause', 'location': location})
return location
if method in ('step_over_instruction', 'step_out_instruction'):
if self.running:
raise SessionError('CPU уже выполняется; сначала Pause')
command = {'step_over_instruction': 'step_over',
'step_out_instruction': 'step_out'}[method]
request_args = {}
if method != 'step_out_instruction':
count = arguments.get('count', 1)
if type(count) is not int or count < 1 or count > 64:
raise SessionError('Число машинных шагов должно быть 1..64')
request_args['count'] = count
self._control(arguments)
self.session.bridge.request(command, **request_args)
self.running = True
self._emit('continued', {'reason': command})
return {'accepted': True, 'command': command}
if method == 'step':
if self.running:
raise SessionError('CPU уже выполняется; сначала Pause')
@@ -643,7 +659,8 @@ RPC_MUTATIONS = frozenset({
'claim_control', 'renew_control', 'release_control', 'input_key',
'break_line', 'break_function', 'clear_breakpoint', 'clear_owned_breakpoints',
'set_source_breakpoints', 'set_function_breakpoints',
'continue', 'pause', 'step', 'source_step',
'continue', 'pause', 'step', 'step_over_instruction',
'step_out_instruction', 'source_step',
})
RPC_GENERATION_MUTATIONS = RPC_MUTATIONS - {
'claim_control', 'renew_control', 'release_control',
+10
View File
@@ -193,6 +193,16 @@ def make_server(client: McpSession | ManagedMcpSession,
"""Выполнить 1..64 машинных инструкций Z80 и вернуть текущую позицию."""
return client.step_instruction(count)
@tool()
def step_over_instruction(count: int = 1) -> dict[str, Any]:
"""Перешагнуть 1..64 машинных инструкций Z80 (вызовы — целиком)."""
return client.step_over_instruction(count)
@tool()
def step_out_instruction() -> dict[str, Any]:
"""Выйти из текущего машинного frame Z80; C source-step не используется."""
return client.step_out_instruction()
@tool()
def step_source(kind: str = 'into') -> dict[str, Any]:
"""Начать асинхронный C-шаг: into, over или out; результат в recent_events."""