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