Topics

UTTORI ASM ยท IN DEVELOPMENT

65816 source export

Export reviewed 65816 analysis as source and raw assets for exact rebuilds.

exportSnes65816Source() converts a validated analysis project and its hash-matching RomImage into mapper-bank native source. It re-decodes persisted CFG nodes from their recorded incoming state, emits only compatible non-conflicting boundaries as instructions, and preserves all other bytes in deterministic incbin assets. The selected internal header, an optional expanded header, and all 16 native/emulation vector words are emitted as named, decoded db/dw source following the SNESdev ROM-header and CPU-vector layouts. Native instructions carry explicit .b/.w/.l operand qualification. Ambient .a8/.a16/.i8/.i16 directives are not emitted: explicit operand sizes preserve the encoding without source churn from captured flag changes. defines.asm covers the SNESdev PPU, MMIO, and DMA/HDMA tables with a hover comment on every register and compatibility aliases for older names. source prepare uses this pure renderer to create a verified immutable Git generation; source preview, apply and finish integrate it with current edits. source build validates and builds ordinary working source.

The editable ram-map.json generates documented symbols in ram-defines.asm and substitutes them in known memory operands. Entries default to canonical WRAM ($7E0000โ€“$7FFFFF). Fixed CPU WRAM mirrors resolve to those entries. Declare "memory": "sram" explicitly for cartridge RAM, using its CPU bus address, for example { "name": "SRAM_LAST_SELECTED_FILE", "address": "$307FFF", "memory": "sram", "description": "Persistent zero-based file index." }. SRAM entries must fit within a standard LoROM/HiROM SRAM window. They match only the declared CPU addresses: the map author must establish the actual cartridge mapping, size and aliases. They do not create ROM data or permit SRAM bindings in struct-map.json.

To add a WRAM name, edit the generated workspace's user-owned ram-map.json:

{
  "format": "uttori-asm-snes-ram-map",
  "schemaVersion": 1,
  "includeSourceInformation": false,
  "variables": [
    { "name": "PlayerHealth", "address": "$7E0100", "size": 2, "description": "Current health." }
  ]
}

includeSourceInformation defaults to false. Set it to true to include provenance citations in generated RAM definition comments. Store new citations in each variable's optional sources array; keep descriptive notes in notes, which remain visible. Existing standalone file/line citations such as Secret of Mana information.txt:L401. and file paths such as research/weather.md in notes also follow this setting. References embedded in explanatory prose are preserved. Descriptions, categories and sizes are always included, and comments end with punctuation. For example, the default renders RAM_SNOW_AMOUNT = $7ECFF7 ; Party โ€” Snow amount.; enabling source information restores its citation. The setting affects generated comments only; the input map retains all citations.

Keep existing entries when adding a variable. Maps live alongside the assembly, under source/ in newly initialized projects. Declare map paths in .uttori/generation-inputs.json recipes relative to its sourceRoot. Analyze changed research, prepare a candidate, preview it with current edits, commit a checkpoint and apply/finish the native merge. Pure rendering generates ram-defines.asm; the merge preserves and combines ordinary source edits. Store original-identity research in .uttori/research/ and reusable layouts in struct-map.json.

Pristine asset declarations in the generation recipe pin original bytes with SHA-256 and either the accepted generation, a bounded romRange, or an immutable originalBlob. Working asset edits stay in the current source branch. Verify pure generations against the original ROM before integrating those edits. See CLI source workflow.

An optional struct-map.json beside main.asm binds reusable layouts to RAM or ROM:

Its optional instructionUses metadata accepts checked native expressions and records capture-backed data references in generated source. See the instruction-use guide for byte checks and provenance.

{
  "format": "uttori-asm-snes-struct-map",
  "schemaVersion": 1,
  "structures": [
    {
      "id": "LevelStats",
      "size": 3,
      "fields": [
        { "name": "hp", "offset": 0, "size": 2, "type": "dw" },
        { "name": "mp", "offset": 2, "size": 1, "type": "db" }
      ]
    }
  ],
  "bindings": [
    {
      "name": "Levels",
      "structure": "LevelStats",
      "address": 12615680,
      "fileOffset": 32768,
      "count": 10
    }
  ]
}

For HiROM, this example places ten records at CPU $C08000, file $008000. Omit fileOffset for canonical WRAM bindings. Export generates and includes structs.asm, names known data operands such as Levels.hp,x, and emits complete ROM records as dataStruct or indexed dataStructs tables with built-in placement checks. Typed fields use db/dw/dl/dd or arrays such as db[2]. Opaque gaps retain their original bytes. Interior labels/comments keep the raw field directives and address assertions so their addresses do not move. The optional metadata type must match size. Size-only v1 inputs retain their previous scalar convention for sizes 1โ€“4 and use byte arrays otherwise. Layout and binding names share the source symbol namespace. Overlapping fields/bindings and conflicts with exportable code or cartridge headers are rejected. Struct names take precedence over flat RAM names at bound fields. Unknown addresses keep the existing naming behavior.

firstIndex defaults to zero. Set it to one for one-based tables: address and fileOffset still locate the first physical entry, while Levels[1].hp names that entry. The native base is reduced by one record so Levels.hp,x accepts the game's original index. This biased base is used only for indexed operand naming. Declare the struct map as a generation recipe so its definitions participate in the next candidate and reviewed native merge. The map and bank sources remain ordinary editable Git inputs.