diff --git a/SabreTools.Serialization/Models/NES/Cart.cs b/SabreTools.Serialization/Models/NES/Cart.cs
new file mode 100644
index 00000000..55b9f78a
--- /dev/null
+++ b/SabreTools.Serialization/Models/NES/Cart.cs
@@ -0,0 +1,47 @@
+namespace SabreTools.Data.Models.NES
+{
+ ///
+ /// NES headered cart
+ ///
+ ///
+ ///
+ public class Cart
+ {
+ ///
+ /// NES 1.0 or 2.0 header
+ ///
+ public Header? Header { get; set; }
+
+ ///
+ /// Trainer, if present (0 or 512 bytes)
+ ///
+ public byte[] Trainer { get; set; } = [];
+
+ ///
+ /// PRG ROM data (16384 * x bytes)
+ ///
+ public byte[] PRGROMData { get; set; } = [];
+
+ ///
+ /// CHR ROM data, if present (8192 * y bytes)
+ ///
+ public byte[] CHRROMData { get; set; } = [];
+
+ ///
+ /// PlayChoice INST-ROM, if present (0 or 8192 bytes)
+ ///
+ public byte[] PlayChoiceINSTROM { get; set; } = [];
+
+ ///
+ /// PlayChoice PROM, if present (16 bytes Data, 16 bytes CounterOut)
+ ///
+ /// This is often missing; see PC10 ROM-Images for details
+ public byte[] PlayChoicePROM { get; set; } = [];
+
+ ///
+ /// Some ROM-Images additionally contain a 128-byte (or sometimes 127-byte)
+ /// title at the end of the file.
+ ///
+ public byte[] Title { get; set; } = [];
+ }
+}
diff --git a/SabreTools.Serialization/Models/NES/Enums.cs b/SabreTools.Serialization/Models/NES/Enums.cs
new file mode 100644
index 00000000..b66b9c16
--- /dev/null
+++ b/SabreTools.Serialization/Models/NES/Enums.cs
@@ -0,0 +1,816 @@
+using System;
+
+namespace SabreTools.Data.Models.NES
+{
+ ///
+ /// Mapper, mirroring, battery, trainer
+ ///
+ /// Bits 4-7 are the lower nybble of mapper number
+ [Flags]
+ public enum Flag6 : byte
+ {
+ #region Bit 0
+
+ ///
+ /// Vertical arrangement ("horizontal mirrored") or mapper-controlled
+ ///
+ /// CIRAM A10 = PPU A11
+ NametableArrangementVertical = 0b00000000,
+
+ ///
+ /// Horizontal arrangement ("vertically mirrored")
+ ///
+ /// CIRAM A10 = PPU A10
+ NametableArrangementHorizontal = 0b00000001,
+
+ #endregion
+
+ #region Bit 1
+
+ ///
+ /// Cartridge contains battery-backed PRG RAM ($6000-7FFF)
+ /// or other persistent memory not present
+ ///
+ BatteryBackedPRGRAMNotPresent = 0b00000000,
+
+ ///
+ /// Cartridge contains battery-backed PRG RAM ($6000-7FFF)
+ /// or other persistent memory present
+ ///
+ BatteryBackedPRGRAMPresent = 0b00000010,
+
+ #endregion
+
+ #region Bit 2
+
+ ///
+ /// 512-byte trainer at $7000-$71FF
+ ///
+ TrainerNotPresent = 0b00000000,
+
+ ///
+ /// 512-byte trainer at $7000-$71FF
+ ///
+ /// Stored before PRG data
+ TrainerPresent = 0b00000100,
+
+ #endregion
+
+ #region Bit 3
+
+ ///
+ /// Alternative nametable layout
+ ///
+ AlternativeNametableLayout = 0b00001000,
+
+ #endregion
+ }
+
+ ///
+ /// Mapper, VS/Playchoice, NES 2.0
+ ///
+ /// Bits 4-7 are the upper nybble of mapper number
+ [Flags]
+ public enum Flag7 : byte
+ {
+ #region Bits 0-1
+
+ ///
+ /// Nintendo Entertainment System/Family Computer
+ ///
+ StandardSystem = 0b00000000,
+
+ ///
+ /// VS Unisystem
+ ///
+ VSUnisystem = 0b00000001,
+
+ ///
+ /// PlayChoice-10 (8 KB of Hint Screen data stored after CHR data)
+ ///
+ PlayChoice10 = 0b00000010,
+
+ ///
+ /// Extended Console Type
+ ///
+ ExtendedConsoleType = 0b00000011,
+
+ #endregion
+
+ #region Bits 2-3
+
+ ///
+ /// If equal to 2, flags 8-15 are in NES 2.0 format
+ ///
+ NES20 = 0b00001000,
+
+ #endregion
+ }
+
+ ///
+ /// TV system (rarely used extension)
+ ///
+ [Flags]
+ public enum TVSystem : byte
+ {
+ NTSC = 0b00000000,
+ PAL = 0b00000001,
+ }
+
+ ///
+ /// TV system, PRG-RAM presence (unofficial, rarely used extension)
+ ///
+ [Flags]
+ public enum Flag10 : byte
+ {
+ #region Bits 0-1
+
+ NTSC = 0b00000000,
+ DualCompatible1 = 0b00000001,
+ PAL = 0b00000010,
+ DualCompatible2 = 0b00000011,
+
+ #endregion
+
+ #region Bit 4
+
+ ///
+ /// PRG RAM ($6000-$7FFF) present
+ ///
+ PRGRAMPresent = 0b00000000,
+
+ ///
+ /// PRG RAM ($6000-$7FFF) not present
+ ///
+ PRGRAMNotPresent = 0b00010000,
+
+ #endregion
+
+ #region Bit 5
+
+ ///
+ /// Board has no bus conflicts
+ ///
+ BoardHasNoBusConflicts = 0b00000000,
+
+ ///
+ /// Board has bus conflicts
+ ///
+ BoardHasBusConflicts = 0b00100000,
+
+ #endregion
+ }
+
+ ///
+ /// CPU/PPU Timing
+ ///
+ [Flags]
+ public enum CPUPPUTiming : byte
+ {
+ #region Bits 0-1
+
+ ///
+ /// NTSC NES
+ ///
+ RP2C02 = 0b00000000,
+
+ ///
+ /// Licensed PAL NES
+ ///
+ RP2C07 = 0b00000001,
+
+ ///
+ /// Multiple-region
+ ///
+ MultipleRegion = 0b00000010,
+
+ ///
+ /// Dendy
+ ///
+ UA6538 = 0b00000011,
+
+ #endregion
+ }
+
+ ///
+ /// Vs. System Type and Extended Console Type
+ ///
+ [Flags]
+ public enum ExtendedSystemType : byte
+ {
+ #region Bits 0-3 (Vs. System Type)
+
+ ///
+ /// Any RP2C03/RC2C03 variant
+ ///
+ AnyRP2C03RC2C03Variant = 0x00,
+
+ ///
+ /// Reserved
+ ///
+ VsReserved1 = 0x01,
+
+ ///
+ /// RP2C04-0001
+ ///
+ RP2C040001 = 0x02,
+
+ ///
+ /// RP2C04-0002
+ ///
+ RP2C040002 = 0x03,
+
+ ///
+ /// RP2C04-0003
+ ///
+ RP2C040003 = 0x04,
+
+ ///
+ /// RP2C04-0004
+ ///
+ RP2C040004 = 0x05,
+
+ ///
+ /// Reserved
+ ///
+ Reserved6 = 0x06,
+
+ ///
+ /// Reserved
+ ///
+ VsReserved7 = 0x07,
+
+ ///
+ /// RC2C05-01 (signature unknown)
+ ///
+ RC2C0501 = 0x08,
+
+ ///
+ /// RC2C05-02 ($2002 AND $3F =$3D)
+ ///
+ RC2C0502 = 0x09,
+
+ ///
+ /// RC2C05-03 ($2002 AND $1F =$1C)
+ ///
+ RC2C0503 = 0x0A,
+
+ ///
+ /// RC2C05-04 ($2002 AND $1F =$1B)
+ ///
+ RC2C0504 = 0x0B,
+
+ ///
+ /// Reserved
+ ///
+ VsReservedC = 0x0C,
+
+ ///
+ /// Reserved
+ ///
+ VsReservedD = 0x0D,
+
+ ///
+ /// Reserved
+ ///
+ VsReservedE = 0x0E,
+
+ ///
+ /// Reserved
+ ///
+ VsReservedF = 0x0F,
+
+ #endregion
+
+ #region Bits 4-7 (Vs. System Type)
+
+ ///
+ /// Vs. Unisystem (normal)
+ ///
+ VsUnisystem = 0x00,
+
+ ///
+ /// Vs. Unisystem (RBI Baseball protection)
+ ///
+ VsUnisystemRBIBaseballProtection = 0x10,
+
+ ///
+ /// Vs. Unisystem (TKO Boxing protection)
+ ///
+ VsUnisystemTKOBoxingProtection = 0x20,
+
+ ///
+ /// Vs. Unisystem (Super Xevious protection)
+ ///
+ VsUnisystemSuperXeviousProtection = 0x30,
+
+ ///
+ /// Vs. Unisystem (Vs. Ice Climber Japan protection)
+ ///
+ VsUnisystemVsIceClimberJapanProtection = 0x40,
+
+ ///
+ /// Vs. Dual System (normal)
+ ///
+ VsDualSystem = 0x50,
+
+ ///
+ /// Vs. Dual System (Raid on Bungeling Bay protection)
+ ///
+ VsDualSystemRaidOnBungelingBayProtection = 0x60,
+
+ #endregion
+
+ #region Bits 0-3 (Extended Console Type)
+
+ ///
+ /// Regular NES/Famicom/Dendy
+ ///
+ RegularSystem = 0x00,
+
+ ///
+ /// Nintendo Vs. System
+ ///
+ NintendoVsSystem = 0x01,
+
+ ///
+ /// Playchoice 10
+ ///
+ Playchoice10 = 0x02,
+
+ ///
+ /// Regular Famiclone, but with CPU that supports Decimal Mode
+ ///
+ RegularFamicloneDecimalMode = 0x03,
+
+ ///
+ /// Regular NES/Famicom with EPSM module or plug-through cartridge
+ ///
+ RegularNESWithEPSM = 0x04,
+
+ ///
+ /// V.R. Technology VT01 with red/cyan STN palette
+ ///
+ VRTechnologyVT01 = 0x05,
+
+ ///
+ /// V.R. Technology VT02
+ ///
+ VRTechnologyVT02 = 0x06,
+
+ ///
+ /// V.R. Technology VT03
+ ///
+ VRTechnologyVT03 = 0x07,
+
+ ///
+ /// V.R. Technology VT09
+ ///
+ VRTechnologyVT09 = 0x08,
+
+ ///
+ /// V.R. Technology VT32
+ ///
+ VRTechnologyVT32 = 0x09,
+
+ ///
+ /// V.R. Technology VT369
+ ///
+ VRTechnologyVT369 = 0x0A,
+
+ ///
+ /// UMC UM6578
+ ///
+ UMCUM6578 = 0x0B,
+
+ ///
+ /// Famicom Network System
+ ///
+ FamicomNetworkSystem = 0x0C,
+
+ ///
+ /// Reserved
+ ///
+ ExtendedConsoleReservedD = 0x0D,
+
+ ///
+ /// Reserved
+ ///
+ ExtendedConsoleReservedE = 0x0E,
+
+ ///
+ /// Reserved
+ ///
+ ExtendedConsoleReservedF = 0x0F,
+
+ #endregion
+ }
+
+ ///
+ /// Default Expansion Device
+ ///
+ public enum DefaultExpansionDevice : byte
+ {
+ ///
+ /// Unspecified
+ ///
+ Unspecified = 0x00,
+
+ ///
+ /// Standard NES/Famicom controllers
+ ///
+ StandardControllers = 0x01,
+
+ ///
+ /// NES Four Score/Satellite with two additional standard controllers
+ ///
+ NESFourScore = 0x02,
+
+ ///
+ /// Famicom Four Players Adapter with two additional standard controllers
+ /// using the "simple" protocol
+ ///
+ FamicomFourPlayersAdapter = 0x03,
+
+ ///
+ /// Vs. System (1P via $4016)
+ ///
+ VsSystem4016 = 0x04,
+
+ ///
+ /// Vs. System (1P via $4017)
+ ///
+ VsSystem4017 = 0x05,
+
+ ///
+ /// Reserved
+ ///
+ Reserved06 = 0x06,
+
+ ///
+ /// Vs. Zapper
+ ///
+ VsZapper = 0x07,
+
+ ///
+ /// Zapper ($4017)
+ ///
+ Zapper4017 = 0x08,
+
+ ///
+ /// Two Zappers
+ ///
+ TwoZappers = 0x09,
+
+ ///
+ /// Bandai Hyper Shot Lightgun
+ ///
+ BandaiHyperShotLightgun = 0x0A,
+
+ ///
+ /// Power Pad Side A
+ ///
+ PowerPadSideA = 0x0B,
+
+ ///
+ /// Power Pad Side B
+ ///
+ PowerPadSideB = 0x0C,
+
+ ///
+ /// Family Trainer Side A
+ ///
+ FamilyTrainerSideA = 0x0D,
+
+ ///
+ /// Family Trainer Side B
+ ///
+ FamilyTrainerSideB = 0x0E,
+
+ ///
+ /// Arkanoid Vaus Controller (NES)
+ ///
+ ArkanoidVausControllerNES = 0x0F,
+
+ ///
+ /// Arkanoid Vaus Controller (Famicom)
+ ///
+ ArkanoidVausControllerFamicom = 0x10,
+
+ ///
+ /// Two Vaus Controllers plus Famicom Data Recorder
+ ///
+ TwoVausControllers = 0x11,
+
+ ///
+ /// Konami Hyper Shot Controller
+ ///
+ KonamiHyperShotController = 0x12,
+
+ ///
+ /// Coconuts Pachinko Controller
+ ///
+ CoconutsPachinkoController = 0x13,
+
+ ///
+ /// Exciting Boxing Punching Bag (Blowup Doll)
+ ///
+ ExcitingBoxingPunchingBag = 0x14,
+
+ ///
+ /// Jissen Mahjong Controller
+ ///
+ JissenMahjongController = 0x15,
+
+ ///
+ /// 米澤 (Yonezawa) Party Tap
+ ///
+ YonezawaPartyTap = 0x16,
+
+ ///
+ /// Oeka Kids Tablet
+ ///
+ OekaKidsTablet = 0x17,
+
+ ///
+ /// Sunsoft Barcode Battler
+ ///
+ SunsoftBarcodeBattler = 0x18,
+
+ ///
+ /// Miracle Piano Keyboard
+ ///
+ MiraclePianoKeyboard = 0x19,
+
+ ///
+ /// Pokkun Moguraa Tap-tap Mat (Whack-a-Mole Mat and Mallet)
+ ///
+ PokkunMoguraaTapTapMat = 0x1A,
+
+ ///
+ /// Top Rider (Inflatable Bicycle)
+ ///
+ TopRider = 0x1B,
+
+ ///
+ /// Double-Fisted (Requires or allows use of two controllers by one player)
+ ///
+ DoubleFisted = 0x1C,
+
+ ///
+ /// Famicom 3D System
+ ///
+ Famicom3DSystem = 0x1D,
+
+ ///
+ /// Doremikko Keyboard
+ ///
+ DoremikkoKeyboard = 0x1E,
+
+ ///
+ /// R.O.B. Gyromite
+ ///
+ ROBGyromite = 0x1F,
+
+ ///
+ /// Famicom Data Recorder ("silent" keyboard)
+ ///
+ FamicomDataRecorder = 0x20,
+
+ ///
+ /// ASCII Turbo File
+ ///
+ ASCIITurboFile = 0x21,
+
+ ///
+ /// IGS Storage Battle Box
+ ///
+ IGSStorageBattleBox = 0x22,
+
+ ///
+ /// Family BASIC Keyboard plus Famicom Data Recorder
+ ///
+ FamilyBASICKeyboard = 0x23,
+
+ ///
+ /// 东达 (Dōngdá) PEC Keyboard
+ ///
+ DongdaPECKeyboard = 0x24,
+
+ ///
+ /// 普澤 (Pǔzé, a.k.a. Bit Corp.) Bit-79 Keyboard
+ ///
+ BitCorpBit79Keyboard = 0x25,
+
+ ///
+ /// 小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard
+ ///
+ SuborKeyboard = 0x26,
+
+ ///
+ /// 小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard plus Macro Winners Mouse
+ ///
+ SuborKeyboardPlusMacroWinnersMouse = 0x27,
+
+ ///
+ /// 小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard plus Subor Mouse via $4016
+ ///
+ SuborKeyboardPlusSuborMouse4016 = 0x28,
+
+ ///
+ /// SNES Mouse ($4016)
+ ///
+ SNESMouse4016 = 0x29,
+
+ ///
+ /// Multicart
+ ///
+ Multicart = 0x2A,
+
+ ///
+ /// Two SNES controllers replacing the two standard NES controllers
+ ///
+ TwoSNESControllers = 0x2B,
+
+ ///
+ /// RacerMate Bicycle
+ ///
+ RacerMateBicycle = 0x2C,
+
+ ///
+ /// U-Force
+ ///
+ UForce = 0x2D,
+
+ ///
+ /// R.O.B. Stack-Up
+ ///
+ ROBStackUp = 0x2E,
+
+ ///
+ /// City Patrolman Lightgun
+ ///
+ CityPatrolmanLightgun = 0x2F,
+
+ ///
+ /// Sharp C1 Cassette Interface
+ ///
+ SharpC1CassetteInterface = 0x30,
+
+ ///
+ /// Standard Controller with swapped Left-Right/Up-Down/B-A
+ ///
+ StandardControllerWithSwappedInputs = 0x31,
+
+ ///
+ /// Excalibur Sudoku Pad
+ ///
+ ExcaliburSudokuPad = 0x32,
+
+ ///
+ /// ABL Pinball
+ ///
+ ABLPinball = 0x33,
+
+ ///
+ /// Golden Nugget Casino extra buttons
+ ///
+ GoldenNuggetCasinoExtraButtons = 0x34,
+
+ ///
+ /// 科达 (Kēdá) Keyboard
+ ///
+ KedaKeyboard = 0x35,
+
+ ///
+ /// 小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard plus Subor Mouse via $4017
+ ///
+ SuborKeyboardPlusSuborMouse4017 = 0x36,
+
+ ///
+ /// Port test controller
+ ///
+ PortTestController = 0x37,
+
+ ///
+ /// Bandai Multi Game Player Gamepad buttons
+ ///
+ BandaiMultiGamePlayerGamepad = 0x38,
+
+ ///
+ /// Venom TV Dance Mat
+ ///
+ VenomTVDanceMat = 0x39,
+
+ ///
+ /// LG TV Remote Control
+ ///
+ LGTVRemoteControl = 0x3A,
+
+ ///
+ /// Famicom Network Controller
+ ///
+ FamicomNetworkController = 0x3B,
+
+ ///
+ /// King Fishing Controller
+ ///
+ KingFishingController = 0x3C,
+
+ ///
+ /// Croaky Karaoke Controller
+ ///
+ CroakyKaraokeController = 0x3D,
+
+ ///
+ /// 科王 (Kēwáng, a.k.a. Kingwon) Keyboard
+ ///
+ KingwonKeyboard = 0x3E,
+
+ ///
+ /// 泽诚 (Zéchéng) Keyboard
+ ///
+ ZechengKeyboard = 0x3F,
+
+ ///
+ /// 小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard plus L90-rotated PS/2 mouse in $4017
+ ///
+ SuborKeyboardPlusL90RotatedPS2Mouse4017 = 0x40,
+
+ ///
+ /// PS/2 Keyboard in UM6578 PS/2 port, PS/2 Mouse via $4017
+ ///
+ PS2KeyboardInUM6578PS2Port = 0x41,
+
+ ///
+ /// PS/2 Mouse in UM6578 PS/2 port
+ ///
+ PS2MouseInUM6578PS2Port = 0x42,
+
+ ///
+ /// 裕兴 (Yùxìng) Mouse via $4016
+ ///
+ YuxingMouse = 0x43,
+
+ ///
+ /// 小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard plus 裕兴 (Yùxìng)
+ /// Mouse mouse in $4016
+ ///
+ SuborKeyboardPlusYuxingMouse = 0x44,
+
+ ///
+ /// Gigggle TV Pump
+ ///
+ GigggleTVPump = 0x45,
+
+ ///
+ /// 步步高 (Bùbùgāo, a.k.a. BBK) Keyboard plus R90-rotated PS/2 mouse in $4017
+ ///
+ BBKKeyboardPlusR90RotatedPS2Mouse = 0x46,
+
+ ///
+ /// Magical Cooking
+ ///
+ MagicalCooking = 0x47,
+
+ ///
+ /// SNES Mouse ($4017)
+ ///
+ SNESMouse4017 = 0x48,
+
+ ///
+ /// Zapper ($4016)
+ ///
+ Zapper4016 = 0x49,
+
+ ///
+ /// Arkanoid Vaus Controller (Prototype)
+ ///
+ ArkanoidVausControllerPrototype = 0x4A,
+
+ ///
+ /// TV 麻雀 Game (TV Mahjong Game) Controller
+ ///
+ TVMahjongGameController = 0x4B,
+
+ ///
+ /// 麻雀激闘伝説 (Mahjong Gekitou Densetsu) Controller
+ ///
+ MahjongGekitouDensetsuController = 0x4C,
+
+ ///
+ /// 小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard plus X-inverted PS/2 mouse in $4017
+ ///
+ SuborKeyboardPlusXInvertedPS2Mouse = 0x4D,
+
+ ///
+ /// IBM PC/XT Keyboard
+ ///
+ IBMPCXTKeyboard = 0x4E,
+
+ ///
+ /// 小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard plus Mega Book Mouse
+ ///
+ SuborKeyboardPlusMegaBookMouse = 0x4F,
+ }
+}
diff --git a/SabreTools.Serialization/Models/NES/Header.cs b/SabreTools.Serialization/Models/NES/Header.cs
new file mode 100644
index 00000000..8d629775
--- /dev/null
+++ b/SabreTools.Serialization/Models/NES/Header.cs
@@ -0,0 +1,48 @@
+namespace SabreTools.Data.Models.NES
+{
+ ///
+ /// Common NES header pieces
+ ///
+ ///
+ ///
+ public abstract class Header
+ {
+ ///
+ /// Constant $4E $45 $53 $1A (ASCII "NES" followed by MS-DOS end-of-file)
+ ///
+ public byte[] IdentificationString { get; set; } = new byte[4];
+
+ ///
+ /// Size of PRG ROM in 16 KB units
+ ///
+ public byte PRGROMSize { get; set; }
+
+ ///
+ /// Size of CHR ROM in 8 KB units
+ ///
+ /// Value 0 means the board uses CHR RAM
+ public byte CHRROMSize { get; set; }
+
+ ///
+ /// Mapper, mirroring, battery, trainer
+ ///
+ public Flag6 Flag6 { get; set; }
+
+ ///
+ /// Mapper, VS/Playchoice, NES 2.0
+ ///
+ ///
+ /// The PlayChoice-10 bit is not part of the official specification,
+ /// and most emulators simply ignore the extra 8 KB of data. PlayChoice
+ /// games are designed to look good with the 2C03 RGB PPU, which handles
+ /// color emphasis differently from a standard NES PPU.
+ ///
+ /// Vs. games have a coin slot and different palettes. The detection
+ /// of which palette a particular game uses is left unspecified.
+ ///
+ /// NES 2.0 is a more recent extension to the format that allows more
+ /// flexibility in ROM and RAM size, among other things.
+ ///
+ public Flag7 Flag7 { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/NES/Header1.cs b/SabreTools.Serialization/Models/NES/Header1.cs
new file mode 100644
index 00000000..a2db94a4
--- /dev/null
+++ b/SabreTools.Serialization/Models/NES/Header1.cs
@@ -0,0 +1,53 @@
+namespace SabreTools.Data.Models.NES
+{
+ ///
+ /// NES 1.0 header information
+ ///
+ ///
+ ///
+ /// Older versions of the iNES emulator ignored bytes 7-15, and several ROM management
+ /// tools wrote messages in there. Commonly, these will be filled with "DiskDude!",
+ /// which results in 64 being added to the mapper number.
+ ///
+ /// A general rule of thumb: if the last 4 bytes are not all zero, and the header is
+ /// not marked for NES 2.0 format, an emulator should either mask off the upper 4 bits
+ /// of the mapper number or simply refuse to load the ROM.
+ ///
+ public class Header1 : Header
+ {
+ // All common header parts take up bytes 0-7
+
+ ///
+ /// Size of PRG RAM in 8 KB units
+ ///
+ ///
+ /// Value 0 infers 8 KB for compatibility; see PRG RAM circuit.
+ /// This was a later extension to the iNES format and not widely used.
+ /// NES 2.0 is recommended for specifying PRG RAM size instead.
+ ///
+ public byte PRGRAMSize { get; set; }
+
+ ///
+ /// TV system (rarely used extension)
+ ///
+ ///
+ /// Though in the official specification, very few emulators honor this bit
+ /// as virtually no ROM images in circulation make use of it.
+ ///
+ public TVSystem TVSystem { get; set; }
+
+ ///
+ /// TV system, PRG-RAM presence (unofficial, rarely used extension)
+ ///
+ ///
+ /// This byte is not part of the official specification, and relatively
+ /// few emulators honor it.
+ ///
+ public Flag10 Flag10 { get; set; }
+
+ ///
+ /// Unused padding to align to 16 bytes
+ ///
+ public byte[] Padding { get; set; } = new byte[5];
+ }
+}
diff --git a/SabreTools.Serialization/Models/NES/Header2.cs b/SabreTools.Serialization/Models/NES/Header2.cs
new file mode 100644
index 00000000..d4013d3c
--- /dev/null
+++ b/SabreTools.Serialization/Models/NES/Header2.cs
@@ -0,0 +1,80 @@
+namespace SabreTools.Data.Models.NES
+{
+ ///
+ /// NES 2.0 header information
+ ///
+ ///
+ public class Header2 : Header
+ {
+ // All common header parts take up bytes 0-7
+
+ ///
+ /// Mapper MSB/Submapper
+ ///
+ ///
+ /// Bits 0-3 - Mapper number bits 8-11
+ /// Bits 4-7 - Submapper number
+ ///
+ public byte MapperMSBSubmapper { get; set; }
+
+ ///
+ /// PRG-ROM/CHR-ROM size MSB
+ ///
+ ///
+ /// Bits 0-3 - PRG-ROM size MSB
+ /// Bits 4-7 - CHR-ROM size MSB
+ ///
+ public byte PRGCHRMSB { get; set; }
+
+ ///
+ /// PRG-RAM/EEPROM size
+ ///
+ ///
+ /// Bits 0-3 - PRG-RAM (volatile) shift count
+ /// Bits 4-7 - PRG-NVRAM/EEPROM (non-volatile) shift count
+ ///
+ /// If the shift count is zero, there is no CHR-(NV)RAM.
+ /// If the shift count is non-zero, the actual size is
+ /// "64 << shift count" bytes, i.e. 8192 bytes for a shift count of 7.
+ ///
+ public byte PRGRAMEEPROMSize { get; set; }
+
+ ///
+ /// CHR-RAM size
+ ///
+ ///
+ /// Bits 0-3 - CHR-RAM size (volatile) shift count
+ /// Bits 4-7 - CHR-NVRAM size (non-volatile) shift count
+ ///
+ /// If the shift count is zero, there is no CHR-(NV)RAM.
+ /// If the shift count is non-zero, the actual size is
+ /// "64 << shift count" bytes, i.e. 8192 bytes for a shift count of 7.
+ ///
+ public byte CHRRAMSize { get; set; }
+
+ ///
+ /// CPU/PPU timing mode
+ ///
+ public CPUPPUTiming CPUPPUTiming { get; set; }
+
+ ///
+ /// Vs. System Type and Extended Console Type
+ ///
+ ///
+ /// When Byte 7 AND 3 =1: Vs. System Type
+ /// When Byte 7 AND 3 =3: Extended Console Type
+ ///
+ public ExtendedSystemType ExtendedSystemType { get; set; }
+
+ ///
+ /// Number of miscellaneous ROMs present
+ ///
+ /// Only bits 0-1 are used
+ public bool MiscellaneousROMs { get; set; }
+
+ ///
+ /// Default Expansion Device
+ ///
+ public DefaultExpansionDevice DefaultExpansionDevice { get; set; }
+ }
+}