openMSX
MSXCPUInterface.cc
Go to the documentation of this file.
1 #include "MSXCPUInterface.hh"
2 #include "DummyDevice.hh"
3 #include "CommandException.hh"
4 #include "TclObject.hh"
5 #include "Interpreter.hh"
6 #include "Reactor.hh"
7 #include "RealTime.hh"
8 #include "MSXMotherBoard.hh"
9 #include "MSXCPU.hh"
10 #include "VDPIODelay.hh"
11 #include "CliComm.hh"
12 #include "MSXMultiIODevice.hh"
13 #include "MSXMultiMemDevice.hh"
14 #include "MSXWatchIODevice.hh"
15 #include "MSXException.hh"
16 #include "CartridgeSlotManager.hh"
17 #include "EventDistributor.hh"
18 #include "Event.hh"
19 #include "HardwareConfig.hh"
20 #include "DeviceFactory.hh"
21 #include "ReadOnlySetting.hh"
22 #include "serialize.hh"
23 #include "checked_cast.hh"
24 #include "outer.hh"
25 #include "ranges.hh"
26 #include "stl.hh"
27 #include "unreachable.hh"
28 #include "xrange.hh"
29 #include <cstring>
30 #include <iomanip>
31 #include <iostream>
32 #include <iterator>
33 #include <memory>
34 
35 using std::string;
36 using std::vector;
37 using std::min;
38 using std::shared_ptr;
39 
40 namespace openmsx {
41 
42 static std::unique_ptr<ReadOnlySetting> breakedSetting;
43 static unsigned breakedSettingCount = 0;
44 
45 
46 // Bitfields used in the disallowReadCache and disallowWriteCache arrays
47 constexpr byte SECONDARY_SLOT_BIT = 0x01;
48 constexpr byte MEMORY_WATCH_BIT = 0x02;
49 constexpr byte GLOBAL_RW_BIT = 0x04;
50 
51 std::ostream& operator<<(std::ostream& os, EnumTypeName<CacheLineCounters>)
52 {
53  return os << "CacheLineCounters";
54 }
55 std::ostream& operator<<(std::ostream& os, EnumValueName<CacheLineCounters> evn)
56 {
57  std::string_view names[size_t(CacheLineCounters::NUM)] = {
58  "NonCachedRead",
59  "NonCachedWrite",
60  "GetReadCacheLine",
61  "GetWriteCacheLine",
62  "SlowRead",
63  "SlowWrite",
64  "DisallowCacheRead",
65  "DisallowCacheWrite",
66  "InvalidateAllSlots",
67  "InvalidateReadWrite",
68  "InvalidateRead",
69  "InvalidateWrite",
70  "FillReadWrite",
71  "FillRead",
72  "FillWrite",
73  };
74  return os << names[size_t(evn.e)];
75 }
76 
78  : memoryDebug (motherBoard_)
79  , slottedMemoryDebug(motherBoard_)
80  , ioDebug (motherBoard_)
81  , slotInfo(motherBoard_.getMachineInfoCommand())
82  , subSlottedInfo(motherBoard_.getMachineInfoCommand())
83  , externalSlotInfo(motherBoard_.getMachineInfoCommand())
84  , inputPortInfo (motherBoard_.getMachineInfoCommand())
85  , outputPortInfo(motherBoard_.getMachineInfoCommand())
86  , dummyDevice(DeviceFactory::createDummyDevice(
87  *motherBoard_.getMachineConfig()))
88  , msxcpu(motherBoard_.getCPU())
89  , cliComm(motherBoard_.getMSXCliComm())
90  , motherBoard(motherBoard_)
91  , fastForward(false)
92 {
93  ranges::fill(primarySlotState, 0);
94  ranges::fill(secondarySlotState, 0);
95  ranges::fill(expanded, 0);
96  ranges::fill(subSlotRegister, 0);
97  ranges::fill(IO_In, dummyDevice.get());
98  ranges::fill(IO_Out, dummyDevice.get());
99  ranges::fill(visibleDevices, dummyDevice.get());
100  for (auto& sub1 : slotLayout) {
101  for (auto& sub2 : sub1) {
102  ranges::fill(sub2, dummyDevice.get());
103  }
104  }
105 
106  // initially allow all regions to be cached
107  memset(disallowReadCache, 0, sizeof(disallowReadCache));
108  memset(disallowWriteCache, 0, sizeof(disallowWriteCache));
109 
110  initialPrimarySlots = motherBoard.getMachineConfig()->parseSlotMap();
111  // Note: SlotState is initialised at reset
112 
113  msxcpu.setInterface(this);
114 
115  if (motherBoard.isTurboR()) {
116  // TODO also MSX2+ needs (slightly different) VDPIODelay
117  delayDevice = DeviceFactory::createVDPIODelay(
118  *motherBoard.getMachineConfig(), *this);
119  for (auto port : xrange(0x98, 0x9c)) {
120  assert(IO_In [port] == dummyDevice.get());
121  assert(IO_Out[port] == dummyDevice.get());
122  IO_In [port] = delayDevice.get();
123  IO_Out[port] = delayDevice.get();
124  }
125  }
126 
127  if (breakedSettingCount++ == 0) {
128  assert(!breakedSetting);
129  breakedSetting = std::make_unique<ReadOnlySetting>(
130  motherBoard.getReactor().getCommandController(),
131  "breaked", "Similar to 'debug breaked'",
132  TclObject("false"));
133  }
134  reset();
135 }
136 
138 {
139  if (--breakedSettingCount == 0) {
140  assert(breakedSetting);
141  breakedSetting = nullptr;
142  }
143 
144  removeAllWatchPoints();
145 
146  if (delayDevice) {
147  for (auto port : xrange(0x98, 0x9c)) {
148  assert(IO_In [port] == delayDevice.get());
149  assert(IO_Out[port] == delayDevice.get());
150  IO_In [port] = dummyDevice.get();
151  IO_Out[port] = dummyDevice.get();
152  }
153  }
154 
155  msxcpu.setInterface(nullptr);
156 
157  #ifndef NDEBUG
158  for (auto port : xrange(256)) {
159  if (IO_In[port] != dummyDevice.get()) {
160  std::cout << "In-port " << port << " still registered "
161  << IO_In[port]->getName() << '\n';
162  UNREACHABLE;
163  }
164  if (IO_Out[port] != dummyDevice.get()) {
165  std::cout << "Out-port " << port << " still registered "
166  << IO_Out[port]->getName() << '\n';
167  UNREACHABLE;
168  }
169  }
170  for (auto primSlot : xrange(4)) {
171  assert(!isExpanded(primSlot));
172  for (auto secSlot : xrange(4)) {
173  for (auto page : xrange(4)) {
174  assert(slotLayout[primSlot][secSlot][page] == dummyDevice.get());
175  }
176  }
177  }
178  #endif
179 }
180 
181 void MSXCPUInterface::removeAllWatchPoints()
182 {
183  while (!watchPoints.empty()) {
184  removeWatchPoint(watchPoints.back());
185  }
186 
187 }
188 
189 byte MSXCPUInterface::readMemSlow(word address, EmuTime::param time)
190 {
192  // something special in this region?
193  if (unlikely(disallowReadCache[address >> CacheLine::BITS])) {
194  // slot-select-ignore reads (e.g. used in 'Carnivore2')
195  for (auto& g : globalReads) {
196  // very primitive address selection mechanism,
197  // but more than enough for now
198  if (unlikely(g.addr == address)) {
199  g.device->globalRead(address, time);
200  }
201  }
202  // execute read watches before actual read
203  if (readWatchSet[address >> CacheLine::BITS]
204  [address & CacheLine::LOW]) {
205  executeMemWatch(WatchPoint::READ_MEM, address);
206  }
207  }
208  if (unlikely((address == 0xFFFF) && isExpanded(primarySlotState[3]))) {
209  return 0xFF ^ subSlotRegister[primarySlotState[3]];
210  } else {
211  return visibleDevices[address >> 14]->readMem(address, time);
212  }
213 }
214 
215 void MSXCPUInterface::writeMemSlow(word address, byte value, EmuTime::param time)
216 {
218  if (unlikely((address == 0xFFFF) && isExpanded(primarySlotState[3]))) {
219  setSubSlot(primarySlotState[3], value);
220  // Confirmed on turboR GT machine: write does _not_ also go to
221  // the underlying (hidden) device. But it's theoretically
222  // possible other slotexpanders behave different.
223  } else {
224  visibleDevices[address>>14]->writeMem(address, value, time);
225  }
226  // something special in this region?
227  if (unlikely(disallowWriteCache[address >> CacheLine::BITS])) {
228  // slot-select-ignore writes (Super Lode Runner)
229  for (auto& g : globalWrites) {
230  // very primitive address selection mechanism,
231  // but more than enough for now
232  if (unlikely(g.addr == address)) {
233  g.device->globalWrite(address, value, time);
234  }
235  }
236  // execute write watches after actual write
237  if (writeWatchSet[address >> CacheLine::BITS]
238  [address & CacheLine::LOW]) {
239  executeMemWatch(WatchPoint::WRITE_MEM, address, value);
240  }
241  }
242 }
243 
245 {
246  if (expanded[ps] == 0) {
247  for (auto page : xrange(4)) {
248  if (slotLayout[ps][0][page] != dummyDevice.get()) {
249  throw MSXException("Can't expand slot because "
250  "it's already in use.");
251  }
252  }
253  }
254  expanded[ps]++;
255  changeExpanded(isExpanded(primarySlotState[3]));
256 }
257 
259  int ps, vector<MSXDevice*> allowed) const
260 {
261  // TODO handle multi-devices
262  allowed.push_back(dummyDevice.get());
263  ranges::sort(allowed); // for set_difference()
264  assert(isExpanded(ps));
265  if (expanded[ps] != 1) return; // ok, still expanded after this
266 
267  std::vector<MSXDevice*> inUse;
268  for (auto ss : xrange(4)) {
269  for (auto page : xrange(4)) {
270  MSXDevice* device = slotLayout[ps][ss][page];
271  std::vector<MSXDevice*> devices;
272  std::vector<MSXDevice*>::iterator end_devices;
273  if (auto* memDev = dynamic_cast<MSXMultiMemDevice*>(device)) {
274  devices = memDev->getDevices();
275  ranges::sort(devices); // for set_difference()
276  end_devices = ranges::unique(devices);
277  } else {
278  devices.push_back(device);
279  end_devices = end(devices);
280  }
281  std::set_difference(begin(devices), end_devices,
282  begin(allowed), end(allowed),
283  std::inserter(inUse, end(inUse)));
284 
285  }
286  }
287  if (inUse.empty()) return; // ok, no more devices in use
288 
289  string msg = strCat("Can't remove slot expander from slot ", ps,
290  " because the following devices are still inserted:");
291  for (auto& d : inUse) {
292  strAppend(msg, ' ', d->getName());
293  }
294  strAppend(msg, '.');
295  throw MSXException(std::move(msg));
296 }
297 
299 {
300 #ifndef NDEBUG
301  try {
302  vector<MSXDevice*> dummy;
303  testUnsetExpanded(ps, dummy);
304  } catch (...) {
305  UNREACHABLE;
306  }
307 #endif
308  expanded[ps]--;
309  changeExpanded(isExpanded(primarySlotState[3]));
310 }
311 
312 void MSXCPUInterface::changeExpanded(bool newExpanded)
313 {
314  if (newExpanded) {
315  disallowReadCache [0xFF] |= SECONDARY_SLOT_BIT;
316  disallowWriteCache[0xFF] |= SECONDARY_SLOT_BIT;
317  } else {
318  disallowReadCache [0xFF] &= ~SECONDARY_SLOT_BIT;
319  disallowWriteCache[0xFF] &= ~SECONDARY_SLOT_BIT;
320  }
321  msxcpu.invalidateAllSlotsRWCache(0xFFFF & CacheLine::HIGH, 0x100);
322 }
323 
324 MSXDevice*& MSXCPUInterface::getDevicePtr(byte port, bool isIn)
325 {
326  MSXDevice** devicePtr = isIn ? &IO_In[port] : &IO_Out[port];
327  while (auto* watch = dynamic_cast<MSXWatchIODevice*>(*devicePtr)) {
328  devicePtr = &watch->getDevicePtr();
329  }
330  if (*devicePtr == delayDevice.get()) {
331  devicePtr = isIn ? &delayDevice->getInDevicePtr (port)
332  : &delayDevice->getOutDevicePtr(port);
333  }
334  return *devicePtr;
335 }
336 
338 {
339  MSXDevice*& devicePtr = getDevicePtr(port, true); // in
340  register_IO(port, true, devicePtr, device); // in
341 }
342 
344 {
345  MSXDevice*& devicePtr = getDevicePtr(port, true); // in
346  unregister_IO(devicePtr, device);
347 }
348 
350 {
351  MSXDevice*& devicePtr = getDevicePtr(port, false); // out
352  register_IO(port, false, devicePtr, device); // out
353 }
354 
356 {
357  MSXDevice*& devicePtr = getDevicePtr(port, false); // out
358  unregister_IO(devicePtr, device);
359 }
360 
361 void MSXCPUInterface::register_IO(int port, bool isIn,
362  MSXDevice*& devicePtr, MSXDevice* device)
363 {
364  if (devicePtr == dummyDevice.get()) {
365  // first, replace DummyDevice
366  devicePtr = device;
367  } else {
368  if (auto* multi = dynamic_cast<MSXMultiIODevice*>(devicePtr)) {
369  // third or more, add to existing MultiIO device
370  multi->addDevice(device);
371  } else {
372  // second, create a MultiIO device
373  multi = new MSXMultiIODevice(device->getHardwareConfig());
374  multi->addDevice(devicePtr);
375  multi->addDevice(device);
376  devicePtr = multi;
377  }
378  if (isIn) {
379  cliComm.printWarning(
380  "Conflicting input port 0x",
381  hex_string<2>(port),
382  " for devices ", devicePtr->getName());
383  }
384  }
385 }
386 
387 void MSXCPUInterface::unregister_IO(MSXDevice*& devicePtr, MSXDevice* device)
388 {
389  if (auto* multi = dynamic_cast<MSXMultiIODevice*>(devicePtr)) {
390  // remove from MultiIO device
391  multi->removeDevice(device);
392  auto& devices = multi->getDevices();
393  if (devices.size() == 1) {
394  // only one remaining, remove MultiIO device
395  devicePtr = devices.front();
396  devices.pop_back();
397  delete multi;
398  }
399  } else {
400  // remove last, put back DummyDevice
401  assert(devicePtr == device);
402  devicePtr = dummyDevice.get();
403  }
404 }
405 
407  byte port, MSXDevice* oldDevice, MSXDevice* newDevice)
408 {
409  MSXDevice*& devicePtr = getDevicePtr(port, true); // in
410  if (devicePtr != oldDevice) {
411  // error, this was not the expected device
412  return false;
413  }
414  devicePtr = newDevice;
415  return true;
416 }
418  byte port, MSXDevice* oldDevice, MSXDevice* newDevice)
419 {
420  MSXDevice*& devicePtr = getDevicePtr(port, false); // out
421  if (devicePtr != oldDevice) {
422  // error, this was not the expected device
423  return false;
424  }
425  devicePtr = newDevice;
426  return true;
427 }
428 
429 static void reportMemOverlap(int ps, int ss, MSXDevice& dev1, MSXDevice& dev2)
430 {
431  throw MSXException(
432  "Overlapping memory devices in slot ", ps, '.', ss,
433  ": ", dev1.getName(), " and ", dev2.getName(), '.');
434 }
435 
436 void MSXCPUInterface::testRegisterSlot(
437  MSXDevice& device, int ps, int ss, int base, int size)
438 {
439  int page = base >> 14;
440  MSXDevice*& slot = slotLayout[ps][ss][page];
441  if (size == 0x4000) {
442  // full 16kb, directly register device (no multiplexer)
443  if (slot != dummyDevice.get()) {
444  reportMemOverlap(ps, ss, *slot, device);
445  }
446  } else {
447  // partial page
448  if (slot == dummyDevice.get()) {
449  // first, ok
450  } else if (auto* multi = dynamic_cast<MSXMultiMemDevice*>(slot)) {
451  // second (or more), check for overlap
452  if (!multi->canAdd(base, size)) {
453  reportMemOverlap(ps, ss, *slot, device);
454  }
455  } else {
456  // conflict with 'full ranged' device
457  reportMemOverlap(ps, ss, *slot, device);
458  }
459  }
460 }
461 
462 void MSXCPUInterface::registerSlot(
463  MSXDevice& device, int ps, int ss, int base, int size)
464 {
465  int page = base >> 14;
466  MSXDevice*& slot = slotLayout[ps][ss][page];
467  if (size == 0x4000) {
468  // full 16kb, directly register device (no multiplexer)
469  assert(slot == dummyDevice.get());
470  slot = &device;
471  } else {
472  // partial page
473  if (slot == dummyDevice.get()) {
474  // first
475  auto* multi = new MSXMultiMemDevice(device.getHardwareConfig());
476  multi->add(device, base, size);
477  slot = multi;
478  } else if (auto* multi = dynamic_cast<MSXMultiMemDevice*>(slot)) {
479  // second or more
480  assert(multi->canAdd(base, size));
481  multi->add(device, base, size);
482  } else {
483  // conflict with 'full ranged' device
484  assert(false);
485  }
486  }
487  invalidateRWCache(base, size, ps, ss);
488  updateVisible(page);
489 }
490 
491 void MSXCPUInterface::unregisterSlot(
492  MSXDevice& device, int ps, int ss, int base, int size)
493 {
494  int page = base >> 14;
495  MSXDevice*& slot = slotLayout[ps][ss][page];
496  if (auto* multi = dynamic_cast<MSXMultiMemDevice*>(slot)) {
497  // partial range
498  multi->remove(device, base, size);
499  if (multi->empty()) {
500  delete multi;
501  slot = dummyDevice.get();
502  }
503  } else {
504  // full 16kb range
505  assert(slot == &device);
506  slot = dummyDevice.get();
507  }
508  invalidateRWCache(base, size, ps, ss);
509  updateVisible(page);
510 }
511 
513  MSXDevice& device, int ps, int ss, int base_, int size_)
514 {
515  if (!isExpanded(ps) && (ss != 0)) {
516  throw MSXException(
517  "Slot ", ps, '.', ss,
518  " does not exist because slot is not expanded.");
519  }
520 
521  // split range on 16kb borders
522  // first check if registration is possible
523  int base = base_;
524  int size = size_;
525  while (size > 0) {
526  int partialSize = min(size, ((base + 0x4000) & ~0x3FFF) - base);
527  testRegisterSlot(device, ps, ss, base, partialSize);
528  base += partialSize;
529  size -= partialSize;
530  }
531  // if all checks are successful, only then actually register
532  base = base_;
533  size = size_;
534  while (size > 0) {
535  int partialSize = min(size, ((base + 0x4000) & ~0x3FFF) - base);
536  registerSlot(device, ps, ss, base, partialSize);
537  base += partialSize;
538  size -= partialSize;
539  }
540 }
541 
543  MSXDevice& device, int ps, int ss, int base, int size)
544 {
545  // split range on 16kb borders
546  while (size > 0) {
547  int partialSize = min(size, ((base + 0x4000) & ~0x3FFF) - base);
548  unregisterSlot(device, ps, ss, base, partialSize);
549  base += partialSize;
550  size -= partialSize;
551  }
552 }
553 
555 {
556  globalWrites.push_back({&device, address});
557 
558  disallowWriteCache[address >> CacheLine::BITS] |= GLOBAL_RW_BIT;
559  msxcpu.invalidateAllSlotsRWCache(address & CacheLine::HIGH, 0x100);
560 }
561 
563 {
564  GlobalRwInfo info = { &device, address };
565  move_pop_back(globalWrites, rfind_unguarded(globalWrites, info));
566 
567  for (auto& g : globalWrites) {
568  if ((g.addr >> CacheLine::BITS) ==
569  (address >> CacheLine::BITS)) {
570  // there is still a global write in this region
571  return;
572  }
573  }
574  disallowWriteCache[address >> CacheLine::BITS] &= ~GLOBAL_RW_BIT;
575  msxcpu.invalidateAllSlotsRWCache(address & CacheLine::HIGH, 0x100);
576 }
577 
579 {
580  globalReads.push_back({&device, address});
581 
582  disallowReadCache[address >> CacheLine::BITS] |= GLOBAL_RW_BIT;
583  msxcpu.invalidateAllSlotsRWCache(address & CacheLine::HIGH, 0x100);
584 }
585 
587 {
588  GlobalRwInfo info = { &device, address };
589  move_pop_back(globalReads, rfind_unguarded(globalReads, info));
590 
591  for (auto& g : globalReads) {
592  if ((g.addr >> CacheLine::BITS) ==
593  (address >> CacheLine::BITS)) {
594  // there is still a global write in this region
595  return;
596  }
597  }
598  disallowReadCache[address >> CacheLine::BITS] &= ~GLOBAL_RW_BIT;
599  msxcpu.invalidateAllSlotsRWCache(address & CacheLine::HIGH, 0x100);
600 }
601 
602 ALWAYS_INLINE void MSXCPUInterface::updateVisible(int page, int ps, int ss)
603 {
604  MSXDevice* newDevice = slotLayout[ps][ss][page];
605  if (visibleDevices[page] != newDevice) {
606  visibleDevices[page] = newDevice;
607  msxcpu.updateVisiblePage(page, ps, ss);
608  }
609 }
610 void MSXCPUInterface::updateVisible(int page)
611 {
612  updateVisible(page, primarySlotState[page], secondarySlotState[page]);
613 }
614 
615 void MSXCPUInterface::invalidateRWCache(word start, unsigned size, int ps, int ss)
616 {
618  msxcpu.invalidateRWCache(start, size, ps, ss, disallowReadCache, disallowWriteCache);
619 }
620 void MSXCPUInterface::invalidateRCache (word start, unsigned size, int ps, int ss)
621 {
623  msxcpu.invalidateRCache(start, size, ps, ss, disallowReadCache);
624 }
625 void MSXCPUInterface::invalidateWCache (word start, unsigned size, int ps, int ss)
626 {
628  msxcpu.invalidateWCache(start, size, ps, ss, disallowWriteCache);
629 }
630 
631 void MSXCPUInterface::fillRWCache(unsigned start, unsigned size, const byte* rData, byte* wData, int ps, int ss)
632 {
634  msxcpu.fillRWCache(start, size, rData, wData, ps, ss, disallowReadCache, disallowWriteCache);
635 }
636 void MSXCPUInterface::fillRCache(unsigned start, unsigned size, const byte* rData, int ps, int ss)
637 {
639  msxcpu.fillRCache(start, size, rData, ps, ss, disallowReadCache);
640 }
641 void MSXCPUInterface::fillWCache(unsigned start, unsigned size, byte* wData, int ps, int ss)
642 {
644  msxcpu.fillWCache(start, size, wData, ps, ss, disallowWriteCache);
645 }
646 
648 {
649  for (auto i : xrange(4)) {
650  setSubSlot(i, 0);
651  }
652  setPrimarySlots(initialPrimarySlots);
653 }
654 
656 {
657  return motherBoard.readIRQVector();
658 }
659 
661 {
662  // Change the slot structure.
663  // Originally the code below was a loop over the 4 pages, and the check
664  // for (un)expanded-slot was done unconditionally at the end. I've
665  // completely unrolled the loop and only check for (un)expanded slot
666  // when the slot in page 3 has changed. I've also added checks for slot
667  // changes for the other 3 pages. Usually when this register is written
668  // only one of the 4 pages actually changes, so these extra checks do
669  // pay off. This does make the code a bit more complex (and the
670  // generated code slightly bigger), but it does make a measurable speed
671  // difference. Changing the slots several hundreds of times per
672  // (EmuTime) is not unusual. So this routine ended up quite high
673  // (top-10) in some profile results.
674  int ps0 = (value >> 0) & 3;
675  if (unlikely(primarySlotState[0] != ps0)) {
676  primarySlotState[0] = ps0;
677  int ss0 = (subSlotRegister[ps0] >> 0) & 3;
678  secondarySlotState[0] = ss0;
679  updateVisible(0, ps0, ss0);
680  }
681  int ps1 = (value >> 2) & 3;
682  if (unlikely(primarySlotState[1] != ps1)) {
683  primarySlotState[1] = ps1;
684  int ss1 = (subSlotRegister[ps1] >> 2) & 3;
685  secondarySlotState[1] = ss1;
686  updateVisible(1, ps1, ss1);
687  }
688  int ps2 = (value >> 4) & 3;
689  if (unlikely(primarySlotState[2] != ps2)) {
690  primarySlotState[2] = ps2;
691  int ss2 = (subSlotRegister[ps2] >> 4) & 3;
692  secondarySlotState[2] = ss2;
693  updateVisible(2, ps2, ss2);
694  }
695  int ps3 = (value >> 6) & 3;
696  if (unlikely(primarySlotState[3] != ps3)) {
697  bool oldExpanded = isExpanded(primarySlotState[3]);
698  bool newExpanded = isExpanded(ps3);
699  primarySlotState[3] = ps3;
700  int ss3 = (subSlotRegister[ps3] >> 6) & 3;
701  secondarySlotState[3] = ss3;
702  updateVisible(3, ps3, ss3);
703  if (unlikely(oldExpanded != newExpanded)) {
704  changeExpanded(newExpanded);
705  }
706  }
707 }
708 
709 void MSXCPUInterface::setSubSlot(byte primSlot, byte value)
710 {
711  subSlotRegister[primSlot] = value;
712  for (int page = 0; page < 4; ++page, value >>= 2) {
713  if (primSlot == primarySlotState[page]) {
714  secondarySlotState[page] = value & 3;
715  // Change the visible devices
716  updateVisible(page);
717  }
718  }
719 }
720 
721 byte MSXCPUInterface::peekMem(word address, EmuTime::param time) const
722 {
723  if ((address == 0xFFFF) && isExpanded(primarySlotState[3])) {
724  return 0xFF ^ subSlotRegister[primarySlotState[3]];
725  } else {
726  return visibleDevices[address >> 14]->peekMem(address, time);
727  }
728 }
729 
730 byte MSXCPUInterface::peekSlottedMem(unsigned address, EmuTime::param time) const
731 {
732  byte primSlot = (address & 0xC0000) >> 18;
733  byte subSlot = (address & 0x30000) >> 16;
734  byte page = (address & 0x0C000) >> 14;
735  word offset = (address & 0xFFFF); // includes page
736  if (!isExpanded(primSlot)) {
737  subSlot = 0;
738  }
739 
740  if ((offset == 0xFFFF) && isExpanded(primSlot)) {
741  return 0xFF ^ subSlotRegister[primSlot];
742  } else {
743  return slotLayout[primSlot][subSlot][page]->peekMem(offset, time);
744  }
745 }
746 
747 byte MSXCPUInterface::readSlottedMem(unsigned address, EmuTime::param time)
748 {
749  byte primSlot = (address & 0xC0000) >> 18;
750  byte subSlot = (address & 0x30000) >> 16;
751  byte page = (address & 0x0C000) >> 14;
752  word offset = (address & 0xFFFF); // includes page
753  if (!isExpanded(primSlot)) {
754  subSlot = 0;
755  }
756 
757  if ((offset == 0xFFFF) && isExpanded(primSlot)) {
758  return 0xFF ^ subSlotRegister[primSlot];
759  } else {
760  return slotLayout[primSlot][subSlot][page]->peekMem(offset, time);
761  }
762 }
763 
764 void MSXCPUInterface::writeSlottedMem(unsigned address, byte value,
765  EmuTime::param time)
766 {
767  byte primSlot = (address & 0xC0000) >> 18;
768  byte subSlot = (address & 0x30000) >> 16;
769  byte page = (address & 0x0C000) >> 14;
770  word offset = (address & 0xFFFF); // includes page
771  if (!isExpanded(primSlot)) {
772  subSlot = 0;
773  }
774 
775  if ((offset == 0xFFFF) && isExpanded(primSlot)) {
776  setSubSlot(primSlot, value);
777  } else {
778  slotLayout[primSlot][subSlot][page]->writeMem(offset, value, time);
779  }
780 }
781 
783 {
784  auto it = ranges::upper_bound(breakPoints, bp, CompareBreakpoints());
785  breakPoints.insert(it, std::move(bp));
786 }
787 
789 {
790  auto [first, last] = ranges::equal_range(breakPoints, bp.getAddress(), CompareBreakpoints());
791  breakPoints.erase(find_if_unguarded(first, last,
792  [&](const BreakPoint& i) { return &i == &bp; }));
793 }
794 void MSXCPUInterface::removeBreakPoint(unsigned id)
795 {
796  if (auto it = ranges::find_if(breakPoints,
797  [&](const BreakPoint& i) { return i.getId() == id; });
798  // could be ==end for a breakpoint that removes itself AND has the -once flag set
799  it != breakPoints.end()) {
800  breakPoints.erase(it);
801  }
802 }
803 
805  std::pair<BreakPoints::const_iterator,
806  BreakPoints::const_iterator> range,
807  MSXMotherBoard& motherBoard)
808 {
809  // create copy for the case that breakpoint/condition removes itself
810  // - keeps object alive by holding a shared_ptr to it
811  // - avoids iterating over a changing collection
812  BreakPoints bpCopy(range.first, range.second);
813  auto& globalCliComm = motherBoard.getReactor().getGlobalCliComm();
814  auto& interp = motherBoard.getReactor().getInterpreter();
815  for (auto& p : bpCopy) {
816  p.checkAndExecute(globalCliComm, interp);
817  if (p.onlyOnce()) {
818  removeBreakPoint(p.getId());
819  }
820  }
821  auto condCopy = conditions;
822  for (auto& c : condCopy) {
823  c.checkAndExecute(globalCliComm, interp);
824  if (c.onlyOnce()) {
825  removeCondition(c.getId());
826  }
827  }
828 }
829 
830 static void registerIOWatch(WatchPoint& watchPoint, MSXDevice** devices)
831 {
832  assert(dynamic_cast<WatchIO*>(&watchPoint));
833  auto& ioWatch = static_cast<WatchIO&>(watchPoint);
834  unsigned beginPort = ioWatch.getBeginAddress();
835  unsigned endPort = ioWatch.getEndAddress();
836  assert(beginPort <= endPort);
837  assert(endPort < 0x100);
838  for (unsigned port = beginPort; port <= endPort; ++port) {
839  ioWatch.getDevice(port).getDevicePtr() = devices[port];
840  devices[port] = &ioWatch.getDevice(port);
841  }
842 }
843 
844 void MSXCPUInterface::setWatchPoint(const shared_ptr<WatchPoint>& watchPoint)
845 {
846  watchPoints.push_back(watchPoint);
847  WatchPoint::Type type = watchPoint->getType();
848  switch (type) {
849  case WatchPoint::READ_IO:
850  registerIOWatch(*watchPoint, IO_In);
851  break;
853  registerIOWatch(*watchPoint, IO_Out);
854  break;
857  updateMemWatch(type);
858  break;
859  default:
860  UNREACHABLE; break;
861  }
862 }
863 
864 static void unregisterIOWatch(WatchPoint& watchPoint, MSXDevice** devices)
865 {
866  assert(dynamic_cast<WatchIO*>(&watchPoint));
867  auto& ioWatch = static_cast<WatchIO&>(watchPoint);
868  unsigned beginPort = ioWatch.getBeginAddress();
869  unsigned endPort = ioWatch.getEndAddress();
870  assert(beginPort <= endPort);
871  assert(endPort < 0x100);
872 
873  for (unsigned port = beginPort; port <= endPort; ++port) {
874  // find pointer to watchpoint
875  MSXDevice** prev = &devices[port];
876  while (*prev != &ioWatch.getDevice(port)) {
877  prev = &checked_cast<MSXWatchIODevice*>(*prev)->getDevicePtr();
878  }
879  // remove watchpoint from chain
880  *prev = checked_cast<MSXWatchIODevice*>(*prev)->getDevicePtr();
881  }
882 }
883 
884 void MSXCPUInterface::removeWatchPoint(shared_ptr<WatchPoint> watchPoint)
885 {
886  // Pass shared_ptr by value to keep the object alive for the duration
887  // of this function, otherwise it gets deleted as soon as it's removed
888  // from the watchPoints collection.
889  if (auto it = ranges::find(watchPoints, watchPoint);
890  it != end(watchPoints)) {
891  // remove before calling updateMemWatch()
892  watchPoints.erase(it);
893  WatchPoint::Type type = watchPoint->getType();
894  switch (type) {
895  case WatchPoint::READ_IO:
896  unregisterIOWatch(*watchPoint, IO_In);
897  break;
899  unregisterIOWatch(*watchPoint, IO_Out);
900  break;
903  updateMemWatch(type);
904  break;
905  default:
906  UNREACHABLE; break;
907  }
908  }
909 }
910 
912 {
913  conditions.push_back(std::move(cond));
914 }
915 
917 {
918  conditions.erase(rfind_if_unguarded(conditions,
919  [&](DebugCondition& e) { return &e == &cond; }));
920 }
921 
922 void MSXCPUInterface::removeCondition(unsigned id)
923 {
924  if (auto it = ranges::find_if(conditions,
925  [&](DebugCondition& e) { return e.getId() == id; });
926  // could be ==end for a condition that removes itself AND has the -once flag set
927  it != conditions.end()) {
928  conditions.erase(it);
929  }
930 }
931 
932 void MSXCPUInterface::updateMemWatch(WatchPoint::Type type)
933 {
934  std::bitset<CacheLine::SIZE>* watchSet =
935  (type == WatchPoint::READ_MEM) ? readWatchSet : writeWatchSet;
936  for (auto i : xrange(CacheLine::NUM)) {
937  watchSet[i].reset();
938  }
939  for (auto& w : watchPoints) {
940  if (w->getType() == type) {
941  unsigned beginAddr = w->getBeginAddress();
942  unsigned endAddr = w->getEndAddress();
943  assert(beginAddr <= endAddr);
944  assert(endAddr < 0x10000);
945  for (unsigned addr = beginAddr; addr <= endAddr; ++addr) {
946  watchSet[addr >> CacheLine::BITS].set(
947  addr & CacheLine::LOW);
948  }
949  }
950  }
951  for (auto i : xrange(CacheLine::NUM)) {
952  if (readWatchSet [i].any()) {
953  disallowReadCache [i] |= MEMORY_WATCH_BIT;
954  } else {
955  disallowReadCache [i] &= ~MEMORY_WATCH_BIT;
956  }
957  if (writeWatchSet[i].any()) {
958  disallowWriteCache[i] |= MEMORY_WATCH_BIT;
959  } else {
960  disallowWriteCache[i] &= ~MEMORY_WATCH_BIT;
961  }
962  }
963  msxcpu.invalidateAllSlotsRWCache(0x0000, 0x10000);
964 }
965 
966 void MSXCPUInterface::executeMemWatch(WatchPoint::Type type,
967  unsigned address, unsigned value)
968 {
969  assert(!watchPoints.empty());
970  if (isFastForward()) return;
971 
972  auto& globalCliComm = motherBoard.getReactor().getGlobalCliComm();
973  auto& interp = motherBoard.getReactor().getInterpreter();
974  interp.setVariable(TclObject("wp_last_address"),
975  TclObject(int(address)));
976  if (value != ~0u) {
977  interp.setVariable(TclObject("wp_last_value"),
978  TclObject(int(value)));
979  }
980 
981  auto wpCopy = watchPoints;
982  for (auto& w : wpCopy) {
983  if ((w->getBeginAddress() <= address) &&
984  (w->getEndAddress() >= address) &&
985  (w->getType() == type)) {
986  w->checkAndExecute(globalCliComm, interp);
987  if (w->onlyOnce()) {
988  removeWatchPoint(w);
989  }
990  }
991  }
992 
993  interp.unsetVariable("wp_last_address");
994  interp.unsetVariable("wp_last_value");
995 }
996 
997 
999 {
1000  assert(!isFastForward());
1001  if (breaked) return;
1002  breaked = true;
1003  msxcpu.exitCPULoopSync();
1004 
1005  Reactor& reactor = motherBoard.getReactor();
1006  reactor.block();
1007  breakedSetting->setReadOnlyValue(TclObject("true"));
1008  reactor.getCliComm().update(CliComm::STATUS, "cpu", "suspended");
1010  std::make_shared<SimpleEvent>(OPENMSX_BREAK_EVENT));
1011 }
1012 
1014 {
1015  assert(!isFastForward());
1017  TclObject("debug break"), TclObject(), true));
1018  doContinue();
1019 }
1020 
1022 {
1023  assert(!isFastForward());
1024  if (breaked) {
1025  breaked = false;
1026 
1027  Reactor& reactor = motherBoard.getReactor();
1028  breakedSetting->setReadOnlyValue(TclObject("false"));
1029  reactor.getCliComm().update(CliComm::STATUS, "cpu", "running");
1030  reactor.unblock();
1031  motherBoard.getRealTime().resync();
1032  }
1033 }
1034 
1036 {
1037  // before the Tcl interpreter is destroyed, we must delete all
1038  // TclObjects. Breakpoints and conditions contain such objects
1039  // for the condition and action.
1040  // TODO it would be nicer if breakpoints and conditions were not
1041  // global objects.
1042  breakPoints.clear();
1043  conditions.clear();
1044 }
1045 
1046 
1047 // class MemoryDebug
1048 
1049 MSXCPUInterface::MemoryDebug::MemoryDebug(MSXMotherBoard& motherBoard_)
1050  : SimpleDebuggable(motherBoard_, "memory",
1051  "The memory currently visible for the CPU.", 0x10000)
1052 {
1053 }
1054 
1055 byte MSXCPUInterface::MemoryDebug::read(unsigned address, EmuTime::param time)
1056 {
1057  auto& interface = OUTER(MSXCPUInterface, memoryDebug);
1058  return interface.peekMem(address, time);
1059 }
1060 
1061 void MSXCPUInterface::MemoryDebug::write(unsigned address, byte value,
1062  EmuTime::param time)
1063 {
1064  auto& interface = OUTER(MSXCPUInterface, memoryDebug);
1065  return interface.writeMem(address, value, time);
1066 }
1067 
1068 
1069 // class SlottedMemoryDebug
1070 
1071 MSXCPUInterface::SlottedMemoryDebug::SlottedMemoryDebug(
1072  MSXMotherBoard& motherBoard_)
1073  : SimpleDebuggable(motherBoard_, "slotted memory",
1074  "The memory in slots and subslots.", 0x10000 * 4 * 4)
1075 {
1076 }
1077 
1078 byte MSXCPUInterface::SlottedMemoryDebug::read(unsigned address, EmuTime::param time)
1079 {
1080  auto& interface = OUTER(MSXCPUInterface, slottedMemoryDebug);
1081  return interface.peekSlottedMem(address, time);
1082 }
1083 
1084 void MSXCPUInterface::SlottedMemoryDebug::write(unsigned address, byte value,
1085  EmuTime::param time)
1086 {
1087  auto& interface = OUTER(MSXCPUInterface, slottedMemoryDebug);
1088  return interface.writeSlottedMem(address, value, time);
1089 }
1090 
1091 
1092 // class SlotInfo
1093 
1094 static unsigned getSlot(
1095  Interpreter& interp, const TclObject& token, const string& itemName)
1096 {
1097  unsigned slot = token.getInt(interp);
1098  if (slot >= 4) {
1099  throw CommandException(itemName, " must be in range 0..3");
1100  }
1101  return slot;
1102 }
1103 
1104 MSXCPUInterface::SlotInfo::SlotInfo(
1105  InfoCommand& machineInfoCommand)
1106  : InfoTopic(machineInfoCommand, "slot")
1107 {
1108 }
1109 
1110 void MSXCPUInterface::SlotInfo::execute(span<const TclObject> tokens,
1111  TclObject& result) const
1112 {
1113  checkNumArgs(tokens, 5, Prefix{2}, "primary secondary page");
1114  auto& interp = getInterpreter();
1115  unsigned ps = getSlot(interp, tokens[2], "Primary slot");
1116  unsigned ss = getSlot(interp, tokens[3], "Secondary slot");
1117  unsigned page = getSlot(interp, tokens[4], "Page");
1118  auto& interface = OUTER(MSXCPUInterface, slotInfo);
1119  if (!interface.isExpanded(ps)) {
1120  ss = 0;
1121  }
1122  interface.slotLayout[ps][ss][page]->getNameList(result);
1123 }
1124 
1125 string MSXCPUInterface::SlotInfo::help(const vector<string>& /*tokens*/) const
1126 {
1127  return "Retrieve name of the device inserted in given "
1128  "primary slot / secondary slot / page.";
1129 }
1130 
1131 
1132 // class SubSlottedInfo
1133 
1134 MSXCPUInterface::SubSlottedInfo::SubSlottedInfo(
1135  InfoCommand& machineInfoCommand)
1136  : InfoTopic(machineInfoCommand, "issubslotted")
1137 {
1138 }
1139 
1140 void MSXCPUInterface::SubSlottedInfo::execute(span<const TclObject> tokens,
1141  TclObject& result) const
1142 {
1143  checkNumArgs(tokens, 3, "primary");
1144  auto& interface = OUTER(MSXCPUInterface, subSlottedInfo);
1145  result = interface.isExpanded(
1146  getSlot(getInterpreter(), tokens[2], "Slot"));
1147 }
1148 
1149 string MSXCPUInterface::SubSlottedInfo::help(
1150  const vector<string>& /*tokens*/) const
1151 {
1152  return "Indicates whether a certain primary slot is expanded.";
1153 }
1154 
1155 
1156 // class ExternalSlotInfo
1157 
1158 MSXCPUInterface::ExternalSlotInfo::ExternalSlotInfo(
1159  InfoCommand& machineInfoCommand)
1160  : InfoTopic(machineInfoCommand, "isexternalslot")
1161 {
1162 }
1163 
1164 void MSXCPUInterface::ExternalSlotInfo::execute(
1165  span<const TclObject> tokens, TclObject& result) const
1166 {
1167  checkNumArgs(tokens, Between{3, 4}, "primary ?secondary?");
1168  int ps = 0;
1169  int ss = 0;
1170  auto& interp = getInterpreter();
1171  switch (tokens.size()) {
1172  case 4:
1173  ss = getSlot(interp, tokens[3], "Secondary slot");
1174  // Fall-through
1175  case 3:
1176  ps = getSlot(interp, tokens[2], "Primary slot");
1177  break;
1178  }
1179  auto& interface = OUTER(MSXCPUInterface, externalSlotInfo);
1180  auto& manager = interface.motherBoard.getSlotManager();
1181  result = manager.isExternalSlot(ps, ss, true);
1182 }
1183 
1184 string MSXCPUInterface::ExternalSlotInfo::help(
1185  const vector<string>& /*tokens*/) const
1186 {
1187  return "Indicates whether a certain slot is external or internal.";
1188 }
1189 
1190 
1191 // class IODebug
1192 
1193 MSXCPUInterface::IODebug::IODebug(MSXMotherBoard& motherBoard_)
1194  : SimpleDebuggable(motherBoard_, "ioports", "IO ports.", 0x100)
1195 {
1196 }
1197 
1198 byte MSXCPUInterface::IODebug::read(unsigned address, EmuTime::param time)
1199 {
1200  auto& interface = OUTER(MSXCPUInterface, ioDebug);
1201  return interface.IO_In[address & 0xFF]->peekIO(address, time);
1202 }
1203 
1204 void MSXCPUInterface::IODebug::write(unsigned address, byte value, EmuTime::param time)
1205 {
1206  auto& interface = OUTER(MSXCPUInterface, ioDebug);
1207  interface.writeIO(word(address), value, time);
1208 }
1209 
1210 
1211 // class IOInfo
1212 
1213 MSXCPUInterface::IOInfo::IOInfo(InfoCommand& machineInfoCommand, const char* name_)
1214  : InfoTopic(machineInfoCommand, name_)
1215 {
1216 }
1217 
1218 void MSXCPUInterface::IOInfo::helper(
1219  span<const TclObject> tokens, TclObject& result, MSXDevice** devices) const
1220 {
1221  checkNumArgs(tokens, 3, "port");
1222  unsigned port = tokens[2].getInt(getInterpreter());
1223  if (port >= 256) {
1224  throw CommandException("Port must be in range 0..255");
1225  }
1226  devices[port]->getNameList(result);
1227 }
1228 void MSXCPUInterface::IInfo::execute(
1229  span<const TclObject> tokens, TclObject& result) const
1230 {
1231  auto& interface = OUTER(MSXCPUInterface, inputPortInfo);
1232  helper(tokens, result, interface.IO_In);
1233 }
1234 void MSXCPUInterface::OInfo::execute(
1235  span<const TclObject> tokens, TclObject& result) const
1236 {
1237  auto& interface = OUTER(MSXCPUInterface, outputPortInfo);
1238  helper(tokens, result, interface.IO_Out);
1239 }
1240 
1241 string MSXCPUInterface::IOInfo::help(const vector<string>& /*tokens*/) const
1242 {
1243  return "Return the name of the device connected to the given IO port.";
1244 }
1245 
1246 
1247 template<typename Archive>
1248 void MSXCPUInterface::serialize(Archive& ar, unsigned /*version*/)
1249 {
1250  // TODO watchPoints ???
1251 
1252  // primary and 4 secondary slot select registers
1253  byte prim = 0;
1254  if (!ar.isLoader()) {
1255  for (auto i : xrange(4)) {
1256  prim |= primarySlotState[i] << (2 * i);
1257  }
1258  }
1259  ar.serialize("primarySlots", prim,
1260  "subSlotRegs", subSlotRegister);
1261  if (ar.isLoader()) {
1262  setPrimarySlots(prim);
1263  for (auto i : xrange(4)) {
1264  setSubSlot(i, subSlotRegister[i]);
1265  }
1266  }
1267 
1268  if (delayDevice) {
1269  ar.serialize("vdpDelay", *delayDevice);
1270  }
1271 }
1273 
1274 } // namespace openmsx
MSXWatchIODevice.hh
openmsx::BreakPoint
Base class for CPU breakpoints.
Definition: BreakPoint.hh:14
openmsx::MSXDevice
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:32
openmsx::MSXMotherBoard::getReactor
Reactor & getReactor()
Definition: MSXMotherBoard.hh:136
openmsx::DeviceFactory::createVDPIODelay
static std::unique_ptr< VDPIODelay > createVDPIODelay(const HardwareConfig &hwConf, MSXCPUInterface &cpuInterface)
Definition: DeviceFactory.cc:327
HardwareConfig.hh
openmsx::FillReadWrite
@ FillReadWrite
Definition: MSXCPUInterface.hh:55
gl::min
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:269
ALWAYS_INLINE
#define ALWAYS_INLINE
Definition: inline.hh:16
openmsx::MSXCPUInterface::doStep
void doStep()
Definition: MSXCPUInterface.cc:1013
unlikely
#define unlikely(x)
Definition: likely.hh:15
serialize.hh
DummyDevice.hh
VDPIODelay.hh
xrange
constexpr auto xrange(T e)
Definition: xrange.hh:155
ranges::sort
void sort(RandomAccessRange &&range)
Definition: ranges.hh:35
openmsx::MSXCPUInterface::setPrimarySlots
void setPrimarySlots(byte value)
Definition: MSXCPUInterface.cc:660
openmsx::InvalidateReadWrite
@ InvalidateReadWrite
Definition: MSXCPUInterface.hh:52
openmsx::Reactor::unblock
void unblock()
Definition: Reactor.cc:606
openmsx::BreakPoint::getId
unsigned getId() const
Definition: BreakPoint.hh:22
TclObject.hh
openmsx::MSXDevice::readMem
virtual byte readMem(word address, EmuTime::param time)
Read a byte from a location at a certain time from this device.
Definition: MSXDevice.cc:426
EnumValueName::e
E e
Definition: ProfileCounters.hh:22
utf8::unchecked::size
size_t size(std::string_view utf8)
Definition: utf8_unchecked.hh:233
openmsx::MSXCPUInterface::register_IO_Out
void register_IO_Out(byte port, MSXDevice *device)
Devices can register their Out ports.
Definition: MSXCPUInterface.cc:349
openmsx::MSXCPU::invalidateRWCache
void invalidateRWCache(unsigned start, unsigned size, int ps, int ss, const byte *disallowRead, const byte *disallowWrite)
Similar to the method above, but only invalidates one specific slot.
Definition: MSXCPU.cc:252
ranges::set_difference
auto set_difference(InputRange1 &&range1, InputRange2 &&range2, OutputIter out)
Definition: ranges.hh:243
openmsx::MSXCPU::setInterface
void setInterface(MSXCPUInterface *interf)
Definition: MSXCPU.cc:78
MSXCPU.hh
openmsx::WatchPoint
Base class for CPU breakpoints.
Definition: WatchPoint.hh:14
openmsx::MSXCPUInterface::isFastForward
bool isFastForward() const
Definition: MSXCPUInterface.hh:297
openmsx::MSXCPU::fillRWCache
void fillRWCache(unsigned start, unsigned size, const byte *rData, byte *wData, int ps, int ss, const byte *disallowRead, const byte *disallowWrite)
Fill the read and write cache lines for a specific slot with the specified value.
Definition: MSXCPU.cc:272
openmsx::SimpleDebuggable
Definition: SimpleDebuggable.hh:13
openmsx::MSXCPUInterface::~MSXCPUInterface
~MSXCPUInterface()
Definition: MSXCPUInterface.cc:137
openmsx::MSXCPUInterface::isExpanded
bool isExpanded(int ps) const
Definition: MSXCPUInterface.hh:248
openmsx::OPENMSX_BREAK_EVENT
@ OPENMSX_BREAK_EVENT
Definition: Event.hh:47
openmsx::CliComm::update
virtual void update(UpdateType type, std::string_view name, std::string_view value)=0
openmsx::WatchPoint::getBeginAddress
unsigned getBeginAddress() const
Definition: WatchPoint.hh:34
ranges.hh
openmsx::Reactor::getEventDistributor
EventDistributor & getEventDistributor()
Definition: Reactor.hh:81
MSXException.hh
openmsx::Reactor::block
void block()
Definition: Reactor.cc:599
openmsx::MSXCPUInterface::MSXCPUInterface
MSXCPUInterface(const MSXCPUInterface &)=delete
end
auto end(const zstring_view &x)
Definition: zstring_view.hh:83
openmsx::MSXException
Definition: MSXException.hh:10
openmsx::HardwareConfig::parseSlotMap
byte parseSlotMap() const
Parses a slot mapping.
Definition: HardwareConfig.cc:301
Interpreter.hh
openmsx::MSXCPUInterface::peekSlottedMem
byte peekSlottedMem(unsigned address, EmuTime::param time) const
Definition: MSXCPUInterface.cc:730
openmsx::WatchPoint::READ_IO
@ READ_IO
Definition: WatchPoint.hh:16
openmsx::SECONDARY_SLOT_BIT
constexpr byte SECONDARY_SLOT_BIT
Definition: MSXCPUInterface.cc:47
openmsx::MSXCPUInterface::invalidateRCache
void invalidateRCache(word start, unsigned size, int ps, int ss)
Definition: MSXCPUInterface.cc:620
openmsx::BreakPoint::getAddress
word getAddress() const
Definition: BreakPoint.hh:21
openmsx::MSXCPUInterface::invalidateWCache
void invalidateWCache(word start, unsigned size, int ps, int ss)
Definition: MSXCPUInterface.cc:625
EnumValueName
Definition: ProfileCounters.hh:20
openmsx::CacheLine::HIGH
constexpr unsigned HIGH
Definition: CacheLine.hh:10
openmsx::WatchPoint::READ_MEM
@ READ_MEM
Definition: WatchPoint.hh:16
openmsx::MSXDevice::writeMem
virtual void writeMem(word address, byte value, EmuTime::param time)
Write a given byte to a given location at a certain time to this device.
Definition: MSXDevice.cc:437
openmsx::FillRead
@ FillRead
Definition: MSXCPUInterface.hh:56
strAppend
void strAppend(std::string &result, Ts &&...ts)
Definition: strCat.hh:669
openmsx::MSXCPUInterface
Definition: MSXCPUInterface.hh:64
openmsx::MSXCPUInterface::setCondition
static void setCondition(DebugCondition cond)
Definition: MSXCPUInterface.cc:911
openmsx::MSXDevice::peekMem
virtual byte peekMem(word address, EmuTime::param time) const
Read a byte from a given memory location.
Definition: MSXDevice.cc:443
ReadOnlySetting.hh
openmsx::MSXCPU::invalidateWCache
void invalidateWCache(unsigned start, unsigned size, int ps, int ss, const byte *disallowWrite)
Definition: MSXCPU.cc:265
openmsx::MEMORY_WATCH_BIT
constexpr byte MEMORY_WATCH_BIT
Definition: MSXCPUInterface.cc:48
openmsx::MSXCPUInterface::checkBreakPoints
static bool checkBreakPoints(unsigned pc, MSXMotherBoard &motherBoard)
Definition: MSXCPUInterface.hh:279
span
Definition: span.hh:126
openmsx::Reactor
Contains the main loop of openMSX.
Definition: Reactor.hh:67
openmsx::DisallowCacheRead
@ DisallowCacheRead
Definition: MSXCPUInterface.hh:49
openmsx::InvalidateWrite
@ InvalidateWrite
Definition: MSXCPUInterface.hh:54
RealTime.hh
openmsx::MSXCPUInterface::registerMemDevice
void registerMemDevice(MSXDevice &device, int ps, int ss, int base, int size)
Devices can register themself in the MSX slotstructure.
Definition: MSXCPUInterface.cc:512
openmsx::MSXCPUInterface::testUnsetExpanded
void testUnsetExpanded(int ps, std::vector< MSXDevice * > allowed) const
Definition: MSXCPUInterface.cc:258
Reactor.hh
openmsx::CliComm::STATUS
@ STATUS
Definition: CliComm.hh:27
OUTER
#define OUTER(type, member)
Definition: outer.hh:41
move_pop_back
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
Definition: stl.hh:182
openmsx::CliComm::printWarning
void printWarning(std::string_view message)
Definition: CliComm.cc:10
openmsx::DebugCondition::getId
unsigned getId() const
Definition: DebugCondition.hh:18
EnumTypeName
Definition: ProfileCounters.hh:13
UNREACHABLE
#define UNREACHABLE
Definition: unreachable.hh:38
openmsx::DeviceFactory
Definition: DeviceFactory.hh:18
openmsx::CacheLine::NUM
constexpr unsigned NUM
Definition: CacheLine.hh:8
openmsx::WatchPoint::Type
Type
Definition: WatchPoint.hh:16
openmsx::MSXCPUInterface::registerGlobalRead
void registerGlobalRead(MSXDevice &device, word address)
(Un)register global read.
Definition: MSXCPUInterface.cc:578
openmsx::MSXCPUInterface::insertBreakPoint
static void insertBreakPoint(BreakPoint bp)
Definition: MSXCPUInterface.cc:782
openmsx::MSXCPUInterface::cleanup
static void cleanup()
Definition: MSXCPUInterface.cc:1035
openmsx::MSXCPU::invalidateAllSlotsRWCache
void invalidateAllSlotsRWCache(word start, unsigned size)
Invalidate the CPU its cache for the interval [start, start + size) For example MSXMemoryMapper and M...
Definition: MSXCPU.cc:183
openmsx::MSXCPUInterface::readIRQVector
byte readIRQVector()
CPU uses this method to read 'extra' data from the databus used in interrupt routines.
Definition: MSXCPUInterface.cc:655
begin
auto begin(const zstring_view &x)
Definition: zstring_view.hh:82
openmsx::MSXCPUInterface::registerGlobalWrite
void registerGlobalWrite(MSXDevice &device, word address)
(Un)register global writes.
Definition: MSXCPUInterface.cc:554
openmsx::CompareBreakpoints
Definition: MSXCPUInterface.hh:29
openmsx::MSXMotherBoard
Definition: MSXMotherBoard.hh:61
openmsx::MSXCPUInterface::replace_IO_In
bool replace_IO_In(byte port, MSXDevice *oldDevice, MSXDevice *newDevice)
These methods replace a previously registered device with a new one.
Definition: MSXCPUInterface.cc:406
EventDistributor.hh
openmsx::Reactor::getCommandController
CommandController & getCommandController()
Definition: Reactor.cc:320
openmsx::MSXWatchIODevice
Definition: MSXWatchIODevice.hh:36
openmsx::MSXCPUInterface::setWatchPoint
void setWatchPoint(const std::shared_ptr< WatchPoint > &watchPoint)
Definition: MSXCPUInterface.cc:844
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:983
openmsx::MSXCPUInterface::writeSlottedMem
void writeSlottedMem(unsigned address, byte value, EmuTime::param time)
Definition: MSXCPUInterface.cc:764
openmsx::MSXCPU::invalidateRCache
void invalidateRCache(unsigned start, unsigned size, int ps, int ss, const byte *disallowRead)
Definition: MSXCPU.cc:259
openmsx::operator<<
std::ostream & operator<<(std::ostream &os, EnumTypeName< CacheLineCounters >)
Definition: MSXCPUInterface.cc:51
openmsx::MSXCPUInterface::fillWCache
void fillWCache(unsigned start, unsigned size, byte *wData, int ps, int ss)
Definition: MSXCPUInterface.cc:641
ranges::find
auto find(InputRange &&range, const T &value)
Definition: ranges.hh:107
openmsx::MSXCPUInterface::reset
void reset()
Reset (the slot state)
Definition: MSXCPUInterface.cc:647
ranges::unique
auto unique(ForwardRange &&range)
Definition: ranges.hh:137
openmsx::MSXCPUInterface::register_IO_In
void register_IO_In(byte port, MSXDevice *device)
Devices can register their In ports.
Definition: MSXCPUInterface.cc:337
openmsx::MSXMotherBoard::readIRQVector
byte readIRQVector()
Definition: MSXMotherBoard.cc:583
openmsx::MSXCPUInterface::changeExpanded
void changeExpanded(bool newExpanded)
Definition: MSXCPUInterface.cc:312
openmsx::DebugCondition
General debugger condition Like breakpoints, but not tied to a specifc address.
Definition: DebugCondition.hh:12
MSXMultiIODevice.hh
g
int g
Definition: ScopedAssign_test.cc:20
openmsx::GLOBAL_RW_BIT
constexpr byte GLOBAL_RW_BIT
Definition: MSXCPUInterface.cc:49
openmsx::MSXCPUInterface::unregister_IO_In
void unregister_IO_In(byte port, MSXDevice *device)
Definition: MSXCPUInterface.cc:343
MSXMultiMemDevice.hh
openmsx::MSXCPUInterface
MSXCPUInterface
Definition: MSXCPUInterface.cc:1272
openmsx::CacheLine::LOW
constexpr unsigned LOW
Definition: CacheLine.hh:9
outer.hh
openmsx::MSXCPUInterface::doBreak
void doBreak()
Definition: MSXCPUInterface.cc:998
openmsx::MSXCPU::updateVisiblePage
void updateVisiblePage(byte page, byte primarySlot, byte secondarySlot)
Inform CPU of bank switch.
Definition: MSXCPU.cc:165
checked_cast.hh
openmsx::MSXCPUInterface::fillRWCache
void fillRWCache(unsigned start, unsigned size, const byte *rData, byte *wData, int ps, int ss)
Definition: MSXCPUInterface.cc:631
openmsx::MSXDevice::getName
virtual std::string getName() const
Returns a human-readable name for this device.
Definition: MSXDevice.cc:382
ProfileCounters< PROFILE_CACHELINES, CacheLineCounters >::tick
void tick(CacheLineCounters e) const
Definition: ProfileCounters.hh:98
span::size
constexpr index_type size() const noexcept
Definition: span.hh:296
openmsx::CacheLine::BITS
constexpr unsigned BITS
Definition: CacheLine.hh:6
openmsx::MSXCPUInterface::removeWatchPoint
void removeWatchPoint(std::shared_ptr< WatchPoint > watchPoint)
Definition: MSXCPUInterface.cc:884
openmsx::Reactor::getCliComm
CliComm & getCliComm()
Definition: Reactor.cc:310
openmsx::word
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
MSXCPUInterface.hh
openmsx::MSXCPUInterface::serialize
void serialize(Archive &ar, unsigned version)
Definition: MSXCPUInterface.cc:1248
openmsx::WatchPoint::WRITE_MEM
@ WRITE_MEM
Definition: WatchPoint.hh:16
openmsx::WatchIO
Definition: MSXWatchIODevice.hh:14
openmsx::MSXCPUInterface::readSlottedMem
byte readSlottedMem(unsigned address, EmuTime::param time)
Definition: MSXCPUInterface.cc:747
openmsx::MSXCPUInterface::unregisterGlobalRead
void unregisterGlobalRead(MSXDevice &device, word address)
Definition: MSXCPUInterface.cc:586
openmsx::MSXCPUInterface::unsetExpanded
void unsetExpanded(int ps)
Definition: MSXCPUInterface.cc:298
openmsx::MSXDevice
MSXDevice
Definition: MSXDevice.cc:539
openmsx::MSXMotherBoard::getMachineConfig
const HardwareConfig * getMachineConfig() const
Definition: MSXMotherBoard.hh:101
openmsx::MSXMotherBoard::isTurboR
bool isTurboR() const
Definition: MSXMotherBoard.cc:298
Event.hh
stl.hh
openmsx::MSXDevice::getHardwareConfig
const HardwareConfig & getHardwareConfig() const
Returns the hardwareconfig this device belongs to.
Definition: MSXDevice.hh:43
find_if_unguarded
ITER find_if_unguarded(ITER first, ITER last, PRED pred)
Faster alternative to 'find_if' when it's guaranteed that the predicate will be true for at least one...
Definition: stl.hh:136
openmsx::TclObject
Definition: TclObject.hh:24
CartridgeSlotManager.hh
openmsx::MSXCPU::fillWCache
void fillWCache(unsigned start, unsigned size, byte *wData, int ps, int ss, const byte *disallowWrite)
Definition: MSXCPU.cc:282
openmsx::MSXCPU::exitCPULoopSync
void exitCPULoopSync()
See CPUCore::exitCPULoopsync()
Definition: MSXCPU.cc:131
ranges::find_if
auto find_if(InputRange &&range, UnaryPredicate pred)
Definition: ranges.hh:113
openmsx::MSXCPUInterface::unregister_IO_Out
void unregister_IO_Out(byte port, MSXDevice *device)
Definition: MSXCPUInterface.cc:355
unreachable.hh
CliComm.hh
openmsx::MSXCPUInterface::invalidateRWCache
void invalidateRWCache(word start, unsigned size, int ps, int ss)
Definition: MSXCPUInterface.cc:615
openmsx::MSXCPUInterface::unregisterMemDevice
void unregisterMemDevice(MSXDevice &device, int ps, int ss, int base, int size)
Definition: MSXCPUInterface.cc:542
ranges::fill
void fill(ForwardRange &&range, const T &value)
Definition: ranges.hh:197
DeviceFactory.hh
openmsx::MSXCPUInterface::setExpanded
void setExpanded(int ps)
Definition: MSXCPUInterface.cc:244
openmsx::MSXCPUInterface::unregisterGlobalWrite
void unregisterGlobalWrite(MSXDevice &device, word address)
Definition: MSXCPUInterface.cc:562
strCat
std::string strCat(Ts &&...ts)
Definition: strCat.hh:591
CommandException.hh
rfind_unguarded
auto rfind_unguarded(RANGE &range, const VAL &val)
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
Definition: stl.hh:157
openmsx::MSXCPUInterface::replace_IO_Out
bool replace_IO_Out(byte port, MSXDevice *oldDevice, MSXDevice *newDevice)
Definition: MSXCPUInterface.cc:417
ranges::upper_bound
auto upper_bound(ForwardRange &&range, const T &value)
Definition: ranges.hh:83
ranges::equal_range
auto equal_range(ForwardRange &&range, const T &value)
Definition: ranges.hh:95
openmsx
This file implemented 3 utility functions:
Definition: Autofire.cc:5
openmsx::MSXMultiMemDevice
Definition: MSXMultiMemDevice.hh:10
openmsx::MSXCPUInterface::fillRCache
void fillRCache(unsigned start, unsigned size, const byte *rData, int ps, int ss)
Definition: MSXCPUInterface.cc:636
openmsx::MSXCPUInterface::removeCondition
static void removeCondition(const DebugCondition &cond)
Definition: MSXCPUInterface.cc:916
MSXMotherBoard.hh
xrange.hh
openmsx::MSXCPUInterface::removeBreakPoint
static void removeBreakPoint(const BreakPoint &bp)
Definition: MSXCPUInterface.cc:788
openmsx::WatchPoint::WRITE_IO
@ WRITE_IO
Definition: WatchPoint.hh:16
openmsx::MSXCPUInterface::peekMem
byte peekMem(word address, EmuTime::param time) const
Peek memory location.
Definition: MSXCPUInterface.cc:721
openmsx::MSXCPUInterface::BreakPoints
std::vector< BreakPoint > BreakPoints
Definition: MSXCPUInterface.hh:255
rfind_if_unguarded
auto rfind_if_unguarded(RANGE &range, PRED pred)
Definition: stl.hh:165
openmsx::DisallowCacheWrite
@ DisallowCacheWrite
Definition: MSXCPUInterface.hh:50
openmsx::InvalidateRead
@ InvalidateRead
Definition: MSXCPUInterface.hh:53
openmsx::EventDistributor::distributeEvent
void distributeEvent(const EventPtr &event)
Schedule the given event for delivery.
Definition: EventDistributor.cc:44
openmsx::MSXCPUInterface::doContinue
void doContinue()
Definition: MSXCPUInterface.cc:1021
openmsx::FillWrite
@ FillWrite
Definition: MSXCPUInterface.hh:57
openmsx::MSXCPU::fillRCache
void fillRCache(unsigned start, unsigned size, const byte *rData, int ps, int ss, const byte *disallowRead)
Definition: MSXCPU.cc:277