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