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