From fe231436d9b2b778a0b787499791343bfa01ada7 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Fri, 19 May 2023 16:09:14 +0200 Subject: [PATCH] patterns/gb: Added Gameboy ROM pattern (#89) * Added gameboy format * Add mime type * Add test * Avoid DMCA :sweating: --- README.md | 1 + patterns/gb.hexpat | 337 ++++++++++++++++++++++++++ tests/patterns/test_data/gb.hexpat.gb | Bin 0 -> 16384 bytes 3 files changed, 338 insertions(+) create mode 100644 patterns/gb.hexpat create mode 100644 tests/patterns/test_data/gb.hexpat.gb diff --git a/README.md b/README.md index a4b973f4..1f45d045 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | FDT | | [`patterns/fdt.hexpat`](patterns/fdt.hexpat) | Flat Linux Device Tree blob | | File System | | [`patterns/fs.hexpat`](patterns/fs.hexpat) | Drive File System | | FLAC | `audio/flac` | [`patterns/flac.hexpat`](patterns/flac.hexpat) | Free Lossless Audio Codec, FLAC Audio Format | +| GB | `application/x-gameboy-rom` | [`patterns/gb.hexpat`](patterns/gb.hexpat) | Gameboy ROM | | GIF | `image/gif` | [`patterns/gif.hexpat`](patterns/gif.hexpat) | GIF image files | | GZIP | `application/gzip` | [`patterns/gzip.hexpat`](patterns/gzip.hexpat) | GZip compressed data format | | ICO | | [`patterns/ico.hexpat`](patterns/ico.hexpat) | Icon (.ico) or Cursor (.cur) files | diff --git a/patterns/gb.hexpat b/patterns/gb.hexpat new file mode 100644 index 00000000..96689294 --- /dev/null +++ b/patterns/gb.hexpat @@ -0,0 +1,337 @@ +#include +#include +#include + +#pragma MIME application/x-gameboy-rom + +namespace format { + + fn rom_type(u8 romType) { + u32 romSize = 32768 * (1 << romType); + u16 romBanks = 2 * (1 << romType); + if(romType == 0x52) { + romSize = 1153434; + romBanks = 72; + } + if(romType == 0x53) { + romSize = 1258291; + romBanks = 80; + } + return std::format("size: {}, banks: {}", type::impl::size_formatter(romSize), romBanks); + }; + + fn ram_type(u8 ramType) { + u16 ramSize; + u16 ramBanks; + if(ramType == 2) { + ramSize = 8192; + ramBanks = 1; + } + if(ramType == 3) { + ramSize = 32768; + ramBanks = 4; + } + if(ramType == 4) { + ramSize = 131072; + ramBanks = 16; + } + if(ramType == 5) { + ramSize = 65536; + ramBanks = 8; + } + return std::format("size: {}, banks: {}", type::impl::size_formatter(ramSize), ramBanks); + }; + + fn rom_features(u8 type) { + str result = "( "; + match(type) { + (0x00): result += "no_mbc "; + (0x01): result += "mbc1 "; + (0x02): result += "mbc1 | ram "; + (0x03): result += "mbc1 | ram | battery "; + (0x05): result += "mbc2 "; + (0x06): result += "mbc2 | battery "; + (0x08): result += "no_mbc | ram "; + (0x09): result += "no_mbc | ram | battery "; + (0x0B): result += "mmm01 "; + (0x0C): result += "mmm01 | ram "; + (0x0D): result += "mmm01 | ram | battery "; + (0x0F): result += "mbc3 | timer | battery "; + (0x10): result += "mbc3 | timer | ram | battery "; + (0x11): result += "mbc3 "; + (0x12): result += "mbc3 | ram "; + (0x13): result += "mbc3 | ram | battery "; + (0x19): result += "mbc5 "; + (0x1A): result += "mbc5 | ram "; + (0x1B): result += "mbc5 | ram | battery "; + (0x1C): result += "mbc5 | rumble "; + (0x1D): result += "mbc5 | rumble | ram "; + (0x1E): result += "mbc5 | rumble | ram | battery "; + (0x20): result += "mbc6 "; + (0x22): result += "mbc7 | sensor | rumble "; + (0xFC): result += "camera "; + (0xFD): result += "tama5 "; + (0xFE): result += "huc3 "; + (0xFF): result += "huc1 | ram | battery "; + } + return result + ")"; + }; + + fn licensee_code(u8 code) { + match(code) { + (0x00): return "None"; + (0x01 | 0x31): return "Nintendo"; + (0x08 | 0x38): return "Capcom"; + (0x09): return "Hot-B"; + (0x0A | 0xE0): return "Jaleco"; + (0x0B): return "Coconuts Japan"; + (0x0C | 0x6E): return "Elite Systems"; + (0x13 | 0x69): return "EA (Electronic Arts)"; + (0x18): return "Hudsonsoft"; + (0x19): return "ITC Entertainment"; + (0x1A): return "Yanoman"; + (0x1D): return "Japan Clary"; + (0x1F | 0x4A | 0x61): return "Virgin Interactive"; + (0x24): return "PCM Complete"; + (0x25): return "San-X"; + (0x28): return "Kotobuki Systems"; + (0x29): return "Seta"; + (0x30 | 0x70): return "Infogrames"; + (0x32 | 0xA2 | 0xB2 | 0xC4): return "Bandai"; + (0x33): return "See new licensee"; + (0x34 | 0xA4): return "Konami"; + (0x35): return "HectorSoft"; + (0x39 | 0x9D): return "Banpresto"; + (0x3C): return ".Entertainment i"; + (0x3E): return "Gremlin"; + (0x41): return "Ubisoft"; + (0x42 | 0xEB): return "Atlus"; + (0x44 | 0x4D): return "Malibu"; + (0x46 | 0xCF): return "Angel"; + (0x47): return "Spectrum Holoby"; + (0x49): return "Irem"; + (0x50): return "Absolute"; + (0x51 | 0xB0): return "Acclaim"; + (0x52): return "Activision"; + (0x53): return "American Sammy"; + (0x54): return "GameTek"; + (0x55): return "Park Place"; + (0x56 | 0xDB | 0xFF): return "LJN"; + (0x57): return "Matchbox"; + (0x59): return "Milton Bradley"; + (0x5A): return "Mindscape"; + (0x5B): return "Romstar"; + (0x5C | 0xD6): return "Naxat Soft"; + (0x5D): return "Tradewest"; + (0x60): return "Titus"; + (0x67): return "Ocean Interactive"; + (0x6F): return "Electro Brain"; + (0x71): return "Interplay"; + (0x72 | 0xAA): return "Broderbund"; + (0x73): return "Sculptered Soft"; + (0x75): return "The Sales Curve"; + (0x78): return "t.hq"; + (0x79): return "Accolade"; + (0x7A): return "Triffix Entertainment"; + (0x7C): return "Microprose"; + (0x7F | 0xC2): return "Kemco"; + (0x80): return "Misawa Entertainment"; + (0x83): return "Lozc"; + (0x86 | 0xC4): return "Tokuma Shoten Intermedia"; + (0x8B): return "Bullet-Proof Software"; + (0x8C): return "Vic Tokai"; + (0x8E): return "Ape"; + (0x8F): return "I'Max"; + (0x91): return "Chunksoft Co."; + (0x92): return "Video System"; + (0x93): return "Tsubaraya Productions Co."; + (0x95): return "Varie Corporation"; + (0x96): return "Yonezawa/S’Pal"; + (0x97): return "Kaneko"; + (0x99): return "Arc"; + (0x9A): return "Nihon Bussan"; + (0x9B): return "Tecmo"; + (0x9C): return "Imagineer"; + (0x9F): return "Nova"; + (0xA1): return "Hori Electric"; + (0xA6): return "Kawada"; + (0xA7): return "Takara"; + (0xA9): return "Technos Japan"; + (0xAC): return "Toei Animation"; + (0xAD): return "Toho"; + (0xAF): return "Namco"; + (0xB1): return "ASCII or Nexsoft"; + (0xB4): return "Square Enix"; + (0xB6): return "HAL Laboratory"; + (0xB7): return "SNK"; + (0xB9 | 0xCE): return "Pony Canyon"; + (0xBA): return "Culture Brain"; + (0xBB): return "Sunsoft"; + (0xBD): return "Sony Imagesoft"; + (0xBF): return "Sammy"; + (0xC0 | 0xD0): return "Taito"; + (0xC3): return "Squaresoft"; + (0xC5): return "Data East"; + (0xC6): return "Tonkinhouse"; + (0xC8): return "Koei"; + (0xC9): return "UFL"; + (0xCA): return "Ultra"; + (0xCB): return "Vap"; + (0xCC): return "Use Corporation"; + (0xCD): return "Meldac"; + (0xD1): return "Sofel"; + (0xD2): return "Quest"; + (0xD3): return "Sigma Enterprises"; + (0xD4): return "ASK Kodansha Co."; + (0xD7): return "Copya System"; + (0xDA): return "Tomy"; + (0xDD): return "NCS"; + (0xDE): return "Human"; + (0xDF): return "Altron"; + (0xE1): return "Towa Chiki"; + (0xE2): return "Yutaka"; + (0xE3): return "Varie"; + (0xE5): return "Epoch"; + (0xE7): return "Athena"; + (0xE8): return "Asmik"; + (0xE9): return "Natsume"; + (0xEA): return "King Records"; + (0xEE): return "IGS"; + (0xF0): return "A Wave"; + (0xF3): return "Extreme Entertainment"; + } + return "Unknown Licensee"; + }; + + fn new_licensee_code(str a) { + if(a[0] == 0 && a[1] == 0) return "See old licensee"; + match(a) { + ("00"): return "None"; + ("01"): return "Nintendo R&D1"; + ("08"): return "Capcom"; + ("13"): return "Electronic Arts"; + ("18"): return "Hudson Soft"; + ("19"): return "b-ai"; + ("20"): return "kss"; + ("22"): return "pow"; + ("24"): return "PCM Complete"; + ("25"): return "san-x"; + ("28"): return "Kemco Japan"; + ("29"): return "seta"; + ("30"): return "Viacom"; + ("31"): return "Nintendo"; + ("32"): return "Bandai"; + ("33"): return "Ocean/Acclaim"; + ("34"): return "Konami"; + ("35"): return "Hector"; + ("37"): return "Taito"; + ("38"): return "Hudson"; + ("39"): return "Banpresto"; + ("41"): return "Ubi Soft"; + ("42"): return "Atlus"; + ("44"): return "Malibu"; + ("46"): return "angel"; + ("47"): return "Bullet-Proof"; + ("49"): return "irem"; + ("50"): return "Absolute"; + ("51"): return "Acclaim"; + ("52"): return "Activision"; + ("53"): return "American sammy"; + ("54"): return "Konami"; + ("55"): return "Hi tech entertainment"; + ("56"): return "LJN"; + ("57"): return "Matchbox"; + ("58"): return "Mattel"; + ("59"): return "Milton Bradley"; + ("60"): return "Titus"; + ("61"): return "Virgin"; + ("64"): return "LucasArts"; + ("67"): return "Ocean"; + ("69"): return "Electronic Arts"; + ("70"): return "Infogrames"; + ("71"): return "Interplay"; + ("72"): return "Broderbund"; + ("73"): return "sculptured"; + ("75"): return "sci"; + ("78"): return "THQ"; + ("79"): return "Accolade"; + ("80"): return "misawa"; + ("83"): return "lozc"; + ("86"): return "Tokuma Shoten Intermedia"; + ("87"): return "Tsukuda Original"; + ("91"): return "Chunksoft"; + ("92"): return "Video system"; + ("93"): return "Ocean/Acclaim"; + ("95"): return "Varie"; + ("96"): return "Yonezawa/s’pal"; + ("97"): return "Kaneko"; + ("99"): return "Pack in soft"; + ("A4"): return "Konami (Yu-Gi-Oh!)"; + } + return "Unknown"; + }; +} + +bitfield pixel_packed { + p1 : 1; + p2 : 1; + p3 : 1; + p4 : 1; + p5 : 1; + p6 : 1; + p7 : 1; + p8 : 1; +}; + +enum CGB : u8 { + NO_CGB = 0x00 ... 0x7F, + BACKWARDS_COMPATIBLE = 0x80, + CGB_ONLY = 0xC0 +}; + + +struct Logo { + pixel_packed rawData[0x30]; +}; + +struct JumpVectors { + u8 rst1[8] [[comment("rst $1")]]; + u8 rst2[8] [[comment("rst $2")]]; + u8 rst3[8] [[comment("rst $3")]]; + u8 rst4[8] [[comment("rst $4")]]; + u8 rst5[8] [[comment("rst $5")]];; + u8 rst6[8] [[comment("rst $6")]]; + u8 rst7[8] [[comment("rst $7")]]; + u8 rst8[8] [[comment("rst $8")]]; + u8 int1[8] [[comment("vblank")]]; + u8 int2[8] [[comment("lcd stat")]]; + u8 int3[8] [[comment("timer")]]; + u8 int4[8] [[comment("serial")]]; + u8 int5[8] [[comment("joypad")]]; +}; + +struct Header { + u32 jmpInstruction; + Logo logo; + char title[0xF]; + CGB cgb; + char newLicenseeCode[2] [[format("format::new_licensee_code")]]; + bool sgbFlag; + u8 type [[format("format::rom_features")]]; + u8 romType [[format("format::rom_type")]]; + u8 ramType [[format("format::ram_type")]]; + bool japanOnly; + u8 licenseeCode [[format("format::licensee_code")]]; + u8 version; + u8 checksum [[comment("Checksum for: $134-$14C")]]; + u16 gloalChecksum [[comment("Checksum for entire range")]]; +}; + +struct Cartrige { + JumpVectors jumpVectors [[comment("Instructions called on interupts or rst instructions")]]; + padding[0x100 - sizeof(JumpVectors)]; + Header header; +}; + + +Cartrige cart @ 0x00; \ No newline at end of file diff --git a/tests/patterns/test_data/gb.hexpat.gb b/tests/patterns/test_data/gb.hexpat.gb new file mode 100644 index 0000000000000000000000000000000000000000..9d3ee9101556225e96d28b331f5b9687a308aafa GIT binary patch literal 16384 zcmeIuEegVL0LJ0JSOh=76L<)#2o8oI%EX|U1#K3OV9_I(Odet^T8CZOs!5XVk zbC!1di+Hw3#`7>7OyVe6e&ybkbkzACB|v}x0RjXF5FkK+009C72oNAZfB*pk1PBly wK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0>21+08Y#xV*mgE literal 0 HcmV?d00001