Skip to main content
Glama

pine_write64

Atomic 64-bit write to PS2 EE memory at an 8-byte aligned address. Accepts a decimal string for values up to 2^64-1 to preserve precision.

Instructions

PURPOSE: Write an unsigned 64-bit little-endian value to EE main address space. USAGE: For true 64-bit writes — full pointers, large IDs, packed doubleword state. Atomic from the emulator's perspective; preferred over chaining two pine_write32 calls (a running game can observe the in-between state). For 8/16/32-bit values use the corresponding sibling. BEHAVIOR: DESTRUCTIVE: overwrites eight bytes from address with no undo. Direct write — bypasses TLB; writes to read-only regions silently dropped. Address MUST be 8-byte aligned. PINE on PCSX2 does NOT enforce alignment — unaligned access typically returns whatever bytes are at the aligned address below, silently corrupting the value. If you need an unaligned multi-byte read, use pine_read_range and assemble the bytes yourself. value is a DECIMAL STRING (0 through 18446744073709551615) to preserve precision past JS's 2^53 number limit. Errors on connection drop or PINE FAIL.

PlayStation 2 main address space landmarks (PCSX2): 0x00100000-0x01FFFFFF EE main RAM (32 MiB) — game code & data; the most common target 0x10000000 Hardware registers (DMA, GIF, VIF, etc.) 0x11000000 VU0 / VU1 memory 0x12000000 GS privileged registers 0x1C000000-0x1C1FFFFF IOP RAM (2 MiB) 0x1F800000 IOP scratchpad 0x70000000 EE scratchpad (16 KiB) PINE memory operations target the EE address space.

RETURNS: 'Wrote VAL_DEC (0xVAL_HEX) → ADDR_HEX' — VAL_DEC may exceed 2^53.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
addressYesAbsolute byte address in the EE main address space (NOT a per-domain offset). Pass as a number; hex literals like 0x00200000 are fine. Reads 8 consecutive bytes starting here. MUST be 8-byte aligned (address % 8 === 0). PINE on PCSX2 does NOT enforce alignment — unaligned access typically returns whatever bytes are at the aligned address below, silently corrupting the value. If you need an unaligned multi-byte read, use pine_read_range and assemble the bytes yourself. Useful range: 0x00100000-0x01FFFFFF for EE main RAM (where 99% of game state lives). An unmapped or invalid address returns a PINE FAIL response.
valueYes64-bit value to write, as a non-negative DECIMAL STRING (digits only, no '0x' prefix, no sign, no separators). Range 0 through 18446744073709551615 (2^64 - 1). Example: "18446744073709551615" writes 0xFFFFFFFFFFFFFFFF. Encoded as a string so values past 2^53 are preserved exactly (JSON numbers lose precision at that point). For signed 64-bit values, encode as two's complement (e.g. -1 → "18446744073709551615").

Implementation Reference

  • Handler case for 'pine_write64' in the CallToolRequestSchema switch: converts the string value to BigInt, calls pine.write64(), and returns a formatted success message.
    case "pine_write64": {
      const v = BigInt(p.value as string);
      await pine.write64(addr(), v);
      return ok(`Wrote ${fmtHex(v)} → ${addrHex(addr())}`);
    }
  • Schema definition for 'pine_write64' tool: name, description, and inputSchema with 'address' (integer) and 'value' (decimal string pattern) properties.
    {
      name: "pine_write64",
      description:
        `PURPOSE: Write an unsigned 64-bit little-endian value to ${ADDR_SPACE}. ` +
        "USAGE: For true 64-bit writes — full pointers, large IDs, packed doubleword state. Atomic from the emulator's perspective; preferred over chaining two pine_write32 calls (a running game can observe the in-between state). For 8/16/32-bit values use the corresponding sibling. " +
        "BEHAVIOR: DESTRUCTIVE: overwrites eight bytes from `address` with no undo. Direct write — bypasses TLB; writes to read-only regions silently dropped. Address MUST be 8-byte aligned. " + target.alignmentNote + " `value` is a DECIMAL STRING (0 through 18446744073709551615) to preserve precision past JS's 2^53 number limit. Errors on connection drop or PINE FAIL.\n\n" +
        MEM + "\n\n" +
        "RETURNS: 'Wrote VAL_DEC (0xVAL_HEX) → ADDR_HEX' — VAL_DEC may exceed 2^53.",
      inputSchema: {
        type: "object",
        required: ["address", "value"],
        properties: {
          address: { type: "integer", minimum: 0, description: addressParamDesc(target, 8) },
          value: {
            type: "string",
            pattern: "^[0-9]+$",
            description:
              "64-bit value to write, as a non-negative DECIMAL STRING (digits only, no '0x' prefix, no sign, no separators). " +
              "Range 0 through 18446744073709551615 (2^64 - 1). Example: \"18446744073709551615\" writes 0xFFFFFFFFFFFFFFFF. " +
              "Encoded as a string so values past 2^53 are preserved exactly (JSON numbers lose precision at that point). " +
              "For signed 64-bit values, encode as two's complement (e.g. -1 → \"18446744073709551615\")."
          },
        },
        additionalProperties: false,
      },
  • src/tools.ts:345-347 (registration)
    The tool is registered via the tool list returned by buildTools(), and the switch handler is set up in registerTools() via server.setRequestHandler(CallToolRequestSchema, ...).
    export function registerTools(server: Server, pine: PineClient, target: TargetInfo): void {
      const TOOLS = buildTools(target);
      server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
  • PineClient.write64() helper: allocates a 12-byte buffer, writes the 32-bit LE address and 64-bit LE bigint value, then sends it over the PINE protocol with the Write64 opcode (0x07).
    async write64(addr: number, val: bigint): Promise<void> {
      const args = Buffer.alloc(12);
      args.writeUInt32LE(addr, 0);
      args.writeBigUInt64LE(val, 4);
      await this.call(Op.Write64, args);
    }
  • Opcode constant: Write64 = 0x07, used to identify the write64 operation in the PINE protocol.
    Write64:      0x07,
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully discloses behaviors: 'DESTRUCTIVE: overwrites eight bytes from address with no undo', 'Direct write — bypasses TLB; writes to read-only regions silently dropped', alignment constraints and silent corruption on unaligned access, atomicity from emulator perspective, and error conditions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with clear sections (PURPOSE, USAGE, BEHAVIOR, returns) and a helpful memory map. Every sentence adds necessary context; no filler. It is front-loaded with purpose and atomicity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite no output schema, the description specifies the return format. It provides extensive context: alignment enforcement details, address space landmarks, atomicity, error handling, and prerequisites. It is self-contained and leaves no ambiguity for a competent agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description adds significant value: explains address landmarks (EE main RAM regions), alignment requirements beyond schema, the reason for decimal string (precision beyond 2^53), and two's complement encoding for signed values.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Write an unsigned 64-bit little-endian value to EE main address space' and distinguishes from siblings by explicitly mentioning 'For true 64-bit writes' and contrasting with chaining two write32 calls. It also references smaller siblings for other bit widths.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly advises when to use this tool ('For true 64-bit writes — full pointers, large IDs, packed doubleword state') and when not ('For 8/16/32-bit values use the corresponding sibling'). Also warns about alignment and recommends pine_read_range for unaligned multi-byte reads.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dmang-dev/mcp-pine'

If you have feedback or need assistance with the MCP directory API, please join our Discord server