.nes file format: format specification

File extension

nes

KS implementation details

License: WTFPL

This page hosts a formal specification of .nes file format using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Block diagram

Format specification in Kaitai Struct YAML

# TODO: Support NES 2.0
meta:
  id: ines
  file-extension: nes
  license: WTFPL
  encoding: ASCII
doc-ref: https://www.nesdev.org/wiki/INES
seq:
  - id: header
    size: 16
    type: header
  - id: trainer
    size: 512
    if: header.f6.trainer
  - id: prg_rom
    size: header.len_prg_rom * 16384
  - id: chr_rom
    size: header.len_chr_rom * 8192
  - id: playchoice10
    type: playchoice10
    if: header.f7.playchoice10
  - id: title
    size-eos: true # Usually only 128/127 bytes
    type: str
    if: not _io.eof
types:
  header:
    seq:
      - id: magic
        contents: [NES, 0x1A]
      - id: len_prg_rom
        type: u1
        doc: Size of PRG ROM in 16 KB units
      - id: len_chr_rom
        type: u1
        doc: Size of CHR ROM in 8 KB units (Value 0 means the board uses CHR RAM)
      - id: f6
        size: 1
        type: f6
      - id: f7
        size: 1
        type: f7
      - id: len_prg_ram
        type: u1
        doc: Size of PRG RAM in 8 KB units (Value 0 infers 8 KB for compatibility; see PRG RAM circuit on nesdev.com)
      - id: f9
        size: 1
        type: f9
      - id: f10
        size: 1
        type: f10
        doc: this one is unofficial
      - id: reserved
        contents: [0, 0, 0, 0, 0]
    instances:
      # TODO: Add an enum for mapper. https://www.nesdev.org/wiki/List_of_mappers
      mapper:
        value: f6.lower_mapper | (f7.upper_mapper << 4)
        doc-ref: https://www.nesdev.org/wiki/Mapper
    types:
      f6:
        doc-ref: https://www.nesdev.org/wiki/INES#Flags_6
        seq:
          - id: lower_mapper
            type: b4
            doc: Lower nibble of mapper number
          - id: four_screen
            type: b1
            doc: Ignore mirroring control or above mirroring bit; instead provide four-screen VRAM
          - id: trainer
            type: b1
            doc: 512-byte trainer at $7000-$71FF (stored before PRG data)
          - id: has_battery_ram
            type: b1
            doc: If on the cartridge contains battery-backed PRG RAM ($6000-7FFF) or other persistent memory
          - id: mirroring
            type: b1
            enum: mirroring
            doc: if 0, horizontal arrangement. if 1, vertical arrangement
        enums:
          mirroring:
            0: horizontal
            1: vertical
      f7:
        doc-ref: https://www.nesdev.org/wiki/INES#Flags_7
        seq:
          - id: upper_mapper
            type: b4
            doc: Upper nibble of mapper number
          - id: format
            type: b2
            doc: If equal to 2, flags 8-15 are in NES 2.0 format
          - id: playchoice10
            type: b1
            doc: Determines if it made for a Nintendo PlayChoice-10 or not
          - id: vs_unisystem
            type: b1
            doc: Determines if it is made for a Nintendo VS Unisystem or not
      f9:
        doc-ref: https://www.nesdev.org/wiki/INES#Flags_9
        seq:
          # TODO: enforce zero (similarly to "contents", but on bit level)
          - id: reserved
            type: b7
          - id: tv_system
            type: b1
            enum: tv_system
            doc: if 0, NTSC. If 1, PAL.
        enums:
          tv_system:
            0: ntsc
            1: pal
      f10:
        doc-ref: https://www.nesdev.org/wiki/INES#Flags_10
        seq:
          # TODO: enforce zero (similarly to "contents", but on bit level)
          - id: reserved1
            type: b2
          - id: bus_conflict
            type: b1
            doc: If 0, no bus conflicts. If 1, bus conflicts.
          # TODO: 0 = true, 1 = false in this case
          - id: prg_ram
            type: b1
            doc: If 0, PRG ram is present. If 1, not present.
          # TODO: enforce zero (similarly to "contents", but on bit level)
          - id: reserved2
            type: b2
          - id: tv_system
            type: b2
            enum: tv_system
            doc: if 0, NTSC. If 2, PAL. If 1 or 3, dual compatible.
        enums:
          tv_system:
            0: ntsc
            1: dual1
            2: pal
            3: dual2
  playchoice10:
    doc-ref: https://www.nesdev.org/wiki/PC10_ROM-Images
    seq:
      - id: inst_rom
        size: 8192
      - id: prom
        type: prom
    types:
      prom:
        seq:
          - id: data
            size: 16
          - id: counter_out
            size: 16