Add bounded logical Z80 disassembly to shared MCP

This commit is contained in:
Александр Петров
2026-09-17 23:11:08 +03:00
parent 113d468c48
commit 958ad0ae0f
13 changed files with 103 additions and 16 deletions
+18 -1
View File
@@ -100,7 +100,7 @@ function exports.startplugin()
instruction_step=true,step_over=true,step_out=true,
bank_guard=true,deferred_breakpoints=true,console_print=true,
shares=true,screen_pixels=true,screen_snapshot=snapdir~=nil,
program_memory=true,list_ports=true},state=state}
program_memory=true,list_ports=true,disassemble_logical=true},state=state}
elseif command=="snapshot" then
local result={state=state,time=now(),paused=machine().paused}
local screen=first_screen()
@@ -200,6 +200,23 @@ function exports.startplugin()
end
return {space="program",address=address,length=length,
hex=table.concat(bytes),generation=generation}
elseif command=="disassemble_logical" then
stopped(request)
local address=number(args.address,0xffff)
local length=number(args.length,256)
assert(length>=1 and address+length<=0x10000,
"Дизассемблирование за пределами logical Z80")
local path=directory.."/_disasm.txt"
os.remove(path) -- Не возвращать файл от прежней команды при ошибке MAME.
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"))
local output=file:read("*a")
file:close()
os.remove(path)
return {space="logical_z80",address=address,length=length,
text=output,generation=generation}
elseif command=="list_ports" then
local result={ports={},truncated=false}
local fields_seen=0
+4
View File
@@ -62,6 +62,10 @@ class McpSession:
return self.call('read_program_memory', {'address': self._address(address),
'length': length})
def disassemble_logical(self, address: str, length: int = 32):
return self.call('disassemble_logical', {'address': self._address(address),
'length': length})
def read_share(self, tag: str, address: str, length: int = 16):
return self.call('read_share', {'tag': tag, 'address': self._address(address),
'length': length})
+12 -1
View File
@@ -224,7 +224,8 @@ class SessionController:
self._emit('control', {'owner': None})
return {'released': owner}
if self.running and method in ('where', 'registers', 'read_memory',
'read_program_memory', 'read_variable',
'read_program_memory', 'disassemble_logical',
'read_variable',
'break_line', 'break_function'):
raise SessionError('Операция требует остановленного CPU; сначала Pause')
if method == 'status':
@@ -328,6 +329,16 @@ class SessionController:
result = self.session.bridge.request('program_memory',
address=address, length=length)
return {**result, 'bank_pages': mapping.bank_pages}
if method == 'disassemble_logical':
address = int(arguments['address'])
length = int(arguments['length'])
if address < 0 or address > 0xffff or length < 1 or length > 256 or \
address + length > 0x10000:
raise SessionError('Дизассемблирование: адрес 0..0xffff, длина 1..256')
mapping = self.session.refresh()
result = self.session.bridge.request('disassemble_logical',
address=address, length=length)
return {**result, 'bank_pages': mapping.bank_pages}
if method == 'variables':
return self.session.model.variables
if method == 'read_variable':
+5
View File
@@ -77,6 +77,11 @@ def make_server(client: McpSession | ManagedMcpSession,
"""Читать 1..4096 байт raw program space 0..0x3ffff; Z80 окна находятся в 0x10000+."""
return client.read_program_memory(address, length)
@tool(annotations=reading)
def disassemble_logical(address: str, length: int = 32) -> dict[str, Any]:
"""Дизассемблировать 1..256 байт текущей logical Z80 памяти при stop; ответ содержит bank_pages."""
return client.disassemble_logical(address, length)
@tool(annotations=reading)
def list_ports() -> dict[str, Any]:
"""Перечислить порты ввода MAME и поля с масками; результат ограничен по размеру."""