Improved 'self-documenting' Nintendo SMC rom format

This commit is contained in:
Michael Becker 2015-07-14 16:00:51 -04:00
parent 95bbce9537
commit 828b9ddf65
6 changed files with 564 additions and 60 deletions

View File

@ -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
{
/// <summary>
/// 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.
/// </summary>
/// <completionlist cref="SMCCartridgeTypes" />
public class SMCCartridgeType
{
private string mvarTitle = String.Empty;
/// <summary>
/// The title of the cartridge type.
/// </summary>
public string Title { get { return mvarTitle; } set { mvarTitle = value; } }
private byte mvarValue = 0;
/// <summary>
/// The single-byte code that represents this cartridge type in the Nintendo SNES game console.
/// </summary>
public byte Value { get { return mvarValue; } set { mvarValue = value; } }
/// <summary>
/// Gets the <see cref="SMCLicensee" /> with the given licensee code if valid.
/// </summary>
/// <param name="value">The licensee code to search on.</param>
/// <returns>If the licensee code is known, returns an instance of the associated <see cref="SMCLicensee" />. Otherwise, returns null.</returns>
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;
}
/// <summary>
/// Creates a new instance of <see cref="SMCCartridgeType" /> with the given title and value.
/// </summary>
/// <param name="title"></param>
/// <param name="value"></param>
public SMCCartridgeType(string title, byte value)
{
mvarTitle = title;
mvarValue = value;
}
/// <summary>
/// Translates this <see cref="SMCCartridgeType" /> into a human-readable string, including the
/// title of the cartridge type and the internal identifier.
/// </summary>
/// <returns>A human-readable string representing this <see cref="SMCCartridgeType" />.</returns>
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);
/// <summary>
/// The cartridge contains only ROM.
/// </summary>
public static SMCCartridgeType ROMOnly { get { return mvarROMOnly; } }
private static SMCCartridgeType mvarROMAndRAM = new SMCCartridgeType("ROM and RAM, no battery", 0x01);
/// <summary>
/// The cartridge contains ROM and RAM but no battery.
/// </summary>
public static SMCCartridgeType ROMAndRAM { get { return mvarROMAndRAM; } }
private static SMCCartridgeType mvarROMAndRAMWithBattery = new SMCCartridgeType("ROM and save-RAM, with battery", 0x02);
/// <summary>
/// The cartridge contains ROM and save-RAM (with a battery).
/// </summary>
public static SMCCartridgeType ROMAndRAMWithBattery { get { return mvarROMAndRAMWithBattery; } }
private static SMCCartridgeType mvarSuperFXNoBattery0x13 = new SMCCartridgeType("SuperFX, no battery", 0x13);
/// <summary>
/// SuperFX, no battery (0x13)
/// </summary>
public static SMCCartridgeType SuperFXNoBattery0x13 { get { return mvarSuperFXNoBattery0x13; } }
private static SMCCartridgeType mvarSuperFXNoBattery0x14 = new SMCCartridgeType("SuperFX, no battery", 0x14);
/// <summary>
/// SuperFX, no battery (0x14)
/// </summary>
public static SMCCartridgeType SuperFXNoBattery0x14 { get { return mvarSuperFXNoBattery0x14; } }
private static SMCCartridgeType mvarSuperFXWithBattery0x15 = new SMCCartridgeType("SuperFX, with battery", 0x15);
/// <summary>
/// SuperFX, with battery (0x15)
/// </summary>
public static SMCCartridgeType SuperFXWithBattery0x15 { get { return mvarSuperFXWithBattery0x15; } }
private static SMCCartridgeType mvarSuperFXWithBattery0x1A = new SMCCartridgeType("SuperFX, with battery", 0x1A);
/// <summary>
/// SuperFX, with battery (0x1A)
/// </summary>
public static SMCCartridgeType SuperFXWithBattery0x1A { get { return mvarSuperFXWithBattery0x1A; } }
private static SMCCartridgeType mvarSA10x34 = new SMCCartridgeType("SA-1", 0x34);
/// <summary>
/// SuperFX, with battery (0x15)
/// </summary>
public static SMCCartridgeType SA10x34 { get { return mvarSA10x34; } }
private static SMCCartridgeType mvarSA10x35 = new SMCCartridgeType("SA-1", 0x35);
/// <summary>
/// SuperFX, with battery (0x1A)
/// </summary>
public static SMCCartridgeType SA10x35 { get { return mvarSA10x35; } }
}
}

View File

