From 93a6926b43115fd0ea2f390116be21fbc1a449f9 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Fri, 6 Mar 2026 15:36:02 -0500 Subject: [PATCH] Split flag 10 --- .../Extensions/NESCart.cs | 28 +++++++++ SabreTools.Serialization/Models/NES/Enums.cs | 59 ++++--------------- .../Models/NES/Header1.cs | 54 ++++++++++++++++- SabreTools.Serialization/Readers/NESCart.cs | 34 +++++++---- .../Wrappers/NESCart.Printing.cs | 50 ++++------------ SabreTools.Serialization/Wrappers/NESCart.cs | 50 ++++++++++------ 6 files changed, 160 insertions(+), 115 deletions(-) diff --git a/SabreTools.Serialization/Extensions/NESCart.cs b/SabreTools.Serialization/Extensions/NESCart.cs index 3be12544..b53e1e85 100644 --- a/SabreTools.Serialization/Extensions/NESCart.cs +++ b/SabreTools.Serialization/Extensions/NESCart.cs @@ -165,6 +165,34 @@ namespace SabreTools.Data.Extensions }; } + /// + /// Convert a value to string + /// + public static string FromTVSystem(this TVSystem system) + { + return system switch + { + TVSystem.NTSC => "NTSC", + TVSystem.PAL => "PAL", + _ => $"Unknown {(byte)system}", + }; + } + + /// + /// Convert a value to string + /// + public static string FromTVSystemExtended(this TVSystemExtended system) + { + return system switch + { + TVSystemExtended.NTSC => "NTSC", + TVSystemExtended.DualCompatible1 => "Dual-compatible (0x01)", + TVSystemExtended.PAL => "PAL", + TVSystemExtended.DualCompatible3 => "Dual-compatible (0x03)", + _ => $"Unknown {(byte)system}", + }; + } + /// /// Convert a value to string /// diff --git a/SabreTools.Serialization/Models/NES/Enums.cs b/SabreTools.Serialization/Models/NES/Enums.cs index aa97467a..f3b568cc 100644 --- a/SabreTools.Serialization/Models/NES/Enums.cs +++ b/SabreTools.Serialization/Models/NES/Enums.cs @@ -1,51 +1,5 @@ -using System; - namespace SabreTools.Data.Models.NES { - /// - /// TV system, PRG-RAM presence (unofficial, rarely used extension) - /// - [Flags] - public enum Flag10 : byte - { - #region Bits 0-1 - - NTSC = 0b000000, - DualCompatible1 = 0b000001, - PAL = 0b000010, - DualCompatible2 = 0b000011, - - #endregion - - #region Bit 4 - - /// - /// PRG RAM ($6000-$7FFF) present - /// - PRGRAMPresent = 0b000000, - - /// - /// PRG RAM ($6000-$7FFF) not present - /// - PRGRAMNotPresent = 0b010000, - - #endregion - - #region Bit 5 - - /// - /// Board has no bus conflicts - /// - BoardHasNoBusConflicts = 0b000000, - - /// - /// Board has bus conflicts - /// - BoardHasBusConflicts = 0b100000, - - #endregion - } - /// /// Console Type /// @@ -625,12 +579,25 @@ namespace SabreTools.Data.Models.NES /// /// TV system (rarely used extension) /// + /// Byte 9 public enum TVSystem : byte { NTSC = 0x00, PAL = 0x01, } + /// + /// TV system with extended values + /// + /// Actually only 2 bits (bits 0-1 of flag 10) + public enum TVSystemExtended : byte + { + NTSC = 0x00, + DualCompatible1 = 0x01, + PAL = 0x02, + DualCompatible3 = 0x03, + } + /// /// Vs. Hardware Type /// diff --git a/SabreTools.Serialization/Models/NES/Header1.cs b/SabreTools.Serialization/Models/NES/Header1.cs index a2db94a4..72a78e26 100644 --- a/SabreTools.Serialization/Models/NES/Header1.cs +++ b/SabreTools.Serialization/Models/NES/Header1.cs @@ -36,14 +36,64 @@ namespace SabreTools.Data.Models.NES /// public TVSystem TVSystem { get; set; } + #region Byte 10 + /// - /// TV system, PRG-RAM presence (unofficial, rarely used extension) + /// TV system with extended values /// /// + /// Byte 10, Bits 0-1 + /// /// This byte is not part of the official specification, and relatively /// few emulators honor it. /// - public Flag10 Flag10 { get; set; } + public TVSystemExtended TVSystemExtended { get; set; } + + /// + /// Unknown reserved bits + /// + /// + /// Byte 10, Bits 2-3 + /// + /// This byte is not part of the official specification, and relatively + /// few emulators honor it. + /// + public byte ReservedBits23 { get; set; } + + /// + /// PRG RAM ($6000-$7FFF) present + /// + /// + /// Byte 10, Bit 4 + /// + /// This byte is not part of the official specification, and relatively + /// few emulators honor it. + /// + public bool PRGRAMPresent { get; set; } + + /// + /// Board has bus conflicts + /// + /// + /// Byte 10, Bit 5 + /// + /// This byte is not part of the official specification, and relatively + /// few emulators honor it. + /// + public bool HasBusConflicts { get; set; } + + /// + /// Unknown reserved bits + /// + /// + /// Byte 10, Bits 6-7 + /// + /// This byte is not part of the official specification, and relatively + /// few emulators honor it. + /// + public byte ReservedBits67 { get; set; } + + #endregion /// /// Unused padding to align to 16 bytes diff --git a/SabreTools.Serialization/Readers/NESCart.cs b/SabreTools.Serialization/Readers/NESCart.cs index 4325857a..cc513d7b 100644 --- a/SabreTools.Serialization/Readers/NESCart.cs +++ b/SabreTools.Serialization/Readers/NESCart.cs @@ -93,17 +93,17 @@ namespace SabreTools.Serialization.Readers byte prgRomSize = data.ReadByteValue(); byte chrRomSize = data.ReadByteValue(); - byte flag6 = data.ReadByteValue(); - NametableArrangement nametableArrangement = (NametableArrangement)(flag6 & 0x01); - bool batteryBackedPrgRam = ((flag6 >> 1) & 0x01) != 0; - bool trainerPresent = ((flag6 >> 2) & 0x01) != 0; - bool alternativeNametableLayout = ((flag6 >> 3) & 0x01) != 0; - byte mapperLowerNibble = (byte)(flag6 >> 4); + byte byte6 = data.ReadByteValue(); + NametableArrangement nametableArrangement = (NametableArrangement)(byte6 & 0x01); + bool batteryBackedPrgRam = ((byte6 >> 1) & 0x01) != 0; + bool trainerPresent = ((byte6 >> 2) & 0x01) != 0; + bool alternativeNametableLayout = ((byte6 >> 3) & 0x01) != 0; + byte mapperLowerNibble = (byte)(byte6 >> 4); - byte flag7 = data.ReadByteValue(); - ConsoleType consoleType = (ConsoleType)(flag7 & 0x03); - bool nes20 = ((flag7 >> 2) & 0x02) == 0x02; - byte mapperUpperNibble = (byte)(flag7 >> 4); + byte byte7 = data.ReadByteValue(); + ConsoleType consoleType = (ConsoleType)(byte7 & 0x03); + bool nes20 = ((byte7 >> 2) & 0x02) == 0x02; + byte mapperUpperNibble = (byte)(byte7 >> 4); // NES 2.0 if (nes20) @@ -147,21 +147,29 @@ namespace SabreTools.Serialization.Readers obj.PRGROMSize = prgRomSize; obj.CHRROMSize = chrRomSize; - // Flag 6 + // Byte 6 obj.NametableArrangement = nametableArrangement; obj.BatteryBackedPRGRAM = batteryBackedPrgRam; obj.TrainerPresent = trainerPresent; obj.AlternativeNametableLayout = alternativeNametableLayout; obj.MapperLowerNibble = mapperLowerNibble; - // Flag 7 + // Byte 7 obj.ConsoleType = consoleType; obj.NES20 = nes20; obj.MapperUpperNibble = mapperUpperNibble; obj.PRGRAMSize = data.ReadByteValue(); obj.TVSystem = (TVSystem)data.ReadByteValue(); - obj.Flag10 = (Flag10)data.ReadByteValue(); + + // Byte 10 + byte byte10 = data.ReadByteValue(); + obj.TVSystemExtended = (TVSystemExtended)(byte10 & 0x03); + obj.ReservedBits23 = (byte)((byte10 >> 2) & 0x03); + obj.PRGRAMPresent = ((byte10 >> 4) & 0x01) == 0x01; + obj.HasBusConflicts = ((byte10 >> 5) & 0x01) == 0x01; + obj.ReservedBits67 = (byte)((byte10 >> 6) & 0x03); + obj.Padding = data.ReadBytes(5); return obj; diff --git a/SabreTools.Serialization/Wrappers/NESCart.Printing.cs b/SabreTools.Serialization/Wrappers/NESCart.Printing.cs index d3418cc0..40a6eeed 100644 --- a/SabreTools.Serialization/Wrappers/NESCart.Printing.cs +++ b/SabreTools.Serialization/Wrappers/NESCart.Printing.cs @@ -91,7 +91,8 @@ namespace SabreTools.Serialization.Wrappers builder.AppendLine(header1.PRGRAMSize, prefixString: " PRG-RAM size in 8KiB units"); // Byte 9 - builder.AppendLine($" TV system: {header1.TVSystem} (0x{header1.TVSystem:X})"); + string tvSystem = header1.TVSystem.FromTVSystem(); + builder.AppendLine(tvSystem, " TV system"); // Byte 10 #region Flag 10 @@ -99,46 +100,21 @@ namespace SabreTools.Serialization.Wrappers builder.AppendLine(" Flag 10:"); // Bits 0-1 -#if NET20 || NET35 - if ((header1.Flag10 & Flag10.DualCompatible2) != 0) -#else - if (header1.Flag10.HasFlag(Flag10.DualCompatible2)) -#endif - builder.AppendLine(" TV System: Dual-compatible"); -#if NET20 || NET35 - else if ((header1.Flag10 & Flag10.PAL) != 0) -#else - else if (header1.Flag10.HasFlag(Flag10.PAL)) -#endif - builder.AppendLine(" TV System: PAL"); -#if NET20 || NET35 - else if ((header1.Flag10 & Flag10.DualCompatible1) != 0) -#else - else if (header1.Flag10.HasFlag(Flag10.DualCompatible1)) -#endif - builder.AppendLine(" TV System: Dual-compatible"); - else - builder.AppendLine(" TV System: NTSC"); + string tvSystemExtended = header1.TVSystemExtended.FromTVSystemExtended(); + builder.AppendLine(tvSystemExtended, " TV System Extended"); + + // Bits 2-3 + builder.AppendLine(header1.ReservedBits23, " Reserved bits 1-2"); // Bit 4 -#if NET20 || NET35 - if ((header1.Flag10 & Flag10.PRGRAMNotPresent) != 0) -#else - if (header1.Flag10.HasFlag(Flag10.PRGRAMNotPresent)) -#endif - builder.AppendLine(" PRG-RAM: Not present"); - else - builder.AppendLine(" PRG-RAM: Present"); + string prgRamPresent = header1.PRGRAMPresent ? "Present" : "Not present"; + builder.AppendLine(prgRamPresent, " PRG-RAM"); // Bit 5 -#if NET20 || NET35 - if ((header1.Flag10 & Flag10.BoardHasBusConflicts) != 0) -#else - if (header1.Flag10.HasFlag(Flag10.BoardHasBusConflicts)) -#endif - builder.AppendLine(" Has Bus Conflicts: True"); - else - builder.AppendLine(" Has Bus Conflicts: False"); + builder.AppendLine(header1.HasBusConflicts, " Has Bus Conflicts"); + + // Bits 6-7 + builder.AppendLine(header1.ReservedBits67, " Reserved bits 6-7"); #endregion diff --git a/SabreTools.Serialization/Wrappers/NESCart.cs b/SabreTools.Serialization/Wrappers/NESCart.cs index f52e1164..d7046889 100644 --- a/SabreTools.Serialization/Wrappers/NESCart.cs +++ b/SabreTools.Serialization/Wrappers/NESCart.cs @@ -147,9 +147,7 @@ namespace SabreTools.Serialization.Wrappers #region NES 1.0 - /// - /// Indicates if the board has bus conflicts - /// + /// /// Defined only for NES 1.0 public bool HasBusConflicts { @@ -159,19 +157,13 @@ namespace SabreTools.Serialization.Wrappers if (Header is null || Header is not Header1 header1) return false; -#if NET20 || NET35 - return (header1.Flag10 & Flag10.BoardHasBusConflicts) != 0; -#else - return header1.Flag10.HasFlag(Flag10.BoardHasBusConflicts); -#endif + return header1.HasBusConflicts; } } - /// - /// Indicates if PRG RAM at $6000-$7FFF is present - /// + /// /// Defined only for NES 1.0 - public bool HasPRGRAM + public bool PRGRAMPresent { get { @@ -179,11 +171,35 @@ namespace SabreTools.Serialization.Wrappers if (Header is null || Header is not Header1 header1) return false; -#if NET20 || NET35 - return (header1.Flag10 & Flag10.PRGRAMNotPresent) == 0; -#else - return !header1.Flag10.HasFlag(Flag10.PRGRAMNotPresent); -#endif + return header1.PRGRAMPresent; + } + } + + /// + /// Defined only for NES 1.0 + public TVSystem TVSystem + { + get + { + // Missing or invalid header + if (Header is null || Header is not Header1 header1) + return TVSystem.NTSC; + + return header1.TVSystem; + } + } + + /// + /// Defined only for NES 1.0 + public TVSystemExtended TVSystemExtended + { + get + { + // Missing or invalid header + if (Header is null || Header is not Header1 header1) + return TVSystemExtended.NTSC; + + return header1.TVSystemExtended; } }