=============================================================================== NES EXTENSION OF THE EXTENSIBLE ROMHACK INTERCHANGE FORMAT File format specification, edition of January 10, 2008 =============================================================================== This document defines the NES Extension of XRIF (XRIF+NES). The purpose of this Extension is to adapt XRIF to the unique needs of patching cartridge files for the Entertainment System / Famicom platform developed by Nintendo, which is ref- ferred to here collectively as the "NES". XRIF+NES is not suitable nor intended for patching Famicom Disk System games, which store their data in a very different way than cartridge-based games do. ----------------------------------- WEBSITE ----------------------------------- http://zerosoul.arc-nova.org/Technology/XRIF+NES/ (Failing that, use a search engine.) =================================== HISTORY =================================== The de-facto standard NES cartridge format is called iNES, after the emulator that popularized it. The de-facto standard patching format for it is IPS. Both formats are adequate enough within their own technical milieu, and for a time, it has been good. However, not everything is so agreed-upon in the NES world. A new format, the Universal NES Interchange Format (UNIF), has been defined and is slowly gaining a foothold in the NES emulation scene. UNIF arranges the cartridge data into "chunks", conveying separate ROM chips in separate chunks, and defining cart- ridge meta-data in a different and more expressive way. While this is adequate within its own technical milieu, it breaks compatibility with iNES, and particularly IPS: in UNIF, data is arranged differently, not only compared to iNES, but potentially to other UNIF files of the same game. IPS depends on the target file being more predictable than that, so, IPS will not work adequately with UNIF. This is a problem that ought to be solved. In order to do so, we must take a step back and try to address the problem at a higher level. IPS can address only raw file offsets, but that's not really what we want. What we do want is to address the cartridge ROM data: the PRG ROM and CHR ROM. Exactly where that data is located within the file is not something we are, or ought to be, concer- ned with. If we want to change, say, the 0x1000th byte of the PRG ROM, we don't care *how* the patcher locates that byte, just as long as it does. IPS, however, *does* force you to specify how, and thus permits no other way to do it, no flexiblity, no adaptibility. ------------------------------------- My original attempt to address this was a UNIF-specific format called UNIF-IPS, even though it had little to do with IPS beyond being a patching format too. This format was made in conjunction with another called "Dynamic UNIF" (D-UNIF) which was a superset of UNIF itself to allow chunk data to reference an extern- al file, such as an iNES file. Both these formats were intended to make working with UNIF more feasable for ROM hackers. Before long, though, I had abandoned both formats as inadequate. Later, I cre- ated another format, similar in principle, but identifying chips by number. This format I called the "Universal NES ROMhack Interchange Format", or UNRIF. This format was the ancestor to XRIF+NES; it had separate chunk types for ad- dressing PRG data and CHR data, each of them starting with two bytes: the chip to address, and the "method" to be used (such as Replace or Copy From Result). The "replace" method had RLE built-in (if the high bit of the "length" field was set, the next byte was repeased for the number given in the remaining bits of the Length field). UNRIF had some of the features of today's XRIF+NES, such as using locales and Unicode in the META chunk (the precursor to INFO). With UNRIF, I had even gotten so far as to post a proposition for it on a pop- ular message board. Most of the responses, though, had two chief concerns: * What about Super NES patching and such? (UNRIF was NES-specific and was never intended to be otherwise.) * What's "Unicode"? It was never implemented, and eventually I abandoned that too. Later, I decided to generalize the format even further, by making it a general-purpose patching format, with NES-specific functionality gotten by way of an "Extension". The resulting format was given the name "Extensible ROMhack Interchange Format": XRIF. However, the format at the time had some important differences from what it is today. For example, there was a fixed-size 0x20-byte header (which UNRIF and UNIF-IPS both had, in turn because UNIF does). The latter half of this was for an "Application declaration", and there were three types of Applications: * Extensions, which had the same basic meaning as now. * Supersets, which might be thought of as "advisory Extensions". The main idea I had in mind was for Super NES patching, where the patch could be laid out as though it were an unheadered+uninterleaved file, and could use a Superset to indicate it's a Super NES patch. If the patcher recognized the Superset, it could adapt it to any Super NES ROM (headered, interleaved, ...), and if it didn't, it could still apply it as a straight XRIF patch if the ROM is of the assumed type. * Platform Declarations, which added no functionality but merely declared the intended platform, for example Game Boy Advance patches. Each of these started with a "sigil" identifying the type: for Extensions this was "+" (hence the naming convention "XRIF+FOO" for some Extension FOO), for Supersets this was "/" (hence "XRIF/FOO"), for Platform Declarations this was "=" (hence "XRIF=GBA"). These were collectively referred to as "Applications" of XRIF. Applications could build on one another, such as having a Platform Declaration of an Exten- sion. However, this flexibility was inhibited by the fact the Application Dec- laration was fixed-length. Then later, in the late days of 2005, I modified the XRIF spec further, making these changes: * Instead of a fixed-size 0x20-byte header, the XRIF header would be incorpor- ated into the chunk structure of the rest of the format. * Application Declarations would be done in a chunk called XAPP, which would al- low them to be as large or small as necessary, and to allow for more flags if necessary, and each Application would be given in its own XAPP chunk. * The Version Number system was abandoned in favor of using flags to indicate what new/optional features were used by the patch. * The IDAT chunk, which was what performed the actual data modification, was replaced with separate chunks for each method: TREP, TRLE, TCFR and so forth. This way, chunks contained only blocks, no extra header bytes or anything. As I wrote the specifiction, I was brainstorming at the same time, and eventu- ally discarded the idea of Supersets and Platform Declarations, leaving only Extensions. (The name of the XAPP chunk remained the same, though.) This became the first edition of today's XRIF format, dated January 3, 2006. XRIF+NES itself, which had existed since the early days of XRIF, was also chan- ged. At first, IDAT was modified so that the first byte specified which NES ROM chip was being addressed. Later, when IDAT was split into TREP and so forth, I decided to convey this separately, using a chunk called CSEL to select a chip, which would be the target of all subsequent Payload chunks (TREP, ...). This way, again, the data-modifying chunks would still contain nothing but blocks, no extra bytes at the start. The specification was written up, and dated January 4, 2006. Although the base XRIF format has undergone several revisions since the original edition (with the January 10, 2008 edition being current as of this writing), XRIF+NES builds upon XRIF, and so the XRIF+NES specification-- that is, the manner in which XRIF+NES extends XRIF-- has not had to change along with it. ------------------------------------- The result is a format which addresses the original problem: if you want to ad- dress the 0x1000th byte of PRG ROM, then XRIF+NES will state as such; it rec- ords WHAT you want to do rather than hard-wiring HOW to do it. The manner in which XRIF extends XRIF+NES is defined in this document. =================================== OVERVIEW ================================== First of all, XRIF+NES is an Extension of XRIF: as such, an XRIF+NES file is an XRIF file, and inherits the basic chunk structure, syntax, and functionality of the XRIF format (including all new and optional features). As such, you will need to be familiar with the base XRIF format in order to understand this Exten- sion of it. The basic approach taken by XRIF+NES is to change the base address of Payload chunks such as TREP. Instead of addressing the target file directly, the patch selects a ROM chip first, and then all Payload chunks address *that* instead. The patcher, rather than the patch, is what must shoulder the burden of deter- mining exactly where in the file that ROM data is. This has the benefit that a single patch can be applied to a cartridge file of any format the patcher sup- ports, or even future cartridge file formats that future patchers might support. There are some new chunks to fill in some extra information that the patcher may require (to work around the shortcomings of the iNES format when necessary), to select ROM chips (CSEL), and a set of chunks to change the cartridge meta- data structure, such as what board type and mirroring the cartridge file says it uses, and to do so in a portable manner. ============== BASE XRIF CHUNKS THAT WORK DIFFERENTLY IN XRIF+NES ============= It is the prerogative of an Extension to change or modify the definition or interpretation of existing XRIF chunks. ------------------------------ XRIF (file header) ----------------------------- The XRIF format allows Extensions to define additional prerequisites as to whe- ther the target file can be treated as "streamable". Under XRIF+NES, no target file is streamable: this flag shall be ignored. ------------------------- XAPP (Extension declaration) ------------------------ XRIF+NES is meant only to extend the base XRIF format, or possibly any general- purpose Extensions (of which none exist at this time that I know of). The Extension name, for XAPP, is "NES". After its nul-terminator is at least one byte giving information about the patch (specific to XRIF+NES). Of these, the first is Advisory, followed by Mandatory, and so on alternating between the two. The difference is in how unrecognized flags in them are to be dealt with: * Unrecognized "advisory" flags can be safely ignored. * Unrecognized "mandatory" flags cannot be. This is done in much the same spirit as for the XRIF chunk. The first flag byte is Advisory: -------X : Whether annotation is "active"; that is, whether the patcher may (0) or must not (1) write annotation data into the target file if its format supports annotation. ------X- : Reserved. Was formerly used for CART. Should always be set to 0. The second flag byte is Mandatory. However, patchers should be prepared to han- dle patches that don't even specify this byte at all (as can be determined from the Length field of the XAPP chunk), because XRIF+NES used to only define a sin- gle flag byte. -------X : Whether CART is (1) or is not (0) used. ------X- : Whether double-byte CSELs are (1) or are not (0) used. -----X-- : Whether chips are (1) or are not (0) created. This makes it legal to CSEL a nonexistent chip, so that a TFSM operation can give it a non- zero size, thereby creating it; or for TFSM to give an existing chip a size of zero, thereby deleting it. ----X--- : Whether simplified cartridge chunks (cPCB, etc) are used (1=Yes). As with XRIF, additional flags may be defined in future editions of this speci- fication, and additional bytes added to its XAPP chunk to accomodate them. Patchers thus need to allow for these extra bytes to be present, and to inter- pret unrecognized flags in accordance with whether it's in an Advisory or Manda- tory byte. ------------------------------- TCRC (Checksum) ------------------------------- The checksum algorithm is performed on the concatenated-together contents of all ROM chips (PRG and CHR), in standard order: all PRG chips, in order, fol- lowed by all CHR chips, in order. For iNES files, it will suffice to operate on the data after the header, and excluding any data beyond the end of the ROM data. Same for iNES Extended. ------------------------------- TFSM (Resizing) ------------------------------- The 2006-01-22 edition of XRIF demoted TFSM from "required" to "optional"; as such, this is true of XRIF+NES as well. Also, the 2008-01-10 edition of XRIF made the relative-sizing methods deprecated, and so it is in XRIF+NES as well. For XRIF+NES, the size, in TFSM, is specified in a different way, by the number of iNES-size banks rather than the exact number of bytes. Also, TFSM operates on the currently-selected ROM chip, not on the file as a whole. When resizing a PRG chip, the size byte is expressed as a multiple of 16 KB; when resizing a CHR chip, the size byte is expressed as a multiple of 8 KB. Thus, TFSM chunks in XRIF+NES contain exactly two bytes: the first being [00], the second being the number of banks to set the chip to as per above. --------------------------- TCFS (Copy from Source) --------------------------- This is required to be supported in XRIF+NES, despite being merely optional in the base XRIF specification. Its flag in the XRIF header is still present and must still be set if TCFS is used in the patch, to inform the patcher that it'll need to make arrangements to keep the original patch data on hand. -------------------- INFO and Simplified Annotation chunks -------------------- These are not changed in XRIF+NES. However, by default, a patcher is allowed to inscribe this data into the target file if the target file's format permits it. An Advisory flag in the XRIF+NES header (the XAPP chunk that invokes it) can be used to prevent this behavior. ===================== NEW CHUNKS DEFINED BY THE EXTENSION ===================== ------------------------------------------------------------------------------- ------------------------------- CSIZ: ROM sizes ------------------------------- ------------------------------------------------------------------------------- The UNIF format (and thus iNES Extended) allows for the fact that NES cart- ridges can have their PRG and/or CHR data spread across multiple chips (up to 16 apiece), but most other formats-- iNES foremost among them-- do not. XRIF+NES can address any of these chips directly, and as such the patcher needs to know where the boundaries between the chips are. If necessary, CSIZ provides this information. The chunk is 32 bytes in length: the first 16 bytes define the sizes of each PRG chip (from first to last) expressed as multiples of 16 KB; the last 16 bytes define the sizes of each CHR chip, expressed as multiples of 8 KB. A chip that is given with a size of zero implies that that chip does not exist. If CSIZ is not given at all, it is assumed that there is one PRG chip and that all PRG is contained on it; so for CHR. CSEL represents the expected sizes of the chips before the patching process begins. As of the 2006-04-26 edition of XRIF+NES, this chunk, if given, must occur only one time, and before any Payload chunks (such as TREP). It is not considered part of any Variation. It is an error if the information in CSIZ does not correspond to what the tar- get file says. For example: * If the sum of the first 16 bytes don't equal the PRG size byte in the iNES header; so for the second 16 bytes and the CHR size byte. * If the first 16 bytes don't correspond to PCSI in iNES Extended, or the second 16 to CCSI, or either to the iNES header as for plain iNES. * If any chip is given as a different size than the corresponding UNIF chunk. This might not necessarily be a result of a patch error. However, if the target file's size is X and the patch thinks it's Y, there's almost certainly going to be problems, so it's highly advisable for the patcher to double-check this and to bail out of they don't add up. ------------------------------------------------------------------------------- ----------------------------- CSEL: ROM selection ----------------------------- ------------------------------------------------------------------------------- This selects the particular PRG or CHR chip that will be the target of subse- quent modifications (until the next CSEL, if any). This affects the interpre- tation of data addresses, which will be offsets into the selected ROM chip, rather than offsets into the target file itself. This behavior is the primary purpose of having this Extension at all. This chunk consists of one or two bytes (the two-byte form is an addition of the 2006-04-26 edition of XRIF+NES, and is indicated with a flag in XAPP), each with the following meaning: ----XXXX : Which chip to select (0=first 1=second ...) ---X---- : Whether the chip is of PRG (0) or CHR (1) You might think of this as an offset into CSEL, in terms of what chip is selec- ted. For example, [00] = first PRG chip (UNIF PRG0), [01] = second PRG chip (UNIF PRG1), [02] = third PRG chip (UNIF PRG2), [10] = first CHR chip (UNIF CHR0), and so on. If two bytes are given, the second one selects the "source" chip for TCFR/TCFS operations, thereby allowing the patch to copy from one chip to another. If only one byte is given, it specifies both the source and target chips. It is not legal to select a chip that doesn't exist in the target file, unless the "patch creates chips" flag is set in XAPP, in which case it's then legal to select a non-existing target chip (presumably to create it by giving it a non- zero size using TFSM). It is never legal to select a non-existent source chip, however. ===================== CARTRIDGE HEADER MODIFICATION CHUNKS ==================== These modify the cartridge meta-data information, such as what board/mapper is in use, what mirroring is in use, and so forth. These chunks have been based, structurally, on XRIF's annotation chunks. The original method, CART, is based on INFO and consolidates all changes into one big chunk. The 2008-01-10 edition of XRIF+NES has added the simplificed cart- ridge chunks, analogous to the simplified annotation chunks, and which are dec- lared as the preferred method for conveying this information. The simplified cartridge chunks' labels all start with a lower-case "c", as with the simplified annotation chunks. +-------------------------------------------------------------------------+ | cPCB | This consists of the PCB label, nul-terminated, as would be | | | found in the UNIF "MAPR" chunk. | |-------------------------------------------------------------------------| | cMAP | This contains one, two or three bytes, which specify the mapper | | | number(s) for iNES and/or iNES 2.0. | | | 1 byte: the iNES 1.0 mapper number. | | | 2 bytes: the iNES 2.0 mapper numbers (upper, lower). | | | 3 bytes: both: iNES 1.0 number followed by iNES 2.0 numbers. | |-------------------------------------------------------------------------| | cMIR | This consists of one byte specifying the name table mirroring | | | used by the cartridge: | | | [00] = Horizontal mirroring, hard-wired. | | | [01] = Vertical mirroring, hard-wired. | | | [02] = One-screen mirroring, all from VRAM $2000. | | | [03] = One-screen mirroring, all from VRAM $2400. | | | [04] = Four-screen mirroring (that is, no mirroring at all). | | | [05] = Mapper-controlled mirroring. | |-------------------------------------------------------------------------| | cSAV | This specifies how the game uses battery-backed PRG RAM (that is,| | | Save-RAM): | | | [00] = The cartridge does not have PRG RAM. | | | [01] = The cartridge has battery-backed PRG RAM. | | | [02] = The cartridge has PRG RAM, but it's not battery-backed. | |-------------------------------------------------------------------------| | cTVB | The television broadcast standard the game expects the console | | | and display set to observe: | | | [00] = NTSC (screen size 256x224 pixels, 60 Hz refresh rate) | | | [01] = PAL (screen size 256x240 pixels, 50 Hz refresh rate) | +-------------------------------------------------------------------------+ Only chunks that represent a *change* in the expected target file state should be given here. For example, if the cartridge's mirroring is not to be changed, then there should be no cMIR chunk. If the board and/or mapper is changed at all, it is recommended to specify as much information (using cPCB and cMAP) about it as possible. If applying the patch to a format other than UNIF or iNES, that uses a differ- ent way to specifying the board/mapper type, then you'll just have to do your best to devise a suitable representation of this information, probably from cPCB. ------------------------------------------------------------------------------- -------------- CART: Consolidated cartridge header modifications -------------- ------------------------------------------------------------------------------- This is based on the structure of INFO, and basically does the same thing as the simplified cartridge chunks, above, and is deprecated in favor of them, but for completeness is described here. First, the "locale" field is present, but should be empty, having only the nul- terminator. The idea is to allow CART to be processed with the same mechanism that processes INFO. BOARD The identifier of the cartridge PCB type. This is what would be written in a UNIF "MAPR" chunk. Equivalent to cPCB. INES-MAPPER An ASCII base-10 (decimal) representation of the iNES mapper number most closely corresponding to the new board type. If this is given, it is also required to specify BOARD. Equivalent to a decimal representation of this information in cMAP. INES2-MAPPERS Two ASCII decimal numbers, comma separated, representing the upper and lower iNES 2.0 mapper numbers. Equivalent to a decimal representation of this information in cMAP. MIRRORING Equivalent to cMIR, but does not accomodate iNES. Must be set to one of these exact values: HORIZONTAL VERTICAL ONE-2000 ONE-2400 FOUR-SCREEN MAPPER INES-MIRRORING As for MIRRORING, but limited to HORIZONTAL, VERTICAL or FOUR-SCREEN. TVCI Equivalent to cTVB, using one of these values: NTSC PAL ============================= MISCELLANEOUS TOPICS ============================ Conversion from one NES cartridge format to another is beyond the scope of this format. The result of patching a file should be a file in the same format. It is allowed, but by no means required, for a patcher to perform cartridge type conversion if the user requests it. It is allowed to rearrange UNIF chunks if it makes things easier for the patcher. It is suggested that patchers load the entire target file into memory and oper- ate on *that*, keeping track of ROM chip boundaries as you go. There are no requirements imposed on patchers as to what NES cartridge formats to support. I imagine most, if not all, will support iNES. It is recommended that UNIF and iNES Extended by supported as well, but, again, this is not a req- uirement. As with all XRIF files, the filename extension of XRIF+NES files is ".xrif", or, for filesystems that only allow three-letter-long filename extensions, ".xri". Personally, I pronounce the name of the format as "EKS-riff plus enn-ee-ess". Those who pronounce it "EKS-riff plus ness" will one day have to answer for this perversion. Of that, you can be certain. =============================== REVISION HISTORY ============================== ------------------------------- JANUARY 4, 2006 ------------------------------- Initial publication. -------------------------------- APRIL 26, 2006 ------------------------------- Made flag bytes (in XAPP) alternate between Advisory and Mandatory, as in XRIF. Moved the CART flag to the second byte, since it's logically Mandatory, not Ad- visory. Added a Mandatory flag for chip creation/deletion. Added a "double-barreled" CSEL that selects the source chip separately, and ad- ded a Mandatory flag for it. Mandated that CSEL, if used, must be present before any Payload chunks. ------------------------------- JANUARY 10, 2008 ------------------------------ Added simplified cartridge chunks (cPCB and so forth). Noted that XRIF+NES does not apply to FDS games. =========================== NOTICE OF COPYING RIGHTS ========================== This document (as well as XRIF+NES itself) was created by Vystrix Nexoth. How- ever, this document, and the format it describes, are both committed to the public domain. This means you're free to distribute copies of this document, and to implement the format described, with no restrictions or requirements imposed on you by me. -- Vystrix Nexoth