@ -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;
/// <summary>
/// Name of the ROM, typically in ASCII, using spaces to pad the name to 21 bytes.
/// </summary>
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;
/// <summary>
/// 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.
/// </summary>
public SMCCartridgeType CartridgeType { get { return mvarCartridgeType; } set { mvarCartridgeType = value; } }
private SMCMemorySize mvarROMSize = SMCMemorySizes.K256;
/// <summary>
/// Indicates the amount of ROM in the cartridge.
/// </summary>
public SMCMemorySize ROMSize { get { return mvarROMSize; } set { mvarROMSize = value; } }
private SMCMemorySize mvarRAMSize = SMCMemorySizes.K256;
/// <summary>
/// Indicates the amount of RAM in the cartridge (excluding the RAM in the SNES system).
/// </summary>
public SMCMemorySize RAMSize { get { return mvarRAMSize; } set { mvarRAMSize = value; } }
private SMCRegion mvarRegion = SMCRegions.Japan;
/// <summary>
/// The region in which the game is licensed.
@ -247,6 +311,13 @@ namespace UniversalEditor.DataFormats.Executable.Nintendo.SNES
/// </summary>
public SMCLicensee Licensee { get { return mvarLicensee; } set { mvarLicensee = value; } }
private byte mvarVersionNumber = 0;
/// <summary>
/// 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.
/// </summary>
public byte VersionNumber { get { return mvarVersionNumber; } set { mvarVersionNumber = value; } }
/// <summary>
/// Loads game data into the specified <see cref="ObjectModel" />.
/// </summary>
@ -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
}
}
}

View File

@ -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
{
/// <summary>
/// Save-RAM size is 32 kilobytes.
/// </summary>
SaveRam32K = 0x00,
/// <summary>
/// Save-RAM size is 8 kilobytes.
/// </summary>
SaveRam8K = 0x04,
/// <summary>
/// Save-RAM size is 2 kilobytes.
/// </summary>
SaveRam2K = 0x08,
/// <summary>
/// Save-RAM size is 0 kilobytes.
/// </summary>
SaveRamNone = 0x0C,
/// <summary>
/// Use HiROM.
/// </summary>
HiRomEnabled = 0x30,
/// <summary>
/// This is a split file but not the last image.
/// </summary>
SplitFile = 0x40,
/// <summary>
/// Jump to $8000 instead of the address in the reset vector.
/// </summary>
ResetVectorAddressOverride = 0x80
}
}

View File

@ -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
}
}

View File

