readMemory
Read raw memory data from the Commodore 64's address space to inspect variables, screen content, sound registers, and system memory for debugging 6502 assembly programs.
Instructions
Read memory from the C64's address space.
Returns raw bytes plus hex and ASCII representations.
C64 memory map highlights:
$0000-$00FF: Zero page (fast access, common variables)
$0100-$01FF: Stack
$0400-$07FF: Default screen RAM (1000 bytes)
$D000-$D3FF: VIC-II registers (graphics)
$D400-$D7FF: SID registers (sound)
$D800-$DBFF: Color RAM
For screen content, consider using readScreen instead for interpreted output. For sprite info, use readSprites for semantic data.
Related tools: writeMemory, readScreen, readSprites, readVicState
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | Start address (0x0000-0xFFFF) | |
| length | No | Number of bytes to read (default: 256, max: 65536) |
Implementation Reference
- src/index.ts:201-277 (registration)MCP server registration of the 'readMemory' tool, including input schema for address and optional length, and the handler function that computes end address, reads raw memory via ViceClient, formats hex dump with ASCII, and adds memory region hints.server.registerTool( "readMemory", { description: `Read memory from the C64's address space. Returns raw bytes plus hex and ASCII representations. C64 memory map highlights: - $0000-$00FF: Zero page (fast access, common variables) - $0100-$01FF: Stack - $0400-$07FF: Default screen RAM (1000 bytes) - $D000-$D3FF: VIC-II registers (graphics) - $D400-$D7FF: SID registers (sound) - $D800-$DBFF: Color RAM For screen content, consider using readScreen instead for interpreted output. For sprite info, use readSprites for semantic data. Related tools: writeMemory, readScreen, readSprites, readVicState`, inputSchema: z.object({ address: z .number() .min(0) .max(0xffff) .describe("Start address (0x0000-0xFFFF)"), length: z .number() .min(1) .max(65536) .optional() .describe("Number of bytes to read (default: 256, max: 65536)"), }), }, async (args) => { const address = args.address; const length = Math.min(args.length || 256, 65536); const endAddress = Math.min(address + length - 1, 0xffff); try { const data = await client.readMemory(address, endAddress); // Format as hex dump const hexLines: string[] = []; const asciiLines: string[] = []; for (let i = 0; i < data.length; i += 16) { const chunk = data.subarray(i, Math.min(i + 16, data.length)); const hex = Array.from(chunk) .map((b) => b.toString(16).padStart(2, "0")) .join(" "); const ascii = Array.from(chunk) .map((b) => (b >= 32 && b < 127 ? String.fromCharCode(b) : ".")) .join(""); hexLines.push( `$${(address + i).toString(16).padStart(4, "0")}: ${hex}` ); asciiLines.push(ascii); } return formatResponse({ address: { value: address, hex: `$${address.toString(16).padStart(4, "0")}`, }, length: data.length, bytes: Array.from(data), hex: hexLines.join("\n"), ascii: asciiLines.join(""), hint: getMemoryHint(address, endAddress), }); } catch (error) { return formatError(error as ViceError); } } );
- src/protocol/client.ts:380-426 (handler)Low-level ViceClient handler implementation for reading memory: validates 16-bit addresses, ensures emulation stopped, constructs VICE binary monitor MemoryGet command packet, sends over socket protocol, parses response, extracts and returns raw memory bytes as Buffer. Called by MCP tool handler.async readMemory( startAddress: number, endAddress: number, memspace: MemorySpace = MemorySpace.MainCPU ): Promise<Buffer> { // Validate addresses if (startAddress < 0 || startAddress > 0xffff) { throw this.makeError( "INVALID_ADDRESS", `Start address 0x${startAddress.toString(16)} is outside C64 memory range`, "C64 addresses are 16-bit (0x0000-0xFFFF)" ); } if (endAddress < 0 || endAddress > 0xffff) { throw this.makeError( "INVALID_ADDRESS", `End address 0x${endAddress.toString(16)} is outside C64 memory range`, "C64 addresses are 16-bit (0x0000-0xFFFF)" ); } if (startAddress > endAddress) { throw this.makeError( "INVALID_RANGE", `Start address (0x${startAddress.toString(16)}) is greater than end address (0x${endAddress.toString(16)})`, "Swap the addresses or check your range" ); } // Ensure VICE is stopped before memory read await this.ensureStopped(); // Build request per official VICE docs: // side_effects(1) + start(2) + end(2) + memspace(1) + bankId(2) = 8 bytes const body = Buffer.alloc(8); body[0] = 0; // No side effects body.writeUInt16LE(startAddress, 1); body.writeUInt16LE(endAddress, 3); body[5] = memspace; body.writeUInt16LE(0, 6); // bankId = 0 (default bank) // VICE sends MemoryGet response with type 0x01 const response = await this.sendCommand(Command.MemoryGet, body, ResponseType.MemoryGet); // Response body: length(2) + data(N) const dataLength = response.body.readUInt16LE(0); return response.body.subarray(2, 2 + dataLength); }
- src/index.ts:220-232 (schema)Zod input schema validation for 'readMemory' tool: requires start address (0-65535), optional length (1-65536, default 256).inputSchema: z.object({ address: z .number() .min(0) .max(0xffff) .describe("Start address (0x0000-0xFFFF)"), length: z .number() .min(1) .max(65536) .optional() .describe("Number of bytes to read (default: 256, max: 65536)"), }),
- src/index.ts:279-289 (helper)Helper function providing contextual hints for common C64 memory regions (zero page, stack, screen RAM, VIC/SID registers, etc.), called by readMemory handler.function getMemoryHint(start: number, end: number): string { if (start <= 0xff) return "Zero page - commonly used for variables and pointers"; if (start >= 0x100 && start <= 0x1ff) return "Stack area"; if (start >= 0x400 && end <= 0x7ff) return "Default screen RAM area"; if (start >= 0xd000 && end <= 0xd3ff) return "VIC-II registers - use readVicState for interpreted data"; if (start >= 0xd400 && end <= 0xd7ff) return "SID registers - use readSidState for interpreted data"; if (start >= 0xd800 && end <= 0xdbff) return "Color RAM"; if (start >= 0xa000 && end <= 0xbfff) return "BASIC ROM (or RAM if bank switched)"; if (start >= 0xe000 && end <= 0xffff) return "KERNAL ROM (or RAM if bank switched)"; return ""; }