OXYGENHUB
◆ main openmsx / src / memory / RomInfo.cc
10.3 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
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
	// Generic ROM types that don't exist in real ROMs
18
	// (should not occur in any database!)
19
	r[GENERIC_8KB]     = {0x2000, "8kB",             "Generic 8kB"};
20
	r[GENERIC_16KB]    = {0x4000, "16kB",            "Generic 16kB"};
21
22
	// ROM mapper types for normal software (mainly games)
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"}; // officially plain 16K
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"}; // plain 32K
49
	r[PLAYBALL]        = {0     , "PlayBall",        "Sony's PlayBall"}; // plain 32K
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"}; // plain 32K
67
	r[ROMHUNTERMK2]    = {0x2000, "ROMHunterMk2",    "ROM Hunter Mk2"}; // variable block size, 8kB smallest
68
	r[DOOLY]           = {0x4000, "Dooly",           "Baby Dinosaur Dooly"}; // officially 32K blocksize, but spread over 2 pages
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"}; // variable block size
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
	// ROM mapper types used for system ROMs in machines
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"}; // TODO: romblocks debuggable?
91
	r[FSA1FM2]         = {0x2000, "FSA1FM2",         "Panasonic FS-A1FM internal mapper 2"};
92
	r[DRAM]            = {0x2000, "DRAM",            "MSXturboR DRAM"};
93
94
	// Non-mapper ROM types
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 = []{ // sorted on description
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"}, // probably actually used in a Zemina Box
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')); // case insensitive
182
		uint32_t d = 0;
183
		for (char c : str) {
184
			d = (d ^ (c & MASK)) * 0x01000193;
185
		}
186
		return d;
187
	}
188
};
189
190
// Construct perfect hash function to lookup RomType by name.
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
} // namespace openmsx