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