Topics

UTTORI ASM · IN DEVELOPMENT

SNES struct map

Describe SNES RAM and ROM records in a checked, reusable struct map.

The optional type property makes field encoding explicit in schema version 1:

{
  "id": "Stats",
  "size": 5,
  "fields": [
    { "name": "hp", "offset": 0, "size": 2, "type": "dw" },
    { "name": "mp", "offset": 2, "size": 1, "type": "db" },
    { "name": "unknown", "offset": 3, "size": 2, "type": "db[2]" }
  ]
}

type must match size exactly. Metadata uses a literal decimal array length, such as dw[3], rather than an assembler expression. Invalid encodings are rejected before a generation is accepted. When type is omitted, sizes 1–4 use scalar types (db, dw, dl, dd). Larger fields become db[size]. Add explicit types when a small field is actually an array. Synthesized gaps always become byte arrays, even if they contain only one or two bytes.

Export generates typed zero-base layouts and addressed bindings in structs.asm. Bindings carry count and firstindex into endstruct. Complete ROM records become dataStruct. Neighboring records from the same binding become dataStructs rows. Every literal is read from the immutable original ROM, including all unknown bytes and generated __gap_* fields.

ROM bindings can add sparse entryComments keyed by decimal logical index:

"entryComments": { "0": "Candy", "5": "Cup of Wishes" }

These comments appear beside their dataStruct or dataStructs rows without splitting the table. Keys must lie within firstIndex through firstIndex + count - 1; unknown entries can be omitted. Values must be non-empty strings, with whitespace normalized onto one comment line. RAM bindings do not emit data rows and cannot use this property. If a ROM record is fragmented, its entry comment appears once before the first field.

Interior labels, comments, bank cuts and region boundaries prevent record grouping. The exporter retains the existing assert pc() == field plus raw directive path for those records. A label or comment at a record start closes and restarts a table. These fallbacks are required for exact placement and source navigation. Do not remove them merely to obtain more initializer blocks. Pure rendering covers the same ROM intervals whether a record is grouped or fragmented. Code/header conflicts reject the candidate. Pure generations must rebuild the original ROM and preserve accepted code unless explicit withdrawals are declared.

Edit struct-map.json, declare it in the generation recipes and prepare/preview a new candidate. Commit a reviewed checkpoint and integrate it with the native Git merge. structs.asm and bank sources are ordinary editable inputs. Keep original-identity record descriptions in the binding's entryComments and research files; the renderer preserves record-entry comments beside accepted includeAsset replacements as well as dataStruct rows. It does not rewrite evidence to enable grouping.