pine_read64
Reads a 64-bit unsigned little-endian value from emulated memory, requiring 8-byte alignment. Returns result as string to maintain precision past 2^53.
Instructions
Read an unsigned 64-bit little-endian value from emulated memory. Address should be 8-byte aligned. Returned as a string to preserve precision past 2^53.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | Memory address (8-byte aligned) |
Implementation Reference
- src/tools.ts:209-209 (handler)Handler case for pine_read64: reads a 64-bit value from emulated memory via pine.read64(addr()), formats it with addrHex and fmtHex, and returns it as text.
case "pine_read64": return ok(`${addrHex(addr())}: ${fmtHex(await pine.read64(addr()))}`); - src/tools.ts:64-72 (schema)Tool schema definition for pine_read64: name, description (64-bit LE read, 8-byte aligned, returned as string for precision), and inputSchema requiring an integer 'address' property.
{ name: "pine_read64", description: "Read an unsigned 64-bit little-endian value from emulated memory. Address should be 8-byte aligned. Returned as a string to preserve precision past 2^53.", inputSchema: { type: "object", required: ["address"], properties: { address: { type: "integer", description: "Memory address (8-byte aligned)" } }, }, }, - src/tools.ts:171-249 (registration)The registerTools() function registers all tools (including pine_read64) via setRequestHandler on the MCP server using ListToolsRequestSchema and CallToolRequestSchema.
export function registerTools(server: Server, pine: PineClient): 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 addr = () => p.address as number; switch (name) { case "pine_ping": { const v = await pine.getVersion(); return ok(`OK — emulator: ${v}`); } case "pine_get_info": { const [title, id, uuid, gameVer, status] = await Promise.all([ pine.getTitle().catch(() => "(unavailable)"), pine.getId().catch(() => "(unavailable)"), pine.getUuid().catch(() => "(unavailable)"), pine.getGameVersion().catch(() => "(unavailable)"), pine.getStatus(), ]); return ok( `Title: ${title}\n` + `Serial: ${id}\n` + `Disc CRC: ${uuid}\n` + `Game version: ${gameVer}\n` + `Status: ${status}`, ); } case "pine_get_status": { return ok(`Status: ${await pine.getStatus()}`); } case "pine_read8": return ok(`${addrHex(addr())}: ${fmtHex(await pine.read8(addr()))}`); case "pine_read16": return ok(`${addrHex(addr())}: ${fmtHex(await pine.read16(addr()))}`); case "pine_read32": return ok(`${addrHex(addr())}: ${fmtHex(await pine.read32(addr()))}`); case "pine_read64": return ok(`${addrHex(addr())}: ${fmtHex(await pine.read64(addr()))}`); case "pine_write8": { await pine.write8(addr(), p.value as number); return ok(`Wrote ${fmtHex(p.value as number)} → ${addrHex(addr())}`); } case "pine_write16": { await pine.write16(addr(), p.value as number); return ok(`Wrote ${fmtHex(p.value as number)} → ${addrHex(addr())}`); } case "pine_write32": { await pine.write32(addr(), p.value as number); return ok(`Wrote ${fmtHex(p.value as number)} → ${addrHex(addr())}`); } case "pine_write64": { const v = BigInt(p.value as string); await pine.write64(addr(), v); return ok(`Wrote ${fmtHex(v)} → ${addrHex(addr())}`); } case "pine_read_range": { const bytes = await pine.readRange(p.address as number, p.length as number); const hex = Array.from(bytes) .map((b) => b.toString(16).padStart(2, "0").toUpperCase()) .join(" "); return ok(`${addrHex(p.address as number)} [${bytes.length} bytes]:\n${hex}`); } case "pine_save_state": { await pine.saveState(p.slot as number); return ok(`Save state triggered for slot ${p.slot}`); } case "pine_load_state": { await pine.loadState(p.slot as number); return ok(`Load state triggered for slot ${p.slot}`); } default: throw new Error(`Unknown tool: ${name}`); } }); - src/pine.ts:230-234 (helper)PineClient.read64() implementation: writes the address as a 32-bit LE buffer, sends Read64 opcode (0x03) over the PINE protocol, and reads the reply as a 64-bit unsigned little-endian bigint.
async read64(addr: number): Promise<bigint> { const args = Buffer.alloc(4); args.writeUInt32LE(addr, 0); const r = await this.call(Op.Read64, args); return r.readBigUInt64LE(0); } - src/tools.ts:163-165 (helper)fmtHex helper: formats a number or bigint as 'decimal (0xHEX)'. Used by the pine_read64 handler to display the 64-bit value in both decimal and hex.
function fmtHex(n: number | bigint): string { return `${n} (0x${n.toString(16).toUpperCase()})`; }