Amstrad CPC Debug — Emulator Interface Specification (inspired from Lone’s work for SugarBOX)The reference implementation is DebugServer.cpp in SugarboxV2. Using WEB API with ACE-DL, new command line optionsenable WEB API with command line ( -enable_webapi ) port may be changed via command line ( -web_port port) disable main window decoration ( -borderless ) Transport
The extension serialises all commands through an internal queue: only one command is in-flight at a time. The emulator must reply to each command before the next one is sent. Commands are processed each 1/50s or as fast as possible when Emulator is paused Command format{ "cmd": "<command_name>", ... }
Fields beyond cmd are command-specific. Response formatA response is any JSON object that does not have "type": "event". The extension reads it as the answer to the currently in-flight command. Error response (optional convention): json { "error": "<human-readable message>" } Event format{ "type": "event", "event": "<event_name>", "body": { ... } }
Events can be sent at any time, independently of the command queue. The extension routes them to the appropriate handler without blocking pending commands. CommandsCore commandsgetStatusReturns all Z80 registers as a flat object. Used to populate the Variables panel. Request: json { "cmd": "getStatus" } Response: ```json { “running”:true, “z80”: { “registers”: { “AF”:11564 ,“BC”:57246 ,“DE”:62977 ,“HL”:64504 ,“AF'”:0 ,“BC'”:65526 ,“DE'”:25612 ,“HL'”:41422, “PC'”:64504 ,“SP'”:49146, “IX”:48203 ,“IY”:48932, “I”:184 ,“R”:245,“WZ”:64504 }, “states”: { “IM”:2 ,“cycleCount”:4 , “nmiIssued”:false } }, “crtc”: { “type”:3, “registers”: { “regSelect”:13,“R0”:63, “R1”:49, “R2”:51, “R3”:140, “R4”:38, “R5”:0, “R6”:32, “R7”:34, “R8”:0, “R9”:7, “R10”:0, “R11”:0, “R12”:19, “R13”:155,“R14”:0,“R15”:0 }, “states”: { “C0”:1, “C4”:19, “C9”:4, “C5”:0, “C3H”:0, “C3V”:0, “hSync”:false, “vSync”:false } }, “gateArray”: { “version”:2, “penSelect”:0, “ink0”:25, “ink1”:25, “ink2”:25, “ink3”:25, “ink4”:25, “ink5”:25, “ink6”:25, “ink7”:25, “ink8”:25, “ink9”:25, “ink10”:25, “ink11”:25, “ink12”:25, “ink13”:25, “ink14”:25, “ink15”:25, “ink16”:25, “currentMode”:0, “requestedMode”:0,“blanking”:false, “vSync”:false,“hSync”:false, “intLineCount”:38, “intPending”:0 }, “ay”: { “registers”: { “regSelect”:14,“R0”:113, “R1”:0, “R2”:56, “R3”:2, “R4”:142, “R5”:0, “R6”:20, “R7”:56, “R8”:11, “R9”:14, “R10”:11, “R11”:0, “R12”:0, “R13”:0,“R14”:0,“R15”:0 }, “ppi”: { “printerPortData”:0, “printerPortStrobe”:true, “ppiControl”:130, “ppiPortA”:14, “ppiPortB”:0, “ppiPortC”:74, “keyboardLine”:10, “ppiCurrentAccess”:0 } } And an optional "asic" block with all registers, status, sprites info and content
Keys are case-insensitive (the extension lowercases them internally).
#### `getEmulatorSettings`
Returns all settings available for the emulator
**Request:**
{ “cmd”: “getEmulatorSettings” } ``` Response: ```json { “status”:“ok”, “settings”:[ {“HspHighlight”:1}, {“IntHighlight”:0}, {“RealTimeGrid”:1}, {“DebugGrid”:1}, {“PlasticCover”:1} ] } Obviously there will be more settings available than this documentation
---
#### `setEmulatorSettings`
Returns all settings available for the emulator
**Request:**
{ “cmd”:“setEmulatorSetting”,“setting”:“RealTimeGrid”, “value”:1 } ``` Response: ```json { “status”:“ok”, } Obviously there will be more settings available than this documentation
---
#### `readRegisters`
Returns all Z80 registers as a flat object. Used to populate the Variables panel.
**Request:**
{ “cmd”: “readRegisters” } ``` Response: json { "AF": 4660, "BC": 1, "DE": 2, "HL": 3, "AF'": 0, "BC'": 0, "DE'": 0, "HL'": 0, "PC": 49152, "SP": 65408, "IX": 0, "IY": 0, "I": 0, "R": 0 } setRegistersWrites one or more register values. Request: json { "cmd": "setRegisters", "hl": 16384, "pc": 49152 } Register names are lowercase. Any subset of registers may be included. Supported registers are a,af,bc,de,hl,a',af',bc',de',hl',ix,iy,pc,sp,i,r. Response: json { "status": "ok" } readMemoryReads a contiguous block of memory. Request: json { "cmd": "readMemory", "address": 16384, "size": 256, "memType": "ram", "bank": -1 }
Response: json { "bytes": [0, 1, 2, 3, ...] } bytes is an array of unsigned integers (0–255), length = size. writeMemoryWrites a contiguous block of memory. Request: json { "cmd": "writeMemory", "address": 16384, "bytes": [0, 1, 2, 3] "memType": "ram", "bank": -1 } - when writing to ram, you can use absolute address and more than 64K of data
Response: json { "status": "ok" } setBreakpointsReplaces the entire breakpoint list on the emulator. Called after every change to any breakpoint (add, remove, re-apply on session start). Request: json { "cmd": "setBreakpoints", "breakpoints": [ { "address": 49152 }, { "address": 48000 }, { "FDC": "calibration" }, { "Winape": 1 }, { "Maxam": 1 }, { "badVBL": 1 }, { "int": 1 }, ] } FDC breaks available are version, specify, sensedrive, calibration,seek,senseint,getid,readdata,readdiag,write,format,scandata,status,timeout,resultread,motorchange and weak Other breakpoints available are Winape, Maxam, VBL, BadVBL, badHBL, INT (set to 1) Response: json { "status": "ok" } setBreakpointAdd a full ACE breakpoint. Existing breakpoints wont be removed, you can call setBreakpoints command with an empty array to reset everything Request: json { "cmd": "setBreakpoint", "breakpointType": "exec", "runMode": "stopper", "address": 12345, "condition": "IX = 0x100" } Request: json { "cmd": "setBreakpoint", "breakpointType": "memory", "runMode": "watcher", "accessMode" : "RW", "value": 123, "valueMask": 255, "address": 12345, "addressMask": 65535, "size": 123, "condition": "IX = 0x100" } Request: json { "cmd": "setBreakpoint", "breakpointType": "IO", "runMode": "stopper", "accessMode" : "W", "value": 123, "valueMask": 255, "address": 12345, "addressMask": 65535, "condition": "IX = 0x100" } ACE breakpoints definition : - breakpointType : exec, memory, io
Response: json { "status": "ok" } continueResume CPU execution. Request: { "cmd": "continue" } Response: { "status": "ok" } The emulator sends a stopped event when execution halts again (breakpoint, error, etc.). Note: continue is also called by the extension on disconnectRequest before closing the TCP connection, to leave the emulator running after the debug session ends. haltPause CPU execution immediately. Request: { "cmd": "halt" } Response: { "status": "ok" } step or stepOverExecute one instruction (Step Over). Handles CALL, RST, and block instructions without stepping into them. Request: { "cmd": "step" } Response: { "status": "ok" } stepInExecute one instruction (Step Into). Enters CALL and RST. Request: { "cmd": "stepIn" } Response: { "status": "ok" } stepOutRun until the current subroutine returns. Typically implemented by placing a temporary breakpoint on the return address read from the stack. Request: { "cmd": "stepOut" } Response: { "status": "ok" } reset or resetHardReset the CPU and machine to their initial state. Request: { "cmd": "reset" } Response: { "status": "ok" } resetSoftSoft reset the CPU, not memory and some hardware Request: { "cmd": "reset" } Response: { "status": "ok" } loadFileRequest: json { "cmd": "loadFile", "filename": "path to the file" } Response (success): json { "status": "ok" } getMemBanks @@TODOReturns the list of addressable memory sources, used to let the user choose which bank to disassemble. Request: { "cmd": "getMemBanks" } Response: json { "sources": [ { "type": "read", "bank": -1, "label": "READ (mapped)" }, { "type": "ram", "bank": 0, "label": "RAM bank 0" }, { "type": "ram", "bank": 1, "label": "RAM bank 1" }, { "type": "rom", "bank": 0, "label": "ROM bank 0 (BASIC)" }, { "type": "cart", "bank": 0, "label": "Cartridge bank 0" } ] } If the command is not supported, return { "error": "unknown command" }. The extension falls back to memType="read", bank=-1 silently. getScreen @@TODOReturns a single snapshot of the currently displayed CPC screen, cropped to the visible window and de-interlaced (i.e. what a real monitor would show). Request: { "cmd": "getScreen" } Response: json { "format": "png", "width": 768, "height": 544, "data": "<base64-encoded PNG bytes>" } If capture is unsupported or unavailable, return { "error": "screen capture unavailable" }. Unknown commandsReturn { "error": "unknown command" } for any unrecognised cmd. The extension checks for result?.error and handles it without throwing. ConcurrencyThe extension sends one command at a time. The emulator does not need to handle concurrent requests. However, events (stopped, mediaChanged) may arrive while a command response is being written — this is safe because the extension dispatches events independently from the command queue. |