| 1 | **************************************************************************** |
| 2 | UNIF file format specifications |
| 3 | (Universal NES Image) file format |
| 4 | |
| 5 | Created by Tennessee Carmel-Veilleux (veilleux@ameth.org) |
| 6 | REV 7b, November 28th, 2000 |
| 7 | |
| 8 | |
| 9 | ***********THIS IS AN OPEN STANDARD. IT IS OPEN TO SUGGESTIONS************** |
| 10 | |
| 11 | Overview |
| 12 | -------- |
| 13 | The UNIF format is a portable, flexible REPLACEMENT of the NES standard |
| 14 | (Designed by Marat Fayzullin). It is a chunked file format in the lines of |
| 15 | the Amiga IFF (LBM), Microsoft RIFF (WAV) and Autodesk 3D studio mesh |
| 16 | files (3DS). The goal of having a chunked definition is to provide |
| 17 | flexibility and ease of implementation, as data is described in blocks |
| 18 | with type IDs referring to them and header information to provide a |
| 19 | selective data reading. The format uses symetric data conversion for |
| 20 | numerical compatibility between the different platforms' byte ordering. |
| 21 | The ordering used is the 6502 Byte order (Intel), so that no more |
| 22 | bickering arrises from people who do not appreciate Network Byte Ordering |
| 23 | (Motorola). |
| 24 | |
| 25 | *** |
| 26 | The extension suggested for use with this format is .UNF (.UNIF under Operating |
| 27 | systems which support longer extensions). |
| 28 | *** |
| 29 | |
| 30 | Byte ordering |
| 31 | ------------- |
| 32 | Byte ordering used throughout the file for DWORDs and WORDs is 6502 Byte |
| 33 | order. The 6502 byte order is LSB, least significant byte first |
| 34 | (Little-endian): |
| 35 | |
| 36 | 3 2 1 0 <- Byte order for MSB (Network Byte order, m68k, PowerPC) |
| 37 | 0 1 2 3 <- Byte order for LSB (80x86, 6502, Z80) |
| 38 | |
| 39 | Care must be taken to convert the WORDs and DWORDs if you are using a |
| 40 | non-LSB platform (Mac, Amiga, some others). |
| 41 | |
| 42 | File format |
| 43 | ----------- |
| 44 | 00h-1Fh : Header |
| 45 | 20h-EOF : Chunks |
| 46 | |
| 47 | I can not think of an easier format to describe :) |
| 48 | |
| 49 | Header |
| 50 | ------ |
| 51 | The 4-byte header contains the string "UNIF" , NON null-terminated, case |
| 52 | as written. This is for identification purposes, a little like .NES' "NES^Z" |
| 53 | It is followed by Revision number and reserved bytes. |
| 54 | |
| 55 | Format: 00h-03h: "UNIF" tag identifier |
| 56 | 04h-07h: DWORD -> Revision number, currently 4 |
| 57 | 08h-1Fh: Reserved for future usage |
| 58 | |
| 59 | Sample structure: |
| 60 | |
| 61 | structure UNIF_header [ |
| 62 | char identification[4]; /* MUST be "UNIF" */ |
| 63 | dword revision; /* Revision number */ |
| 64 | byte expansion[24]; |
| 65 | ]; |
| 66 | |
| 67 | Chunks |
| 68 | ------ |
| 69 | Each chunks is composed of 3 distinct elements: |
| 70 | 00h-03h: Chunk ID string |
| 71 | 04h-07h: DWORD -> Block Length of Data |
| 72 | 08h-?? : Data |
| 73 | |
| 74 | All the chunks are written sequentially in the file. If you do not understand |
| 75 | a chunk by its ID, simply jump over it using the data length information. |
| 76 | *** ALL THE CHUNKS ARE OPTIONAL *** |
| 77 | That means that there are NO mandatory chunks, and you support only the |
| 78 | ONES YOU WISH, passing over the others while you are interpreting the |
| 79 | file. |
| 80 | |
| 81 | Sample structure: |
| 82 | |
| 83 | structure UNIF_chunk [ |
| 84 | char chunk_ID[4]; /* Chunk identification string. Can also be considered a |
| 85 | number. ASCII format */ |
| 86 | dword length; /* Data length, in little-endian format */ |
| 87 | ]; |
| 88 | |
| 89 | The different chunks: |
| 90 | --------------------- |
| 91 | ******************************************************************************* |
| 92 | How chunks are described: |
| 93 | ID field: Contains the 4-characters string identifier for the chunk |
| 94 | |
| 95 | Length: Length of the block. If it is "??", then the block may have |
| 96 | variable data size depending on the cartridge. |
| 97 | |
| 98 | Revision: First revision in which the chunk appeared. If your reader supports |
| 99 | a lower revision, you might be unable to read the chunk, simply pass |
| 100 | over it. The Revision used by the cart is written in the header. The |
| 101 | number represents the Revision Number of the most recent chunk |
| 102 | contained in the file. Example : If you have 5 chunks of revision 1 |
| 103 | and 2 chunks of revision 4 in the file, the Revision number in the |
| 104 | header will be 4. |
| 105 | |
| 106 | Description: Complete description of the contents and encoding of the chunk |
| 107 | ******************************************************************************* |
| 108 | |
| 109 | ID: [MAPR] |
| 110 | Length: ?? (Suggested max: 32 chars) |
| 111 | Revision: 1 |
| 112 | Description: This is supplemental information about the mapper. DO NOT USE |
| 113 | A MAPPER NUMBER HERE ! Rather use the BOARD NAME. There is |
| 114 | already a list in progress describing each NES cart and the |
| 115 | board it uses. The string is NULL-TERMINATED. |
| 116 | |
| 117 | examples: N,R,O,M,,0 -> This "No mapper" |
| 118 | U,N,R,O,M,0 -> This is (LS161+LS32) |
| 119 | |
| 120 | NOTA: This mapper organization suggests that emulators must be rewritten |
| 121 | to emulate the ACTUAL CARTRIDGE HARDWARE, and not solely a case of another |
| 122 | mapper number. That means you have to make for UNROM: |
| 123 | 1- Mapper handler (74LS161+74LS32) |
| 124 | 2- CHR-RAM Handler |
| 125 | |
| 126 | Those components can be reused, since many boards only have a slight |
| 127 | difference in them compared to similar ones. |
| 128 | |
| 129 | **IT SHOULD BE NOTED THAT**: A board name tells you EVERYTHING there is to |
| 130 | know about a board. You do not need other chunks to tell you how much RAM |
| 131 | there is, or if it is VRAM. It is all implied by the board name. A list |
| 132 | will soon be distributed containing board name information. |
| 133 | |
| 134 | Address of board table for North American Games and Board Names description: |
| 135 | http://www.parodius.com/~veilleux/boardtable.txt |
| 136 | http://www.parodius.com/~veilleux/boardnames |
| 137 | |
| 138 | ID: [READ] |
| 139 | Length: ?? |
| 140 | Revision: 1 |
| 141 | Description: Commentaries for the user of the ROM image. In the case of a |
| 142 | homebrew game, this can be very useful to store credit and maker |
| 143 | information. *** This could be "Incitation to littering". Please do not |
| 144 | put garbage in there. It is meant for either mapper information or |
| 145 | licensing information for homebrew games.*** |
| 146 | |
| 147 | |
| 148 | ID: [NAME] |
| 149 | Length: ?? |
| 150 | Revision: 1 |
| 151 | Description: NULL-terminated string containing the name of the game. If not |
| 152 | present, use the filename as the name. |
| 153 | |
| 154 | ID: [TVCI] |
| 155 | Length: BYTE |
| 156 | Revision: 6 |
| 157 | Description: Television Standards Compatability Information set to: |
| 158 | 0- Originally NTSC cartridge |
| 159 | 1- Originally PAL cartridge |
| 160 | 2- Does not matter |
| 161 | NOTE: ALL North American carts that are dumps of the North American |
| 162 | Version are NTSC. All licensed famicom games are NTSC. |
| 163 | |
| 164 | ID: [DINF] |
| 165 | Length: 204 |
| 166 | Revision: 2 |
| 167 | Description: Dumper information block: |
| 168 | structure dumper_info [ |
| 169 | |
| 170 | char dumper_name[100]; /* NULL-terminated string containing the name |
| 171 | of the person who dumped the cart. */ |
| 172 | byte day; /* Day of the month when cartridge was dumped */ |
| 173 | byte month; /* Month of the year when cartridge was dumped */ |
| 174 | word year; /* Year during which the cartridge was dumped */ |
| 175 | char dumper_agent[100]; /* NULL-terminated string containing the name of |
| 176 | the ROM-dumping means used */ |
| 177 | ] |
| 178 | |
| 179 | ID: [CTRL] |
| 180 | Length: BYTE |
| 181 | Revision: 7 |
| 182 | Description: Bitfield containing information about the controllers used by the |
| 183 | cartridge. |
| 184 | |
| 185 | Bit 0: Regular Joypad |
| 186 | Bit 1: Zapper |
| 187 | Bit 2: R.O.B |
| 188 | Bit 3: Arkanoid Controller |
| 189 | Bit 4: Power Pad |
| 190 | Bit 5: Four-Score adapter |
| 191 | Bit 6: Expansion (Do not touch) |
| 192 | Bit 7: Expansion (Do not touch) |
| 193 | |
| 194 | ID: [PCK0] through [PCKF] |
| 195 | Length: DWORD |
| 196 | Reivision: 5 |
| 197 | Description: This block contains a 32-bit CRC which can be used to make |
| 198 | sure that the ROM content matches a checksum when burning on EPROM. This |
| 199 | block provides a checksum for [PRG0] through [PRGF] inclusively |
| 200 | |
| 201 | ID: [CCK0] through [CCKF] |
| 202 | Length: DWORD |
| 203 | Reivision: 5 |
| 204 | Description: This block contains a 32-bit CRC which can be used to make |
| 205 | sure that the ROM content matches a checksum when burning on EPROM. This |
| 206 | block provides a checksum for [CHR0] through [CHRF] inclusively |
| 207 | |
| 208 | ID: [PRG0] through [PRGF] |
| 209 | Length: ?? |
| 210 | Revision: 4 |
| 211 | Description: Chunks containing the Binary data of the PRG ROM. If there |
| 212 | are more than 1 PRG chips on the PRG bus, use PRG1, PRG2, PRG4, etc. |
| 213 | The way PRGs are handled depends on the mapper and emulator. Most generaly |
| 214 | (99%), only use PRG0. (Some carts have been witnessed with 8 PRG ROMs). |
| 215 | |
| 216 | ID: [CHR0] through [CHRF] |
| 217 | Length: ?? |
| 218 | Revision: 4 |
| 219 | Description: Chunks containing the binary data of the CHR ROM. If there |
| 220 | are more than 1 CHR chips on the CHR bus, use CHR1, CHR2, CHR4, etc. The |
| 221 | way CHRs are handled depends on the mapper and emulator. Most generaly |
| 222 | (99%), only CHR0 is used. |
| 223 | |
| 224 | ID: [BATR] |
| 225 | Length: BYTE |
| 226 | Revision: 5 |
| 227 | Description: The presence of this block indicates that the board indeed |
| 228 | contains a battery. This is necessary because many boards have the |
| 229 | capability of a battery (the traces and holes are there), but they only |
| 230 | use RAM and don't add the battery at manufacturing time. Examples: |
| 231 | * SAROM: MMC1B, PRG ROM, CHR ROM, optional 8k of RAM (battery) |
| 232 | * SKROM: MMC1B, PRG ROM, CHR ROM, 8k optional RAM (battery) |
| 233 | |
| 234 | Both these boards (SAROM and SKROM) can have a battery, but usually they |
| 235 | don't have it. |
| 236 | |
| 237 | ID: [VROR] |
| 238 | Length: BYTE |
| 239 | Revision: 5 |
| 240 | Description: This is a VRAM Override. If this chunk is present, then the |
| 241 | CHR-ROM area will be considered as RAM even if ROM is present. This |
| 242 | overrides board identification. This is present so that homemade carts |
| 243 | which use NROM or others and replace the CHR-ROM with CHR-RAM can still be |
| 244 | interpreted (since NROM is always CHR-ROM in commercial games). |
| 245 | |
| 246 | ID: [MIRR] |
| 247 | Length: BYTE |
| 248 | Revision: 5 |
| 249 | Description: This chunk tells you how the hardwired mirroring is setup on |
| 250 | the board. The board name CANNOT tell you (in most cases) what the |
| 251 | mirroring is, since the all have solder pads to select the mirroring at |
| 252 | manufacturing time. The following values are legal: |
| 253 | |
| 254 | * $00 - Horizontal Mirroring (Hard Wired) |
| 255 | * $01 - Vertical Mirroring (Hard Wired) |
| 256 | * $02 - Mirror All Pages From $2000 (Hard Wired) |
| 257 | * $03 - Mirror All Pages From $2400 (Hard Wired) |
| 258 | * $04 - Four Screens of VRAM (Hard Wired) |
| 259 | * $05 - Mirroring Controlled By Mapper Hardware |
| 260 | |
| 261 | Conclusion |
| 262 | ---------- |
| 263 | This ends the specification for Revision 6 of UNIF. If you have ANY |
| 264 | suggestions to make regarding the UNIF file format, such as chunk ideas or |
| 265 | modifications, or would like to collaborate to the elaboration and design |
| 266 | process, e-mail me at veilleux@ameth.org. |
| 267 | |
| 268 | A multi-platform C Code Library for UNIF support was made by Evan Teran. It |
| 269 | is available at http://www.pretendo.org/~proxy/. |
| 270 | |
| 271 | [References] |
| 272 | {.NES file format specifications} by Marat Fayzullin (fms@cs.umd.edu) |
| 273 | {NESDEV mailing list} by Various authors |
| 274 | {NES technical documentation} by Jeremy Chadwick (yoshi@parodius.com) |
| 275 | |
| 276 | [Credits] |
| 277 | Neal Tew for his neat emulator and great contribution to the NESdev |
| 278 | community. |
| 279 | |
| 280 | Jeremy Chadwick (yoshi@parodius.com) for his contribution to the NESdev |
| 281 | community and great advice over the time. |
| 282 | |
| 283 | Mark Knibbs (mark_k@iname.com) for his excellent web site as well as his |
| 284 | more than honorable contribution to the NES world |
| 285 | |
| 286 | Matthew Conte (itsbroke@classicgaming.com) for his CajoNES and Nofrendo |
| 287 | programs |
| 288 | |
| 289 | Michael Iwaniec (mrbananmos@yahoo.com) for his interest in UNIF and |
| 290 | constructive criticism. |
| 291 | |
| 292 | Kevin Horton (khorton@iquest.net) for his proposals and support of |
| 293 | UNIF. He's also been a fantastic help to me in my learning curve of the |
| 294 | NES's hardware aspects. |
| 295 | |
| 296 | /Firebug/ (firebug@cfl.rr.com) for the ideas brought with NIFF |
| 297 | |
| 298 | T. Alex Reed {W1k} (rizen@netzero.net) for suggestions of additions |
| 299 | to UNIF. He also pointed out some mistakes in the original specifications. |
| 300 | |
| 301 | Evan Teran {PrOxY} (emt3734@rit.edu) for making suggestions as well as |
| 302 | writing a .NES->UNIF converter and the LIB_UNIF library. |