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