@ -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
{
/// <summary>
/// A company that has licensed the use of the Nintendo SNES game console for development.
/// </summary>
/// <completionlist cref="SMCMemorySizes" />
public class SMCMemorySize
{
private string mvarTitle = String.Empty;
/// <summary>
/// The title of the memory size.
/// </summary>
public string Title { get { return mvarTitle; } set { mvarTitle = value; } }
private byte mvarValue = 0;
/// <summary>
/// The single-byte code that represents this memory size in the Nintendo SNES game console.
/// </summary>
public byte Value { get { return mvarValue; } set { mvarValue = value; } }
/// <summary>
/// Gets the <see cref="SMCMemorySize" /> with the given value if valid.
/// </summary>
/// <param name="value">The memory size code to search on.</param>
/// <returns>If the code is known, returns an instance of the associated <see cref="SMCMemorySize" />. Otherwise, returns null.</returns>
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;
}
/// <summary>
/// Creates a new instance of <see cref="SMCMemorySize" /> with the given title and value.
/// </summary>
/// <param name="title"></param>
/// <param name="value"></param>
public SMCMemorySize(string title, byte value)
{
mvarTitle = title;
mvarValue = value;
}
/// <summary>
/// Translates this <see cref="SMCLicensee" /> into a human-readable string, including the
/// title of the region and the country code.
/// </summary>
/// <returns>A human-readable string representing this <see cref="SMCLicensee" />.</returns>
public override string ToString()
{
return mvarTitle + " (0x" + mvarValue.ToString("X").PadLeft(2, '0') + ")";
}
}
/// <summary>
/// Licensees that have been defined by the SNES SMC data format. This class cannot be inherited.
/// </summary>
public sealed class SMCMemorySizes
{
private static SMCMemorySize mvarNone = new SMCMemorySize("(none)", 0x00);
/// <summary>
/// Gets the <see cref="SMCMemorySize" /> representing no memory.
/// </summary>
public static SMCMemorySize None { get { return mvarNone; } }
private static SMCMemorySize mvarK2 = new SMCMemorySize("2 KB (2048 bytes)", 0x01);
/// <summary>
/// Gets the <see cref="SMCMemorySize" /> representing 2KB (2048 bytes) worth of memory. This is the amount of RAM used in "Super Mario World".
/// </summary>
public static SMCMemorySize K2 { get { return mvarK2; } }
private static SMCMemorySize mvarK4 = new SMCMemorySize("4 KB (4096 bytes)", 0x02);
/// <summary>
/// Gets the <see cref="SMCMemorySize" /> representing 4KB (4096 bytes) worth of memory.
/// </summary>
public static SMCMemorySize K4 { get { return mvarK4; } }
private static SMCMemorySize mvarK8 = new SMCMemorySize("8 KB (8192 bytes)", 0x03);
/// <summary>
/// Gets the <see cref="SMCMemorySize" /> representing 8KB (8192 bytes) worth of memory.
/// </summary>
public static SMCMemorySize K8 { get { return mvarK8; } }
private static SMCMemorySize mvarK16 = new SMCMemorySize("16 KB (16 384 bytes)", 0x04);
/// <summary>
/// Gets the <see cref="SMCMemorySize" /> representing 16KB (16 384 bytes) worth of memory.
/// </summary>
public static SMCMemorySize K16 { get { return mvarK16; } }
private static SMCMemorySize mvarK32 = new SMCMemorySize("32 KB (32 768 bytes)", 0x05);
/// <summary>
/// Gets the <see cref="SMCMemorySize" /> representing 32KB (32 768 bytes) worth of memory. This is the amount of RAM used in "Mario Paint".
/// </summary>
public static SMCMemorySize K32 { get { return mvarK32; } }
private static SMCMemorySize mvarK64 = new SMCMemorySize("64 KB (65 536 bytes)", 0x06);
/// <summary>
/// Gets the <see cref="SMCMemorySize" /> representing 64KB (65 536 bytes) worth of memory.
/// </summary>
public static SMCMemorySize K64 { get { return mvarK64; } }
private static SMCMemorySize mvarK128 = new SMCMemorySize("128 KB (131 072 bytes)", 0x07);
/// <summary>
/// Gets the <see cref="SMCMemorySize" /> representing 128KB (131 072 bytes) worth of memory. This is the amount of RAM used in "Dezaemon - Kaite Tsukutte Asoberu".
/// </summary>
public static SMCMemorySize K128 { get { return mvarK128; } }
private static SMCMemorySize mvarK256 = new SMCMemorySize("256 KB (262 144 bytes)", 0x08);
/// <summary>
/// Gets the <see cref="SMCMemorySize" /> representing 256KB (262 144 bytes) worth of memory. This is the minimum amount of ROM.
/// </summary>
public static SMCMemorySize K256 { get { return mvarK256; } }
private static SMCMemorySize mvarK512 = new SMCMemorySize("512 KB (524 288 bytes)", 0x09);
/// <summary>
/// Gets the <see cref="SMCMemorySize" /> representing 512KB (524 288 bytes) worth of memory.
/// </summary>
public static SMCMemorySize K512 { get { return mvarK512; } }
private static SMCMemorySize mvarM1 = new SMCMemorySize("1 MB (1 048 576 bytes)", 0x0A);
/// <summary>
/// Gets the <see cref="SMCMemorySize" /> representing 1MB (1 048 576 bytes) worth of memory.
/// </summary>
public static SMCMemorySize M1 { get { return mvarM1; } }
private static SMCMemorySize mvarM2 = new SMCMemorySize("2 MB (2 097 152 bytes)", 0x0B);
/// <summary>
/// Gets the <see cref="SMCMemorySize" /> representing 2MB (2 097 152 bytes) worth of memory.
/// </summary>
public static SMCMemorySize M2 { get { return mvarM2; } }
private static SMCMemorySize mvarM4 = new SMCMemorySize("4 MB (4 194 304 bytes)", 0x0C);
/// <summary>
/// Gets the <see cref="SMCMemorySize" /> representing 4MB (4 194 304 bytes) worth of memory.
/// </summary>
public static SMCMemorySize M4 { get { return mvarM4; } }
}
}

View File

@ -37,8 +37,12 @@
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="DataFormats\Executable\Nintendo\SNES\SMCLayout.cs" />
<Compile Include="DataFormats\Executable\Nintendo\SNES\SMCMemorySize.cs" />
<Compile Include="DataFormats\Executable\Nintendo\SNES\SMCCartridgeType.cs" />
<Compile Include="DataFormats\Executable\Nintendo\SNES\SMCDataFormat.cs" />
<Compile Include="DataFormats\Executable\Nintendo\SNES\SMCExtendedHeader.cs" />
<Compile Include="DataFormats\Executable\Nintendo\SNES\SMCExtendedHeaderFlags.cs" />
<Compile Include="DataFormats\Executable\Nintendo\SNES\SMCLicensee.cs" />
<Compile Include="DataFormats\Executable\Nintendo\SNES\SMCRegion.cs" />
<Compile Include="DataFormats\Executable\Nintendo\SNES\SMCSaveRAMSize.cs" />