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