| name | nes-format |
| description | iNES, NES 2.0, and UNIF ROM format reference. Use when reading, writing, parsing, or debugging .nes/.unf ROM files, or handling NES ROM headers. |
NES ROM Format Reference
Three ROM formats exist: iNES, NES 2.0, and UNIF. NES 2.0 is the current standard and recommended for new dumps. UNIF is deprecated.
Format Detection Quick Guide
| Signature in file | Format |
|---|
NES + $1A + byte 7 bits 3-2 = 10 | NES 2.0 |
NES + $1A + byte 7 bits 3-2 ≠ 10 | iNES |
UNIF | UNIF |
iNES Format (.nes)
Created by Marat Fayzullin for the iNES emulator. Uses an 8-bit mapper number (0–255). Bytes 8–15 are loosely defined and vary between iNES revisions. NES 2.0 repurposes them with a formal specification.
File Layout
[16-byte Header] [optional 512-byte Trainer] [PRG-ROM data] [CHR-ROM data]
Some ROM images also have a 128-byte title at the end of the file.
Header Byte Map
| Byte | Field |
|---|
| 0–3 | $4E $45 $53 $1A — "NES" + MS-DOS EOF |
| 4 | PRG-ROM size in 16KB units |
| 5 | CHR-ROM size in 8KB units (0 = CHR-RAM used) |
| 6 | Flags 6: NNNN FTBM |
| 7 | Flags 7: NNNN xxTT |
| 8 | PRG-RAM size in 8KB units (0 infers 8KB for compatibility) |
| 9 | TV system: bit 0 = 1 if PAL |
| 10 | Unofficial extension: TV system, PRG-RAM presence, bus conflicts |
| 11–15 | Padding (should be zero, but some tools wrote identifying strings here) |
Byte 6 Flags (NNNN FTBM)
| Bit | Name | Meaning |
|---|
| 0 | M | Nametable arrangement: 0 = vertical mirroring, 1 = horizontal mirroring |
| 1 | B | Battery-backed PRG-RAM at $6000–$7FFF (or other persistent memory) |
| 2 | T | Trainer present between header and PRG-ROM (512 bytes at $7000–$71FF) |
| 3 | F | Alternative nametable layout (mapper-dependent, often 4-screen) |
| 7–4 | N | Mapper number low nibble (D3–D0) |
Mirroring notes:
- Mappers that control mirroring themselves (MMC1, MMC3, AxROM) ignore bit 0.
- Bit 3 does not always mean 4-screen — some mappers use different combinations (e.g., UNROM 512:
%....1..0 = 1-screen, %....1..1 = 4-screen).
- Mappers with hard-wired 4-screen (Napoleon Senki, Vs. System, GTROM) may have bit 3 redundantly set.
Trainer: 512 bytes loaded at $7000–$71FF. Holds mapper translation / CHR-RAM caching code for early RAM cartridges and Nesticle. Not present on unmodified dumps of original cartridges.
Byte 7 Flags (NNNN xxTT)
| Bit | Name | Meaning |
|---|
| 1–0 | T | Console type: 0 = NES/Famicom, 1 = Vs. System, 2 = PlayChoice-10 |
| 3–2 | x | NES 2.0 identifier: must be 10 (2) for NES 2.0 |
| 7–4 | N | Mapper number high nibble (D7–D4) |
Mapper number = (byte 7 bits 7–4) << 4 | (byte 6 bits 7–4) → 0–255 for iNES.
PlayChoice-10 games have 8KB of Hint Screen data stored after CHR data. Vs. games have a coin slot and different palettes.
See references/mappers.md for the full mapper reference with detailed specifications.
Byte 10 (Unofficial Extension)
Not part of the original spec; few emulators honor it.
| Bits | Field |
|---|
| 1–0 | TV system: 0 = NTSC, 2 = PAL, 1/3 = dual compatible |
| 5–4 | PRG-RAM: 0 = present, 1 = absent |
| 6 | Bus conflicts: 0 = none, 1 = has bus conflicts |
Bytes 11–15
Should be zero. If the last 4 bytes are not all zero and this is not NES 2.0, an emulator should mask off the upper 4 bits of the mapper number or refuse to load. Some tools wrote identifying strings here (e.g., "DiskDude!").
iNES Revision Detection
- If byte 7 AND $0C = $08 → NES 2.0
- If byte 7 AND $0C = $04 → Archaic iNES (no mapper high nibble)
- If byte 7 AND $0C = $00, and bytes 12–15 are all zero → iNES
- Otherwise → iNES 0.7 or Archaic iNES (treat with caution)
NES 2.0 Format (.nes)
Identified by (byte 7 & $0C) == $08. Backward-compatible with iNES for bytes 0–7. Extends the mapper number to 12 bits (0–4095), adds a submapper for disambiguating board variants, and formally specifies RAM/NVRAM sizing.
File Layout
[16-byte Header] [optional Trainer] [PRG-ROM] [CHR-ROM] [optional Misc ROMs]
Byte 8 — Mapper MSB / Submapper
| Bits | Field |
|---|
| 3–0 | Mapper number D11–D8 (extends to 12 bits total, 0–4095) |
| 7–4 | Submapper number (0–15, disambiguates board/chip variants without relying on checksums) |
See references/mappers.md for the full mapper reference with detailed specifications.
Byte 9 — ROM Size MSB
| Bits | Field |
|---|
| 3–0 | PRG-ROM size MSB (together with byte 4 → 12-bit PRG size) |
| 7–4 | CHR-ROM size MSB (together with byte 5 → 12-bit CHR size) |
Simple mode (MSB nibble $0–$E): PRG = value × 16KB, CHR = value × 8KB. Max: ~63 MB PRG, ~31 MB CHR.
Exponent-multiplier mode (MSB nibble = $F): Used when simple notation cannot represent the exact size. Header bits are reinterpreted:
- Exponent E = bits D9–D4 (0–63)
- Multiplier MM = bits D1–D0, actual multiplier = MM×2+1 (1, 3, 5, or 7)
- Size = 2^E × (MM×2+1) bytes
If actual ROM size is odd and unrepresentable, pad to a representable size.
For Vs. Dual System: first half of PRG belongs to unit 1, second half to unit 2. Known splits exist for Vs. Gumshoe and Vs. Raid on Bungeling Bay.
Byte 10 — PRG-RAM / NVRAM Size
| Bits | Field |
|---|
| 4–0 | PRG-RAM (volatile) shift count |
| 7–5 | PRG-NVRAM/EEPROM (non-volatile) shift count |
Size formula: 64 << shift_count bytes. Shift count 0 = absent (compatibility: 0 infers no RAM).
Battery bit rule: If the upper nibble (NVRAM) is non-zero, byte 6 bit 1 (B) must be set. The reverse also applies unless the only battery-backed memory is mapper-internal or PRG-ROM is self-flashable.
Excludes: mapper-internal memory not CPU-mapped, MMC5 EXRAM, self-flashable PRG-ROM, external storage (cassette, Turbo File).
Byte 11 — CHR-RAM / CHR-NVRAM Size
| Bits | Field |
|---|
| 4–0 | CHR-RAM (volatile) shift count |
| 7–5 | CHR-NVRAM (non-volatile) shift count |
Same encoding as byte 10. Critical: emulators must not assume 8KB CHR-RAM when CHR-ROM is absent — all CHR-RAM must be explicitly specified. Nametable memory (PPU $2000–$2FFF) is excluded from this count even if 4-screen bit is set.
Byte 12 — CPU/PPU Timing
Two low bits:
| Value | Name | Meaning |
|---|
| 0 | RP2C02 | NTSC NES |
| 1 | RP2C07 | Licensed PAL NES |
| 2 | Multiple region | Self-adjusting to both NTSC and PAL |
| 3 | UA6538 | Dendy (PAL variant, 50.0063 Hz) |
Convention for assigning the correct value:
- Licensed games: 0 for JP/NA releases, 1 for EU/AU/OC/HK, 2 when the same PRG-ROM shipped in both regions, never 3.
- Unlicensed/homebrew: author designation first; 2 for self-adjusting; 3 for Chinese releases (Waixing etc.); default to 0.
- VTxx Famiclones only support RP2C02 or UA6538 → use 0, 2, or 3.
Byte 13 — Vs. System / Extended Console Type
Interpretation depends on byte 7 bits 1–0 (Console Type):
When Console Type = 1 (Vs. System):
| Bits | Field |
|---|
| 3–0 | Vs. PPU variant (RP2C03-xxxx, RP2C04-0001 through -0004, RC2C05-01 through -04) |
| 7–4 | Vs. Hardware type: 0=Normal, 1=RBI Baseball, 2=TKO Boxing, 3=Super Xevious, 4=Ice Climber, 5=Dual System Normal, 6=Dual System Raid on Bungeling Bay |
RP2C04/RC2C05 PPUs use different palettes for copy protection. RC2C05 swaps $2000/$2001 and returns a signature in $2002.
When Console Type = 3 (Extended Console):
| Value | Console |
|---|
| 0 | Regular NES/Famicom/Dendy |
| 1 | Nintendo Vs. System |
| 2 | PlayChoice-10 |
| 3 | Famiclone with Decimal Mode CPU |
| 4 | NES/Famicom with EPSM module |
| 5 | VT01 (red/cyan STN palette) |
| 6 | VT02 |
| 7 | VT03 |
| 8 | VT09 |
| 9 | VT32 |
| A | VT369 |
| B | UMC UM6578 |
| C | Famicom Network System |
Byte 14 — Miscellaneous ROMs
Bits 1–0: count of extra ROMs after CHR-ROM (0–3). Defined uses:
- PlayChoice-10: INST-ROM (8KB) + PROM data (16 bytes) + PROM counter out (16 bytes) = 3 misc ROMs
- VT369: 4KB embedded ROM
- Mapper 086 submapper 1: speech data ROM
- Mapper 355: PIC16C54 microcontroller ROM for copy protection
- Mappers 561/562: non-standard trainers (different size/location than $7000)
Byte 15 — Default Expansion Device
7-bit ID for the expected peripheral at $4016/$4017. $00 = unspecified, $01 = standard controllers. This typically denotes the device required to play the game; for optional devices it lists the device if having it connected doesn't preclude normal controllers. Does not cover cartridge-connected devices (those belong to the mapper definition).
See references/device-ids.md for the complete 80-entry device ID table.
UNIF Format (.unf / .unif)
UNIF uses chunked TLV (Type–Length–Value) blocks, allowing flexible ordering. Deprecated — its originator abandoned the format in December 2008. NES 2.0 is recommended for new work. A few game rips still only exist as UNIF.
File Layout
[32-byte Header] [Chunk] [Chunk] ...
Header:
| Offset | Size | Value |
|---|
| 0 | 4 | UNIF (literal ASCII) |
| 4 | 4 | LE32 — minimum version needed to parse all chunks |
| 8 | 24 | Null bytes |
Each chunk:
| Offset | Size | Value |
|---|
| 0 | 4 | Type ID (4 ASCII characters) |
| 4 | 4 | LE32 — content length |
| 8 | N | Content (encoding depends on type) |
Required Chunk
| Type | Content | Notes |
|---|
MAPR | Null-terminated UTF-8 | PCB identifier (e.g., "NES-SNROM", "HVC-UNROM"). Not a mapper number, not a free-form description. |
ROM Data Chunks
| Type | Content | Min Ver |
|---|
PRGn | Raw binary, n-th PRG-ROM chip (n in hex, 0-indexed) | 4 |
CHRn | Raw binary, n-th CHR-ROM chip | 4 |
PCKn | LE32 CRC-32 of n-th PRG-ROM | 5 |
CCKn | LE32 CRC-32 of n-th CHR-ROM | 5 |
Optional Metadata Chunks
| Type | Content | Notes |
|---|
NAME | Null-terminated UTF-8 | Game name |
READ | Null-terminated UTF-8 | Comments / license info |
DINF | 204-byte struct | Dumper name (100 bytes), date (day/month/year), tool name (100 bytes) |
BATR | 1-byte boolean | Battery-backed RAM present (doesn't disambiguate which RAM) |
MIRR | 1 byte | Mirroring: 0=horiz, 1=vert, 2=1scrA, 3=1scrB, 4=4scr, 5=mapper-controlled |
TVCI | 1 byte | TV: 0=NTSC only, 1=PAL only, 2=compatible with both |
CTRL | 1-byte bitmask | Controllers: 1=standard, 2=Zapper, 4=R.O.B., 8=Arkanoid, 16=Power Pad, 32=Four Score |
VROR | 1 byte | Treat CHR-ROM as RAM (deprecated, ignored by most emulators) |
Key UNIF Shortcomings
- No PRG-RAM field — two VRC4 games on identical PCBs can differ in PRG-RAM
- Unordered chunks make patching impossible without unpacking to an intermediate form
- MAPR abuse — users pick already-supported PCB names rather than creating accurate new ones for emulator compatibility
- BATR ambiguity — doesn't specify which RAM is battery-backed when multiple are present
- CTRL limitations — no port assignment, no Famicom-specific peripherals, no SNES controller via adapter, no mouse
- No support for fully describing Vs. System or PlayChoice-10 hardware
- ENCODING — before 2013, only 7-bit ASCII was assumed; UTF-8 adopted Q1 2013