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);
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 (
const auto&
g : globalWrites) {
596 globalReads.push_back({&device, address});
604 GlobalRwInfo info = { &device, address };
607 for (
const 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 (
const 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 for(
auto wpCopy = watchPoints;
auto& w : wpCopy) {
1009 if ((w->getBeginAddress() <= address) &&
1010 (w->getEndAddress() >= address) &&
1011 (w->getType() == type)) {
1012 bool remove = w->checkAndExecute(globalCliComm, interp);
1019 interp.unsetVariable(
"wp_last_address");
1020 interp.unsetVariable(
"wp_last_value");
1027 if (breaked)
return;
1033 breakedSetting->setReadOnlyValue(
TclObject(
"true"));
1054 breakedSetting->setReadOnlyValue(
TclObject(
"false"));
1068 breakPoints.clear();
1074 assert(0 <= ps && ps < 4);
1075 assert(0 <= ss && ss < 4);
1076 assert(0 <= page && page < 4);
1077 return slotLayout[ps][ss][page];
1082MSXCPUInterface::MemoryDebug::MemoryDebug(
MSXMotherBoard& motherBoard_)
1084 "The memory currently visible for the CPU.", 0x10000)
1088byte MSXCPUInterface::MemoryDebug::read(
unsigned address, EmuTime::param time)
1090 const auto&
interface =
OUTER(MSXCPUInterface, memoryDebug);
1091 return interface.peekMem(narrow<word>(address), time);
1094void MSXCPUInterface::MemoryDebug::write(
unsigned address,
byte value,
1095 EmuTime::param time)
1098 return interface.writeMem(narrow<word>(address), value, time);
1104MSXCPUInterface::SlottedMemoryDebug::SlottedMemoryDebug(
1105 MSXMotherBoard& motherBoard_)
1106 : SimpleDebuggable(motherBoard_,
"slotted memory",
1107 "The memory in slots and subslots.", 0x10000 * 4 * 4)
1111byte MSXCPUInterface::SlottedMemoryDebug::read(
unsigned address, EmuTime::param time)
1114 return interface.peekSlottedMem(address, time);
1117void MSXCPUInterface::SlottedMemoryDebug::write(
unsigned address,
byte value,
1118 EmuTime::param time)
1121 return interface.writeSlottedMem(address, value, time);
1127static unsigned getSlot(
1128 Interpreter& interp,
const TclObject& token,
const std::string& itemName)
1130 unsigned slot = token.getInt(interp);
1132 throw CommandException(itemName,
" must be in range 0..3");
1137MSXCPUInterface::SlotInfo::SlotInfo(
1138 InfoCommand& machineInfoCommand)
1139 : InfoTopic(machineInfoCommand,
"slot")
1143void MSXCPUInterface::SlotInfo::execute(std::span<const TclObject> tokens,
1144 TclObject& result)
const
1146 checkNumArgs(tokens, 5, Prefix{2},
"primary secondary page");
1147 auto& interp = getInterpreter();
1148 unsigned ps = getSlot(interp, tokens[2],
"Primary slot");
1149 unsigned ss = getSlot(interp, tokens[3],
"Secondary slot");
1150 unsigned page = getSlot(interp, tokens[4],
"Page");
1152 if (!interface.isExpanded(narrow<int>(ps))) {
1155 interface.slotLayout[ps][ss][page]->getNameList(result);
1158std::string MSXCPUInterface::SlotInfo::help(std::span<const TclObject> )
const
1160 return "Retrieve name of the device inserted in given "
1161 "primary slot / secondary slot / page.";
1167MSXCPUInterface::SubSlottedInfo::SubSlottedInfo(
1168 InfoCommand& machineInfoCommand)
1169 : InfoTopic(machineInfoCommand,
"issubslotted")
1173void MSXCPUInterface::SubSlottedInfo::execute(std::span<const TclObject> tokens,
1174 TclObject& result)
const
1176 checkNumArgs(tokens, 3,
"primary");
1178 result = interface.isExpanded(narrow<int>(
1179 getSlot(getInterpreter(), tokens[2],
"Slot")));
1182std::string MSXCPUInterface::SubSlottedInfo::help(
1183 std::span<const TclObject> )
const
1185 return "Indicates whether a certain primary slot is expanded.";
1191MSXCPUInterface::ExternalSlotInfo::ExternalSlotInfo(
1192 InfoCommand& machineInfoCommand)
1193 : InfoTopic(machineInfoCommand,
"isexternalslot")
1197void MSXCPUInterface::ExternalSlotInfo::execute(
1198 std::span<const TclObject> tokens, TclObject& result)
const
1200 checkNumArgs(tokens, Between{3, 4},
"primary ?secondary?");
1203 auto& interp = getInterpreter();
1204 switch (tokens.size()) {
1206 ss = narrow<int>(getSlot(interp, tokens[3],
"Secondary slot"));
1209 ps = narrow<int>(getSlot(interp, tokens[2],
"Primary slot"));
1213 const auto& manager = interface.motherBoard.getSlotManager();
1214 result = manager.isExternalSlot(ps, ss,
true);
1217std::string MSXCPUInterface::ExternalSlotInfo::help(
1218 std::span<const TclObject> )
const
1220 return "Indicates whether a certain slot is external or internal.";
1226MSXCPUInterface::IODebug::IODebug(MSXMotherBoard& motherBoard_)
1227 : SimpleDebuggable(motherBoard_,
"ioports",
"IO ports.", 0x100)
1231byte MSXCPUInterface::IODebug::read(
unsigned address, EmuTime::param time)
1234 return interface.IO_In[address & 0xFF]->peekIO(narrow<word>(address), time);
1237void MSXCPUInterface::IODebug::write(
unsigned address,
byte value, EmuTime::param time)
1240 interface.writeIO(
word(address), value, time);
1246MSXCPUInterface::IOInfo::IOInfo(InfoCommand& machineInfoCommand,
const char* name_)
1247 : InfoTopic(machineInfoCommand, name_)
1251void MSXCPUInterface::IOInfo::helper(
1252 std::span<const TclObject> tokens, TclObject& result, std::span<MSXDevice*, 256> devices)
const
1254 checkNumArgs(tokens, 3,
"port");
1255 unsigned port = tokens[2].getInt(getInterpreter());
1257 throw CommandException(
"Port must be in range 0..255");
1259 devices[port]->getNameList(result);
1261void MSXCPUInterface::IInfo::execute(
1262 std::span<const TclObject> tokens, TclObject& result)
const
1265 helper(tokens, result, interface.IO_In);
1267void MSXCPUInterface::OInfo::execute(
1268 std::span<const TclObject> tokens, TclObject& result)
const
1271 helper(tokens, result, interface.IO_Out);
1274std::string MSXCPUInterface::IOInfo::help(std::span<const TclObject> )
const
1276 return "Return the name of the device connected to the given IO port.";
1280template<
typename Archive>
1287 if constexpr (!Archive::IS_LOADER) {
1288 for (
auto i :
xrange(4)) {
1289 prim |=
byte(primarySlotState[i] << (2 * i));
1292 ar.serialize(
"primarySlots", prim,
1293 "subSlotRegs", subSlotRegister);
1294 if constexpr (Archive::IS_LOADER) {
1296 for (
auto i :
xrange(
byte(4))) {
1297 setSubSlot(i, subSlotRegister[i]);
1302 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)