mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-09-24 07:45:06 +00:00
Split flag 7
This commit is contained in:
@@ -4,6 +4,21 @@ namespace SabreTools.Data.Extensions
|
||||
{
|
||||
public static class NESCart
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert a <see cref="CPUPPConsoleTypeUTiming"/> value to string
|
||||
/// </summary>
|
||||
public static string FromConsoleType(this ConsoleType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
ConsoleType.StandardSystem => "Nintendo Entertainment System/Family Computer",
|
||||
ConsoleType.VSUnisystem => "VS Unisystem",
|
||||
ConsoleType.PlayChoice10 => "PlayChoice-10 (8 KB of Hint Screen data stored after CHR data)",
|
||||
ConsoleType.ExtendedConsoleType => "Extended Console Type",
|
||||
_ => $"Unknown {(byte)type}",
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a <see cref="CPUPPUTiming"/> value to string
|
||||
/// </summary>
|
||||
|
||||
@@ -2,47 +2,6 @@ using System;
|
||||
|
||||
namespace SabreTools.Data.Models.NES
|
||||
{
|
||||
/// <summary>
|
||||
/// Mapper, VS/Playchoice, NES 2.0
|
||||
/// </summary>
|
||||
/// <remarks>Bits 4-7 are the upper nybble of mapper number</remarks>
|
||||
[Flags]
|
||||
public enum Flag7 : byte
|
||||
{
|
||||
#region Bits 0-1
|
||||
|
||||
/// <summary>
|
||||
/// Nintendo Entertainment System/Family Computer
|
||||
/// </summary>
|
||||
StandardSystem = 0b0000,
|
||||
|
||||
/// <summary>
|
||||
/// VS Unisystem
|
||||
/// </summary>
|
||||
VSUnisystem = 0b0001,
|
||||
|
||||
/// <summary>
|
||||
/// PlayChoice-10 (8 KB of Hint Screen data stored after CHR data)
|
||||
/// </summary>
|
||||
PlayChoice10 = 0b0010,
|
||||
|
||||
/// <summary>
|
||||
/// Extended Console Type
|
||||
/// </summary>
|
||||
ExtendedConsoleType = 0b0011,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Bits 2-3
|
||||
|
||||
/// <summary>
|
||||
/// If equal to 2, flags 8-15 are in NES 2.0 format
|
||||
/// </summary>
|
||||
NES20 = 0b1000,
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TV system, PRG-RAM presence (unofficial, rarely used extension)
|
||||
/// </summary>
|
||||
|
||||
@@ -23,45 +23,49 @@ namespace SabreTools.Data.Models.NES
|
||||
/// <remarks>Value 0 means the board uses CHR RAM</remarks>
|
||||
public byte CHRROMSize { get; set; }
|
||||
|
||||
#region Flag 6
|
||||
#region Byte 6
|
||||
|
||||
/// <summary>
|
||||
/// Nametable arrangement
|
||||
/// </summary>
|
||||
/// <remarks>Flag 6, Bit 0</remarks>
|
||||
/// <remarks>Byte 6, Bit 0</remarks>
|
||||
public NametableArrangement NametableArrangement { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cartridge contains battery-backed PRG RAM ($6000-7FFF)
|
||||
/// or other persistent memory
|
||||
/// </summary>
|
||||
/// <remarks>Flag 6, Bit 1</remarks>
|
||||
/// <remarks>Byte 6, Bit 1</remarks>
|
||||
public bool BatteryBackedPRGRAM { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 512-byte trainer at $7000-$71FF
|
||||
/// </summary>
|
||||
/// <remarks>Flag 6, Bit 2</remarks>
|
||||
/// <remarks>Byte 6, Bit 2</remarks>
|
||||
public bool TrainerPresent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Alternative nametable layout
|
||||
/// </summary>
|
||||
/// <remarks>Flag 6, Bit 3</remarks>
|
||||
/// <remarks>Byte 6, Bit 3</remarks>
|
||||
public bool AlternativeNametableLayout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Lower nibble of Mapper number
|
||||
/// </summary>
|
||||
/// <remarks>Flag 6, Bits 4-7</remarks>
|
||||
/// <remarks>Byte 6, Bits 4-7</remarks>
|
||||
public byte MapperLowerNibble { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Byte 7
|
||||
|
||||
/// <summary>
|
||||
/// Mapper, VS/Playchoice, NES 2.0
|
||||
/// Nametable arrangement
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Byte 7, Bits 0-1
|
||||
///
|
||||
/// 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
|
||||
@@ -69,10 +73,26 @@ namespace SabreTools.Data.Models.NES
|
||||
///
|
||||
/// Vs. games have a coin slot and different palettes. The detection
|
||||
/// of which palette a particular game uses is left unspecified.
|
||||
/// </remarks>
|
||||
public ConsoleType ConsoleType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates NES 2.0 format
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Byte 7, Bits 2-3 == 0x02
|
||||
///
|
||||
/// NES 2.0 is a more recent extension to the format that allows more
|
||||
/// flexibility in ROM and RAM size, among other things.
|
||||
/// </remarks>
|
||||
public Flag7 Flag7 { get; set; }
|
||||
public bool NES20 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Upper nibble of Mapper number
|
||||
/// </summary>
|
||||
/// <remarks>Byte 7, Bits 4-7</remarks>
|
||||
public byte MapperUpperNibble { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,13 +60,7 @@ namespace SabreTools.Serialization.Readers
|
||||
cart.CHRROMData = data.ReadBytes(chrRomSize);
|
||||
|
||||
// Read the PlayChoice INST-ROM and PROM data, if necessary
|
||||
#if NET20 || NET35
|
||||
if ((cart.Header.Flag7 & Flag7.PlayChoice10) != 0
|
||||
&& (cart.Header.Flag7 & Flag7.VSUnisystem) == 0)
|
||||
#else
|
||||
if (cart.Header.Flag7.HasFlag(Flag7.PlayChoice10)
|
||||
&& !cart.Header.Flag7.HasFlag(Flag7.VSUnisystem))
|
||||
#endif
|
||||
if (cart.Header.ConsoleType == ConsoleType.PlayChoice10)
|
||||
{
|
||||
cart.PlayChoiceINSTROM = data.ReadBytes(8192);
|
||||
cart.PlayChoicePROM = data.ReadBytes(32);
|
||||
@@ -106,14 +100,13 @@ namespace SabreTools.Serialization.Readers
|
||||
bool alternativeNametableLayout = ((flag6 >> 3) & 0x01) != 0;
|
||||
byte mapperLowerNibble = (byte)(flag6 >> 4);
|
||||
|
||||
Flag7 flag7 = (Flag7)data.ReadByteValue();
|
||||
byte flag7 = data.ReadByteValue();
|
||||
ConsoleType consoleType = (ConsoleType)(flag7 & 0x03);
|
||||
bool nes20 = ((flag7 >> 2) & 0x02) == 0x02;
|
||||
byte mapperUpperNibble = (byte)(flag7 >> 4);
|
||||
|
||||
// NES 2.0
|
||||
#if NET20 || NET35
|
||||
if ((flag7 & Flag7.NES20) != 0)
|
||||
#else
|
||||
if (flag7.HasFlag(Flag7.NES20))
|
||||
#endif
|
||||
if (nes20)
|
||||
{
|
||||
var obj = new Header2();
|
||||
|
||||
@@ -128,7 +121,11 @@ namespace SabreTools.Serialization.Readers
|
||||
obj.AlternativeNametableLayout = alternativeNametableLayout;
|
||||
obj.MapperLowerNibble = mapperLowerNibble;
|
||||
|
||||
obj.Flag7 = flag7;
|
||||
// Flag 7
|
||||
obj.ConsoleType = consoleType;
|
||||
obj.NES20 = nes20;
|
||||
obj.MapperUpperNibble = mapperUpperNibble;
|
||||
|
||||
obj.MapperMSBSubmapper = data.ReadByteValue();
|
||||
obj.PRGCHRMSB = data.ReadByteValue();
|
||||
obj.PRGRAMEEPROMSize = data.ReadByteValue();
|
||||
@@ -157,7 +154,11 @@ namespace SabreTools.Serialization.Readers
|
||||
obj.AlternativeNametableLayout = alternativeNametableLayout;
|
||||
obj.MapperLowerNibble = mapperLowerNibble;
|
||||
|
||||
obj.Flag7 = flag7;
|
||||
// Flag 7
|
||||
obj.ConsoleType = consoleType;
|
||||
obj.NES20 = nes20;
|
||||
obj.MapperUpperNibble = mapperUpperNibble;
|
||||
|
||||
obj.PRGRAMSize = data.ReadByteValue();
|
||||
obj.TVSystem = (TVSystem)data.ReadByteValue();
|
||||
obj.Flag10 = (Flag10)data.ReadByteValue();
|
||||
|
||||
@@ -74,40 +74,15 @@ namespace SabreTools.Serialization.Wrappers
|
||||
builder.AppendLine(" Flag 7:");
|
||||
|
||||
// Bits 0-1
|
||||
#if NET20 || NET35
|
||||
if ((header.Flag7 & Flag7.ExtendedConsoleType) != 0)
|
||||
#else
|
||||
if (header.Flag7.HasFlag(Flag7.ExtendedConsoleType))
|
||||
#endif
|
||||
builder.AppendLine(" System Type: Extended Console Type");
|
||||
#if NET20 || NET35
|
||||
else if ((header.Flag7 & Flag7.PlayChoice10) != 0)
|
||||
#else
|
||||
else if (header.Flag7.HasFlag(Flag7.PlayChoice10))
|
||||
#endif
|
||||
builder.AppendLine(" System Type: PlayChoice-10");
|
||||
#if NET20 || NET35
|
||||
else if ((header.Flag7 & Flag7.VSUnisystem) != 0)
|
||||
#else
|
||||
else if (header.Flag7.HasFlag(Flag7.VSUnisystem))
|
||||
#endif
|
||||
builder.AppendLine(" System Type: Vs. Unisystem");
|
||||
else
|
||||
builder.AppendLine(" System Type: Nintendo Entertainment System/Family Computer");
|
||||
string consoleType = header.ConsoleType.FromConsoleType();
|
||||
builder.AppendLine(consoleType, " System Type");
|
||||
|
||||
// Bits 2-3
|
||||
#if NET20 || NET35
|
||||
if ((header.Flag7 & Flag7.NES20) != 0)
|
||||
#else
|
||||
if (header.Flag7.HasFlag(Flag7.NES20))
|
||||
#endif
|
||||
builder.AppendLine(" NES 2.0: True");
|
||||
else
|
||||
builder.AppendLine(" NES 2.0: False");
|
||||
builder.AppendLine(header.NES20, " NES 2.0");
|
||||
|
||||
#endregion
|
||||
|
||||
byte mapperNumber = (byte)((((byte)header.Flag7 >> 4) << 4) | header.MapperLowerNibble);
|
||||
byte mapperNumber = (byte)((header.MapperUpperNibble << 4) | header.MapperLowerNibble);
|
||||
builder.AppendLine(mapperNumber, " Mapper number");
|
||||
|
||||
if (header is Header1 header1)
|
||||
@@ -175,7 +150,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
// Byte 8
|
||||
byte mapperMsb = (byte)(header2.MapperMSBSubmapper & 0x0F);
|
||||
ushort extendedMapperNumber = (ushort)((mapperMsb << 8)
|
||||
| (byte)((((byte)header.Flag7 >> 4) << 4)
|
||||
| (byte)((header.MapperUpperNibble << 4)
|
||||
| header.MapperLowerNibble));
|
||||
byte submapperNumber = (byte)(header2.MapperMSBSubmapper >> 4);
|
||||
|
||||
@@ -221,21 +196,13 @@ namespace SabreTools.Serialization.Wrappers
|
||||
builder.AppendLine(cpuTiming, " CPU timing");
|
||||
|
||||
// Byte 13
|
||||
#if NET20 || NET35
|
||||
if ((header.Flag7 & Flag7.ExtendedConsoleType) != 0)
|
||||
#else
|
||||
if (header.Flag7.HasFlag(Flag7.ExtendedConsoleType))
|
||||
#endif
|
||||
if (header.ConsoleType == ConsoleType.ExtendedConsoleType)
|
||||
{
|
||||
ExtendedConsoleType extendedConsoleType = (ExtendedConsoleType)(header2.ExtendedSystemType & 0x0F);
|
||||
string extendedConsoleTypeString = extendedConsoleType.FromExtendedConsoleType();
|
||||
builder.AppendLine(extendedConsoleTypeString, " Extended console type");
|
||||
}
|
||||
#if NET20 || NET35
|
||||
else if ((header.Flag7 & Flag7.VSUnisystem) != 0)
|
||||
#else
|
||||
else if (header.Flag7.HasFlag(Flag7.VSUnisystem))
|
||||
#endif
|
||||
else if (header.ConsoleType == ConsoleType.VSUnisystem)
|
||||
{
|
||||
VsSystemType vsSystemType = (VsSystemType)(header2.ExtendedSystemType & 0x0F);
|
||||
string vsSystemTypeString = vsSystemType.FromVsSystemType();
|
||||
|
||||
@@ -48,107 +48,8 @@ namespace SabreTools.Serialization.Wrappers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the game is meant for an extended console type
|
||||
/// </summary>
|
||||
/// <remarks>Possibly only valid for NES 2.0</remarks>
|
||||
public bool IsExtendedConsole
|
||||
{
|
||||
get
|
||||
{
|
||||
// Missing header
|
||||
if (Header is null)
|
||||
return false;
|
||||
|
||||
#if NET20 || NET35
|
||||
return (Header.Flag7 & Flag7.ExtendedConsoleType) != 0;
|
||||
#else
|
||||
return Header.Flag7.HasFlag(Flag7.ExtendedConsoleType);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the cart is using an NES 2.0 header
|
||||
/// </summary>
|
||||
public bool IsNES20
|
||||
{
|
||||
get
|
||||
{
|
||||
// Missing header
|
||||
if (Header is null)
|
||||
return false;
|
||||
|
||||
#if NET20 || NET35
|
||||
return (Header.Flag7 & Flag7.NES20) != 0;
|
||||
#else
|
||||
return Header.Flag7.HasFlag(Flag7.NES20);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the game is meant for PlayChoice-10
|
||||
/// </summary>
|
||||
public bool IsPlayChoice10
|
||||
{
|
||||
get
|
||||
{
|
||||
// Missing header
|
||||
if (Header is null)
|
||||
return false;
|
||||
|
||||
#if NET20 || NET35
|
||||
return (Header.Flag7 & Flag7.PlayChoice10) != 0
|
||||
&& (Header.Flag7 & Flag7.VSUnisystem) == 0;
|
||||
#else
|
||||
return Header.Flag7.HasFlag(Flag7.PlayChoice10)
|
||||
&& !Header.Flag7.HasFlag(Flag7.VSUnisystem);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the game is meant for a standard console
|
||||
/// </summary>
|
||||
public bool IsStandardConsole
|
||||
{
|
||||
get
|
||||
{
|
||||
// Missing header
|
||||
if (Header is null)
|
||||
return false;
|
||||
|
||||
#if NET20 || NET35
|
||||
return (Header.Flag7 & Flag7.PlayChoice10) == 0
|
||||
&& (Header.Flag7 & Flag7.VSUnisystem) == 0;
|
||||
#else
|
||||
return !Header.Flag7.HasFlag(Flag7.PlayChoice10)
|
||||
&& !Header.Flag7.HasFlag(Flag7.VSUnisystem);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the game is meant for Vs. Unisystem
|
||||
/// </summary>
|
||||
public bool IsVsUnisystem
|
||||
{
|
||||
get
|
||||
{
|
||||
// Missing header
|
||||
if (Header is null)
|
||||
return false;
|
||||
|
||||
#if NET20 || NET35
|
||||
return (Header.Flag7 & Flag7.PlayChoice10) == 0
|
||||
&& (Header.Flag7 & Flag7.VSUnisystem) != 0;
|
||||
#else
|
||||
return !Header.Flag7.HasFlag(Flag7.PlayChoice10)
|
||||
&& Header.Flag7.HasFlag(Flag7.VSUnisystem);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/// <inheritdoc cref="Header.ConsoleType"/>
|
||||
public ConsoleType ConsoleType => Header?.ConsoleType ?? ConsoleType.StandardSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Mapper number
|
||||
@@ -162,7 +63,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
if (Header is null)
|
||||
return 0;
|
||||
|
||||
int mapperNumber = (((byte)Header.Flag7 >> 4) << 4) | Header.MapperLowerNibble;
|
||||
int mapperNumber = (Header.MapperUpperNibble << 4) | Header.MapperLowerNibble;
|
||||
if (Header is Header2 header2)
|
||||
mapperNumber = ((header2.MapperMSBSubmapper & 0x0F) << 8) | mapperNumber;
|
||||
|
||||
@@ -174,6 +75,9 @@ namespace SabreTools.Serialization.Wrappers
|
||||
public NametableArrangement NametableArrangement
|
||||
=> Header?.NametableArrangement ?? NametableArrangement.Vertical;
|
||||
|
||||
/// <inheritdoc cref="Header.NES20"/>
|
||||
public bool NES20 => Header?.NES20 ?? false;
|
||||
|
||||
/// <summary>
|
||||
/// PRG-RAM size in bytes
|
||||
/// </summary>
|
||||
@@ -366,15 +270,11 @@ namespace SabreTools.Serialization.Wrappers
|
||||
if (Header is null || Header is not Header2 header2)
|
||||
return ExtendedConsoleType.RegularSystem;
|
||||
|
||||
#if NET20 || NET35
|
||||
if ((Header.Flag7 & Flag7.ExtendedConsoleType) != 0)
|
||||
#else
|
||||
if (Header.Flag7.HasFlag(Flag7.ExtendedConsoleType))
|
||||
#endif
|
||||
return (ExtendedConsoleType)(header2.ExtendedSystemType & 0x0F);
|
||||
// Invalid console type
|
||||
if (ConsoleType != ConsoleType.ExtendedConsoleType)
|
||||
return ExtendedConsoleType.RegularSystem;
|
||||
|
||||
// If flag is unset
|
||||
return ExtendedConsoleType.RegularSystem;
|
||||
return (ExtendedConsoleType)(header2.ExtendedSystemType & 0x0F);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,15 +340,11 @@ namespace SabreTools.Serialization.Wrappers
|
||||
if (Header is null || Header is not Header2 header2)
|
||||
return VsHardwareType.VsUnisystem;
|
||||
|
||||
#if NET20 || NET35
|
||||
else if ((Header.Flag7 & Flag7.VSUnisystem) != 0)
|
||||
#else
|
||||
else if (Header.Flag7.HasFlag(Flag7.VSUnisystem))
|
||||
#endif
|
||||
return (VsHardwareType)(header2.ExtendedSystemType >> 4);
|
||||
// Invalid console type
|
||||
if (ConsoleType != ConsoleType.VSUnisystem)
|
||||
return VsHardwareType.VsUnisystem;
|
||||
|
||||
// If flag is unset
|
||||
return VsHardwareType.VsUnisystem;
|
||||
return (VsHardwareType)(header2.ExtendedSystemType >> 4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,15 +361,11 @@ namespace SabreTools.Serialization.Wrappers
|
||||
if (Header is null || Header is not Header2 header2)
|
||||
return VsSystemType.AnyRP2C03RC2C03Variant;
|
||||
|
||||
#if NET20 || NET35
|
||||
else if ((Header.Flag7 & Flag7.VSUnisystem) != 0)
|
||||
#else
|
||||
else if (Header.Flag7.HasFlag(Flag7.VSUnisystem))
|
||||
#endif
|
||||
return (VsSystemType)(header2.ExtendedSystemType & 0x0F);
|
||||
// Invalid console type
|
||||
if (ConsoleType != ConsoleType.VSUnisystem)
|
||||
return VsSystemType.AnyRP2C03RC2C03Variant;
|
||||
|
||||
// If flag is unset
|
||||
return VsSystemType.AnyRP2C03RC2C03Variant;
|
||||
return (VsSystemType)(header2.ExtendedSystemType & 0x0F);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user