From 828b9ddf652154e5a11f6837295cb60d91d82b57 Mon Sep 17 00:00:00 2001 From: alcexhim Date: Tue, 14 Jul 2015 16:00:51 -0400 Subject: [PATCH] Improved 'self-documenting' Nintendo SMC rom format --- .../Nintendo/SNES/SMCCartridgeType.cs | 134 +++++++++ .../Executable/Nintendo/SNES/SMCDataFormat.cs | 274 ++++++++++++++---- .../Nintendo/SNES/SMCExtendedHeaderFlags.cs | 39 +++ .../Executable/Nintendo/SNES/SMCLayout.cs | 13 + .../Executable/Nintendo/SNES/SMCMemorySize.cs | 160 ++++++++++ .../UniversalEditor.Plugins.Nintendo.csproj | 4 + 6 files changed, 564 insertions(+), 60 deletions(-) create mode 100644 CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCCartridgeType.cs create mode 100644 CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCExtendedHeaderFlags.cs create mode 100644 CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCLayout.cs create mode 100644 CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCMemorySize.cs diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCCartridgeType.cs b/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCCartridgeType.cs new file mode 100644 index 00000000..48998f9b --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCCartridgeType.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace UniversalEditor.DataFormats.Executable.Nintendo.SNES +{ + /// + /// Indicates the hardware in the cartridge. Emulators use this byte to decide which hardware to emulate. A real SNES ignores this byte and uses the real hardware in the real cartridge. + /// + /// + public class SMCCartridgeType + { + private string mvarTitle = String.Empty; + /// + /// The title of the cartridge type. + /// + public string Title { get { return mvarTitle; } set { mvarTitle = value; } } + + private byte mvarValue = 0; + /// + /// The single-byte code that represents this cartridge type in the Nintendo SNES game console. + /// + public byte Value { get { return mvarValue; } set { mvarValue = value; } } + + + /// + /// Gets the with the given licensee code if valid. + /// + /// The licensee code to search on. + /// If the licensee code is known, returns an instance of the associated . Otherwise, returns null. + public static SMCCartridgeType FromCode(byte value) + { + Type t = typeof(SMCCartridgeTypes); + + MethodAttributes methodAttributes = MethodAttributes.Public | MethodAttributes.Static; + PropertyInfo[] properties = t.GetProperties(); + for (int i = 0; i < properties.Length; i++) + { + PropertyInfo propertyInfo = properties[i]; + if (propertyInfo.PropertyType == typeof(SMCCartridgeType)) + { + MethodInfo getMethod = propertyInfo.GetGetMethod(); + if (getMethod != null && (getMethod.Attributes & methodAttributes) == methodAttributes) + { + object[] index = null; + SMCCartridgeType val = (SMCCartridgeType)propertyInfo.GetValue(null, index); + + if (val.Value == value) return val; + } + } + } + return null; + } + + /// + /// Creates a new instance of with the given title and value. + /// + /// + /// + public SMCCartridgeType(string title, byte value) + { + mvarTitle = title; + mvarValue = value; + } + + /// + /// Translates this into a human-readable string, including the + /// title of the cartridge type and the internal identifier. + /// + /// A human-readable string representing this . + public override string ToString() + { + return mvarTitle + " (0x" + mvarValue.ToString("X").PadLeft(2, '0') + ")"; + } + } + public sealed class SMCCartridgeTypes + { + private static SMCCartridgeType mvarROMOnly = new SMCCartridgeType("ROM-only", 0x00); + /// + /// The cartridge contains only ROM. + /// + public static SMCCartridgeType ROMOnly { get { return mvarROMOnly; } } + + private static SMCCartridgeType mvarROMAndRAM = new SMCCartridgeType("ROM and RAM, no battery", 0x01); + /// + /// The cartridge contains ROM and RAM but no battery. + /// + public static SMCCartridgeType ROMAndRAM { get { return mvarROMAndRAM; } } + + private static SMCCartridgeType mvarROMAndRAMWithBattery = new SMCCartridgeType("ROM and save-RAM, with battery", 0x02); + /// + /// The cartridge contains ROM and save-RAM (with a battery). + /// + public static SMCCartridgeType ROMAndRAMWithBattery { get { return mvarROMAndRAMWithBattery; } } + + private static SMCCartridgeType mvarSuperFXNoBattery0x13 = new SMCCartridgeType("SuperFX, no battery", 0x13); + /// + /// SuperFX, no battery (0x13) + /// + public static SMCCartridgeType SuperFXNoBattery0x13 { get { return mvarSuperFXNoBattery0x13; } } + + private static SMCCartridgeType mvarSuperFXNoBattery0x14 = new SMCCartridgeType("SuperFX, no battery", 0x14); + /// + /// SuperFX, no battery (0x14) + /// + public static SMCCartridgeType SuperFXNoBattery0x14 { get { return mvarSuperFXNoBattery0x14; } } + + private static SMCCartridgeType mvarSuperFXWithBattery0x15 = new SMCCartridgeType("SuperFX, with battery", 0x15); + /// + /// SuperFX, with battery (0x15) + /// + public static SMCCartridgeType SuperFXWithBattery0x15 { get { return mvarSuperFXWithBattery0x15; } } + + private static SMCCartridgeType mvarSuperFXWithBattery0x1A = new SMCCartridgeType("SuperFX, with battery", 0x1A); + /// + /// SuperFX, with battery (0x1A) + /// + public static SMCCartridgeType SuperFXWithBattery0x1A { get { return mvarSuperFXWithBattery0x1A; } } + + private static SMCCartridgeType mvarSA10x34 = new SMCCartridgeType("SA-1", 0x34); + /// + /// SuperFX, with battery (0x15) + /// + public static SMCCartridgeType SA10x34 { get { return mvarSA10x34; } } + + private static SMCCartridgeType mvarSA10x35 = new SMCCartridgeType("SA-1", 0x35); + /// + /// SuperFX, with battery (0x1A) + /// + public static SMCCartridgeType SA10x35 { get { return mvarSA10x35; } } + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCDataFormat.cs b/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCDataFormat.cs index e2727b76..7556a898 100644 --- a/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCDataFormat.cs +++ b/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCDataFormat.cs @@ -21,6 +21,42 @@ namespace UniversalEditor.DataFormats.Executable.Nintendo.SNES _dfr = base.MakeReferenceInternal(); _dfr.Capabilities.Add(typeof(ExecutableObjectModel), DataFormatCapabilities.All); + _dfr.ExportOptions.Add(new CustomOptionText("GameName", "Game &name:", String.Empty, 21)); + _dfr.ExportOptions.Add(new CustomOptionChoice("CartridgeType", "Cartridge &type:", true, new CustomOptionFieldChoice[] + { + new CustomOptionFieldChoice(SMCCartridgeTypes.ROMOnly, true), + new CustomOptionFieldChoice(SMCCartridgeTypes.ROMAndRAM), + new CustomOptionFieldChoice(SMCCartridgeTypes.ROMAndRAMWithBattery), + + // Values greater than $02 indicate special add-on hardware in the cartridge. The caveat is that emulators like + // Snes9x may ignore these values unless the add-on (at $ffd6) is compatible with the ROM layout (at $ffd5). + new CustomOptionFieldChoice(SMCCartridgeTypes.SuperFXNoBattery0x13, true), + new CustomOptionFieldChoice(SMCCartridgeTypes.SuperFXNoBattery0x14), + new CustomOptionFieldChoice(SMCCartridgeTypes.SuperFXWithBattery0x15), + new CustomOptionFieldChoice(SMCCartridgeTypes.SuperFXWithBattery0x1A), + new CustomOptionFieldChoice(SMCCartridgeTypes.SA10x34), + new CustomOptionFieldChoice(SMCCartridgeTypes.SA10x35) + })); + + CustomOptionFieldChoice[] _smcMemorySizes = new CustomOptionFieldChoice[] + { + new CustomOptionFieldChoice(SMCMemorySizes.K2), + new CustomOptionFieldChoice(SMCMemorySizes.K4), + new CustomOptionFieldChoice(SMCMemorySizes.K8), + new CustomOptionFieldChoice(SMCMemorySizes.K16), + new CustomOptionFieldChoice(SMCMemorySizes.K32), + new CustomOptionFieldChoice(SMCMemorySizes.K64), + new CustomOptionFieldChoice(SMCMemorySizes.K128), + new CustomOptionFieldChoice(SMCMemorySizes.K256, true), + new CustomOptionFieldChoice(SMCMemorySizes.K512), + new CustomOptionFieldChoice(SMCMemorySizes.M1), + new CustomOptionFieldChoice(SMCMemorySizes.M2), + new CustomOptionFieldChoice(SMCMemorySizes.M4), + }; + + _dfr.ExportOptions.Add(new CustomOptionChoice("ROMSize", "RO&M size:", true, _smcMemorySizes)); + _dfr.ExportOptions.Add(new CustomOptionChoice("RAMSize", "R&AM size:", true, _smcMemorySizes)); + _dfr.ExportOptions.Add(new CustomOptionChoice("Region", "&Region:", false, new CustomOptionFieldChoice[] { new CustomOptionFieldChoice(SMCRegions.Japan), @@ -224,6 +260,7 @@ namespace UniversalEditor.DataFormats.Executable.Nintendo.SNES new CustomOptionFieldChoice(SMCLicensees.Psygnosis), new CustomOptionFieldChoice(SMCLicensees.Davidson), })); + _dfr.ExportOptions.Add(new CustomOptionNumber("VersionNumber", "&Version number:", 0, Byte.MinValue, Byte.MaxValue)); _dfr.Sources.Add("http://romhack.wikia.com/wiki/SNES_ROM_layout"); _dfr.Sources.Add("http://romhack.wikia.com/wiki/SNES_header"); @@ -235,6 +272,33 @@ namespace UniversalEditor.DataFormats.Executable.Nintendo.SNES private SMCExtendedHeader mvarExtendedHeader = new SMCExtendedHeader(); public SMCExtendedHeader ExtendedHeader { get { return mvarExtendedHeader; } } + private string mvarGameName = String.Empty; + /// + /// Name of the ROM, typically in ASCII, using spaces to pad the name to 21 bytes. + /// + public string GameName { get { return mvarGameName; } set { mvarGameName = value; } } + + private SMCLayout mvarROMLayout = SMCLayout.LoROM; + public SMCLayout ROMLayout { get { return mvarROMLayout; } set { mvarROMLayout = value; } } + + private SMCCartridgeType mvarCartridgeType = SMCCartridgeTypes.ROMOnly; + /// + /// indicates the hardware in the cartridge. Emulators use this byte to decide which hardware to emulate. A real SNES ignores this byte and uses the real hardware in the real cartridge. + /// + public SMCCartridgeType CartridgeType { get { return mvarCartridgeType; } set { mvarCartridgeType = value; } } + + private SMCMemorySize mvarROMSize = SMCMemorySizes.K256; + /// + /// Indicates the amount of ROM in the cartridge. + /// + public SMCMemorySize ROMSize { get { return mvarROMSize; } set { mvarROMSize = value; } } + + private SMCMemorySize mvarRAMSize = SMCMemorySizes.K256; + /// + /// Indicates the amount of RAM in the cartridge (excluding the RAM in the SNES system). + /// + public SMCMemorySize RAMSize { get { return mvarRAMSize; } set { mvarRAMSize = value; } } + private SMCRegion mvarRegion = SMCRegions.Japan; /// /// The region in which the game is licensed. @@ -247,6 +311,13 @@ namespace UniversalEditor.DataFormats.Executable.Nintendo.SNES /// public SMCLicensee Licensee { get { return mvarLicensee; } set { mvarLicensee = value; } } + private byte mvarVersionNumber = 0; + /// + /// Typically contains 0x00. Most ROM hackers never touch this byte, so multiple versions of a ROM + /// hack may share the same value of this byte. A few ROM hackers actually set this byte. + /// + public byte VersionNumber { get { return mvarVersionNumber; } set { mvarVersionNumber = value; } } + /// /// Loads game data into the specified . /// @@ -257,74 +328,82 @@ namespace UniversalEditor.DataFormats.Executable.Nintendo.SNES if (exe == null) throw new ObjectModelNotSupportedException(); Reader reader = base.Accessor.Reader; - - mvarExtendedHeader.Enabled = (base.Accessor.Length % 1024 == 512); - if (mvarExtendedHeader.Enabled) + #region Extended Header { - #region 00-02 The size of the ROM dump, in units of 8 kilobytes, as a little-endian integer. + mvarExtendedHeader.Enabled = (base.Accessor.Length % 1024 == 512); + if (mvarExtendedHeader.Enabled) { - mvarExtendedHeader.FileSize = reader.ReadInt16(); - mvarExtendedHeader.FileSize *= 8000; - } - #endregion - #region 02-03 Flags - byte flags = reader.ReadByte(); - mvarExtendedHeader.SplitFile = ((flags & 0x40) == 0x40); - mvarExtendedHeader.HiRomEnabled = ((flags & 0x30) == 0x30); + #region 00-02 The size of the ROM dump, in units of 8 kilobytes, as a little-endian integer. + { + mvarExtendedHeader.FileSize = reader.ReadInt16(); + mvarExtendedHeader.FileSize *= 8000; + } + #endregion + #region 02-03 Flags + SMCExtendedHeaderFlags flags = (SMCExtendedHeaderFlags)reader.ReadByte(); + mvarExtendedHeader.SplitFile = ((flags & SMCExtendedHeaderFlags.SplitFile) == SMCExtendedHeaderFlags.SplitFile); + mvarExtendedHeader.HiRomEnabled = ((flags & SMCExtendedHeaderFlags.HiRomEnabled) == SMCExtendedHeaderFlags.HiRomEnabled); - if ((flags & 0x04) == 0x04) - { - mvarExtendedHeader.SaveRAMSize = SMCSaveRAMSize.SaveRAM8K; - } - else if ((flags & 0x08) == 0x08) - { - mvarExtendedHeader.SaveRAMSize = SMCSaveRAMSize.SaveRAM2K; - } - else if ((flags & 0x0C) == 0x0C) - { - mvarExtendedHeader.SaveRAMSize = SMCSaveRAMSize.SaveRAMNone; - } + if ((flags & SMCExtendedHeaderFlags.SaveRam8K) == SMCExtendedHeaderFlags.SaveRam8K) + { + mvarExtendedHeader.SaveRAMSize = SMCSaveRAMSize.SaveRAM8K; + } + else if ((flags & SMCExtendedHeaderFlags.SaveRam2K) == SMCExtendedHeaderFlags.SaveRam2K) + { + mvarExtendedHeader.SaveRAMSize = SMCSaveRAMSize.SaveRAM2K; + } + else if ((flags & SMCExtendedHeaderFlags.SaveRamNone) == SMCExtendedHeaderFlags.SaveRamNone) + { + mvarExtendedHeader.SaveRAMSize = SMCSaveRAMSize.SaveRAMNone; + } - if ((flags & 0x80) == 0x80) - { - mvarExtendedHeader.ResetVectorOverride = 0x8000; - } - #endregion - #region 03-04 HiRom/LoRom (Pro Fighter specific) - byte hiRomLoRom = reader.ReadByte(); - if ((flags & 0x30) != 0x30) - { - // only set HiRom/LoRom from this field if not set in a flag - mvarExtendedHeader.HiRomEnabled = ((hiRomLoRom & 0x80) == 0x80); - } - #endregion - #region 04-06 DSP-1 settings (Pro Fighter specific) - mvarExtendedHeader.DSP1Settings = reader.ReadInt16(); - #endregion - #region 06-08 Unknown - ushort unknown1 = reader.ReadUInt16(); - #endregion - #region 08-16 SUPERUFO - string creator = reader.ReadFixedLengthString(8); // SUPERUFO - mvarExtendedHeader.Creator = creator; - #endregion - #region 16-24 Extra data - byte[] extradata = reader.ReadBytes(8); - #endregion + if ((flags & SMCExtendedHeaderFlags.ResetVectorAddressOverride) == SMCExtendedHeaderFlags.ResetVectorAddressOverride) + { + mvarExtendedHeader.ResetVectorOverride = 0x8000; + } + #endregion + #region 03-04 HiRom/LoRom (Pro Fighter specific) + byte hiRomLoRom = reader.ReadByte(); + if ((flags & SMCExtendedHeaderFlags.HiRomEnabled) != SMCExtendedHeaderFlags.HiRomEnabled) + { + // only set HiRom/LoRom from this field if not set in a flag + mvarExtendedHeader.HiRomEnabled = ((hiRomLoRom & 0x80) == 0x80); + } + if (mvarExtendedHeader.HiRomEnabled) + { + mvarROMLayout = SMCLayout.HiROM; + } + #endregion + #region 04-06 DSP-1 settings (Pro Fighter specific) + mvarExtendedHeader.DSP1Settings = reader.ReadInt16(); + #endregion + #region 06-08 Unknown + ushort unknown1 = reader.ReadUInt16(); + #endregion + #region 08-16 SUPERUFO + string creator = reader.ReadFixedLengthString(8); // SUPERUFO + mvarExtendedHeader.Creator = creator; + #endregion + #region 16-24 Extra data + byte[] extradata = reader.ReadBytes(8); + #endregion - if (mvarExtendedHeader.HiRomEnabled) - { - base.Accessor.Seek(0x101c0, SeekOrigin.Begin); - } - else - { - base.Accessor.Seek(0x81c0, SeekOrigin.Begin); + if (mvarExtendedHeader.HiRomEnabled) + { + base.Accessor.Seek(0x101c0, SeekOrigin.Begin); + } + else + { + base.Accessor.Seek(0x81c0, SeekOrigin.Begin); + } } } + #endregion #region SNES header - string gamename = reader.ReadFixedLengthString(21).Trim(); + mvarGameName = reader.ReadFixedLengthString(21).Trim(); + byte romLayout = reader.ReadByte(); if (romLayout == 0x20) { @@ -335,8 +414,13 @@ namespace UniversalEditor.DataFormats.Executable.Nintendo.SNES // HiROM } byte cartridgeType = reader.ReadByte(); + mvarCartridgeType = SMCCartridgeType.FromCode(cartridgeType); + byte romsize = reader.ReadByte(); + mvarROMSize = SMCMemorySize.FromCode(romsize); + byte ramsize = reader.ReadByte(); + mvarRAMSize = SMCMemorySize.FromCode(ramsize); // Country code, which selects the video in the emulator. Values $00, $01, $0d use NTSC. // Values in range $02..$0c use PAL. Other values are invalid. @@ -353,7 +437,7 @@ namespace UniversalEditor.DataFormats.Executable.Nintendo.SNES } - byte versionNumber = reader.ReadByte(); + mvarVersionNumber = reader.ReadByte(); ushort checksumComplement = reader.ReadUInt16(); ushort checksum = reader.ReadUInt16(); @@ -390,7 +474,77 @@ namespace UniversalEditor.DataFormats.Executable.Nintendo.SNES ExecutableObjectModel exe = (objectModel as ExecutableObjectModel); if (exe == null) throw new ObjectModelNotSupportedException(); - throw new NotImplementedException(); + Writer writer = base.Accessor.Writer; + + #region SNES header + writer.WriteFixedLengthString(mvarGameName, 21, ' '); + + switch (mvarROMLayout) + { + case SMCLayout.LoROM: + { + writer.WriteByte(0x20); + break; + } + case SMCLayout.HiROM: + { + writer.WriteByte(0x21); + break; + } + } + + writer.WriteByte((byte)(mvarCartridgeType != null ? mvarCartridgeType.Value : 0)); + writer.WriteByte((byte)(mvarROMSize != null ? mvarROMSize.Value : 0)); + writer.WriteByte((byte)(mvarRAMSize != null ? mvarRAMSize.Value : 0)); + writer.WriteByte((byte)(mvarRegion != null ? mvarRegion.Value : 0)); + writer.WriteByte((byte)(mvarLicensee != null ? mvarLicensee.Value : 0)); + + if (mvarLicensee != null && mvarLicensee.Value == 0x33) + { + + } + + writer.WriteByte(mvarVersionNumber); + + ushort checksumComplement = 0; + ushort checksum = 0; + writer.WriteUInt16(checksumComplement); + writer.WriteUInt16(checksum); + + int unknown2 = 0; + writer.WriteInt32(unknown2); + + short nativeInterruptVectorCOP = 0; + short nativeInterruptVectorBRK = 0; + short nativeInterruptVectorABORT = 0; + short nativeInterruptVectorNMI = 0; // vertical blank + short nativeInterruptVectorUnused = 0; + short nativeInterruptVectorIRQ = 0; + + writer.WriteInt16(nativeInterruptVectorCOP); + writer.WriteInt16(nativeInterruptVectorBRK); + writer.WriteInt16(nativeInterruptVectorABORT); + writer.WriteInt16(nativeInterruptVectorNMI); + writer.WriteInt16(nativeInterruptVectorUnused); + writer.WriteInt16(nativeInterruptVectorIRQ); + + int unknown3 = 0; + writer.WriteInt32(unknown3); + + short emulationInterruptVectorCOP = 0; + short emulationInterruptVectorUnused = 0; + short emulationInterruptVectorABORT = 0; + short emulationInterruptVectorNMI = 0; // vertical blank + short emulationInterruptVectorRESET = 0; + short emulationInterruptVectorIRQorBRK = 0; + + writer.WriteInt16(emulationInterruptVectorCOP); + writer.WriteInt16(emulationInterruptVectorUnused); + writer.WriteInt16(emulationInterruptVectorABORT); + writer.WriteInt16(emulationInterruptVectorNMI); + writer.WriteInt16(emulationInterruptVectorRESET); + writer.WriteInt16(emulationInterruptVectorIRQorBRK); + #endregion } } } diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCExtendedHeaderFlags.cs b/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCExtendedHeaderFlags.cs new file mode 100644 index 00000000..f44d0c3c --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCExtendedHeaderFlags.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UniversalEditor.DataFormats.Executable.Nintendo.SNES +{ + public enum SMCExtendedHeaderFlags : byte + { + /// + /// Save-RAM size is 32 kilobytes. + /// + SaveRam32K = 0x00, + /// + /// Save-RAM size is 8 kilobytes. + /// + SaveRam8K = 0x04, + /// + /// Save-RAM size is 2 kilobytes. + /// + SaveRam2K = 0x08, + /// + /// Save-RAM size is 0 kilobytes. + /// + SaveRamNone = 0x0C, + /// + /// Use HiROM. + /// + HiRomEnabled = 0x30, + /// + /// This is a split file but not the last image. + /// + SplitFile = 0x40, + /// + /// Jump to $8000 instead of the address in the reset vector. + /// + ResetVectorAddressOverride = 0x80 + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCLayout.cs b/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCLayout.cs new file mode 100644 index 00000000..ab48fc0c --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCLayout.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UniversalEditor.DataFormats.Executable.Nintendo.SNES +{ + public enum SMCLayout + { + LoROM = 0x20, + HiROM = 0x21 + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCMemorySize.cs b/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCMemorySize.cs new file mode 100644 index 00000000..8382a1f1 --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/DataFormats/Executable/Nintendo/SNES/SMCMemorySize.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace UniversalEditor.DataFormats.Executable.Nintendo.SNES +{ + /// + /// A company that has licensed the use of the Nintendo SNES game console for development. + /// + /// + public class SMCMemorySize + { + private string mvarTitle = String.Empty; + /// + /// The title of the memory size. + /// + public string Title { get { return mvarTitle; } set { mvarTitle = value; } } + + private byte mvarValue = 0; + /// + /// The single-byte code that represents this memory size in the Nintendo SNES game console. + /// + public byte Value { get { return mvarValue; } set { mvarValue = value; } } + + /// + /// Gets the with the given value if valid. + /// + /// The memory size code to search on. + /// If the code is known, returns an instance of the associated . Otherwise, returns null. + public static SMCMemorySize FromCode(byte value) + { + Type t = typeof(SMCMemorySizes); + + MethodAttributes methodAttributes = MethodAttributes.Public | MethodAttributes.Static; + PropertyInfo[] properties = t.GetProperties(); + for (int i = 0; i < properties.Length; i++) + { + PropertyInfo propertyInfo = properties[i]; + if (propertyInfo.PropertyType == typeof(SMCMemorySize)) + { + MethodInfo getMethod = propertyInfo.GetGetMethod(); + if (getMethod != null && (getMethod.Attributes & methodAttributes) == methodAttributes) + { + object[] index = null; + SMCMemorySize val = (SMCMemorySize)propertyInfo.GetValue(null, index); + + if (val.Value == value) return val; + } + } + } + return null; + } + + /// + /// Creates a new instance of with the given title and value. + /// + /// + /// + public SMCMemorySize(string title, byte value) + { + mvarTitle = title; + mvarValue = value; + } + + /// + /// Translates this into a human-readable string, including the + /// title of the region and the country code. + /// + /// A human-readable string representing this . + public override string ToString() + { + return mvarTitle + " (0x" + mvarValue.ToString("X").PadLeft(2, '0') + ")"; + } + } + /// + /// Licensees that have been defined by the SNES SMC data format. This class cannot be inherited. + /// + public sealed class SMCMemorySizes + { + private static SMCMemorySize mvarNone = new SMCMemorySize("(none)", 0x00); + /// + /// Gets the representing no memory. + /// + public static SMCMemorySize None { get { return mvarNone; } } + + private static SMCMemorySize mvarK2 = new SMCMemorySize("2 KB (2048 bytes)", 0x01); + /// + /// Gets the representing 2KB (2048 bytes) worth of memory. This is the amount of RAM used in "Super Mario World". + /// + public static SMCMemorySize K2 { get { return mvarK2; } } + + private static SMCMemorySize mvarK4 = new SMCMemorySize("4 KB (4096 bytes)", 0x02); + /// + /// Gets the representing 4KB (4096 bytes) worth of memory. + /// + public static SMCMemorySize K4 { get { return mvarK4; } } + + private static SMCMemorySize mvarK8 = new SMCMemorySize("8 KB (8192 bytes)", 0x03); + /// + /// Gets the representing 8KB (8192 bytes) worth of memory. + /// + public static SMCMemorySize K8 { get { return mvarK8; } } + + private static SMCMemorySize mvarK16 = new SMCMemorySize("16 KB (16 384 bytes)", 0x04); + /// + /// Gets the representing 16KB (16 384 bytes) worth of memory. + /// + public static SMCMemorySize K16 { get { return mvarK16; } } + + private static SMCMemorySize mvarK32 = new SMCMemorySize("32 KB (32 768 bytes)", 0x05); + /// + /// Gets the representing 32KB (32 768 bytes) worth of memory. This is the amount of RAM used in "Mario Paint". + /// + public static SMCMemorySize K32 { get { return mvarK32; } } + + private static SMCMemorySize mvarK64 = new SMCMemorySize("64 KB (65 536 bytes)", 0x06); + /// + /// Gets the representing 64KB (65 536 bytes) worth of memory. + /// + public static SMCMemorySize K64 { get { return mvarK64; } } + + private static SMCMemorySize mvarK128 = new SMCMemorySize("128 KB (131 072 bytes)", 0x07); + /// + /// Gets the representing 128KB (131 072 bytes) worth of memory. This is the amount of RAM used in "Dezaemon - Kaite Tsukutte Asoberu". + /// + public static SMCMemorySize K128 { get { return mvarK128; } } + + private static SMCMemorySize mvarK256 = new SMCMemorySize("256 KB (262 144 bytes)", 0x08); + /// + /// Gets the representing 256KB (262 144 bytes) worth of memory. This is the minimum amount of ROM. + /// + public static SMCMemorySize K256 { get { return mvarK256; } } + + private static SMCMemorySize mvarK512 = new SMCMemorySize("512 KB (524 288 bytes)", 0x09); + /// + /// Gets the representing 512KB (524 288 bytes) worth of memory. + /// + public static SMCMemorySize K512 { get { return mvarK512; } } + + private static SMCMemorySize mvarM1 = new SMCMemorySize("1 MB (1 048 576 bytes)", 0x0A); + /// + /// Gets the representing 1MB (1 048 576 bytes) worth of memory. + /// + public static SMCMemorySize M1 { get { return mvarM1; } } + + private static SMCMemorySize mvarM2 = new SMCMemorySize("2 MB (2 097 152 bytes)", 0x0B); + /// + /// Gets the representing 2MB (2 097 152 bytes) worth of memory. + /// + public static SMCMemorySize M2 { get { return mvarM2; } } + + private static SMCMemorySize mvarM4 = new SMCMemorySize("4 MB (4 194 304 bytes)", 0x0C); + /// + /// Gets the representing 4MB (4 194 304 bytes) worth of memory. + /// + public static SMCMemorySize M4 { get { return mvarM4; } } + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/UniversalEditor.Plugins.Nintendo.csproj b/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/UniversalEditor.Plugins.Nintendo.csproj index 65f2ceee..a1545d13 100644 --- a/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/UniversalEditor.Plugins.Nintendo.csproj +++ b/CSharp/Plugins/UniversalEditor.Plugins.Nintendo/UniversalEditor.Plugins.Nintendo.csproj @@ -37,8 +37,12 @@ + + + +