diff --git a/patterns/ne.hexpat b/patterns/ne.hexpat index 3cae5c2..6c825b1 100644 --- a/patterns/ne.hexpat +++ b/patterns/ne.hexpat @@ -1,3 +1,4 @@ +#pragma author gmestanley #pragma description Microsoft DOS NE executable #pragma MIME application/x-ms-ne-executable diff --git a/patterns/nes.hexpat b/patterns/nes.hexpat index 1fdce89..6292ada 100644 --- a/patterns/nes.hexpat +++ b/patterns/nes.hexpat @@ -2,87 +2,265 @@ #pragma description Nintendo Entertainment System ROM (.nes) #pragma MIME application/x-nes-rom -import std.mem; import std.string; -bitfield iNES07Flags { - mirroringIsVertical : 1; - batterybackedPRGRAM : 1; - trainerOf512Bytes : 1; - ignoreMirroring : 1; - mapperLowerNybble : 4; - vsUnisystem : 1; - playchoice10 : 1; - nes2Format : 2 [[name("nes2.0Format")]]; - mapperHigherNybble : 4; -} [[name("iNES0.7Flags")]]; - -bitfield Flags9 { - isPAL : 1; - padding : 7; +bitfield Flags { + mirroringIsHorizontal : 1; + ignoreMirroring : 1; + batterybackedPRGRAM : 1; + trainerOf512Bytes : 1; + lowerMapperNybble : 4; }; -bitfield Flags10 { - tvSystem : 2; - padding : 2; - prgRAM : 1; - busConflicts : 1; - padding : 2; +enum ConsoleType : u8 { + Regular, + VsSystem, + PlayChoice10, + ExtendedConsoleType }; -struct iNESFlags { - iNES07Flags ines07Flags [[name("ines0.7Flags")]]; - if (!ines07Flags.nes2Format) { - u8 prgRAM8KBMultiplier; - Flags9 flags9; - Flags10 flags10; - restLength = 5; - } - else { - restLength = 9; - } +fn consoleType(u8 bits) { + ConsoleType type = bits; + return type; }; -u8 restLength; +fn nes2Format(u8 bits) { + return std::string::to_string(bits == 2) + " (" + std::string::to_string(bits) + ")"; +}; + +bitfield iNESFlags7 { + consoleType : 2 [[format("consoleType")]]; + nes2Format : 2 [[format("nes2Format"), name("nes2.0Format")]]; + higherMapperNybble : 4; +}; + +bitfield iNESFlags9 { + tvSystem : 1 [[comment("0 = NTSC, 1 = PAL")]]; + padding : 7; +}; + +fn formatDualTVSystem(u8 bits) { + match (bits) { + (0): return "NTSC"; + (2): return "PAL"; + (1 || 3): return "Dual Compatible"; + } +}; + +bitfield iNESFlags10 { + dualTVSystem : 2 [[format("formatDualTVSystem")]]; + padding : 2; + prgRAM : 1; + busConflicts : 1; +}; + +bitfield MapperExtra { + highestMapperNybble : 4; + submapper : 4; +}; + +bitfield ROMSize { + extraPRGROMSize : 4; + extraCHRROMSize : 4; +}; + +bitfield PRGRAMSize { + prgRAMShiftCount : 4; + eepromShiftCount : 4 [[comment("EEPROM = Non-volatile PRG RAM")]]; +}; + +bitfield CHRRAMSize { + chrRAMSizeShiftCount : 4; + chrNVRAMSizeShiftCount : 4; +}; + +enum TimingList : u8 { + NTSC, + PAL, + MultiRegion, + Dendy +}; + +fn Timing(u8 value) { + TimingList type = value; + return type; +}; + +bitfield Timing { + processorTiming : 2 [[format("Timing")]]; + padding : 6; +}; + +bitfield VsSystemType { + vsPPUType : 4; + vsHardwareType: 4; +}; + +enum ExtendedConsoleType : ConsoleType { + DecimalModeFamiclone = 3, + PlugThrough, + VT01, + VT02, + VT03, + VT09, + VT32, + VT3xx, + UM6578, + FamicomNetworkSystem +}; + +fn formatExtendedConsoleType(u8 nybble) { + ExtendedConsoleType type = nybble; + return type; +}; + +bitfield ExtendedConsoleTypeByte { + type : 4 [[format("formatExtendedConsoleType")]]; + padding : 4; +}; + +bitfield MiscellaneousROMs { + numberOfMiscellaneousROMs : 2; + padding : 6; +}; + +bitfield DefaultExpansionDevice { + defaultExpansionDevice : 6; +}; + +struct NES2Attributes { + MapperExtra mapperExtra; + ROMSize romSize; + PRGRAMSize prgRAMSize; + CHRRAMSize chrRAMSize; + Timing timing; + if (parent.inesFlags7.consoleType == ConsoleType::VsSystem) { + VsSystemType vsSystemType; + } + else if (parent.inesFlags7.consoleType == ConsoleType::ExtendedConsoleType) { + ExtendedConsoleTypeByte ExtendedConsoleTypeByte; + } + else { + padding[1]; + } + MiscellaneousROMs miscellaneousROMs; + DefaultExpansionDevice defaultExpansionDevice; +}; + +fn renderEOF(str string) { + return "\"NES\""; +}; struct Header { - char identifier[4]; - u8 prgROM16KBMultiplier; - u8 chrROM8KBMultiplier; - iNESFlags inesFlags; - char rest[restLength]; + char identifier[4] [[format("renderEOF")]]; + u8 prgROMSizeBy16KiBs; + u8 chrROMSizeBy8KiBs; + Flags flags; + if ($[0x07] & 12 != 4) { + iNESFlags7 inesFlags7; + if (inesFlags7.nes2Format) + NES2Attributes nes2Attributes; + else if ($[0x07] & 12 == 0 && !std::mem::read_unsigned($, 4)) { + u8 prgRAMSizeBy8KiBs; + iNESFlags9 inesFlags9; + iNESFlags10 inesFlags10; + } + } }; Header header @ 0x00; -enum EncodingType : u8 { - ASCII = 1 +u8 trainer[512*header.flags.trainerOf512Bytes] @ 0x10; + +enum CHRType : u8 { + CHRROM, + CHRRAM }; +fn chrType(u8 value) { + CHRType enumValue = value; + return enumValue; +}; + +fn chrSize(u8 value) { + u24 actualSize; + if (value == 4) actualSize = 262144; + else actualSize = 8192 * header.chrROMSizeBy8KiBs; + return std::string::to_string(value) + " (" + std::string::to_string(actualSize) + ")"; +}; + +bitfield MemorySize { + prgROMSizeBy16KiBs : 4; + chrType : 1 [[format("chrType")]]; + chrSize : 3 [[format("chrSize")]]; +}; + +enum ArrangementList : u8 { + Horizontal, + Vertical +}; + +fn arrangement(u8 value) { + ArrangementList enumValue = value; + return enumValue; +}; + +enum MapperList : u8 { + NROM, + CNROM, + UNROM, + GNROM, + MMC +}; + +fn mapper(u8 value) { + MapperList enumValue = value; + return enumValue; +}; + +bitfield CartridgeType { + nametableArrangement : 1 [[format("arrangement")]]; + mapper : 7 [[format("mapper")]]; +}; + +enum EncodingType : u8 { + None, + ASCII, + JIS +}; + +fn titleLength(u8 value) { return value+1; }; + struct OfficialHeader { - char title[16] [[hex::spec_name("Title Registration Area")]]; - u16 programChecksum; - u16 characterChecksum; - u8 memorySize [[hex::spec_name("Cartridge Memory Size")]]; - u8 cartridgeType; - EncodingType encodingType [[hex::spec_name("Registration Character Type Distinction")]]; - u8 titleLength [[hex::spec_name("Registration Characters Count")]]; - u8 makerID [[hex::spec_name("Maker Code")]]; - u8 complementaryChecksum; + char title[16] [[hex::spec_name("Title Registration Area")]]; + u16 programChecksum; + u16 characterChecksum; + MemorySize memorySize [[hex::spec_name("Cartridge Memory Size")]]; + CartridgeType cartridgeType; + EncodingType encodingType [[hex::spec_name("Registration Characters Type Distinction")]]; + u8 titleLength [[hex::spec_name("Registration Characters Count"), transform("titleLength")]]; + u8 licenseeID [[hex::spec_name("Maker Code")]]; + u8 complementaryChecksum [[hex::spec_name("Checksum for characterChecksum~makerID")]]; }; -union OfficialHeaderUnion { - u8 miscellaneousData[26]; - OfficialHeader officialHeader; +u24 calculatedPRGROMSize = 16384 * ((0x0100 * $[9] & 0x0F) * ($[7] & 12 == 8) + header.prgROMSizeBy16KiBs); + +fn hasOfficialHeader() { + u8 sum; + for (u8 i = 0, i < 8, i += 1) { + sum += $[(calculatedPRGROMSize - 14) + i]; + } + return !sum; }; struct PRGROM { - u8 data[16384*header.prgROM16KBMultiplier-32]; - OfficialHeaderUnion officialHeaderUnion; - u16 nmi; - u16 entryPoint; - u16 externalIRQ; + u8 data[calculatedPRGROMSize - 26 * hasOfficialHeader() - 6]; + if (hasOfficialHeader()) + OfficialHeader officialHeader; + u16 nmi; + u16 resetVector [[comment("Entry Point")]]; + u16 externalIRQ; }; -PRGROM prgROM @ sizeof(header); -u8 chrROM[8192*header.chrROM8KBMultiplier] @ sizeof(header)+sizeof(prgROM); \ No newline at end of file +PRGROM prgROM @ 0x10 + sizeof(trainer); +u8 chrROM[8192 * ((0x0100 * $[9] >> 4) * ($[7] & 12 == 8) + header.chrROMSizeBy8KiBs)] @ addressof(prgROM) + 16384 * header.prgROMSizeBy16KiBs;