45static std::optional<ReadOnlySetting> breakedSetting;
46static unsigned breakedSettingCount = 0;
50static constexpr byte SECONDARY_SLOT_BIT = 0x01;
51static constexpr byte MEMORY_WATCH_BIT = 0x02;
52static constexpr byte GLOBAL_RW_BIT = 0x04;
56 return os <<
"CacheLineCounters";
70 "InvalidateReadWrite",
77 return os << names[size_t(evn.
e)];
81 : memoryDebug (motherBoard_)
82 , slottedMemoryDebug(motherBoard_)
83 , ioDebug (motherBoard_)
84 , slotInfo(motherBoard_.getMachineInfoCommand())
85 , subSlottedInfo(motherBoard_.getMachineInfoCommand())
86 , externalSlotInfo(motherBoard_.getMachineInfoCommand())
87 , inputPortInfo (motherBoard_.getMachineInfoCommand())
88 , outputPortInfo(motherBoard_.getMachineInfoCommand())
90 *motherBoard_.getMachineConfig()))
91 , msxcpu(motherBoard_.getCPU())
92 , cliComm(motherBoard_.getMSXCliComm())
93 , motherBoard(motherBoard_)
94 , pauseSetting(motherBoard.getReactor().getGlobalSettings().getPauseSetting())
103 for (
auto& sub1 : slotLayout) {
104 for (
auto& sub2 : sub1) {
122 for (
auto port :
xrange(0x98, 0x9c)) {
123 assert(IO_In [port] == dummyDevice.get());
124 assert(IO_Out[port] == dummyDevice.get());
125 IO_In [port] = delayDevice.get();
126 IO_Out[port] = delayDevice.get();
130 if (breakedSettingCount++ == 0) {
131 assert(!breakedSetting);
132 breakedSetting.emplace(
134 "breaked",
"Similar to 'debug breaked'",
142 if (--breakedSettingCount == 0) {
143 assert(breakedSetting);
144 breakedSetting.reset();
147 removeAllWatchPoints();
150 for (
auto port :
xrange(0x98, 0x9c)) {
151 assert(IO_In [port] == delayDevice.get());
152 assert(IO_Out[port] == delayDevice.get());
153 IO_In [port] = dummyDevice.get();
154 IO_Out[port] = dummyDevice.get();
161 for (
auto port :
xrange(256)) {
162 if (IO_In[port] != dummyDevice.get()) {
163 std::cout <<
"In-port " << port <<
" still registered "
164 << IO_In[port]->getName() <<
'\n';
167 if (IO_Out[port] != dummyDevice.get()) {
168 std::cout <<
"Out-port " << port <<
" still registered "
169 << IO_Out[port]->getName() <<
'\n';
173 for (
auto primSlot :
xrange(4)) {
175 for (
auto secSlot :
xrange(4)) {
176 for (
auto page :
xrange(4)) {
177 assert(slotLayout[primSlot][secSlot][page] == dummyDevice.get());
184void MSXCPUInterface::removeAllWatchPoints()
186 while (!watchPoints.empty()) {
191byte MSXCPUInterface::readMemSlow(
word address, EmuTime::param time)
197 for (
auto&
g : globalReads) {
200 if (
g.addr == address) [[unlikely]] {
201 g.device->globalRead(address, time);
210 if ((address == 0xFFFF) &&
isExpanded(primarySlotState[3])) [[unlikely]] {
211 return 0xFF ^ subSlotRegister[primarySlotState[3]];
213 return visibleDevices[address >> 14]->readMem(address, time);
217void MSXCPUInterface::writeMemSlow(
word address,
byte value, EmuTime::param time)
220 if ((address == 0xFFFF) &&
isExpanded(primarySlotState[3])) [[unlikely]] {
221 setSubSlot(primarySlotState[3], value);
226 visibleDevices[address>>14]->writeMem(address, value, time);
231 for (
auto&
g : globalWrites) {
234 if (
g.addr == address) [[unlikely]] {
235 g.device->globalWrite(address, value, time);
254 if (expanded[ps] == 0) {
255 for (
auto page :
xrange(4)) {
256 if (slotLayout[ps][0][page] != dummyDevice.get()) {
258 "it's already in use.");
268 std::span<
const std::unique_ptr<MSXDevice>> allowed)
const
271 if (expanded[ps] != 1)
return;
273 std::vector<MSXDevice*> inUse;
276 return (dev == dummyDevice.get()) ||
277 contains(allowed, dev, [](
const auto& d) {
return d.get(); });
280 if (!isAllowed(dev)) {
282 inUse.push_back(dev);
287 for (
auto ss :
xrange(4)) {
288 for (
auto page :
xrange(4)) {
289 MSXDevice* device = slotLayout[ps][ss][page];
291 for (
auto* dev : memDev->getDevices()) {
300 if (inUse.empty())
return;
302 auto msg =
strCat(
"Can't remove slot expander from slot ", ps,
303 " because the following devices are still inserted:");
304 for (
auto& d : inUse) {
315 std::span<const std::unique_ptr<MSXDevice>> dummy;
328 disallowReadCache [0xFF] |= SECONDARY_SLOT_BIT;
329 disallowWriteCache[0xFF] |= SECONDARY_SLOT_BIT;
331 disallowReadCache [0xFF] &= ~SECONDARY_SLOT_BIT;
332 disallowWriteCache[0xFF] &= ~SECONDARY_SLOT_BIT;
337MSXDevice*& MSXCPUInterface::getDevicePtr(
byte port,
bool isIn)
339 MSXDevice** devicePtr = isIn ? &IO_In[port] : &IO_Out[port];
341 devicePtr = &watch->getDevicePtr();
343 if (*devicePtr == delayDevice.get()) {
344 devicePtr = isIn ? &delayDevice->getInDevicePtr (port)
345 : &delayDevice->getOutDevicePtr(port);
352 MSXDevice*& devicePtr = getDevicePtr(port,
true);
353 register_IO(port,
true, devicePtr, device);
358 MSXDevice*& devicePtr = getDevicePtr(port,
true);
359 unregister_IO(devicePtr, device);
364 MSXDevice*& devicePtr = getDevicePtr(port,
false);
365 register_IO(port,
false, devicePtr, device);
370 MSXDevice*& devicePtr = getDevicePtr(port,
false);
371 unregister_IO(devicePtr, device);
374void MSXCPUInterface::register_IO(
int port,
bool isIn,
377 if (devicePtr == dummyDevice.get()) {
381 if (
auto* multi =
dynamic_cast<MSXMultiIODevice*
>(devicePtr)) {
383 multi->addDevice(device);
387 multi->addDevice(devicePtr);
388 multi->addDevice(device);
393 if (devices.getAttributeValueAsBool(
"overlap_warning",
true)) {
395 "Conflicting input port 0x",
397 " for devices ", devicePtr->
getName());
403void MSXCPUInterface::unregister_IO(MSXDevice*& devicePtr, MSXDevice* device)
405 if (
auto* multi =
dynamic_cast<MSXMultiIODevice*
>(devicePtr)) {
407 multi->removeDevice(device);
408 auto& devices = multi->getDevices();
409 if (devices.size() == 1) {
411 devicePtr = devices.front();
417 assert(devicePtr == device);
418 devicePtr = dummyDevice.get();
425 MSXDevice*& devicePtr = getDevicePtr(port,
true);
426 if (devicePtr != oldDevice) {
430 devicePtr = newDevice;
436 MSXDevice*& devicePtr = getDevicePtr(port,
false);
437 if (devicePtr != oldDevice) {
441 devicePtr = newDevice;
445[[noreturn]]
static void reportMemOverlap(
int ps,
int ss,
const MSXDevice& dev1,
const MSXDevice& dev2)
448 "Overlapping memory devices in slot ", ps,
'.', ss,
452void MSXCPUInterface::testRegisterSlot(
453 const MSXDevice& device,
int ps,
int ss,
unsigned base,
unsigned size)
455 auto page = base >> 14;
456 MSXDevice*& slot = slotLayout[ps][ss][page];
457 if (size == 0x4000) {
459 if (slot != dummyDevice.get()) {
460 reportMemOverlap(ps, ss, *slot, device);
464 if (slot == dummyDevice.get()) {
466 }
else if (
auto* multi =
dynamic_cast<MSXMultiMemDevice*
>(slot)) {
468 if (!multi->canAdd(base, size)) {
469 reportMemOverlap(ps, ss, *slot, device);
473 reportMemOverlap(ps, ss, *slot, device);
478void MSXCPUInterface::registerSlot(
479 MSXDevice& device,
int ps,
int ss,
unsigned base,
unsigned size)
481 auto page = narrow<byte>(base >> 14);
482 MSXDevice*& slot = slotLayout[ps][ss][page];
483 if (size == 0x4000) {
485 assert(slot == dummyDevice.get());
489 if (slot == dummyDevice.get()) {
491 auto* multi =
new MSXMultiMemDevice(device.getHardwareConfig());
492 multi->add(device, base, size);
494 }
else if (
auto* multi =
dynamic_cast<MSXMultiMemDevice*
>(slot)) {
496 assert(multi->canAdd(base, size));
497 multi->add(device, base, size);
507void MSXCPUInterface::unregisterSlot(
508 MSXDevice& device,
int ps,
int ss,
unsigned base,
unsigned size)
510 auto page = narrow<byte>(base >> 14);
511 MSXDevice*& slot = slotLayout[ps][ss][page];
512 if (
auto* multi =
dynamic_cast<MSXMultiMemDevice*
>(slot)) {
514 multi->remove(device, base, size);
515 if (multi->empty()) {
517 slot = dummyDevice.get();
521 assert(slot == &device);
522 slot = dummyDevice.get();
529 MSXDevice& device,
int ps,
int ss,
unsigned base_,
unsigned size_)
533 "Slot ", ps,
'.', ss,
534 " does not exist because slot is not expanded.");
542 auto partialSize = std::min(size, ((base + 0x4000) & ~0x3FFF) - base);
543 testRegisterSlot(device, ps, ss, base, partialSize);
551 auto partialSize = std::min(size, ((base + 0x4000) & ~0x3FFF) - base);
552 registerSlot(device, ps, ss, base, partialSize);
559 MSXDevice& device,
int ps,
int ss,
unsigned base,
unsigned size)
563 auto partialSize = std::min(size, ((base + 0x4000) & ~0x3FFF) - base);
564 unregisterSlot(device, ps, ss, base, partialSize);
572 globalWrites.push_back({&device, address});
580 GlobalRwInfo info = { &device, address };
583 for (
auto&
g : globalWrites) {
596 globalReads.push_back({&device, address});
604 GlobalRwInfo info = { &device, address };
607 for (
auto&
g : globalReads) {
618ALWAYS_INLINE void MSXCPUInterface::updateVisible(
byte page,
byte ps,
byte ss)
620 MSXDevice* newDevice = slotLayout[ps][ss][page];
621 if (visibleDevices[page] != newDevice) {
622 visibleDevices[page] = newDevice;
626void MSXCPUInterface::updateVisible(
byte page)
628 updateVisible(page, primarySlotState[page], secondarySlotState[page]);
634 msxcpu.
invalidateRWCache(start, size, ps, ss, disallowReadCache, disallowWriteCache);
639 msxcpu.
invalidateRCache(start, size, ps, ss, disallowReadCache, disallowWriteCache);
644 msxcpu.
invalidateWCache(start, size, ps, ss, disallowReadCache, disallowWriteCache);
650 msxcpu.
fillRWCache(start, size, rData, wData, ps, ss, disallowReadCache, disallowWriteCache);
655 msxcpu.
fillRCache(start, size, rData, ps, ss, disallowReadCache, disallowWriteCache);
660 msxcpu.
fillWCache(start, size, wData, ps, ss, disallowReadCache, disallowWriteCache);
665 for (
auto i :
xrange(
byte(4))) {
690 if (
byte ps0 = (value >> 0) & 3; primarySlotState[0] != ps0) [[unlikely]] {
691 primarySlotState[0] = ps0;
692 byte ss0 = (subSlotRegister[ps0] >> 0) & 3;
693 secondarySlotState[0] = ss0;
694 updateVisible(0, ps0, ss0);
696 if (
byte ps1 = (value >> 2) & 3; primarySlotState[1] != ps1) [[unlikely]] {
697 primarySlotState[1] = ps1;
698 byte ss1 = (subSlotRegister[ps1] >> 2) & 3;
699 secondarySlotState[1] = ss1;
700 updateVisible(1, ps1, ss1);
702 if (
byte ps2 = (value >> 4) & 3; primarySlotState[2] != ps2) [[unlikely]] {
703 primarySlotState[2] = ps2;
704 byte ss2 = (subSlotRegister[ps2] >> 4) & 3;
705 secondarySlotState[2] = ss2;
706 updateVisible(2, ps2, ss2);
708 if (
byte ps3 = (value >> 6) & 3; primarySlotState[3] != ps3) [[unlikely]] {
709 bool oldExpanded =
isExpanded(primarySlotState[3]);
711 primarySlotState[3] = ps3;
712 byte ss3 = (subSlotRegister[ps3] >> 6) & 3;
713 secondarySlotState[3] = ss3;
714 updateVisible(3, ps3, ss3);
715 if (oldExpanded != newExpanded) [[unlikely]] {
721void MSXCPUInterface::setSubSlot(
byte primSlot,
byte value)
723 subSlotRegister[primSlot] = value;
724 for (
byte page = 0; page < 4; ++page, value >>= 2) {
725 if (primSlot == primarySlotState[page]) {
726 secondarySlotState[page] = value & 3;
735 if ((address == 0xFFFF) &&
isExpanded(primarySlotState[3])) {
736 return 0xFF ^ subSlotRegister[primarySlotState[3]];
738 return visibleDevices[address >> 14]->peekMem(address, time);
744 byte primSlot = (address & 0xC0000) >> 18;
745 byte subSlot = (address & 0x30000) >> 16;
746 byte page = (address & 0x0C000) >> 14;
747 word offset = (address & 0xFFFF);
752 if ((offset == 0xFFFF) &&
isExpanded(primSlot)) {
753 return 0xFF ^ subSlotRegister[primSlot];
755 return slotLayout[primSlot][subSlot][page]->peekMem(offset, time);
761 byte primSlot = (address & 0xC0000) >> 18;
762 byte subSlot = (address & 0x30000) >> 16;
763 byte page = (address & 0x0C000) >> 14;
764 word offset = (address & 0xFFFF);
769 if ((offset == 0xFFFF) &&
isExpanded(primSlot)) {
770 return 0xFF ^ subSlotRegister[primSlot];
772 return slotLayout[primSlot][subSlot][page]->peekMem(offset, time);
779 byte primSlot = (address & 0xC0000) >> 18;
780 byte subSlot = (address & 0x30000) >> 16;
781 byte page = (address & 0x0C000) >> 14;
782 word offset = (address & 0xFFFF);
787 if ((offset == 0xFFFF) &&
isExpanded(primSlot)) {
788 setSubSlot(primSlot, value);
790 slotLayout[primSlot][subSlot][page]->writeMem(offset, value, time);
798 breakPoints.insert(it, std::move(bp));
812 it != breakPoints.end()) {
814 breakPoints.erase(it);
819 std::pair<BreakPoints::const_iterator,
820 BreakPoints::const_iterator> range)
829 for (
auto& p : bpCopy) {
830 bool remove = p.checkAndExecute(globalCliComm, interp);
835 auto condCopy = conditions;
836 for (
auto& c : condCopy) {
837 bool remove = c.checkAndExecute(globalCliComm, interp);
844static void registerIOWatch(WatchPoint& watchPoint, std::span<MSXDevice*, 256> devices)
846 auto& ioWatch = checked_cast<WatchIO&>(watchPoint);
847 unsigned beginPort = ioWatch.getBeginAddress();
848 unsigned endPort = ioWatch.getEndAddress();
849 assert(beginPort <= endPort);
850 assert(endPort < 0x100);
851 for (
unsigned port = beginPort; port <= endPort; ++port) {
852 ioWatch.getDevice(narrow_cast<byte>(port)).getDevicePtr() = devices[port];
853 devices[port] = &ioWatch.getDevice(narrow_cast<byte>(port));
860 watchPoints.push_back(watchPoint);
865 registerIOWatch(*watchPoint, IO_In);
868 registerIOWatch(*watchPoint, IO_Out);
872 updateMemWatch(type);
879static void unregisterIOWatch(
WatchPoint& watchPoint, std::span<MSXDevice*, 256> devices)
881 auto& ioWatch = checked_cast<WatchIO&>(watchPoint);
882 unsigned beginPort = ioWatch.getBeginAddress();
883 unsigned endPort = ioWatch.getEndAddress();
884 assert(beginPort <= endPort);
885 assert(endPort < 0x100);
887 for (
unsigned port = beginPort; port <= endPort; ++port) {
890 while (*prev != &ioWatch.getDevice(narrow_cast<byte>(port))) {
891 prev = &checked_cast<MSXWatchIODevice*>(*prev)->getDevicePtr();
894 *prev = checked_cast<MSXWatchIODevice*>(*prev)->getDevicePtr();
904 it !=
end(watchPoints)) {
907 watchPoints.erase(it);
912 unregisterIOWatch(*watchPoint, IO_In);
915 unregisterIOWatch(*watchPoint, IO_Out);
919 updateMemWatch(type);
930 it != watchPoints.end()) {
938 conditions.push_back(std::move(cond));
945 [](
auto& e) {
return &e; }));
952 it != conditions.end()) {
954 conditions.erase(it);
960 std::span<std::bitset<CacheLine::SIZE>,
CacheLine::NUM> watchSet =
962 for (
auto i :
xrange(CacheLine::NUM)) {
965 for (
auto& w : watchPoints) {
966 if (w->getType() == type) {
967 unsigned beginAddr = w->getBeginAddress();
968 unsigned endAddr = w->getEndAddress();
969 assert(beginAddr <= endAddr);
970 assert(endAddr < 0x10000);
971 for (
unsigned addr = beginAddr; addr <= endAddr; ++addr) {
978 if (readWatchSet [i].any()) {
979 disallowReadCache [i] |= MEMORY_WATCH_BIT;
981 disallowReadCache [i] &= ~MEMORY_WATCH_BIT;
983 if (writeWatchSet[i].any()) {
984 disallowWriteCache[i] |= MEMORY_WATCH_BIT;
986 disallowWriteCache[i] &= ~MEMORY_WATCH_BIT;
993 unsigned address,
unsigned value)
995 assert(!watchPoints.empty());
1001 TclObject(
int(address)));
1003 interp.setVariable(TclObject(
"wp_last_value"),
1004 TclObject(
int(value)));
1008 auto wpCopy = watchPoints;
1009 for (
auto& w : wpCopy) {
1010 if ((w->getBeginAddress() <= address) &&
1011 (w->getEndAddress() >= address) &&
1012 (w->getType() == type)) {
1013 bool remove = w->checkAndExecute(globalCliComm, interp);
1020 interp.unsetVariable(
"wp_last_address");
1021 interp.unsetVariable(
"wp_last_value");
1028 if (breaked)
return;
1034 breakedSetting->setReadOnlyValue(
TclObject(
"true"));
1055 breakedSetting->setReadOnlyValue(
TclObject(
"false"));
1069 breakPoints.clear();
1075 assert(0 <= ps && ps < 4);
1076 assert(0 <= ss && ss < 4);
1077 assert(0 <= page && page < 4);
1078 return slotLayout[ps][ss][page];
1083MSXCPUInterface::MemoryDebug::MemoryDebug(
MSXMotherBoard& motherBoard_)
1085 "The memory currently visible for the CPU.", 0x10000)
1089byte MSXCPUInterface::MemoryDebug::read(
unsigned address, EmuTime::param time)
1091 auto&
interface =
OUTER(MSXCPUInterface, memoryDebug);
1092 return interface.peekMem(narrow<word>(address), time);
1095void MSXCPUInterface::MemoryDebug::write(
unsigned address,
byte value,
1096 EmuTime::param time)
1099 return interface.writeMem(narrow<word>(address), value, time);
1105MSXCPUInterface::SlottedMemoryDebug::SlottedMemoryDebug(
1106 MSXMotherBoard& motherBoard_)
1107 : SimpleDebuggable(motherBoard_,
"slotted memory",
1108 "The memory in slots and subslots.", 0x10000 * 4 * 4)
1112byte MSXCPUInterface::SlottedMemoryDebug::read(
unsigned address, EmuTime::param time)
1115 return interface.peekSlottedMem(address, time);
1118void MSXCPUInterface::SlottedMemoryDebug::write(
unsigned address,
byte value,
1119 EmuTime::param time)
1122 return interface.writeSlottedMem(address, value, time);
1128static unsigned getSlot(
1129 Interpreter& interp,
const TclObject& token,
const std::string& itemName)
1131 unsigned slot = token.getInt(interp);
1133 throw CommandException(itemName,
" must be in range 0..3");
1138MSXCPUInterface::SlotInfo::SlotInfo(
1139 InfoCommand& machineInfoCommand)
1140 : InfoTopic(machineInfoCommand,
"slot")
1144void MSXCPUInterface::SlotInfo::execute(std::span<const TclObject> tokens,
1145 TclObject& result)
const
1147 checkNumArgs(tokens, 5, Prefix{2},
"primary secondary page");
1148 auto& interp = getInterpreter();
1149 unsigned ps = getSlot(interp, tokens[2],
"Primary slot");
1150 unsigned ss = getSlot(interp, tokens[3],
"Secondary slot");
1151 unsigned page = getSlot(interp, tokens[4],
"Page");
1153 if (!interface.isExpanded(narrow<int>(ps))) {
1156 interface.slotLayout[ps][ss][page]->getNameList(result);
1159std::string MSXCPUInterface::SlotInfo::help(std::span<const TclObject> )
const
1161 return "Retrieve name of the device inserted in given "
1162 "primary slot / secondary slot / page.";
1168MSXCPUInterface::SubSlottedInfo::SubSlottedInfo(
1169 InfoCommand& machineInfoCommand)
1170 : InfoTopic(machineInfoCommand,
"issubslotted")
1174void MSXCPUInterface::SubSlottedInfo::execute(std::span<const TclObject> tokens,
1175 TclObject& result)
const
1177 checkNumArgs(tokens, 3,
"primary");
1179 result = interface.isExpanded(narrow<int>(
1180 getSlot(getInterpreter(), tokens[2],
"Slot")));
1183std::string MSXCPUInterface::SubSlottedInfo::help(
1184 std::span<const TclObject> )
const
1186 return "Indicates whether a certain primary slot is expanded.";
1192MSXCPUInterface::ExternalSlotInfo::ExternalSlotInfo(
1193 InfoCommand& machineInfoCommand)
1194 : InfoTopic(machineInfoCommand,
"isexternalslot")
1198void MSXCPUInterface::ExternalSlotInfo::execute(
1199 std::span<const TclObject> tokens, TclObject& result)
const
1201 checkNumArgs(tokens, Between{3, 4},
"primary ?secondary?");
1204 auto& interp = getInterpreter();
1205 switch (tokens.size()) {
1207 ss = narrow<int>(getSlot(interp, tokens[3],
"Secondary slot"));
1210 ps = narrow<int>(getSlot(interp, tokens[2],
"Primary slot"));
1214 auto& manager = interface.motherBoard.getSlotManager();
1215 result = manager.isExternalSlot(ps, ss,
true);
1218std::string MSXCPUInterface::ExternalSlotInfo::help(
1219 std::span<const TclObject> )
const
1221 return "Indicates whether a certain slot is external or internal.";
1227MSXCPUInterface::IODebug::IODebug(MSXMotherBoard& motherBoard_)
1228 : SimpleDebuggable(motherBoard_,
"ioports",
"IO ports.", 0x100)
1232byte MSXCPUInterface::IODebug::read(
unsigned address, EmuTime::param time)
1235 return interface.IO_In[address & 0xFF]->peekIO(narrow<word>(address), time);
1238void MSXCPUInterface::IODebug::write(
unsigned address,
byte value, EmuTime::param time)
1241 interface.writeIO(
word(address), value, time);
1247MSXCPUInterface::IOInfo::IOInfo(InfoCommand& machineInfoCommand,
const char* name_)
1248 : InfoTopic(machineInfoCommand, name_)
1252void MSXCPUInterface::IOInfo::helper(
1253 std::span<const TclObject> tokens, TclObject& result, std::span<MSXDevice*, 256> devices)
const
1255 checkNumArgs(tokens, 3,
"port");
1256 unsigned port = tokens[2].getInt(getInterpreter());
1258 throw CommandException(
"Port must be in range 0..255");
1260 devices[port]->getNameList(result);
1262void MSXCPUInterface::IInfo::execute(
1263 std::span<const TclObject> tokens, TclObject& result)
const
1266 helper(tokens, result, interface.IO_In);
1268void MSXCPUInterface::OInfo::execute(
1269 std::span<const TclObject> tokens, TclObject& result)
const
1272 helper(tokens, result, interface.IO_Out);
1275std::string MSXCPUInterface::IOInfo::help(std::span<const TclObject> )
const
1277 return "Return the name of the device connected to the given IO port.";
1281template<
typename Archive>
1288 if constexpr (!Archive::IS_LOADER) {
1289 for (
auto i :
xrange(4)) {
1290 prim |=
byte(primarySlotState[i] << (2 * i));
1293 ar.serialize(
"primarySlots", prim,
1294 "subSlotRegs", subSlotRegister);
1295 if constexpr (Archive::IS_LOADER) {
1297 for (
auto i :
xrange(
byte(4))) {
1298 setSubSlot(i, subSlotRegister[i]);
1303 ar.serialize(
"vdpDelay", *delayDevice);
void tick(CacheLineCounters e) const
Base class for CPU breakpoints.
virtual void update(UpdateType type, std::string_view name, std::string_view value)=0
void printWarning(std::string_view message)
General debugger condition Like breakpoints, but not tied to a specific address.
static std::unique_ptr< VDPIODelay > createVDPIODelay(const HardwareConfig &hwConf, MSXCPUInterface &cpuInterface)
static constexpr EmuDuration epsilon()
void distributeEvent(Event &&event)
Schedule the given event for delivery.
byte parseSlotMap() const
Parses a slot mapping.
const XMLElement & getDevicesElem() const
void setVariable(const TclObject &name, const TclObject &value)
void register_IO_Out(byte port, MSXDevice *device)
Devices can register their Out ports.
void setWatchPoint(const std::shared_ptr< WatchPoint > &watchPoint)
void invalidateRWCache(word start, unsigned size, int ps, int ss)
MSXCPUInterface(MSXMotherBoard &motherBoard)
void insertBreakPoint(BreakPoint bp)
void register_IO_In(byte port, MSXDevice *device)
Devices can register their In ports.
MSXDevice * getMSXDevice(int ps, int ss, int page)
void fillWCache(unsigned start, unsigned size, byte *wData, int ps, int ss)
void unregister_IO_In(byte port, MSXDevice *device)
bool replace_IO_Out(byte port, MSXDevice *oldDevice, MSXDevice *newDevice)
void changeExpanded(bool newExpanded)
void unregisterMemDevice(MSXDevice &device, int ps, int ss, unsigned base, unsigned size)
void removeCondition(const DebugCondition &cond)
byte peekMem(word address, EmuTime::param time) const
Peek memory location.
byte readIRQVector() const
CPU uses this method to read 'extra' data from the data bus used in interrupt routines.
void testUnsetExpanded(int ps, std::span< const std::unique_ptr< MSXDevice > > allowed) const
void writeSlottedMem(unsigned address, byte value, EmuTime::param time)
void setPrimarySlots(byte value)
void invalidateRCache(word start, unsigned size, int ps, int ss)
void unregisterGlobalWrite(MSXDevice &device, word address)
void unregisterGlobalRead(MSXDevice &device, word address)
byte peekSlottedMem(unsigned address, EmuTime::param time) const
void removeWatchPoint(std::shared_ptr< WatchPoint > watchPoint)
void fillRWCache(unsigned start, unsigned size, const byte *rData, byte *wData, int ps, int ss)
void reset()
Reset (the slot state)
void setCondition(DebugCondition cond)
void invalidateWCache(word start, unsigned size, int ps, int ss)
void unsetExpanded(int ps)
bool isFastForward() const
bool checkBreakPoints(unsigned pc)
void serialize(Archive &ar, unsigned version)
void registerGlobalRead(MSXDevice &device, word address)
(Un)register global read.
byte readSlottedMem(unsigned address, EmuTime::param time)
void registerMemDevice(MSXDevice &device, int ps, int ss, unsigned base, unsigned size)
Devices can register themself in the MSX slot structure.
void removeBreakPoint(const BreakPoint &bp)
void unregister_IO_Out(byte port, MSXDevice *device)
void registerGlobalWrite(MSXDevice &device, word address)
(Un)register global writes.
std::vector< BreakPoint > BreakPoints
bool replace_IO_In(byte port, MSXDevice *oldDevice, MSXDevice *newDevice)
These methods replace a previously registered device with a new one.
void fillRCache(unsigned start, unsigned size, const byte *rData, int ps, int ss)
bool isExpanded(int ps) const
void invalidateAllSlotsRWCache(word start, unsigned size)
Invalidate the CPU its cache for the interval [start, start + size) For example MSXMemoryMapper and M...
void fillWCache(unsigned start, unsigned size, byte *wData, int ps, int ss, std::span< const byte, 256 > disallowRead, std::span< const byte, 256 > disallowWrite)
void updateVisiblePage(byte page, byte primarySlot, byte secondarySlot)
Inform CPU of bank switch.
void fillRCache(unsigned start, unsigned size, const byte *rData, int ps, int ss, std::span< const byte, 256 > disallowRead, std::span< const byte, 256 > disallowWrite)
void fillRWCache(unsigned start, unsigned size, const byte *rData, byte *wData, int ps, int ss, std::span< const byte, 256 > disallowRead, std::span< const byte, 256 > disallowWrite)
Fill the read and write cache lines for a specific slot with the specified value.
void invalidateRCache(unsigned start, unsigned size, int ps, int ss, std::span< const byte, 256 > disallowRead, std::span< const byte, 256 > disallowWrite)
void exitCPULoopSync()
See CPUCore::exitCPULoopSync()
void invalidateRWCache(unsigned start, unsigned size, int ps, int ss, std::span< const byte, 256 > disallowRead, std::span< const byte, 256 > disallowWrite)
Similar to the method above, but only invalidates one specific slot.
void setInterface(MSXCPUInterface *interface)
void invalidateWCache(unsigned start, unsigned size, int ps, int ss, std::span< const byte, 256 > disallowRead, std::span< const byte, 256 > disallowWrite)
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
const HardwareConfig & getHardwareConfig() const
Returns the hardwareconfig this device belongs to.
virtual const std::string & getName() const
Returns a human-readable name for this device.
const HardwareConfig * getMachineConfig() const
Scheduler & getScheduler()
StateChangeDistributor & getStateChangeDistributor()
byte readIRQVector() const
Contains the main loop of openMSX.
CommandController & getCommandController()
GlobalCliComm & getGlobalCliComm()
Interpreter & getInterpreter()
EventDistributor & getEventDistributor()
void schedule(EmuTime::param limit)
Schedule till a certain moment in time.
auto tempBlockNewEventsDuringReplay()
Base class for CPU breakpoints.
This file implemented 3 utility functions:
uint8_t byte
8 bit unsigned integer
std::ostream & operator<<(std::ostream &os, EnumTypeName< CacheLineCounters >)
uint16_t word
16 bit unsigned integer
constexpr void fill(ForwardRange &&range, const T &value)
auto remove(ForwardRange &&range, const T &value)
auto find(InputRange &&range, const T &value)
auto upper_bound(ForwardRange &&range, const T &value, Compare comp={}, Proj proj={})
auto equal_range(ForwardRange &&range, const T &value, Compare comp={})
#define OUTER(type, member)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
ITER find_unguarded(ITER first, ITER last, const VAL &val, Proj proj={})
Faster alternative to 'find' when it's guaranteed that the value will be found (if not the behavior i...
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
auto rfind_unguarded(RANGE &range, const VAL &val, Proj proj={})
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
TemporaryString tmpStrCat(Ts &&... ts)
void strAppend(std::string &result, Ts &&...ts)
constexpr auto xrange(T e)
constexpr auto end(const zstring_view &x)