openMSX
RomFactory.cc
Go to the documentation of this file.
1#include "RomFactory.hh"
2
3#include "RomTypes.hh"
4#include "RomInfo.hh"
5#include "RomPageNN.hh"
6#include "RomPlain.hh"
7#include "RomDRAM.hh"
8#include "RomGeneric8kB.hh"
9#include "RomGeneric16kB.hh"
10#include "RomKonami.hh"
11#include "RomKonamiSCC.hh"
13#include "RomAscii8kB.hh"
14#include "RomAscii8_8.hh"
15#include "RomAscii16kB.hh"
16#include "RomMSXWrite.hh"
17#include "RomPadial8kB.hh"
18#include "RomPadial16kB.hh"
19#include "RomSuperLodeRunner.hh"
20#include "RomSuperSwangi.hh"
21#include "RomMitsubishiMLTS2.hh"
22#include "RomMSXDOS2.hh"
23#include "RomAscii16_2.hh"
24#include "RomRType.hh"
25#include "RomCrossBlaim.hh"
26#include "RomHarryFox.hh"
27#include "RomPanasonic.hh"
28#include "RomNational.hh"
29#include "RomNeo8.hh"
30#include "RomNeo16.hh"
31#include "RomMajutsushi.hh"
32#include "RomSynthesizer.hh"
33#include "RomPlayBall.hh"
34#include "RomNettouYakyuu.hh"
35#include "RomGameMaster2.hh"
36#include "RomHalnote.hh"
37#include "RomZemina25in1.hh"
38#include "RomZemina80in1.hh"
39#include "RomZemina90in1.hh"
40#include "RomZemina126in1.hh"
41#include "RomHolyQuran.hh"
42#include "RomHolyQuran2.hh"
43#include "RomFSA1FM.hh"
44#include "RomManbow2.hh"
45#include "RomMatraInk.hh"
47#include "RomArc.hh"
48#include "RomAlAlamiah30in1.hh"
49#include "RomRetroHard31in1.hh"
50#include "ROMHunterMk2.hh"
52#include "ReproCartridgeV1.hh"
53#include "ReproCartridgeV2.hh"
55#include "RomDooly.hh"
56#include "RomMSXtra.hh"
57#include "RomRamFile.hh"
58#include "RomColecoMegaCart.hh"
59#include "RomMultiRom.hh"
60#include "Rom.hh"
61#include "Reactor.hh"
62#include "MSXMotherBoard.hh"
63#include "RomDatabase.hh"
64#include "DeviceConfig.hh"
65#include "XMLElement.hh"
66#include "MSXException.hh"
67
68#include "enumerate.hh"
69#include "one_of.hh"
70#include "xrange.hh"
71
72#include <bit>
73#include <memory>
74
75using std::make_unique;
76
78
79[[nodiscard]] static RomType guessRomType(const Rom& rom)
80{
81 auto size = rom.size();
82 if (size == 0) {
83 return ROM_NORMAL;
84 }
85 //std::span data = rom; // TODO error with clang-13/libc++
86 std::span data{std::to_address(rom.begin()), size};
87
88 if (const size_t signatureOffset = 16, signatureSize = 8; size >= (signatureOffset + signatureSize)) {
89 auto signature = std::string_view(std::bit_cast<const char*>(data.data()) + signatureOffset, signatureSize);
90 if (signature == std::string_view("ROM_NEO8")) return ROM_NEO8;
91 if (signature == std::string_view("ROM_NE16")) return ROM_NEO16;
92 }
93 if (size < 0x10000) {
94 if ((size <= 0x4000) &&
95 (data[0] == 'A') && (data[1] == 'B')) {
96 auto initAddr = word(data[2] + 256 * data[3]);
97 auto textAddr = word(data[8] + 256 * data[9]);
98 if ((textAddr & 0xC000) == 0x8000) {
99 if ((initAddr == 0) ||
100 (((initAddr & 0xC000) == 0x8000) &&
101 (data[initAddr & (size - 1)] == 0xC9))) {
102 return ROM_PAGE2;
103 }
104 }
105 }
106 // not correct for Konami-DAC, but does this really need
107 // to be correct for _every_ rom?
108 return ROM_MIRRORED;
109 } else if (size == 0x10000 && !((data[0] == 'A') && (data[1] == 'B'))) {
110 // 64 kB ROMs can be plain or memory mapped...
111 // check here for plain, if not, try the auto detection
112 // (thanks for the hint, hap)
113 return ROM_MIRRORED;
114 } else {
115 // GameCartridges do their bank switching by using the Z80
116 // instruction ld(nn),a in the middle of program code. The
117 // address nn depends upon the GameCartridge mapper type used.
118 // To guess which mapper it is, we will look how much writes
119 // with this instruction to the mapper-registers-addresses
120 // occur.
121
122 std::array<unsigned, ROM_LAST> typeGuess = {}; // 0-initialized
123 for (auto i : xrange(size - 3)) {
124 if (data[i] == 0x32) {
125 auto value = word(data[i + 1] + (data[i + 2] << 8));
126 switch (value) {
127 case 0x5000:
128 case 0x9000:
129 case 0xb000:
130 typeGuess[ROM_KONAMI_SCC]++;
131 break;
132 case 0x4000:
133 case 0x8000:
134 case 0xa000:
135 typeGuess[ROM_KONAMI]++;
136 break;
137 case 0x6800:
138 case 0x7800:
139 typeGuess[ROM_ASCII8]++;
140 break;
141 case 0x6000:
142 typeGuess[ROM_KONAMI]++;
143 typeGuess[ROM_ASCII8]++;
144 typeGuess[ROM_ASCII16]++;
145 break;
146 case 0x7000:
147 typeGuess[ROM_KONAMI_SCC]++;
148 typeGuess[ROM_ASCII8]++;
149 typeGuess[ROM_ASCII16]++;
150 break;
151 case 0x77ff:
152 typeGuess[ROM_ASCII16]++;
153 break;
154 }
155 }
156 }
157 if (typeGuess[ROM_ASCII8]) typeGuess[ROM_ASCII8]--; // -1 -> max_int
159 for (auto [i, tg] : enumerate(typeGuess)) {
160 if (tg && (tg >= typeGuess[type])) {
161 type = static_cast<RomType>(i);
162 }
163 }
164 return type;
165 }
166}
167
168std::unique_ptr<MSXDevice> create(const DeviceConfig& config)
169{
170 Rom rom(std::string(config.getAttributeValue("id")), "rom", config);
171
172 // Get specified mapper type from the config.
173 RomType type = [&] {
174 // if no type is mentioned, we assume 'mirrored' which works for most
175 // plain ROMs...
176 std::string_view typeStr = config.getChildData("mappertype", "Mirrored");
177 if (typeStr == "auto") {
178 // First check whether the (possibly patched) SHA1 is in the DB
179 const RomInfo* romInfo = config.getReactor().getSoftwareDatabase().fetchRomInfo(rom.getSHA1());
180 // If not found, try the original SHA1 in the DB
181 if (!romInfo) {
183 }
184 // If still not found, guess the mapper type
185 if (!romInfo) {
186 auto machineType = config.getMotherBoard().getMachineType();
187 if (machineType == "Coleco") {
188 if (rom.size() == one_of(128*1024u, 256*1024u, 512*1024u, 1024*1024u)) {
189 return ROM_COLECOMEGACART;
190 } else {
191 return ROM_PAGE23;
192 }
193 } else {
194 return guessRomType(rom);
195 }
196 } else {
197 return romInfo->getRomType();
198 }
199 } else {
200 // Use mapper type from config, even if this overrides DB.
201 auto t = RomInfo::nameToRomType(typeStr);
202 if (t == ROM_UNKNOWN) {
203 throw MSXException("Unknown mappertype: ", typeStr);
204 }
205 return t;
206 }
207 }();
208
209 // Store actual detected mapper type in config (override the possible
210 // 'auto' value). This way we're sure that on savestate/loadstate we're
211 // using the same mapper type (for example when the user's rom-database
212 // was updated).
213 // We do it at this point so that constructors used below can use this
214 // information for warning messages etc.
215 auto& doc = const_cast<DeviceConfig&>(config).getXMLDocument();
216 doc.setChildData(const_cast<XMLElement&>(*config.getXML()),
217 "mappertype", RomInfo::romTypeToName(type).data());
218
219 std::unique_ptr<MSXRom> result;
220 switch (type) {
221 case ROM_MIRRORED:
222 case ROM_MIRRORED0000:
223 case ROM_MIRRORED4000:
224 case ROM_MIRRORED8000:
225 case ROM_MIRROREDC000:
226 case ROM_NORMAL:
227 case ROM_NORMAL0000:
228 case ROM_NORMAL4000:
229 case ROM_NORMAL8000:
230 case ROM_NORMALC000:
231 result = make_unique<RomPlain>(config, std::move(rom), type);
232 break;
233 case ROM_PAGE0:
234 case ROM_PAGE1:
235 case ROM_PAGE01:
236 case ROM_PAGE2:
237 case ROM_PAGE12:
238 case ROM_PAGE012:
239 case ROM_PAGE3:
240 case ROM_PAGE23:
241 case ROM_PAGE123:
242 case ROM_PAGE0123:
243 result = make_unique<RomPageNN>(config, std::move(rom), type);
244 break;
245 case ROM_DRAM:
246 result = make_unique<RomDRAM>(config, std::move(rom));
247 break;
248 case ROM_GENERIC_8KB:
249 result = make_unique<RomGeneric8kB>(config, std::move(rom));
250 break;
251 case ROM_GENERIC_16KB:
252 result = make_unique<RomGeneric16kB>(config, std::move(rom));
253 break;
254 case ROM_KONAMI_SCC:
255 result = make_unique<RomKonamiSCC>(config, std::move(rom));
256 break;
257 case ROM_KONAMI:
258 result = make_unique<RomKonami>(config, std::move(rom));
259 break;
260 case ROM_KBDMASTER:
261 result = make_unique<RomKonamiKeyboardMaster>(config, std::move(rom));
262 break;
263 case ROM_ASCII8:
264 result = make_unique<RomAscii8kB>(config, std::move(rom));
265 break;
266 case ROM_ASCII16:
267 result = make_unique<RomAscii16kB>(config, std::move(rom));
268 break;
269 case ROM_MSXWRITE:
270 result = make_unique<RomMSXWrite>(config, std::move(rom));
271 break;
272 case ROM_PADIAL8:
273 result = make_unique<RomPadial8kB>(config, std::move(rom));
274 break;
275 case ROM_PADIAL16:
276 result = make_unique<RomPadial16kB>(config, std::move(rom));
277 break;
279 result = make_unique<RomSuperLodeRunner>(config, std::move(rom));
280 break;
281 case ROM_SUPERSWANGI:
282 result = make_unique<RomSuperSwangi>(config, std::move(rom));
283 break;
285 result = make_unique<RomMitsubishiMLTS2>(config, std::move(rom));
286 break;
287 case ROM_MSXDOS2:
288 result = make_unique<RomMSXDOS2>(config, std::move(rom));
289 break;
290 case ROM_R_TYPE:
291 result = make_unique<RomRType>(config, std::move(rom));
292 break;
293 case ROM_CROSS_BLAIM:
294 result = make_unique<RomCrossBlaim>(config, std::move(rom));
295 break;
296 case ROM_HARRY_FOX:
297 result = make_unique<RomHarryFox>(config, std::move(rom));
298 break;
299 case ROM_ASCII8_8:
300 result = make_unique<RomAscii8_8>(
301 config, std::move(rom), RomAscii8_8::SubType::ASCII8_8);
302 break;
303 case ROM_ASCII8_32:
304 result = make_unique<RomAscii8_8>(
305 config, std::move(rom), RomAscii8_8::SubType::ASCII8_32);
306 break;
307 case ROM_ASCII8_2:
308 result = make_unique<RomAscii8_8>(
309 config, std::move(rom), RomAscii8_8::SubType::ASCII8_2);
310 break;
311 case ROM_KOEI_8:
312 result = make_unique<RomAscii8_8>(
313 config, std::move(rom), RomAscii8_8::SubType::KOEI_8);
314 break;
315 case ROM_KOEI_32:
316 result = make_unique<RomAscii8_8>(
317 config, std::move(rom), RomAscii8_8::SubType::KOEI_32);
318 break;
319 case ROM_WIZARDRY:
320 result = make_unique<RomAscii8_8>(
321 config, std::move(rom), RomAscii8_8::SubType::WIZARDRY);
322 break;
323 case ROM_ASCII16_2:
324 result = make_unique<RomAscii16_2>(config, std::move(rom), RomAscii16_2::SubType::ASCII16_2);
325 break;
326 case ROM_ASCII16_8:
327 result = make_unique<RomAscii16_2>(config, std::move(rom), RomAscii16_2::SubType::ASCII16_8);
328 break;
329 case ROM_GAME_MASTER2:
330 result = make_unique<RomGameMaster2>(config, std::move(rom));
331 break;
332 case ROM_PANASONIC:
333 result = make_unique<RomPanasonic>(config, std::move(rom));
334 break;
335 case ROM_NATIONAL:
336 result = make_unique<RomNational>(config, std::move(rom));
337 break;
338 case ROM_NEO8:
339 result = make_unique<RomNeo8>(config, std::move(rom));
340 break;
341 case ROM_NEO16:
342 result = make_unique<RomNeo16>(config, std::move(rom));
343 break;
344 case ROM_MAJUTSUSHI:
345 result = make_unique<RomMajutsushi>(config, std::move(rom));
346 break;
347 case ROM_SYNTHESIZER:
348 result = make_unique<RomSynthesizer>(config, std::move(rom));
349 break;
350 case ROM_PLAYBALL:
351 result = make_unique<RomPlayBall>(config, std::move(rom));
352 break;
354 result = make_unique<RomNettouYakyuu>(config, std::move(rom));
355 break;
356 case ROM_HALNOTE:
357 result = make_unique<RomHalnote>(config, std::move(rom));
358 break;
359 case ROM_ZEMINA25IN1:
360 result = make_unique<RomZemina25in1>(config, std::move(rom));
361 break;
362 case ROM_ZEMINA80IN1:
363 result = make_unique<RomZemina80in1>(config, std::move(rom));
364 break;
365 case ROM_ZEMINA90IN1:
366 result = make_unique<RomZemina90in1>(config, std::move(rom));
367 break;
368 case ROM_ZEMINA126IN1:
369 result = make_unique<RomZemina126in1>(config, std::move(rom));
370 break;
371 case ROM_HOLY_QURAN:
372 result = make_unique<RomHolyQuran>(config, std::move(rom));
373 break;
374 case ROM_HOLY_QURAN2:
375 result = make_unique<RomHolyQuran2>(config, std::move(rom));
376 break;
377 case ROM_FSA1FM1:
378 result = make_unique<RomFSA1FM1>(config, std::move(rom));
379 break;
380 case ROM_FSA1FM2:
381 result = make_unique<RomFSA1FM2>(config, std::move(rom));
382 break;
383 case ROM_MANBOW2:
384 case ROM_MANBOW2_2:
388 result = make_unique<RomManbow2>(config, std::move(rom), type);
389 break;
390 case ROM_MATRAINK:
391 result = make_unique<RomMatraInk>(config, std::move(rom));
392 break;
394 result = make_unique<RomMatraCompilation>(config, std::move(rom));
395 break;
396 case ROM_ARC:
397 result = make_unique<RomArc>(config, std::move(rom));
398 break;
400 result = make_unique<RomAlAlamiah30in1>(config, std::move(rom));
401 break;
403 result = make_unique<RomRetroHard31in1>(config, std::move(rom));
404 break;
405 case ROM_ROMHUNTERMK2:
406 result = make_unique<ROMHunterMk2>(config, std::move(rom));
407 break;
409 result = make_unique<MegaFlashRomSCCPlus>(config, std::move(rom));
410 break;
412 result = make_unique<ReproCartridgeV1>(config, std::move(rom));
413 break;
415 result = make_unique<ReproCartridgeV2>(config, std::move(rom));
416 break;
418 result = make_unique<KonamiUltimateCollection>(config, std::move(rom));
419 break;
420 case ROM_DOOLY:
421 result = make_unique<RomDooly>(config, std::move(rom));
422 break;
423 case ROM_MSXTRA:
424 result = make_unique<RomMSXtra>(config, std::move(rom));
425 break;
426 case ROM_MULTIROM:
427 result = make_unique<RomMultiRom>(config, std::move(rom));
428 break;
429 case ROM_RAMFILE:
430 result = make_unique<RomRamFile>(config, std::move(rom));
431 break;
433 result = make_unique<RomColecoMegaCart>(config, std::move(rom));
434 break;
435 default:
436 throw MSXException("Unknown ROM type");
437 }
438
439 return result;
440}
441
442} // namespace openmsx::RomFactory
TclObject t
Reactor & getReactor() const
MSXMotherBoard & getMotherBoard() const
std::string_view getChildData(std::string_view name) const
const XMLElement * getXML() const
std::string_view getAttributeValue(std::string_view attName) const
std::string_view getMachineType() const
RomDatabase & getSoftwareDatabase()
Definition Reactor.cc:315
const RomInfo * fetchRomInfo(const Sha1Sum &sha1sum) const
Lookup an entry in the database by sha1sum.
static std::string_view romTypeToName(RomType type)
Definition RomInfo.cc:188
RomType getRomType() const
Definition RomInfo.hh:61
static RomType nameToRomType(std::string_view name)
Definition RomInfo.cc:178
const Sha1Sum & getSHA1() const
Definition Rom.cc:359
auto begin() const
Definition Rom.hh:37
const Sha1Sum & getOriginalSHA1() const
Definition Rom.cc:351
auto size() const
Definition Rom.hh:36
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
Definition enumerate.hh:28
std::unique_ptr< MSXDevice > create(const DeviceConfig &config)
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
@ ROM_HALNOTE
Definition RomTypes.hh:26
@ ROM_COLECOMEGACART
Definition RomTypes.hh:17
@ ROM_MATRACOMPILATION
Definition RomTypes.hh:44
@ ROM_DRAM
Definition RomTypes.hh:20
@ ROM_PADIAL8
Definition RomTypes.hh:66
@ ROM_ASCII16_2
Definition RomTypes.hh:15
@ ROM_FSA1FM1
Definition RomTypes.hh:21
@ ROM_FSA1FM2
Definition RomTypes.hh:22
@ ROM_ZEMINA126IN1
Definition RomTypes.hh:91
@ ROM_PADIAL16
Definition RomTypes.hh:67
@ ROM_NORMAL0000
Definition RomTypes.hh:62
@ ROM_KOEI_8
Definition RomTypes.hh:32
@ ROM_MIRRORED8000
Definition RomTypes.hh:50
@ ROM_UNKNOWN
Definition RomTypes.hh:94
@ ROM_ZEMINA90IN1
Definition RomTypes.hh:90
@ ROM_PAGE1
Definition RomTypes.hh:69
@ ROM_SYNTHESIZER
Definition RomTypes.hh:86
@ ROM_PAGE2
Definition RomTypes.hh:71
@ ROM_PANASONIC
Definition RomTypes.hh:78
@ ROM_GENERIC_16KB
Definition RomTypes.hh:25
@ ROM_REPRO_CARTRIDGE2
Definition RomTypes.hh:37
@ ROM_PAGE01
Definition RomTypes.hh:70
@ ROM_MANBOW2_2
Definition RomTypes.hh:41
@ ROM_ZEMINA80IN1
Definition RomTypes.hh:89
@ ROM_ROMHUNTERMK2
Definition RomTypes.hh:83
@ ROM_HAMARAJANIGHT
Definition RomTypes.hh:27
@ ROM_MIRRORED0000
Definition RomTypes.hh:48
@ ROM_CROSS_BLAIM
Definition RomTypes.hh:18
@ ROM_RETROHARD31IN1
Definition RomTypes.hh:82
@ ROM_MANBOW2
Definition RomTypes.hh:40
@ ROM_NETTOU_YAKYUU
Definition RomTypes.hh:60
@ ROM_MULTIROM
Definition RomTypes.hh:56
@ ROM_GAME_MASTER2
Definition RomTypes.hh:23
@ ROM_MEGAFLASHROMSCC
Definition RomTypes.hh:45
@ ROM_PAGE3
Definition RomTypes.hh:74
@ ROM_MIRRORED4000
Definition RomTypes.hh:49
@ ROM_PAGE12
Definition RomTypes.hh:72
@ ROM_MEGAFLASHROMSCCPLUS
Definition RomTypes.hh:46
@ ROM_MSXDOS2
Definition RomTypes.hh:53
@ ROM_ASCII16
Definition RomTypes.hh:14
@ ROM_ZEMINA25IN1
Definition RomTypes.hh:88
@ ROM_MAJUTSUSHI
Definition RomTypes.hh:39
@ ROM_ARC
Definition RomTypes.hh:8
@ ROM_SUPERLODERUNNER
Definition RomTypes.hh:84
@ ROM_SUPERSWANGI
Definition RomTypes.hh:85
@ ROM_PAGE123
Definition RomTypes.hh:76
@ ROM_ASCII8_32
Definition RomTypes.hh:12
@ ROM_PAGE23
Definition RomTypes.hh:75
@ ROM_KONAMI_ULTIMATE_COLLECTION
Definition RomTypes.hh:38
@ ROM_NATIONAL
Definition RomTypes.hh:57
@ ROM_NORMALC000
Definition RomTypes.hh:65
@ ROM_NORMAL4000
Definition RomTypes.hh:63
@ ROM_KBDMASTER
Definition RomTypes.hh:31
@ ROM_RBSC_FLASH_KONAMI_SCC
Definition RomTypes.hh:42
@ ROM_MIRRORED
Definition RomTypes.hh:47
@ ROM_ASCII16_8
Definition RomTypes.hh:16
@ ROM_NEO16
Definition RomTypes.hh:59
@ ROM_HARRY_FOX
Definition RomTypes.hh:28
@ ROM_R_TYPE
Definition RomTypes.hh:80
@ ROM_NORMAL8000
Definition RomTypes.hh:64
@ ROM_WIZARDRY
Definition RomTypes.hh:87
@ ROM_NORMAL
Definition RomTypes.hh:61
@ ROM_KONAMI
Definition RomTypes.hh:34
@ ROM_MATRAINK
Definition RomTypes.hh:43
@ ROM_PLAYBALL
Definition RomTypes.hh:79
@ ROM_PAGE0123
Definition RomTypes.hh:77
@ ROM_RAMFILE
Definition RomTypes.hh:81
@ ROM_MITSUBISHIMLTS2
Definition RomTypes.hh:52
@ ROM_ASCII8_2
Definition RomTypes.hh:11
@ ROM_PAGE012
Definition RomTypes.hh:73
@ ROM_PAGE0
Definition RomTypes.hh:68
@ ROM_MSXTRA
Definition RomTypes.hh:54
@ ROM_MIRROREDC000
Definition RomTypes.hh:51
@ ROM_GENERIC_8KB
Definition RomTypes.hh:24
@ ROM_KOEI_32
Definition RomTypes.hh:33
@ ROM_HOLY_QURAN2
Definition RomTypes.hh:30
@ ROM_MSXWRITE
Definition RomTypes.hh:55
@ ROM_ASCII8_8
Definition RomTypes.hh:13
@ ROM_NEO8
Definition RomTypes.hh:58
@ ROM_DOOLY
Definition RomTypes.hh:19
@ ROM_KONAMI_SCC
Definition RomTypes.hh:35
@ ROM_REPRO_CARTRIDGE1
Definition RomTypes.hh:36
@ ROM_HOLY_QURAN
Definition RomTypes.hh:29
@ ROM_ALALAMIAH30IN1
Definition RomTypes.hh:9
@ ROM_ASCII8
Definition RomTypes.hh:10
constexpr auto xrange(T e)
Definition xrange.hh:132