pine_write32
Write a 32-bit little-endian value to a specified aligned address in the emulator's EE main memory for cheats or data modifications.
Instructions
PURPOSE: Write an unsigned 32-bit little-endian value to the emulator's EE main address space at the given absolute address. USAGE: Use for 32-bit cheats and pokes — timestamps, large counters, RGBA colors, the lower half of pointers. For single byte / 16-bit values use pine_write8/write16; for true 64-bit fields use pine_write64 — chaining two pine_write32 calls is non-atomic and can be observed mid-update by the running game. For big-endian layouts, byteswap into a little-endian value yourself first. BEHAVIOR: DESTRUCTIVE: overwrites four bytes starting at address with no undo. Direct memory write — bypasses TLB protection and DMA mediation; writes to read-only regions (BIOS) are silently dropped with no error. Address MUST be 4-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. Values are NOT truncated by this tool: the schema rejects anything outside 0-4294967295 (0x00000000-0xFFFFFFFF) before the call ever reaches PINE. Returns an error if the connection drops or PINE returns FAIL on a wholly invalid address.
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: Single line 'Wrote VAL_DEC (0xVAL_HEX) → ADDR_HEX'.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | Absolute byte address in the EE main address space (NOT a per-domain offset). Pass as a number; hex literals like 0x00200000 are fine. Reads 4 consecutive bytes starting here. MUST be 4-byte aligned (address % 4 === 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. | |
| value | Yes | 32-bit value to write. Must be 0-4294967295 (0x00000000-0xFFFFFFFF). LSB lands at `address`, MSB at `address+3`. For signed 32-bit values, encode as two's complement (e.g. -1 → 0xFFFFFFFF). For floats, reinterpret the IEEE-754 bits as an integer first. Values outside the range are rejected by the schema, NOT silently truncated — pass the value you actually want stored. |
Implementation Reference
- src/tools.ts:394-397 (handler)The handler/case for pine_write32 in the CallToolRequestSchema switch statement. Calls pine.write32() with the address and value, then returns a confirmation string.
case "pine_write32": { await pine.write32(addr(), p.value as number); return ok(`Wrote ${fmtHex(p.value as number)} → ${addrHex(addr())}`); } - src/tools.ts:244-268 (schema)The tool schema definition for pine_write32: declares address (integer, 4-byte aligned) and value (0-4294967295) parameters.
name: "pine_write32", description: `PURPOSE: Write an unsigned 32-bit little-endian value to the emulator's ${ADDR_SPACE} at the given absolute address. ` + "USAGE: Use for 32-bit cheats and pokes — timestamps, large counters, RGBA colors, the lower half of pointers. For single byte / 16-bit values use pine_write8/write16; for true 64-bit fields use pine_write64 — chaining two pine_write32 calls is non-atomic and can be observed mid-update by the running game. For big-endian layouts, byteswap into a little-endian value yourself first. " + "BEHAVIOR: DESTRUCTIVE: overwrites four bytes starting at `address` with no undo. Direct memory write — bypasses TLB protection and DMA mediation; writes to read-only regions (BIOS) are silently dropped with no error. Address MUST be 4-byte aligned. " + target.alignmentNote + " Values are NOT truncated by this tool: the schema rejects anything outside 0-4294967295 (0x00000000-0xFFFFFFFF) before the call ever reaches PINE. Returns an error if the connection drops or PINE returns FAIL on a wholly invalid address.\n\n" + MEM + "\n\n" + "RETURNS: Single line 'Wrote VAL_DEC (0xVAL_HEX) → ADDR_HEX'.", inputSchema: { type: "object", required: ["address", "value"], properties: { address: { type: "integer", minimum: 0, description: addressParamDesc(target, 4) }, value: { type: "integer", minimum: 0, maximum: 4294967295, description: "32-bit value to write. Must be 0-4294967295 (0x00000000-0xFFFFFFFF). LSB lands at `address`, MSB at `address+3`. " + "For signed 32-bit values, encode as two's complement (e.g. -1 → 0xFFFFFFFF). For floats, reinterpret the IEEE-754 bits as an integer first. " + "Values outside the range are rejected by the schema, NOT silently truncated — pass the value you actually want stored." }, }, additionalProperties: false, }, }, - src/tools.ts:346-347 (registration)Tools are registered via ListToolsRequestSchema handler returning the TOOLS array built by buildTools(), which includes pine_write32.
const TOOLS = buildTools(target); server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS })); - src/pine.ts:248-253 (helper)The low-level PineClient.write32() helper: allocates an 8-byte buffer, writes the 32-bit address (LE) and 32-bit value (LE), then calls the transport layer with Op.Write32 (0x06).
async write32(addr: number, val: number): Promise<void> { const args = Buffer.alloc(8); args.writeUInt32LE(addr, 0); args.writeUInt32LE(val, 4); await this.call(Op.Write32, args); } - src/pine.ts:32-42 (helper)The PINE protocol opcode constant for Write32 (0x06), used by the helper write32().
Write32: 0x06, Write64: 0x07, Version: 0x08, SaveState: 0x09, LoadState: 0x0A, Title: 0x0B, ID: 0x0C, UUID: 0x0D, GameVersion: 0x0E, Status: 0x0F, } as const;