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<const MSXDevice*> inUse;
275 auto isAllowed = [&](
const MSXDevice* dev) {
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 const MSXDevice* device = slotLayout[ps][ss][page];
291 for (
const 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 (
const 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);
409void MSXCPUInterface::register_IO(
int port,
bool isIn,
412 if (devicePtr == dummyDevice.get()) {
416 if (
auto* multi =
dynamic_cast<MSXMultiIODevice*
>(devicePtr)) {
418 multi->addDevice(device);
422 multi->addDevice(devicePtr);
423 multi->addDevice(device);
428 if (devices.getAttributeValueAsBool(
"overlap_warning",
true)) {
430 "Conflicting input port 0x",
432 " for devices ", devicePtr->
getName());
438void MSXCPUInterface::unregister_IO(MSXDevice*& devicePtr, MSXDevice* device)
440 if (
auto* multi =
dynamic_cast<MSXMultiIODevice*
>(devicePtr)) {
442 multi->removeDevice(device);
443 auto& devices = multi->getDevices();
444 if (devices.size() == 1) {
446 devicePtr = devices.front();
452 assert(devicePtr == device);
453 devicePtr = dummyDevice.get();
460 MSXDevice*& devicePtr = getDevicePtr(port,
true);
461 if (devicePtr != oldDevice) {
465 devicePtr = newDevice;
471 MSXDevice*& devicePtr = getDevicePtr(port,
false);
472 if (devicePtr != oldDevice) {
476 devicePtr = newDevice;
480[[noreturn]]
static void reportMemOverlap(
int ps,
int ss,
const MSXDevice& dev1,
const MSXDevice& dev2)
483 "Overlapping memory devices in slot ", ps,
'.', ss,
487void MSXCPUInterface::testRegisterSlot(
488 const MSXDevice& device,
int ps,
int ss,
unsigned base,
unsigned size)
490 auto page = base >> 14;
491 MSXDevice*& slot = slotLayout[ps][ss][page];
492 if (size == 0x4000) {
494 if (slot != dummyDevice.get()) {
495 reportMemOverlap(ps, ss, *slot, device);
499 if (slot == dummyDevice.get()) {
501 }
else if (
auto* multi =
dynamic_cast<MSXMultiMemDevice*
>(slot)) {
503 if (!multi->canAdd(base, size)) {
504 reportMemOverlap(ps, ss, *slot, device);
508 reportMemOverlap(ps, ss, *slot, device);
513void MSXCPUInterface::registerSlot(
514 MSXDevice& device,
int ps,
int ss,
unsigned base,
unsigned size)
516 auto page = narrow<byte>(base >> 14);
517 MSXDevice*& slot = slotLayout[ps][ss][page];
518 if (size == 0x4000) {
520 assert(slot == dummyDevice.get());
524 if (slot == dummyDevice.get()) {
526 auto* multi =
new MSXMultiMemDevice(device.getHardwareConfig());
527 multi->add(device, base, size);
529 }
else if (
auto* multi =
dynamic_cast<MSXMultiMemDevice*
>(slot)) {
531 assert(multi->canAdd(base, size));
532 multi->add(device, base, size);
542void MSXCPUInterface::unregisterSlot(
543 MSXDevice& device,
int ps,
int ss,
unsigned base,
unsigned size)
545 auto page = narrow<byte>(base >> 14);
546 MSXDevice*& slot = slotLayout[ps][ss][page];
547 if (
auto* multi =
dynamic_cast<MSXMultiMemDevice*
>(slot)) {
549 multi->remove(device, base, size);
550 if (multi->empty()) {
552 slot = dummyDevice.get();
556 assert(slot == &device);
557 slot = dummyDevice.get();
564 MSXDevice& device,
int ps,
int ss,
unsigned base_,
unsigned size_)
568 "Slot ", ps,
'.', ss,
569 " does not exist because slot is not expanded.");
577 auto partialSize = std::min(size, ((base + 0x4000) & ~0x3FFF) - base);
578 testRegisterSlot(device, ps, ss, base, partialSize);
586 auto partialSize = std::min(size, ((base + 0x4000) & ~0x3FFF) - base);
587 registerSlot(device, ps, ss, base, partialSize);
594 MSXDevice& device,
int ps,
int ss,
unsigned base,
unsigned size)
598 auto partialSize = std::min(size, ((base + 0x4000) & ~0x3FFF) - base);
599 unregisterSlot(device, ps, ss, base, partialSize);
607 globalWrites.push_back({&device, address});
615 GlobalRwInfo info = { &device, address };
618 for (
const auto&
g : globalWrites) {
631 globalReads.push_back({&device, address});
639 GlobalRwInfo info = { &device, address };
642 for (
const auto&
g : globalReads) {
653ALWAYS_INLINE void MSXCPUInterface::updateVisible(
byte page,
byte ps,
byte ss)
655 MSXDevice* newDevice = slotLayout[ps][ss][page];
656 if (visibleDevices[page] != newDevice) {
657 visibleDevices[page] = newDevice;
661void MSXCPUInterface::updateVisible(
byte page)
663 updateVisible(page, primarySlotState[page], secondarySlotState[page]);
669 msxcpu.
invalidateRWCache(start, size, ps, ss, disallowReadCache, disallowWriteCache);
674 msxcpu.
invalidateRCache(start, size, ps, ss, disallowReadCache, disallowWriteCache);
679 msxcpu.
invalidateWCache(start, size, ps, ss, disallowReadCache, disallowWriteCache);
685 msxcpu.
fillRWCache(start, size, rData, wData, ps, ss, disallowReadCache, disallowWriteCache);
690 msxcpu.
fillRCache(start, size, rData, ps, ss, disallowReadCache, disallowWriteCache);
695 msxcpu.
fillWCache(start, size, wData, ps, ss, disallowReadCache, disallowWriteCache);
700 for (
auto i :
xrange(
byte(4))) {
725 if (
byte ps0 = (value >> 0) & 3; primarySlotState[0] != ps0) [[unlikely]] {
726 primarySlotState[0] = ps0;
727 byte ss0 = (subSlotRegister[ps0] >> 0) & 3;
728 secondarySlotState[0] = ss0;
729 updateVisible(0, ps0, ss0);
731 if (
byte ps1 = (value >> 2) & 3; primarySlotState[1] != ps1) [[unlikely]] {
732 primarySlotState[1] = ps1;
733 byte ss1 = (subSlotRegister[ps1] >> 2) & 3;
734 secondarySlotState[1] = ss1;
735 updateVisible(1, ps1, ss1);
737 if (
byte ps2 = (value >> 4) & 3; primarySlotState[2] != ps2) [[unlikely]] {
738 primarySlotState[2] = ps2;
739 byte ss2 = (subSlotRegister[ps2] >> 4) & 3;
740 secondarySlotState[2] = ss2;
741 updateVisible(2, ps2, ss2);
743 if (
byte ps3 = (value >> 6) & 3; primarySlotState[3] != ps3) [[unlikely]] {
744 bool oldExpanded =
isExpanded(primarySlotState[3]);
746 primarySlotState[3] = ps3;
747 byte ss3 = (subSlotRegister[ps3] >> 6) & 3;
748 secondarySlotState[3] = ss3;
749 updateVisible(3, ps3, ss3);
750 if (oldExpanded != newExpanded) [[unlikely]] {
756void MSXCPUInterface::setSubSlot(
byte primSlot,
byte value)
758 subSlotRegister[primSlot] = value;
759 for (
byte page = 0; page < 4; ++page, value >>= 2) {
760 if (primSlot == primarySlotState[page]) {
761 secondarySlotState[page] = value & 3;
770 if ((address == 0xFFFF) &&
isExpanded(primarySlotState[3])) {
771 return 0xFF ^ subSlotRegister[primarySlotState[3]];
773 return visibleDevices[address >> 14]->peekMem(address, 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 return 0xFF ^ subSlotRegister[primSlot];
790 return slotLayout[primSlot][subSlot][page]->peekMem(offset, time);
796 byte primSlot = (address & 0xC0000) >> 18;
797 byte subSlot = (address & 0x30000) >> 16;
798 byte page = (address & 0x0C000) >> 14;
799 word offset = (address & 0xFFFF);
804 if ((offset == 0xFFFF) &&
isExpanded(primSlot)) {
805 return 0xFF ^ subSlotRegister[primSlot];
807 return slotLayout[primSlot][subSlot][page]->peekMem(offset, time);
814 byte primSlot = (address & 0xC0000) >> 18;
815 byte subSlot = (address & 0x30000) >> 16;
816 byte page = (address & 0x0C000) >> 14;
817 word offset = (address & 0xFFFF);
822 if ((offset == 0xFFFF) &&
isExpanded(primSlot)) {
823 setSubSlot(primSlot, value);
825 slotLayout[primSlot][subSlot][page]->writeMem(offset, value, time);
833 breakPoints.insert(it, std::move(bp));
847 it != breakPoints.end()) {
849 breakPoints.erase(it);
854 std::pair<BreakPoints::const_iterator,
855 BreakPoints::const_iterator> range)
864 for (
auto& p : bpCopy) {
865 bool remove = p.checkAndExecute(globalCliComm, interp);
870 auto condCopy = conditions;
871 for (
auto& c : condCopy) {
872 bool remove = c.checkAndExecute(globalCliComm, interp);
879static void registerIOWatch(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);
886 for (
unsigned port = beginPort; port <= endPort; ++port) {
887 ioWatch.getDevice(narrow_cast<byte>(port)).getDevicePtr() = devices[port];
888 devices[port] = &ioWatch.getDevice(narrow_cast<byte>(port));
895 watchPoints.push_back(watchPoint);
900 registerIOWatch(*watchPoint, IO_In);
903 registerIOWatch(*watchPoint, IO_Out);
907 updateMemWatch(type);
914static void unregisterIOWatch(
WatchPoint& watchPoint, std::span<MSXDevice*, 256> devices)
916 auto& ioWatch = checked_cast<WatchIO&>(watchPoint);
917 unsigned beginPort = ioWatch.getBeginAddress();
918 unsigned endPort = ioWatch.getEndAddress();
919 assert(beginPort <= endPort);
920 assert(endPort < 0x100);
922 for (
unsigned port = beginPort; port <= endPort; ++port) {
925 while (*prev != &ioWatch.getDevice(narrow_cast<byte>(port))) {
926 prev = &checked_cast<MSXWatchIODevice*>(*prev)->getDevicePtr();
929 *prev = checked_cast<MSXWatchIODevice*>(*prev)->getDevicePtr();
939 it !=
end(watchPoints)) {
942 watchPoints.erase(it);
947 unregisterIOWatch(*watchPoint, IO_In);
950 unregisterIOWatch(*watchPoint, IO_Out);
954 updateMemWatch(type);
965 it != watchPoints.end()) {
973 conditions.push_back(std::move(cond));
980 [](
auto& e) {
return &e; }));
987 it != conditions.end()) {
989 conditions.erase(it);
995 std::span<std::bitset<CacheLine::SIZE>,
CacheLine::NUM> watchSet =
997 for (
auto i :
xrange(CacheLine::NUM)) {
1000 for (
const auto& w : watchPoints) {
1001 if (w->getType() == type) {
1002 unsigned beginAddr = w->getBeginAddress();
1003 unsigned endAddr = w->getEndAddress();
1004 assert(beginAddr <= endAddr);
1005 assert(endAddr < 0x10000);
1006 for (
unsigned addr = beginAddr; addr <= endAddr; ++addr) {
1013 if (readWatchSet [i].any()) {
1014 disallowReadCache [i] |= MEMORY_WATCH_BIT;
1016 disallowReadCache [i] &= ~MEMORY_WATCH_BIT;
1018 if (writeWatchSet[i].any()) {
1019 disallowWriteCache[i] |= MEMORY_WATCH_BIT;
1021 disallowWriteCache[i] &= ~MEMORY_WATCH_BIT;
1028 unsigned address,
unsigned value)
1030 assert(!watchPoints.empty());
1036 TclObject(
int(address)));
1038 interp.setVariable(TclObject(
"wp_last_value"),
1039 TclObject(
int(value)));
1043 for(
auto wpCopy = watchPoints;
auto& w : wpCopy) {
1044 if ((w->getBeginAddress() <= address) &&
1045 (w->getEndAddress() >= address) &&
1046 (w->getType() == type)) {
1047 bool remove = w->checkAndExecute(globalCliComm, interp);
1054 interp.unsetVariable(
"wp_last_address");
1055 interp.unsetVariable(
"wp_last_value");
1062 if (breaked)
return;
1068 breakedSetting->setReadOnlyValue(
TclObject(
"true"));
1089 breakedSetting->setReadOnlyValue(
TclObject(
"false"));
1103 breakPoints.clear();
1109 assert(0 <= ps && ps < 4);
1110 assert(0 <= ss && ss < 4);
1111 assert(0 <= page && page < 4);
1112 return slotLayout[ps][ss][page];
1117MSXCPUInterface::MemoryDebug::MemoryDebug(
MSXMotherBoard& motherBoard_)
1119 "The memory currently visible for the CPU.", 0x10000)
1123byte MSXCPUInterface::MemoryDebug::read(
unsigned address, EmuTime::param time)
1125 const auto&
interface =
OUTER(MSXCPUInterface, memoryDebug);
1126 return interface.peekMem(narrow<word>(address), time);
1129void MSXCPUInterface::MemoryDebug::write(
unsigned address,
byte value,
1130 EmuTime::param time)
1133 return interface.writeMem(narrow<word>(address), value, time);
1139MSXCPUInterface::SlottedMemoryDebug::SlottedMemoryDebug(
1140 MSXMotherBoard& motherBoard_)
1141 : SimpleDebuggable(motherBoard_,
"slotted memory",
1142 "The memory in slots and subslots.", 0x10000 * 4 * 4)
1146byte MSXCPUInterface::SlottedMemoryDebug::read(
unsigned address, EmuTime::param time)
1149 return interface.peekSlottedMem(address, time);
1152void MSXCPUInterface::SlottedMemoryDebug::write(
unsigned address,
byte value,
1153 EmuTime::param time)
1156 return interface.writeSlottedMem(address, value, time);
1162static unsigned getSlot(
1163 Interpreter& interp,
const TclObject& token,
const std::string& itemName)
1165 unsigned slot = token.getInt(interp);
1167 throw CommandException(itemName,
" must be in range 0..3");
1172MSXCPUInterface::SlotInfo::SlotInfo(
1173 InfoCommand& machineInfoCommand)
1174 : InfoTopic(machineInfoCommand,
"slot")
1178void MSXCPUInterface::SlotInfo::execute(std::span<const TclObject> tokens,
1179 TclObject& result)
const
1181 checkNumArgs(tokens, 5, Prefix{2},
"primary secondary page");
1182 auto& interp = getInterpreter();
1183 unsigned ps = getSlot(interp, tokens[2],
"Primary slot");
1184 unsigned ss = getSlot(interp, tokens[3],
"Secondary slot");
1185 unsigned page = getSlot(interp, tokens[4],
"Page");
1187 if (!interface.isExpanded(narrow<int>(ps))) {
1190 interface.slotLayout[ps][ss][page]->getNameList(result);
1193std::string MSXCPUInterface::SlotInfo::help(std::span<const TclObject> )
const
1195 return "Retrieve name of the device inserted in given "
1196 "primary slot / secondary slot / page.";
1202MSXCPUInterface::SubSlottedInfo::SubSlottedInfo(
1203 InfoCommand& machineInfoCommand)
1204 : InfoTopic(machineInfoCommand,
"issubslotted")
1208void MSXCPUInterface::SubSlottedInfo::execute(std::span<const TclObject> tokens,
1209 TclObject& result)
const
1211 checkNumArgs(tokens, 3,
"primary");
1213 result = interface.isExpanded(narrow<int>(
1214 getSlot(getInterpreter(), tokens[2],
"Slot")));
1217std::string MSXCPUInterface::SubSlottedInfo::help(
1218 std::span<const TclObject> )
const
1220 return "Indicates whether a certain primary slot is expanded.";
1226MSXCPUInterface::ExternalSlotInfo::ExternalSlotInfo(
1227 InfoCommand& machineInfoCommand)
1228 : InfoTopic(machineInfoCommand,
"isexternalslot")
1232void MSXCPUInterface::ExternalSlotInfo::execute(
1233 std::span<const TclObject> tokens, TclObject& result)
const
1235 checkNumArgs(tokens, Between{3, 4},
"primary ?secondary?");
1238 auto& interp = getInterpreter();
1239 switch (tokens.size()) {
1241 ss = narrow<int>(getSlot(interp, tokens[3],
"Secondary slot"));
1244 ps = narrow<int>(getSlot(interp, tokens[2],
"Primary slot"));
1248 const auto& manager = interface.motherBoard.getSlotManager();
1249 result = manager.isExternalSlot(ps, ss,
true);
1252std::string MSXCPUInterface::ExternalSlotInfo::help(
1253 std::span<const TclObject> )
const
1255 return "Indicates whether a certain slot is external or internal.";
1261MSXCPUInterface::IODebug::IODebug(MSXMotherBoard& motherBoard_)
1262 : SimpleDebuggable(motherBoard_,
"ioports",
"IO ports.", 0x100)
1266byte MSXCPUInterface::IODebug::read(
unsigned address, EmuTime::param time)
1269 return interface.IO_In[address & 0xFF]->peekIO(narrow<word>(address), time);
1272void MSXCPUInterface::IODebug::write(
unsigned address,
byte value, EmuTime::param time)
1275 interface.writeIO(
word(address), value, time);
1281MSXCPUInterface::IOInfo::IOInfo(InfoCommand& machineInfoCommand,
const char* name_)
1282 : InfoTopic(machineInfoCommand, name_)
1286void MSXCPUInterface::IOInfo::helper(
1287 std::span<const TclObject> tokens, TclObject& result, std::span<MSXDevice*, 256> devices)
const
1289 checkNumArgs(tokens, 3,
"port");
1290 unsigned port = tokens[2].getInt(getInterpreter());
1292 throw CommandException(
"Port must be in range 0..255");
1294 devices[port]->getNameList(result);
1296void MSXCPUInterface::IInfo::execute(
1297 std::span<const TclObject> tokens, TclObject& result)
const
1300 helper(tokens, result, interface.IO_In);
1302void MSXCPUInterface::OInfo::execute(
1303 std::span<const TclObject> tokens, TclObject& result)
const
1306 helper(tokens, result, interface.IO_Out);
1309std::string MSXCPUInterface::IOInfo::help(std::span<const TclObject> )
const
1311 return "Return the name of the device connected to the given IO port.";
1315template<
typename Archive>
1322 if constexpr (!Archive::IS_LOADER) {
1323 for (
auto i :
xrange(4)) {
1324 prim |=
byte(primarySlotState[i] << (2 * i));
1327 ar.serialize(
"primarySlots", prim,
1328 "subSlotRegs", subSlotRegister);
1329 if constexpr (Archive::IS_LOADER) {
1331 for (
auto i :
xrange(
byte(4))) {
1332 setSubSlot(i, subSlotRegister[i]);
1337 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 unregister_IO_In_range(byte port, unsigned num, MSXDevice *device)
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 unregister_IO_Out_range(byte port, unsigned num, MSXDevice *device)
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 unregister_IO_InOut_range(byte port, unsigned num, MSXDevice *device)
void unregisterMemDevice(MSXDevice &device, int ps, int ss, unsigned base, unsigned size)
void register_IO_In_range(byte port, unsigned num, MSXDevice *device)
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 unregister_IO_InOut(byte port, MSXDevice *device)
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
void register_IO_InOut(byte port, MSXDevice *device)
Convenience methods for {un}register_IO_{In,Out}.
bool checkBreakPoints(unsigned pc)
void serialize(Archive &ar, unsigned version)
void register_IO_Out_range(byte port, unsigned num, MSXDevice *device)
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 register_IO_InOut_range(byte port, unsigned num, MSXDevice *device)
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)