openMSX
Carnivore2.cc
Go to the documentation of this file.
1 #include "Carnivore2.hh"
2 #include "IDEDevice.hh"
3 #include "IDEDeviceFactory.hh"
4 #include "MSXCPU.hh"
5 #include "cstd.hh"
6 #include "one_of.hh"
7 #include "ranges.hh"
8 #include "xrange.hh"
9 #include <array>
10 
11 namespace openmsx {
12 
13 static constexpr auto sectorInfo = [] {
14  // 8 * 8kB, followed by 127 * 64kB
15  using Info = AmdFlash::SectorInfo;
16  std::array<Info, 8 + 127> result = {};
17  cstd::fill(result.begin(), result.begin() + 8, Info{ 8 * 1024, false});
18  cstd::fill(result.begin() + 8, result.end(), Info{64 * 1024, false});
19  return result;
20 }();
21 
23  : MSXDevice(config)
24  , MSXMapperIOClient(getMotherBoard())
25  , flash("Carnivore2 flash", sectorInfo, 0x207e,
26  AmdFlash::Addressing::BITS_12, config)
27  , ram(config, getName() + " ram", "ram", 2048 * 1024)
28  , eeprom(getName() + " eeprom",
29  DeviceConfig(config, config.getChild("eeprom")))
30  , scc(getName() + " scc", config, getCurrentTime(), SCC::SCC_Compatible)
31  , ym2413(getName() + " ym2413", config)
32 {
33  ideDevices[0] = IDEDeviceFactory::create(
34  DeviceConfig(config, config.findChild("master")));
35  ideDevices[1] = IDEDeviceFactory::create(
36  DeviceConfig(config, config.findChild("slave")));
37 }
38 
39 Carnivore2::~Carnivore2() = default;
40 
41 void Carnivore2::powerUp(EmuTime::param time)
42 {
43  writeSndLVL(0x1b, time);
44  scc.powerUp(time);
45  reset(time);
46 }
47 
48 void Carnivore2::reset(EmuTime::param time)
49 {
50  subSlotReg = 0;
51  port3C = 0;
52 
53  // config regs
54  configRegs[0x00] = 0x30; // CardMDR
55  for (int i : {0x01, 0x02, 0x03}) configRegs[i] = 0; // AddrM<i>
56  configRegs[0x05] = shadowConfigRegs[0x05] = 0; // AddrFR
57 
58  configRegs[0x06] = shadowConfigRegs[0x06] = 0xF8; // R1Mask
59  configRegs[0x07] = shadowConfigRegs[0x07] = 0x50; // R1Addr
60  configRegs[0x08] = shadowConfigRegs[0x08] = 0x00; // R1Reg
61  configRegs[0x09] = shadowConfigRegs[0x09] = 0x85; // R1Mult
62  configRegs[0x0a] = shadowConfigRegs[0x0a] = 0x03; // B1MaskR
63  configRegs[0x0b] = shadowConfigRegs[0x0b] = 0x40; // B1AdrD
64 
65  for (int i : {0x0f, 0x15, 0x1b}) {
66  configRegs[i] = shadowConfigRegs[i] = 0; // R<i>Mult
67  }
68 
69  configRegs[0x1e] = shadowConfigRegs[0x1e] = 0xff;
70  configRegs[0x20] = 0x02;
71 
72  writeCfgEEPR(0, time);
73 
74  // multi-mapper
75  scc.reset(time);
76  sccMode = 0;
77  ranges::iota(sccBank, 0);
78 
79  // ide
80  ideControlReg = 0;
81  ideSelectedDevice = 0;
82  ideSoftReset = false;
83  ideDevices[0]->reset(time);
84  ideDevices[1]->reset(time);
85 
86  // memory mapper
87  ranges::iota(memMapRegs, 0); // Note: different from how BIOS initializes these registers
88 
89  // fm-pac
90  ym2413.reset(time);
91  fmPacEnable = 0x10;
92  fmPacBank = 0;
93  fmPac5ffe = 0;
94  fmPac5fff = 0;
95 }
96 
97 void Carnivore2::globalRead(word address, EmuTime::param /*time*/)
98 {
99  if (!delayedConfig()) return;
100 
101  if ((!delayedConfig4000() && (address == 0x0000) && (getCPU().isM1Cycle(address))) ||
102  ( delayedConfig4000() && (address <= 0x4000) && (address < 0x4010))) {
103  // activate delayed configuration
104  for (auto i : xrange(0x05, 0x1f)) {
105  configRegs[i] = shadowConfigRegs[i];
106  }
107  }
108 }
109 
110 byte Carnivore2::getSubSlot(word address) const
111 {
112  if (slotExpanded()) {
113  byte page = address >> 14;
114  byte subSlot = (subSlotReg >> (2 * page)) & 0x03;
115  return subSlotEnabled(subSlot) ? subSlot : -1;
116  } else {
117  for (auto i : xrange(4)) {
118  if (subSlotEnabled(i)) return i;
119  }
120  return byte(-1);
121  }
122 }
123 
124 byte Carnivore2::readMem(word address, EmuTime::param time)
125 {
126  if (slotExpanded() && (address == 0xffff)) {
127  return subSlotReg ^ 0xff;
128  }
129  switch (getSubSlot(address)) {
130  case 0: return readMultiMapperSlot(address, time);
131  case 1: return readIDESlot(address, time);
132  case 2: return readMemoryMapperSlot(address);
133  case 3: return readFmPacSlot(address);
134  default: return 0xff;
135  }
136 }
137 
138 byte Carnivore2::peekMem(word address, EmuTime::param time) const
139 {
140  if (slotExpanded() && (address == 0xffff)) {
141  return subSlotReg ^ 0xff;
142  }
143  switch (getSubSlot(address)) {
144  case 0: return peekMultiMapperSlot(address, time);
145  case 1: return peekIDESlot(address, time);
146  case 2: return peekMemoryMapperSlot(address);
147  case 3: return peekFmPacSlot(address);
148  default: return 0xff;
149  }
150 }
151 
152 void Carnivore2::writeMem(word address, byte value, EmuTime::param time)
153 {
154  if (slotExpanded() && (address == 0xffff)) {
155  subSlotReg = value;
156  // this does not block the writes below
157  }
158 
159  switch (getSubSlot(address)) {
160  case 0: writeMultiMapperSlot(address, value, time); break;
161  case 1: writeIDESlot(address, value, time); break;
162  case 2: writeMemoryMapperSlot(address, value); break;
163  case 3: writeFmPacSlot(address, value, time); break;
164  default: /*unmapped, do nothing*/ break;
165  }
166 }
167 
168 unsigned Carnivore2::getDirectFlashAddr() const
169 {
170  return (configRegs[0x01] << 0) |
171  (configRegs[0x02] << 8) |
172  (configRegs[0x03] << 16); // already masked to 7 bits
173 }
174 
175 byte Carnivore2::peekConfigRegister(word address, EmuTime::param time) const
176 {
177  address &= 0x3f;
178  if ((0x05 <= address) && (address <= 0x1e)) {
179  // only these registers have a shadow counterpart,
180  // reads happen from the shadowed version
181  return shadowConfigRegs[address];
182  } else {
183  switch (address) {
184  case 0x04: return flash.peek(getDirectFlashAddr());
185  case 0x1f: return configRegs[0x00]; // mirror 'CardMDR' register
186  case 0x23: return configRegs[address] |
187  int(eeprom.read_DO(time));
188  default: return configRegs[address];
189  }
190  }
191 }
192 
193 byte Carnivore2::readConfigRegister(word address, EmuTime::param time)
194 {
195  address &= 0x3f;
196  if (address == 0x04) {
197  return flash.read(getDirectFlashAddr());
198  } else {
199  return peekConfigRegister(address, time);
200  }
201 }
202 
203 static constexpr float volumeLevel(byte volume)
204 {
205  constexpr byte tab[8] = {5, 6, 7, 8, 10, 12, 14, 16};
206  return tab[volume & 7] / 16.0f;
207 }
208 
209 void Carnivore2::writeSndLVL(byte value, EmuTime::param time)
210 {
211  configRegs[0x22] = value;
212  ym2413.setSoftwareVolume(volumeLevel(value >> 3), time);
213  scc .setSoftwareVolume(volumeLevel(value >> 0), time);
214 }
215 
216 void Carnivore2::writeCfgEEPR(byte value, EmuTime::param time)
217 {
218  configRegs[0x23] = value & 0x0e;
219  eeprom.write_DI (value & 2, time);
220  eeprom.write_CLK(value & 4, time);
221  eeprom.write_CS (value & 8, time);
222 }
223 
224 void Carnivore2::writeConfigRegister(word address, byte value, EmuTime::param time)
225 {
226  address &= 0x3f;
227  if ((0x05 <= address) && (address <= 0x1e)) {
228  // shadow registers
229  if (address == 0x05) value &= 0x7f;
230  if ((address == 0x1e) && ((value & 0x8f) == 0x0f)) return; // ignore write
231 
232  shadowConfigRegs[address] = value;
233  if (!delayedConfig()) configRegs[address] = value;
234  } else {
235  switch (address) {
236  case 0x03: configRegs[address] = value & 0x7f; break;
237  case 0x04: flash.write(getDirectFlashAddr(), value); break;
238  case 0x1f: configRegs[0x00] = value; break; // mirror 'CardMDR' register
239  case 0x20: configRegs[address] = value & 0x07; break;
240  case 0x22: writeSndLVL(value, time); break;
241  case 0x23: writeCfgEEPR(value, time); break;
242  //case 0x24: // TODO PSG key-click
243  default: configRegs[address] = value; break;
244  }
245  }
246 }
247 
248 bool Carnivore2::isConfigReg(word address) const
249 {
250  if (configRegs[0x00] & 0x80) return false; // config regs disabled
251  unsigned base = ((configRegs[0x00] & 0x60) << 9) | 0xF80;
252  return (base <= address) && (address < (base + 0x40));
253 }
254 
255 std::pair<unsigned, byte> Carnivore2::decodeMultiMapper(word address) const
256 {
257  // check up to 4 possible banks
258  for (auto i : xrange(4)) {
259  const byte* base = configRegs + (i * 6) + 6; // points to R<i>Mask
260  byte mult = base[3];
261  if (mult & 8) continue; // bank disabled
262 
263  byte sizeCode = mult & 7;
264  if (sizeCode < 3) continue; // invalid size
265 
266  // check address
267  bool mirroringDisabled = mult & 0x40;
268  static constexpr byte checkMasks[2][8] = {
269  { 0x00, 0x00, 0x00, 0x30, 0x60, 0xc0, 0x80, 0x00 }, // mirroring enabled
270  { 0x00, 0x00, 0x00, 0xf0, 0xe0, 0xc0, 0x80, 0x00 }, // mirroring disabled
271  };
272  byte checkMask = checkMasks[mirroringDisabled][sizeCode];
273  if (((address >> 8) & checkMask) != (base[5] & checkMask)) continue;
274 
275  // found bank
276  byte bank = base[2] & base[4];
277  unsigned size = 512 << sizeCode; // 7->64k, 6->32k, ..., 3->4k
278  unsigned addr = (bank * size) | (address & (size - 1));
279  addr += configRegs[0x05] * 0x10000; // 64kB block offset
280  addr &= 0x7fffff; // 8MB
281  return {addr, mult};
282  }
283  return {unsigned(-1), byte(-1)};
284 }
285 
286 bool Carnivore2::sccAccess(word address) const
287 {
288  if (!sccEnabled()) return false;
289  if (sccMode & 0x20) {
290  // check scc plus
291  return (0xb800 <= address) && (address < 0xc000) &&
292  ((sccBank[3] & 0x80) == 0x80);
293  } else {
294  // check scc compatible
295  return (0x9800 <= address) && (address < 0xa000) &&
296  ((sccBank[2] & 0x3f) == 0x3f);
297  }
298 }
299 
300 byte Carnivore2::readMultiMapperSlot(word address, EmuTime::param time)
301 {
302  if (isConfigReg(address)) {
303  return readConfigRegister(address, time);
304  }
305 
306  auto [addr, mult] = decodeMultiMapper(address);
307  if (addr == unsigned(-1)) return 0xff; // unmapped
308 
309  if (mult & 0x20) {
310  return ram[addr & 0x1fffff]; // 2MB
311  } else {
312  return flash.read(addr);
313  }
314  // note: no reads from scc
315 }
316 
317 byte Carnivore2::peekMultiMapperSlot(word address, EmuTime::param time) const
318 {
319  if (isConfigReg(address)) {
320  return peekConfigRegister(address, time);
321  }
322 
323  auto [addr, mult] = decodeMultiMapper(address);
324  if (addr == unsigned(-1)) return 0xff; // unmapped
325 
326  if (mult & 0x20) {
327  return ram[addr & 0x1fffff]; // 2MB
328  } else {
329  return flash.peek(addr);
330  }
331 }
332 
333 void Carnivore2::writeMultiMapperSlot(word address, byte value, EmuTime::param time)
334 {
335  if (isConfigReg(address)) {
336  // this blocks writes to switch-region and bank-region
337  return writeConfigRegister(address, value, time);
338  }
339 
340  // check (all) 4 bank switch regions
341  for (auto i : xrange(4)) {
342  byte* base = configRegs + (i * 6) + 6; // points to R<i>Mask
343  byte mask = base[0];
344  byte addr = base[1];
345  byte mult = base[3];
346  if (mult & 0x80) { // enable bit in R<i>Mult
347  if (((address >> 8) & mask) == (addr & mask)) {
348  // update actual+shadow reg
349  configRegs[(i * 6) + 6 + 2] = value;
350  shadowConfigRegs[(i * 6) + 6 + 2] = value;
351  }
352  }
353  }
354 
355  auto [addr, mult] = decodeMultiMapper(address);
356  if ((addr != unsigned(-1)) && (mult & 0x10)) { // write enable
357  if (mult & 0x20) {
358  ram[addr & 0x1fffff] = value; // 2MB
359  } else {
360  flash.write(addr, value);
361  }
362  }
363 
364  if (sccEnabled() && ((address | 1) == 0xbfff)) {
365  // write scc mode register (write-only)
366  sccMode = value;
367  scc.setChipMode((sccMode & 0x20) ? SCC::SCC_plusmode : SCC::SCC_Compatible);
368  }
369  if (((sccMode & 0x10) == 0x00) && // note: no check for sccEnabled()
370  ((address & 0x1800) == 0x1000)) {
371  byte region = (address >> 13) - 2;
372  sccBank[region] = value;
373  } else if (sccAccess(address)) {
374  scc.writeMem(address & 0xff, value, time);
375  }
376 }
377 
378 byte Carnivore2::readIDESlot(word address, EmuTime::param time)
379 {
380  // TODO mirroring is different from SunriseIDE
381  if (ideRegsEnabled() && ((address & 0xfe00) == 0x7c00)) {
382  // 0x7c00-0x7dff IDE data register
383  switch (address & 1) {
384  case 0: { // data low
385  auto tmp = ideReadData(time);
386  ideRead = tmp >> 8;
387  return tmp & 0xff;
388  }
389  case 1: // data high
390  return ideRead;
391  }
392  }
393  if (ideRegsEnabled() && ((address & 0xff00) == 0x7e00)) {
394  // 0x7e00-0x7eff IDE registers
395  return ideReadReg(address & 0xf, time);
396  }
397  if ((0x4000 <= address) && (address < 0x8000)) {
398  // read IDE flash rom
399  unsigned addr = (address & 0x3fff) + (ideBank() * 0x4000) + 0x10000;
400  if (readBIOSfromRAM()) {
401  return ram[addr];
402  } else {
403  return flash.read(addr);
404  }
405  }
406  return 0xff;
407 }
408 
409 byte Carnivore2::peekIDESlot(word address, EmuTime::param /*time*/) const
410 {
411  if (ideRegsEnabled() && ((address & 0xfe00) == 0x7c00)) {
412  // 0x7c00-0x7dff IDE data register
413  return 0xff; // TODO not yet implemented
414  }
415  if (ideRegsEnabled() && ((address & 0xff00) == 0x7e00)) {
416  // 0x7e00-0x7eff IDE registers
417  return 0xff; // TODO not yet implemented
418  }
419  if ((0x4000 <= address) && (address < 0x8000)) {
420  // read IDE flash rom
421  unsigned addr = (address & 0x3fff) + (ideBank() * 0x4000) + 0x10000;
422  if (readBIOSfromRAM()) {
423  return ram[addr];
424  } else {
425  return flash.peek(addr);
426  }
427  }
428  return 0xff;
429 }
430 
431 void Carnivore2::writeIDESlot(word address, byte value, EmuTime::param time)
432 {
433  // TODO mirroring is different from SunriseIDE
434  if (address == 0x4104) {
435  ideControlReg = value;
436 
437  } else if (ideRegsEnabled() && ((address & 0xfe00) == 0x7c00)) {
438  // 0x7c00-0x7dff IDE data register
439  switch (address & 1) {
440  case 0: // data low
441  ideWrite = value;
442  break;
443  case 1: { // data high
444  word tmp = (value << 8) | ideWrite;
445  ideWriteData(tmp, time);
446  break;
447  }
448  }
449 
450  } else if (ideRegsEnabled() && ((address & 0xff00) == 0x7e00)) {
451  // 0x7e00-0x7eff IDE registers
452  ideWriteReg(address & 0xf, value, time);
453  }
454 }
455 
456 word Carnivore2::ideReadData(EmuTime::param time)
457 {
458  return ideDevices[ideSelectedDevice]->readData(time);
459 }
460 
461 void Carnivore2::ideWriteData(word value, EmuTime::param time)
462 {
463  ideDevices[ideSelectedDevice]->writeData(value, time);
464 }
465 
466 byte Carnivore2::ideReadReg(byte reg, EmuTime::param time)
467 {
468  if (reg == 14) reg = 7; // alternate status register
469 
470  if (ideSoftReset) {
471  if (reg == 7) { // read status
472  return 0xff; // busy
473  } else { // all others
474  return 0x7f; // don't care
475  }
476  } else {
477  if (reg == 0) {
478  return ideReadData(time) & 0xff;
479  } else {
480  auto result = ideDevices[ideSelectedDevice]->readReg(reg, time);
481  if (reg == 6) {
482  result = (result & 0xef) | (ideSelectedDevice ? 0x10 : 0x00);
483  }
484  return result;
485  }
486  }
487 }
488 
489 void Carnivore2::ideWriteReg(byte reg, byte value, EmuTime::param time)
490 {
491  if (ideSoftReset) {
492  if ((reg == 14) && !(value & 0x04)) {
493  // clear SRST
494  ideSoftReset = false;
495  }
496  // ignore all other writes
497  } else {
498  if (reg == 0) {
499  ideWriteData((value << 8) | value, time);
500  } else {
501  if ((reg == 14) && (value & 0x04)) {
502  // set SRST
503  ideSoftReset = true;
504  ideDevices[0]->reset(time);
505  ideDevices[1]->reset(time);
506  } else {
507  if (reg == 6) {
508  ideSelectedDevice = (value & 0x10) ? 1 : 0;
509  }
510  ideDevices[ideSelectedDevice]->writeReg(reg, value, time);
511  }
512  }
513  }
514 }
515 
516 bool Carnivore2::isMemmapControl(word address) const
517 {
518  return (port3C & 0x80) &&
519  (( (port3C & 0x08) && ((address & 0xc000) == 0x4000)) ||
520  (!(port3C & 0x08) && ((address & 0xc000) == 0x8000)));
521 }
522 
523 unsigned Carnivore2::getMemoryMapperAddress(word address) const
524 {
525  return (address & 0x3fff) +
526  0x4000 * memMapRegs[address >> 14] +
527  0x100000; // 2nd half of 2MB
528 }
529 
530 bool Carnivore2::isMemoryMapperWriteProtected(word address) const
531 {
532  byte page = address >> 14;
533  return (port3C & (1 << page)) != 0;
534 }
535 
536 byte Carnivore2::peekMemoryMapperSlot(word address) const
537 {
538  if (isMemmapControl(address)) {
539  switch (address & 0xff) {
540  case 0x3c:
541  return port3C;
542  case 0xfc: case 0xfd: case 0xfe: case 0xff:
543  return memMapRegs[address & 0x03];
544  }
545  }
546  return ram[getMemoryMapperAddress(address)];
547 }
548 
549 byte Carnivore2::readMemoryMapperSlot(word address)
550 {
551  return peekMemoryMapperSlot(address);
552 }
553 
554 void Carnivore2::writeMemoryMapperSlot(word address, byte value)
555 {
556  if (isMemmapControl(address)) {
557  switch (address & 0xff) {
558  case 0x3c:
559  value |= (value & 0x02) << 6; // TODO should be '(.. 0x20) << 2' ???
560  port3C = value;
561  return;
562  case 0xfc: case 0xfd: case 0xfe: case 0xff:
563  memMapRegs[address & 0x03] = value & 0x3f;
564  return;
565  }
566  }
567  if (!isMemoryMapperWriteProtected(address)) {
568  ram[getMemoryMapperAddress(address)] = value;
569  }
570 }
571 
572 byte Carnivore2::readFmPacSlot(word address)
573 {
574  if (address == 0x7ff6) {
575  return fmPacEnable; // enable
576  } else if (address == 0x7ff7) {
577  return fmPacBank; // bank
578  } else if ((0x4000 <= address) && (address < 0x8000)) {
579  if (fmPacSramEnabled()) {
580  if (address < 0x5ffe) {
581  return ram[(address & 0x1fff) | 0xfe000];
582  } else if (address == 0x5ffe) {
583  return fmPac5ffe; // always 0x4d
584  } else if (address == 0x5fff) {
585  return fmPac5fff; // always 0x69
586  } else {
587  return 0xff;
588  }
589  } else {
590  unsigned addr = (address & 0x3fff) + (0x4000 * fmPacBank) + 0x30000;
591  if (readBIOSfromRAM()) {
592  return ram[addr];
593  } else {
594  return flash.read(addr);
595  }
596  }
597  }
598  return 0xff;
599 }
600 
601 byte Carnivore2::peekFmPacSlot(word address) const
602 {
603  if (address == 0x7ff6) {
604  return fmPacEnable; // enable
605  } else if (address == 0x7ff7) {
606  return fmPacBank; // bank
607  } else if ((0x4000 <= address) && (address < 0x8000)) {
608  if (fmPacSramEnabled()) {
609  if (address < 0x5ffe) {
610  return ram[(address & 0x1fff) | 0xfe000];
611  } else if (address == 0x5ffe) {
612  return fmPac5ffe; // always 0x4d
613  } else if (address == 0x5fff) {
614  return fmPac5fff; // always 0x69
615  } else {
616  return 0xff;
617  }
618  } else {
619  unsigned addr = (address & 0x3fff) + (0x4000 * fmPacBank) + 0x30000;
620  if (readBIOSfromRAM()) {
621  return ram[addr];
622  } else {
623  return flash.peek(addr);
624  }
625  }
626  }
627  return 0xff;
628 }
629 
630 void Carnivore2::writeFmPacSlot(word address, byte value, EmuTime::param time)
631 {
632  if ((0x4000 <= address) && (address < 0x5ffe)) {
633  if (fmPacSramEnabled()) {
634  ram[(address & 0x1fff) | 0xfe000] = value;
635  }
636  } else if (address == 0x5ffe) {
637  fmPac5ffe = value;
638  } else if (address == 0x5fff) {
639  fmPac5fff = value;
640  } else if (address == one_of(0x7ff4, 0x7ff5)) {
641  ym2413.writePort(address & 1, value, time);
642  } else if (address == 0x7ff6) {
643  fmPacEnable = value & 0x11;
644  } else if (address == 0x7ff7) {
645  fmPacBank = value & 0x03;
646  }
647 }
648 
649 byte Carnivore2::readIO(word port, EmuTime::param time)
650 {
651  return peekIO(port, time);
652 }
653 
654 byte Carnivore2::peekIO(word port, EmuTime::param /*time*/) const
655 {
656  // reading ports 0x3c, 0x7c, 0x7d has no effect
657  if (memMapReadEnabled() && ((port & 0xfc) == 0xfc)) {
658  // memory mapper registers
659  return getSelectedSegment(port & 3);
660  }
661  return 0xff;
662 }
663 
664 void Carnivore2::writeIO(word port, byte value, EmuTime::param time)
665 {
666  if (((port & 0xfe) == 0x7c) &&
667  (fmPacPortEnabled1() || fmPacPortEnabled2())) {
668  // fm-pac registers
669  ym2413.writePort(port & 1, value, time);
670  } else if (((port & 0xff) == 0x3c) && writePort3cEnabled()) {
671  // only change bit 7
672  port3C = (port3C & 0x7F) | (value & 0x80);
673 
674  } else if ((port & 0xfc) == 0xfc) {
675  // memory mapper registers
676  memMapRegs[port & 0x03] = value & 0x3f;
677  invalidateDeviceRWCache(0x4000 * (port & 0x03), 0x4000);
678  }
679 }
680 
681 byte Carnivore2::getSelectedSegment(byte page) const
682 {
683  return memMapRegs[page];
684 }
685 
686 // version 1: initial version
687 // version 2: removed fmPacRegSelect
688 template<typename Archive>
689 void Carnivore2::serialize(Archive& ar, unsigned /*version*/)
690 {
691  ar.template serializeBase<MSXDevice>(*this);
692  ar.serialize("flash", flash,
693  "ram", ram,
694  "eeprom", eeprom,
695  "configRegs", configRegs,
696  "shadowConfigRegs", shadowConfigRegs,
697  "subSlotReg", subSlotReg,
698  "port3C", port3C,
699 
700  "scc", scc,
701  "sccMode", sccMode,
702  "sccBank", sccBank);
703 
704  ar.serializePolymorphic("master", *ideDevices[0]);
705  ar.serializePolymorphic("slave", *ideDevices[1]);
706  ar.serialize("ideSoftReset", ideSoftReset,
707  "ideSelectedDevice", ideSelectedDevice,
708  "ideControlReg", ideControlReg,
709  "ideRead", ideRead,
710  "ideWrite", ideWrite,
711 
712  "memMapRegs", memMapRegs,
713 
714  "ym2413", ym2413,
715  "fmPacEnable", fmPacEnable,
716  "fmPacBank", fmPacBank,
717  "fmPac5ffe", fmPac5ffe,
718  "fmPac5fff", fmPac5fff);
719 
720  if (ar.isLoader()) {
721  auto time = getCurrentTime();
722  writeSndLVL (configRegs[0x22], time);
723  writeCfgEEPR(configRegs[0x23], time);
724  }
725 }
728 
729 } // namespace openmsx
Definition: one_of.hh:7
void write(unsigned address, byte value)
Definition: AmdFlash.cc:268
byte peek(unsigned address) const
Definition: AmdFlash.cc:215
byte read(unsigned address) const
Definition: AmdFlash.cc:251
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
Definition: Carnivore2.cc:654
void reset(EmuTime::param time) override
This method is called on reset.
Definition: Carnivore2.cc:48
void writeMem(word address, byte value, EmuTime::param time) override
Write a given byte to a given location at a certain time to this device.
Definition: Carnivore2.cc:152
void serialize(Archive &ar, unsigned version)
Definition: Carnivore2.cc:689
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
Definition: Carnivore2.cc:649
void globalRead(word address, EmuTime::param time) override
Global reads.
Definition: Carnivore2.cc:97
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition: Carnivore2.cc:41
~Carnivore2() override
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: Carnivore2.cc:124
Carnivore2(const DeviceConfig &config)
Definition: Carnivore2.cc:22
void writeIO(word port, byte value, EmuTime::param time) override
Write a byte to a given IO port at a certain time to this device.
Definition: Carnivore2.cc:664
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: Carnivore2.cc:138
byte getSelectedSegment(byte page) const override
Definition: Carnivore2.cc:681
const XMLElement * findChild(std::string_view name) const
Definition: DeviceConfig.cc:61
void write_CS(bool value, EmuTime::param time)
Definition: EEPROM_93C46.cc:76
void write_CLK(bool value, EmuTime::param time)
Definition: EEPROM_93C46.cc:91
bool read_DO(EmuTime::param time) const
Definition: EEPROM_93C46.cc:65
void write_DI(bool value, EmuTime::param time)
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:32
MSXCPU & getCPU() const
Definition: MSXDevice.cc:136
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
Definition: MSXDevice.hh:208
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:132
void writeMem(byte address, byte value, EmuTime::param time)
Definition: SCC.cc:287
void setChipMode(ChipMode newMode)
Definition: SCC.cc:185
void powerUp(EmuTime::param time)
Definition: SCC.cc:143
@ SCC_plusmode
Definition: SCC.hh:14
@ SCC_Compatible
Definition: SCC.hh:14
void reset(EmuTime::param time)
Definition: SCC.cc:175
void setSoftwareVolume(float volume, EmuTime::param time)
Change the 'software volume' of this sound device.
Definition: SoundDevice.cc:146
void writePort(bool port, byte value, EmuTime::param time)
Definition: YM2413.cc:85
void reset(EmuTime::param time)
Definition: YM2413.cc:79
constexpr void fill(ForwardIt first, ForwardIt last, const T &value)
Definition: cstd.hh:111
std::unique_ptr< IDEDevice > create(const DeviceConfig &config)
string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:742
This file implemented 3 utility functions:
Definition: Autofire.cc:5
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
AmdFlash::SectorInfo Info
Definition: RomManbow2.cc:17
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
constexpr nibble mask[4][13]
Definition: RP5C01.cc:34
constexpr void iota(ForwardIt first, ForwardIt last, T value)
Definition: ranges.hh:204
size_t size(std::string_view utf8)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:983
constexpr auto xrange(T e)
Definition: xrange.hh:155