| 1 |
#include "RomInfo.hh" |
| 2 |
|
| 3 |
#include "MinimalPerfectHash.hh" |
| 4 |
#include "StringOp.hh" |
| 5 |
#include "stl.hh" |
| 6 |
|
| 7 |
#include <array> |
| 8 |
#include <cassert> |
| 9 |
|
| 10 |
namespace openmsx { |
| 11 |
|
| 12 |
using enum RomType; |
| 13 |
|
| 14 |
static constexpr auto romTypeInfoArray = [] { |
| 15 |
array_with_enum_index<RomType, RomInfo::RomTypeInfo> r = {}; |
| 16 |
|
| 17 |
|
| 18 |
|
| 19 |
r[GENERIC_8KB] = {0x2000, "8kB", "Generic 8kB"}; |
| 20 |
r[GENERIC_16KB] = {0x4000, "16kB", "Generic 16kB"}; |
| 21 |
|
| 22 |
|
| 23 |
r[KONAMI] = {0x2000, "Konami", "Konami MegaROM"}; |
| 24 |
r[KONAMI_SCC] = {0x2000, "KonamiSCC", "Konami with SCC"}; |
| 25 |
r[KBDMASTER] = {0x4000, "KeyboardMaster", "Konami Keyboard Master with VLM5030"}; |
| 26 |
r[ASCII8] = {0x2000, "ASCII8", "ASCII 8kB"}; |
| 27 |
r[ASCII8R] = {0x2000, "ASCII8-R", "ASCII 8kB with reversed bank registers"}; |
| 28 |
r[ASCII16] = {0x4000, "ASCII16", "ASCII 16kB"}; |
| 29 |
r[ASCII16X] = {0x4000, "ASCII16-X", "ASCII-X 16kB"}; |
| 30 |
r[R_TYPE] = {0x4000, "R-Type", "R-Type"}; |
| 31 |
r[CROSS_BLAIM] = {0x4000, "CrossBlaim", "Cross Blaim"}; |
| 32 |
r[HARRY_FOX] = {0x4000, "HarryFox", "Harry Fox"}; |
| 33 |
r[HALNOTE] = {0x2000, "Halnote", "Halnote"}; |
| 34 |
r[ZEMINA25IN1] = {0x2000, "Zemina25in1", "Zemina 25 in 1"}; |
| 35 |
r[ZEMINA80IN1] = {0x2000, "Zemina80in1", "Zemina 80 in 1"}; |
| 36 |
r[ZEMINA90IN1] = {0x2000, "Zemina90in1", "Zemina 90 in 1"}; |
| 37 |
r[ZEMINA126IN1] = {0x2000, "Zemina126in1", "Zemina 126 in 1"}; |
| 38 |
r[ASCII16_2] = {0x4000, "ASCII16SRAM2", "ASCII 16kB with 2kB SRAM"}; |
| 39 |
r[ASCII16_8] = {0x4000, "ASCII16SRAM8", "ASCII 16kB with 8kB SRAM"}; |
| 40 |
r[ASCII8_8] = {0x2000, "ASCII8SRAM8", "ASCII 8kB with 8kB SRAM"}; |
| 41 |
r[ASCII8_32] = {0x2000, "ASCII8SRAM32", "ASCII 8kB with 32kB SRAM"}; |
| 42 |
r[ASCII8_2] = {0x2000, "ASCII8SRAM2", "ASCII 8kB with 2kB SRAM"}; |
| 43 |
r[KOEI_8] = {0x2000, "KoeiSRAM8", "Koei with 8kB SRAM"}; |
| 44 |
r[KOEI_32] = {0x2000, "KoeiSRAM32", "Koei with 32kB SRAM"}; |
| 45 |
r[WIZARDRY] = {0x2000, "Wizardry", "Wizardry"}; |
| 46 |
r[GAME_MASTER2] = {0x1000, "GameMaster2", "Konami's Game Master 2"}; |
| 47 |
r[MAJUTSUSHI] = {0x2000, "Majutsushi", "Hai no Majutsushi"}; |
| 48 |
r[SYNTHESIZER] = {0 , "Synthesizer", "Konami's Synthesizer"}; |
| 49 |
r[PLAYBALL] = {0 , "PlayBall", "Sony's PlayBall"}; |
| 50 |
r[NETTOU_YAKYUU] = {0x2000, "NettouYakyuu", "Nettou Yakuu"}; |
| 51 |
r[HOLY_QURAN] = {0x2000, "AlQuranDecoded", "Holy Qu'ran (pre-decrypted)"}; |
| 52 |
r[HOLY_QURAN2] = {0x2000, "AlQuran", "Holy Qu'ran"}; |
| 53 |
r[PADIAL8] = {0x2000, "Padial8", "Padial 8kB"}; |
| 54 |
r[PADIAL16] = {0x4000, "Padial16", "Padial 16kB"}; |
| 55 |
r[SUPERLODERUNNER] = {0x4000, "SuperLodeRunner", "Super Lode Runner"}; |
| 56 |
r[SUPERSWANGI] = {0x4000, "SuperSwangi", "Super Swangi"}; |
| 57 |
r[MSXDOS2] = {0x4000, "MSXDOS2", "MSX-DOS2"}; |
| 58 |
r[MITSUBISHIMLTS2] = {0x2000, "MitsubishiMLTS2", "Mitsubishi ML-TS2 firmware"}; |
| 59 |
r[MANBOW2] = {0x2000, "Manbow2", "Manbow2"}; |
| 60 |
r[MANBOW2_2] = {0x2000, "Manbow2_2", "Manbow2 - Second Release"}; |
| 61 |
r[RBSC_FLASH_KONAMI_SCC]={0x2000,"RBSC_Flash_KonamiSCC","RBSC 2MB flash, Konami SCC mapper"}; |
| 62 |
r[HAMARAJANIGHT] = {0x2000, "HamarajaNight", "Best of Hamaraja Night"}; |
| 63 |
r[MEGAFLASHROMSCC] = {0x2000, "MegaFlashRomScc", "Mega Flash ROM SCC"}; |
| 64 |
r[MATRAINK] = {0 , "MatraInk", "Matra Ink"}; |
| 65 |
r[MATRACOMPILATION]= {0x2000, "MatraCompilation","Matra Compilation"}; |
| 66 |
r[ARC] = {0 , "Arc", "Parallax' ARC"}; |
| 67 |
r[ROMHUNTERMK2] = {0x2000, "ROMHunterMk2", "ROM Hunter Mk2"}; |
| 68 |
r[DOOLY] = {0x4000, "Dooly", "Baby Dinosaur Dooly"}; |
| 69 |
r[MSXTRA] = {0 , "MSXtra", "PTC MSXtra"}; |
| 70 |
r[MSXWRITE] = {0x4000, "MSXWrite", "Japanese MSX Write"}; |
| 71 |
r[MULTIROM] = {0x4000, "MultiRom", "MultiRom Collection"}; |
| 72 |
r[RAMFILE] = {0 , "RAMFILE", "Tecall MSX RAMFILE"}; |
| 73 |
r[RETROHARD31IN1] = {0x2000, "RetroHardMultiCart31in1", "RetroHard MultiCart 31 in 1"}; |
| 74 |
r[ALALAMIAH30IN1] = {0x8000, "AlAlamiah30-in-1", "Al Alamiah 30-in-1"}; |
| 75 |
r[COLECOMEGACART] = {0x4000, "ColecoMegaCart", "ColecoVision MegaCart"}; |
| 76 |
r[MEGAFLASHROMSCCPLUS]={0 ,"MegaFlashRomSccPlus","Mega Flash ROM SCC Plus"}; |
| 77 |
r[REPRO_CARTRIDGE1]= {0x2000, "ReproCartridgeV1","Repro Cartridge V1"}; |
| 78 |
r[REPRO_CARTRIDGE2]= {0x2000, "ReproCartridgeV2","Repro Cartridge V2"}; |
| 79 |
r[YAMANOOTO ]= {0x2000, "Yamanooto", "Yamanooto"}; |
| 80 |
r[KONAMI_ULTIMATE_COLLECTION]={0x2000,"KonamiUltimateCollection","Konami Ultimate Collection"}; |
| 81 |
r[NEO8] = {0x2000, "NEO-8", "NEO-8 mapper"}; |
| 82 |
r[NEO16] = {0x4000, "NEO-16", "NEO-16 mapper"}; |
| 83 |
r[WONDERKID] = {0x4000, "WonderKid", "Wonder Kid"}; |
| 84 |
r[KOREAN128IN1] = {0x2000, "Korean128in1", "Korean 128 in 1"}; |
| 85 |
r[NAMCO] = {0, "Namco", "Namco 16kB"}; |
| 86 |
|
| 87 |
|
| 88 |
r[PANASONIC] = {0x2000, "Panasonic", "Panasonic internal mapper"}; |
| 89 |
r[NATIONAL] = {0x4000, "National", "National internal mapper"}; |
| 90 |
r[FSA1FM1] = {0 , "FSA1FM1", "Panasonic FS-A1FM internal mapper 1"}; |
| 91 |
r[FSA1FM2] = {0x2000, "FSA1FM2", "Panasonic FS-A1FM internal mapper 2"}; |
| 92 |
r[DRAM] = {0x2000, "DRAM", "MSXturboR DRAM"}; |
| 93 |
|
| 94 |
|
| 95 |
r[MIRRORED] = {0, "Mirrored", "Plain rom, mirrored (any size)"}; |
| 96 |
r[MIRRORED0000] = {0, "Mirrored0000", "Plain rom, mirrored start at 0x0000"}; |
| 97 |
r[MIRRORED4000] = {0, "Mirrored4000", "Plain rom, mirrored start at 0x4000"}; |
| 98 |
r[MIRRORED8000] = {0, "Mirrored8000", "Plain rom, mirrored start at 0x8000"}; |
| 99 |
r[MIRROREDC000] = {0, "MirroredC000", "Plain rom, mirrored start at 0xC000"}; |
| 100 |
r[NORMAL] = {0, "Normal", "Plain rom (any size)"}; |
| 101 |
r[NORMAL0000] = {0, "Normal0000", "Plain rom start at 0x0000"}; |
| 102 |
r[NORMAL4000] = {0, "Normal4000", "Plain rom start at 0x4000"}; |
| 103 |
r[NORMAL8000] = {0, "Normal8000", "Plain rom start at 0x8000"}; |
| 104 |
r[NORMALC000] = {0, "NormalC000", "Plain rom start at 0xC000"}; |
| 105 |
r[PAGE0] = {0, "Page0", "Plain 16kB page 0"}; |
| 106 |
r[PAGE1] = {0, "Page1", "Plain 16kB page 1"}; |
| 107 |
r[PAGE2] = {0, "Page2", "Plain 16kB page 2 (BASIC)"}; |
| 108 |
r[PAGE3] = {0, "Page3", "Plain 16kB page 3"}; |
| 109 |
r[PAGE01] = {0, "Page01", "Plain 32kB page 0-1"}; |
| 110 |
r[PAGE12] = {0, "Page12", "Plain 32kB page 1-2"}; |
| 111 |
r[PAGE23] = {0, "Page23", "Plain 32kB page 2-3"}; |
| 112 |
r[PAGE012] = {0, "Page012", "Plain 48kB page 0-2"}; |
| 113 |
r[PAGE123] = {0, "Page123", "Plain 48kB page 1-3"}; |
| 114 |
r[PAGE0123] = {0, "Page0123", "Plain 64kB"}; |
| 115 |
return r; |
| 116 |
}(); |
| 117 |
const array_with_enum_index<RomType, RomInfo::RomTypeInfo>& RomInfo::getRomTypeInfo() |
| 118 |
{ |
| 119 |
return romTypeInfoArray; |
| 120 |
} |
| 121 |
|
| 122 |
constexpr auto sortedRomTypes = []{ |
| 123 |
std::array<RomType, std::size(romTypeInfoArray)> result = {}; |
| 124 |
std::ranges::generate(result, [i = 0]() mutable { return RomType(i++); }); |
| 125 |
std::ranges::sort(result, {}, [](auto i) { return romTypeInfoArray[i].description; }); |
| 126 |
return result; |
| 127 |
}(); |
| 128 |
const std::array<RomType, size_t(RomType::NUM)>& RomInfo::getSortedRomTypes() |
| 129 |
{ |
| 130 |
return sortedRomTypes; |
| 131 |
} |
| 132 |
|
| 133 |
struct RomTypeAndName { |
| 134 |
RomType romType; |
| 135 |
std::string_view name; |
| 136 |
}; |
| 137 |
static constexpr std::array aliasTable = { |
| 138 |
RomTypeAndName{GENERIC_8KB, "0"}, |
| 139 |
RomTypeAndName{GENERIC_8KB, "GenericKonami"}, |
| 140 |
RomTypeAndName{GENERIC_16KB,"1"}, |
| 141 |
RomTypeAndName{KONAMI_SCC, "2"}, |
| 142 |
RomTypeAndName{KONAMI_SCC, "SCC"}, |
| 143 |
RomTypeAndName{KONAMI_SCC, "KONAMI5"}, |
| 144 |
RomTypeAndName{KONAMI, "KONAMI4"}, |
| 145 |
RomTypeAndName{KONAMI, "3"}, |
| 146 |
RomTypeAndName{ASCII8, "4"}, |
| 147 |
RomTypeAndName{ASCII16, "5"}, |
| 148 |
RomTypeAndName{MIRRORED, "64kB"}, |
| 149 |
RomTypeAndName{MIRRORED, "Plain"}, |
| 150 |
RomTypeAndName{NORMAL0000, "0x0000"}, |
| 151 |
RomTypeAndName{NORMAL4000, "0x4000"}, |
| 152 |
RomTypeAndName{NORMAL8000, "0x8000"}, |
| 153 |
RomTypeAndName{NORMALC000, "0xC000"}, |
| 154 |
RomTypeAndName{ASCII16_2, "HYDLIDE2"}, |
| 155 |
RomTypeAndName{GAME_MASTER2,"RC755"}, |
| 156 |
RomTypeAndName{NORMAL8000, "ROMBAS"}, |
| 157 |
RomTypeAndName{R_TYPE, "RTYPE"}, |
| 158 |
RomTypeAndName{ZEMINA80IN1, "KOREAN80IN1"}, |
| 159 |
RomTypeAndName{ZEMINA90IN1, "KOREAN90IN1"}, |
| 160 |
RomTypeAndName{ZEMINA126IN1,"KOREAN126IN1"}, |
| 161 |
RomTypeAndName{HOLY_QURAN, "HolyQuran"}, |
| 162 |
}; |
| 163 |
|
| 164 |
static constexpr auto combinedRomTable = [] { |
| 165 |
constexpr auto N = std::size(romTypeInfoArray) + std::size(aliasTable); |
| 166 |
std::array<RomTypeAndName, N> result = {}; |
| 167 |
size_t i = 0; |
| 168 |
for (const auto& e : romTypeInfoArray) { |
| 169 |
result[i].romType = static_cast<RomType>(i); |
| 170 |
result[i].name = e.name; |
| 171 |
++i; |
| 172 |
} |
| 173 |
for (const auto& e : aliasTable) { |
| 174 |
result[i++] = e; |
| 175 |
} |
| 176 |
return result; |
| 177 |
}(); |
| 178 |
|
| 179 |
struct RomTypeNameHash { |
| 180 |
[[nodiscard]] constexpr uint32_t operator()(std::string_view str) const { |
| 181 |
constexpr auto MASK = uint8_t(~('a' - 'A')); |
| 182 |
uint32_t d = 0; |
| 183 |
for (char c : str) { |
| 184 |
d = (d ^ (c & MASK)) * 0x01000193; |
| 185 |
} |
| 186 |
return d; |
| 187 |
} |
| 188 |
}; |
| 189 |
|
| 190 |
|
| 191 |
static constexpr auto pmh = [] { |
| 192 |
auto getKey = [](size_t i) { return combinedRomTable[i].name; }; |
| 193 |
return PerfectMinimalHash::create<std::size(combinedRomTable)>(RomTypeNameHash{}, getKey); |
| 194 |
}(); |
| 195 |
|
| 196 |
RomType RomInfo::nameToRomType(std::string_view name) |
| 197 |
{ |
| 198 |
auto idx = pmh.lookupIndex(name); |
| 199 |
assert(idx < std::size(combinedRomTable)); |
| 200 |
if (StringOp::casecmp cmp; cmp(combinedRomTable[idx].name, name)) { |
| 201 |
return combinedRomTable[idx].romType; |
| 202 |
} |
| 203 |
return RomType::UNKNOWN; |
| 204 |
} |
| 205 |
|
| 206 |
zstring_view RomInfo::romTypeToName(RomType type) |
| 207 |
{ |
| 208 |
if (type == RomType::UNKNOWN) return "unknown"; |
| 209 |
return romTypeInfoArray[type].name; |
| 210 |
} |
| 211 |
|
| 212 |
std::string_view RomInfo::getDescription(RomType type) |
| 213 |
{ |
| 214 |
return romTypeInfoArray[type].description; |
| 215 |
} |
| 216 |
|
| 217 |
unsigned RomInfo::getBlockSize(RomType type) |
| 218 |
{ |
| 219 |
return romTypeInfoArray[type].blockSize; |
| 220 |
} |
| 221 |
|
| 222 |
} |