ppsspp_read32
Read an unsigned 32-bit value from PSP memory at a specified physical address. Use for 32-bit fields like timestamps, pointers, or RGBA colors without side effects.
Instructions
PURPOSE: Read an unsigned 32-bit little-endian value from PSP memory at the given physical address. USAGE: Use for 32-bit fields — timestamps, large counters, pointers, RGBA colors. For 8/16-bit use ppsspp_read8/read16; for spans use ppsspp_read_range. BEHAVIOR: No side effects — pure read. PSP is little-endian. Returns an error if address+4 exceeds the valid memory region. RETURNS: Single line 'ADDR_HEX: VAL_DEC (0xVAL_HEX)'.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | PSP physical address. PSP memory layout: user RAM starts at 0x08800000 (or 0x08000000 — varies by firmware allocation), kernel RAM at 0x08000000-0x087FFFFF, VRAM at 0x04000000-0x041FFFFF, scratchpad at 0x00010000-0x00013FFF, hardware regs at 0xBC000000+. Most game state lives in user RAM. Note PPSSPP may also accept 0x88xxxxxx kernel-mode mirrors of the same physical memory. |
Implementation Reference
- src/tools.ts:442-445 (handler)Handler for ppsspp_read32 tool. Calls PPSSPP's `memory.read_u32` RPC with the provided address parameter and formats the result as a hex string.
case "ppsspp_read32": { const r = await pp.call<{ value: number }>("memory.read_u32", { address: a() }); return ok(`${addrHex(a())}: ${fmtHex(r.value)}`); } - src/tools.ts:94-109 (schema)Schema/definition of ppsspp_read32 tool: name, description, and inputSchema requiring an integer 'address' parameter with minimum 0.
{ name: "ppsspp_read32", description: "PURPOSE: Read an unsigned 32-bit little-endian value from PSP memory at the given physical address. " + "USAGE: Use for 32-bit fields — timestamps, large counters, pointers, RGBA colors. For 8/16-bit use ppsspp_read8/read16; for spans use ppsspp_read_range. " + "BEHAVIOR: No side effects — pure read. PSP is little-endian. Returns an error if address+4 exceeds the valid memory region. " + "RETURNS: Single line 'ADDR_HEX: VAL_DEC (0xVAL_HEX)'.", inputSchema: { type: "object", required: ["address"], properties: { address: { type: "integer", minimum: 0, description: ADDRESS_PARAM_DESC }, }, additionalProperties: false, }, }, - src/ppsspp.ts:235-271 (handler)Generic PpssppClient.call() method used by the ppsspp_read32 handler to send the 'memory.read_u32' event to PPSSPP's WebSocket debugger.
async call<T extends Record<string, unknown> = Record<string, unknown>>( event: string, params: Record<string, unknown> = {}, ): Promise<T> { // Auto-(re)connect on demand. PPSSPP can be launched, closed, relaunched // at any point during the MCP server's lifetime; ensureConnected() will // bring the socket back up (or throw a clear error if PPSSPP isn't // reachable). Without this, a single failed connect at MCP boot would // leave every subsequent tool call broken until MCP-client restart. await this.ensureConnected(); return new Promise<T>((resolve, reject) => { const ticket = `t${this.nextTicket++}`; const pending: PendingCmd = { ticket, resolve: (r) => resolve(r as T), reject, }; const timer = setTimeout(() => { this.inflight.delete(ticket); reject(new Error( `PPSSPP call "${event}" timed out (${this.timeoutMs}ms) — ` + `is PPSSPP running with "Allow remote debugger" enabled?`, )); }, this.timeoutMs); const origResolve = pending.resolve, origReject = pending.reject; pending.resolve = (r) => { clearTimeout(timer); origResolve(r); }; pending.reject = (e) => { clearTimeout(timer); origReject(e); }; this.inflight.set(ticket, pending); const msg = JSON.stringify({ event, ticket, ...params }); if (process.env.MCP_PPSSPP_DEBUG) { process.stderr.write(`[trace] TX: ${msg}\n`); } this.ws!.send(msg); }); } - src/tools.ts:405-411 (registration)Registration function: registerTools() sets up the ListToolsRequestSchema (exposes the TOOLS array) and CallToolRequestSchema (routes to the switch-case handler) on the MCP server.
export function registerTools(server: Server, pp: PpssppClient): void { server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS })); server.setRequestHandler(CallToolRequestSchema, async (req) => { const { name, arguments: args = {} } = req.params; const p = args as Record<string, unknown>; const a = () => p.address as number; - src/index.ts:39-39 (registration)Entry point calling registerTools(server, pp) to connect the tool definitions to the MCP server.
registerTools(server, pp);