openMSX
MSXMotherBoard.cc
Go to the documentation of this file.
1#include "MSXMotherBoard.hh"
2
3#include "BooleanSetting.hh"
5#include "CassettePort.hh"
6#include "Command.hh"
7#include "CommandException.hh"
8#include "ConfigException.hh"
9#include "Debugger.hh"
10#include "DeviceFactory.hh"
11#include "EventDelay.hh"
12#include "EventDistributor.hh"
13#include "FileException.hh"
14#include "GlobalCliComm.hh"
15#include "GlobalSettings.hh"
16#include "HardwareConfig.hh"
17#include "InfoTopic.hh"
18#include "JoystickPort.hh"
19#include "LedStatus.hh"
20#include "MSXCPU.hh"
21#include "MSXCPUInterface.hh"
22#include "MSXCliComm.hh"
24#include "MSXDevice.hh"
25#include "MSXDeviceSwitch.hh"
27#include "MSXMapperIO.hh"
28#include "MSXMixer.hh"
29#include "Observer.hh"
30#include "PanasonicMemory.hh"
31#include "PluggingController.hh"
32#include "Reactor.hh"
33#include "RealTime.hh"
34#include "RenShaTurbo.hh"
35#include "ReverseManager.hh"
36#include "Schedulable.hh"
37#include "Scheduler.hh"
38#include "SimpleDebuggable.hh"
40#include "TclObject.hh"
41#include "XMLElement.hh"
42#include "serialize.hh"
43#include "serialize_stl.hh"
44
45#include "ScopedAssign.hh"
46#include "one_of.hh"
47#include "ranges.hh"
48#include "stl.hh"
49#include "unreachable.hh"
50#include "view.hh"
51
52#include <cassert>
53#include <functional>
54#include <iostream>
55#include <memory>
56
57using std::make_unique;
58using std::string;
59
60namespace openmsx {
61
63{
64public:
65 explicit AddRemoveUpdate(MSXMotherBoard& motherBoard);
71private:
72 MSXMotherBoard& motherBoard;
73};
74
75class ResetCmd final : public RecordedCommand
76{
77public:
78 explicit ResetCmd(MSXMotherBoard& motherBoard);
79 void execute(std::span<const TclObject> tokens, TclObject& result,
80 EmuTime::param time) override;
81 [[nodiscard]] string help(std::span<const TclObject> tokens) const override;
82private:
83 MSXMotherBoard& motherBoard;
84};
85
86class LoadMachineCmd final : public Command
87{
88public:
89 explicit LoadMachineCmd(MSXMotherBoard& motherBoard);
90 void execute(std::span<const TclObject> tokens, TclObject& result) override;
91 [[nodiscard]] string help(std::span<const TclObject> tokens) const override;
92 void tabCompletion(std::vector<string>& tokens) const override;
93private:
94 MSXMotherBoard& motherBoard;
95};
96
97class ListExtCmd final : public Command
98{
99public:
100 explicit ListExtCmd(MSXMotherBoard& motherBoard);
101 void execute(std::span<const TclObject> tokens, TclObject& result) override;
102 [[nodiscard]] string help(std::span<const TclObject> tokens) const override;
103private:
104 MSXMotherBoard& motherBoard;
105};
106
107class RemoveExtCmd final : public RecordedCommand
108{
109public:
110 explicit RemoveExtCmd(MSXMotherBoard& motherBoard);
111 void execute(std::span<const TclObject> tokens, TclObject& result,
112 EmuTime::param time) override;
113 [[nodiscard]] string help(std::span<const TclObject> tokens) const override;
114 void tabCompletion(std::vector<string>& tokens) const override;
115private:
116 MSXMotherBoard& motherBoard;
117};
118
119class MachineNameInfo final : public InfoTopic
120{
121public:
122 explicit MachineNameInfo(MSXMotherBoard& motherBoard);
123 void execute(std::span<const TclObject> tokens,
124 TclObject& result) const override;
125 [[nodiscard]] string help(std::span<const TclObject> tokens) const override;
126private:
127 MSXMotherBoard& motherBoard;
128};
129
130class MachineTypeInfo final : public InfoTopic
131{
132public:
133 explicit MachineTypeInfo(MSXMotherBoard& motherBoard);
134 void execute(std::span<const TclObject> tokens,
135 TclObject& result) const override;
136 [[nodiscard]] string help(std::span<const TclObject> tokens) const override;
137private:
138 MSXMotherBoard& motherBoard;
139};
140
141class MachineExtensionInfo final : public InfoTopic
142{
143public:
144 explicit MachineExtensionInfo(MSXMotherBoard& motherBoard);
145 void execute(std::span<const TclObject> tokens,
146 TclObject& result) const override;
147 [[nodiscard]] string help(std::span<const TclObject> tokens) const override;
148 void tabCompletion(std::vector<string>& tokens) const override;
149private:
150 MSXMotherBoard& motherBoard;
151};
152
153class MachineMediaInfo final : public InfoTopic
154{
155public:
156 explicit MachineMediaInfo(MSXMotherBoard& motherBoard);
158 assert(providers.empty());
159 }
160 void execute(std::span<const TclObject> tokens,
161 TclObject& result) const override;
162 [[nodiscard]] string help(std::span<const TclObject> tokens) const override;
163 void tabCompletion(std::vector<string>& tokens) const override;
164 void registerProvider(std::string_view name, MediaInfoProvider& provider);
166private:
167 struct ProviderInfo {
168 ProviderInfo(std::string_view n, MediaInfoProvider* p)
169 : name(n), provider(p) {} // clang-15 workaround
170 std::string_view name;
171 MediaInfoProvider* provider;
172 };
173 // There will only be a handful of providers, use an unsorted vector.
174 std::vector<ProviderInfo> providers;
175};
176
177class DeviceInfo final : public InfoTopic
178{
179public:
180 explicit DeviceInfo(MSXMotherBoard& motherBoard);
181 void execute(std::span<const TclObject> tokens,
182 TclObject& result) const override;
183 [[nodiscard]] string help(std::span<const TclObject> tokens) const override;
184 void tabCompletion(std::vector<string>& tokens) const override;
185private:
186 MSXMotherBoard& motherBoard;
187};
188
189class FastForwardHelper final : private Schedulable
190{
191public:
192 explicit FastForwardHelper(MSXMotherBoard& motherBoard);
193 void setTarget(EmuTime::param targetTime);
194private:
195 void executeUntil(EmuTime::param time) override;
196 MSXMotherBoard& motherBoard;
197};
198
200{
201public:
202 explicit JoyPortDebuggable(MSXMotherBoard& motherBoard);
203 [[nodiscard]] byte read(unsigned address, EmuTime::param time) override;
204 void write(unsigned address, byte value) override;
205};
206
207class SettingObserver final : public Observer<Setting>
208{
209public:
210 explicit SettingObserver(MSXMotherBoard& motherBoard);
211 void update(const Setting& setting) noexcept override;
212private:
213 MSXMotherBoard& motherBoard;
214};
215
216
217static unsigned machineIDCounter = 0;
218
220 : reactor(reactor_)
221 , machineID(strCat("machine", ++machineIDCounter))
222 , msxCliComm(make_unique<MSXCliComm>(*this, reactor.getGlobalCliComm()))
223 , msxEventDistributor(make_unique<MSXEventDistributor>())
224 , stateChangeDistributor(make_unique<StateChangeDistributor>())
225 , msxCommandController(make_unique<MSXCommandController>(
226 reactor.getGlobalCommandController(), reactor,
227 *this, *msxEventDistributor, machineID))
228 , scheduler(make_unique<Scheduler>())
229 , msxMixer(make_unique<MSXMixer>(
230 reactor.getMixer(), *this,
231 reactor.getGlobalSettings()))
232 , videoSourceSetting(*msxCommandController)
233 , suppressMessagesSetting(*msxCommandController, "suppressmessages",
234 "Suppress info, warning and error messages for this machine. "
235 "Intended use is for scripts that create temporary machines "
236 "of which you don't want to see warning messages about blank "
237 "SRAM content or PSG port directions for instance.",
238 false, Setting::DONT_SAVE)
239 , fastForwardHelper(make_unique<FastForwardHelper>(*this))
240 , settingObserver(make_unique<SettingObserver>(*this))
241 , powerSetting(reactor.getGlobalSettings().getPowerSetting())
242{
243 slotManager = make_unique<CartridgeSlotManager>(*this);
244 reverseManager = make_unique<ReverseManager>(*this);
245 resetCommand = make_unique<ResetCmd>(*this);
246 loadMachineCommand = make_unique<LoadMachineCmd>(*this);
247 listExtCommand = make_unique<ListExtCmd>(*this);
248 extCommand = make_unique<ExtCmd>(*this, "ext");
249 removeExtCommand = make_unique<RemoveExtCmd>(*this);
250 machineNameInfo = make_unique<MachineNameInfo>(*this);
251 machineTypeInfo = make_unique<MachineTypeInfo>(*this);
252 machineExtensionInfo = make_unique<MachineExtensionInfo>(*this);
253 machineMediaInfo = make_unique<MachineMediaInfo>(*this);
254 deviceInfo = make_unique<DeviceInfo>(*this);
255 debugger = make_unique<Debugger>(*this);
256
257 msxMixer->mute(); // powered down
258
259 // Do this before machine-specific settings are created, otherwise
260 // a setting-info CliComm message is send with a machine id that hasn't
261 // been announced yet over CliComm.
262 addRemoveUpdate = make_unique<AddRemoveUpdate>(*this);
263
264 // TODO: Initialization of this field cannot be done much earlier because
265 // EventDelay creates a setting, calling getMSXCliComm()
266 // on MSXMotherBoard, so "pimpl" has to be set up already.
267 eventDelay = make_unique<EventDelay>(
268 *scheduler, *msxCommandController,
269 reactor.getEventDistributor(), *msxEventDistributor,
270 *reverseManager);
271 realTime = make_unique<RealTime>(
272 *this, reactor.getGlobalSettings(), *eventDelay);
273
274 powerSetting.attach(*settingObserver);
275 suppressMessagesSetting.attach(*settingObserver);
276}
277
279{
280 suppressMessagesSetting.detach(*settingObserver);
281 powerSetting.detach(*settingObserver);
282 deleteMachine();
283
284 assert(mapperIOCounter == 0);
285 assert(availableDevices.empty());
286 assert(extensions.empty());
287 assert(!machineConfig2);
288 assert(!getMachineConfig());
289}
290
291void MSXMotherBoard::deleteMachine()
292{
293 while (!extensions.empty()) {
294 try {
295 removeExtension(*extensions.back());
296 } catch (MSXException& e) {
297 std::cerr << "Internal error: failed to remove "
298 "extension while deleting a machine: "
299 << e.getMessage() << '\n';
300 assert(false);
301 }
302 }
303
304 machineConfig2.reset();
305 machineConfig = nullptr;
306}
307
309{
310 assert(!getMachineConfig());
311 machineConfig = machineConfig_;
312
313 // make sure the CPU gets instantiated from the main thread
314 assert(!msxCpu);
315 msxCpu = make_unique<MSXCPU>(*this);
316 msxCpuInterface = make_unique<MSXCPUInterface>(*this);
317}
318
319std::string_view MSXMotherBoard::getMachineType() const
320{
321 if (const HardwareConfig* machine = getMachineConfig()) {
322 if (const auto* info = machine->getConfig().findChild("info")) {
323 if (const auto* type = info->findChild("type")) {
324 return type->getData();
325 }
326 }
327 }
328 return "";
329}
330
332{
333 const HardwareConfig* config = getMachineConfig();
334 assert(config);
335 return config->getConfig().getChild("devices").findChild("S1990") != nullptr;
336}
337
339{
340 const HardwareConfig* config = getMachineConfig();
341 assert(config);
342 const XMLElement& devices = config->getConfig().getChild("devices");
343 return devices.findChild("T7775") != nullptr ||
344 devices.findChild("T7937") != nullptr ||
345 devices.findChild("T9763") != nullptr ||
346 devices.findChild("T9769") != nullptr;
347}
348
349string MSXMotherBoard::loadMachine(const string& machine)
350{
351 assert(machineName.empty());
352 assert(extensions.empty());
353 assert(!machineConfig2);
354 assert(!getMachineConfig());
355
356 try {
357 machineConfig2 = HardwareConfig::createMachineConfig(*this, machine);
358 setMachineConfig(machineConfig2.get());
359 } catch (FileException& e) {
360 throw MSXException("Machine \"", machine, "\" not found: ",
361 e.getMessage());
362 } catch (MSXException& e) {
363 throw MSXException("Error in \"", machine, "\" machine: ",
364 e.getMessage());
365 }
366 try {
367 machineConfig->parseSlots();
368 machineConfig->createDevices();
369 } catch (MSXException& e) {
370 throw MSXException("Error in \"", machine, "\" machine: ",
371 e.getMessage());
372 }
373 if (powerSetting.getBoolean()) {
374 powerUp();
375 }
376 machineName = machine;
377 return machineName;
378}
379
380std::unique_ptr<HardwareConfig> MSXMotherBoard::loadExtension(std::string_view name, std::string_view slotName)
381{
382 try {
384 *this, string(name), slotName);
385 } catch (FileException& e) {
386 throw MSXException(
387 "Extension \"", name, "\" not found: ", e.getMessage());
388 } catch (MSXException& e) {
389 throw MSXException(
390 "Error in \"", name, "\" extension: ", e.getMessage());
391 }
392}
393
395 std::string_view name, std::unique_ptr<HardwareConfig> extension)
396{
397 try {
398 extension->parseSlots();
399 extension->createDevices();
400 } catch (MSXException& e) {
401 throw MSXException(
402 "Error in \"", name, "\" extension: ", e.getMessage());
403 }
404 string result = extension->getName();
405 extensions.push_back(std::move(extension));
406 getMSXCliComm().update(CliComm::EXTENSION, result, "add");
407 return result;
408}
409
410HardwareConfig* MSXMotherBoard::findExtension(std::string_view extensionName)
411{
412 auto it = ranges::find(extensions, extensionName, &HardwareConfig::getName);
413 return (it != end(extensions)) ? it->get() : nullptr;
414}
415
417{
418 extension.testRemove();
419 getMSXCliComm().update(CliComm::EXTENSION, extension.getName(), "remove");
420 auto it = rfind_unguarded(extensions, &extension,
421 [](auto& e) { return e.get(); });
422 extensions.erase(it);
423}
424
426{
427 return *msxCliComm;
428}
429
431{
432 assert(getMachineConfig()); // needed for PluggableFactory::createAll()
433 if (!pluggingController) {
434 pluggingController = make_unique<PluggingController>(*this);
435 }
436 return *pluggingController;
437}
438
440{
441 assert(getMachineConfig()); // because CPU needs to know if we're
442 // emulating turbor or not
443 return *msxCpu;
444}
445
447{
448 assert(getMachineConfig());
449 return *msxCpuInterface;
450}
451
453{
454 if (!panasonicMemory) {
455 panasonicMemory = make_unique<PanasonicMemory>(*this);
456 }
457 return *panasonicMemory;
458}
459
461{
462 if (!deviceSwitch) {
464 }
465 return *deviceSwitch;
466}
467
469{
470 if (!cassettePort) {
471 assert(getMachineConfig());
472 if (getMachineConfig()->getConfig().findChild("CassettePort")) {
473 cassettePort = make_unique<CassettePort>(*getMachineConfig());
474 } else {
475 cassettePort = make_unique<DummyCassettePort>();
476 }
477 }
478 return *cassettePort;
479}
480
482{
483 assert(port < 2);
484 if (!joystickPort[0]) {
485 assert(getMachineConfig());
486 // some MSX machines only have 1 instead of 2 joystick ports
487 std::string_view ports = getMachineConfig()->getConfig().getChildData(
488 "JoystickPorts", "AB");
489 if (ports != one_of("AB", "", "A", "B")) {
490 throw ConfigException(
491 "Invalid JoystickPorts specification, "
492 "should be one of '', 'A', 'B' or 'AB'.");
493 }
495 if (ports == one_of("AB", "A")) {
496 joystickPort[0] = make_unique<JoystickPort>(
497 ctrl, "joyporta", "MSX Joystick port A");
498 } else {
499 joystickPort[0] = make_unique<DummyJoystickPort>();
500 }
501 if (ports == one_of("AB", "B")) {
502 joystickPort[1] = make_unique<JoystickPort>(
503 ctrl, "joyportb", "MSX Joystick port B");
504 } else {
505 joystickPort[1] = make_unique<DummyJoystickPort>();
506 }
507 joyPortDebuggable = make_unique<JoyPortDebuggable>(*this);
508 }
509 return *joystickPort[port];
510}
511
513{
514 if (!renShaTurbo) {
515 assert(getMachineConfig());
516 renShaTurbo = make_unique<RenShaTurbo>(
517 *this,
518 getMachineConfig()->getConfig());
519 }
520 return *renShaTurbo;
521}
522
524{
525 if (!ledStatus) {
526 (void)getMSXCliComm(); // force init, to be on the safe side
527 ledStatus = make_unique<LedStatus>(
528 reactor.getRTScheduler(),
529 *msxCommandController,
530 *msxCliComm);
531 }
532 return *ledStatus;
533}
534
536{
537 return *msxCommandController;
538}
539
541{
542 return msxCommandController->getMachineInfoCommand();
543}
544
545EmuTime::param MSXMotherBoard::getCurrentTime() const
546{
547 return scheduler->getCurrentTime();
548}
549
551{
552 if (!powered) {
553 return false;
554 }
555 assert(getMachineConfig()); // otherwise powered cannot be true
556
557 getCPU().execute(false);
558 return true;
559}
560
561void MSXMotherBoard::fastForward(EmuTime::param time, bool fast)
562{
563 assert(powered);
564 assert(getMachineConfig());
565
566 if (time <= getCurrentTime()) return;
567
568 ScopedAssign sa(fastForwarding, fast);
569 realTime->disable();
570 msxMixer->mute();
571 fastForwardHelper->setTarget(time);
572 while (time > getCurrentTime()) {
573 // note: this can run (slightly) past the requested time
574 getCPU().execute(true); // fast-forward mode
575 }
576 realTime->enable();
577 msxMixer->unmute();
578}
579
581{
582 if (getMachineConfig()) {
583 getCPU().setPaused(true);
584 }
585 msxMixer->mute();
586}
587
589{
590 if (getMachineConfig()) {
591 getCPU().setPaused(false);
592 }
593 msxMixer->unmute();
594}
595
597{
598 availableDevices.push_back(&device);
599}
600
602{
603 move_pop_back(availableDevices, rfind_unguarded(availableDevices, &device));
604}
605
607{
608 if (!powered) return;
609 assert(getMachineConfig());
610
611 EmuTime::param time = getCurrentTime();
613 for (auto& d : availableDevices) {
614 d->reset(time);
615 }
616 getCPU().doReset(time);
617 // let everyone know we're booting, note that the fact that this is
618 // done after the reset call to the devices is arbitrary here
620}
621
623{
624 byte result = 0xff;
625 for (auto& d : availableDevices) {
626 result &= d->readIRQVector();
627 }
628 return result;
629}
630
632{
633 if (powered) return;
634 if (!getMachineConfig()) return;
635
636 powered = true;
637 // TODO: If our "powered" field is always equal to the power setting,
638 // there is not really a point in keeping it.
639 // TODO: assert disabled see note in Reactor::run() where this method
640 // is called
641 //assert(powerSetting.getBoolean() == powered);
642 powerSetting.setBoolean(true);
643 // TODO: We could make the power LED a device, so we don't have to handle
644 // it separately here.
646
647 EmuTime::param time = getCurrentTime();
649 for (auto& d : availableDevices) {
650 d->powerUp(time);
651 }
652 getCPU().doReset(time);
653 msxMixer->unmute();
654 // let everyone know we're booting, note that the fact that this is
655 // done after the reset call to the devices is arbitrary here
657}
658
659void MSXMotherBoard::powerDown()
660{
661 if (!powered) return;
662
663 powered = false;
664 // TODO: This assertion fails in 1 case: when quitting with a running MSX.
665 // How do we want the Reactor to shutdown: immediately or after
666 // handling all pending commands/events/updates?
667 //assert(powerSetting.getBoolean() == powered);
668 powerSetting.setBoolean(false);
670
671 msxMixer->mute();
672
673 EmuTime::param time = getCurrentTime();
674 for (auto& d : availableDevices) {
675 d->powerDown(time);
676 }
677}
678
679void MSXMotherBoard::activate(bool active_)
680{
681 active = active_;
682 auto event = active ? Event(MachineActivatedEvent())
684 msxEventDistributor->distributeEvent(event, scheduler->getCurrentTime());
685 if (active) {
686 realTime->resync();
687 }
688}
689
696
701
703{
704 auto it = ranges::find(availableDevices, name, &MSXDevice::getName);
705 return (it != end(availableDevices)) ? *it : nullptr;
706}
707
709{
710 if (mapperIOCounter == 0) {
712
713 MSXCPUInterface& cpuInterface = getCPUInterface();
714 for (auto port : {0xfc, 0xfd, 0xfe, 0xff}) {
715 cpuInterface.register_IO_Out(narrow_cast<byte>(port), mapperIO.get());
716 cpuInterface.register_IO_In (narrow_cast<byte>(port), mapperIO.get());
717 }
718 }
719 ++mapperIOCounter;
720 return *mapperIO;
721}
722
724{
725 assert(mapperIO);
726 assert(mapperIOCounter);
727 --mapperIOCounter;
728 if (mapperIOCounter == 0) {
729 MSXCPUInterface& cpuInterface = getCPUInterface();
730 for (auto port : {0xfc, 0xfd, 0xfe, 0xff}) {
731 cpuInterface.unregister_IO_Out(narrow_cast<byte>(port), mapperIO.get());
732 cpuInterface.unregister_IO_In (narrow_cast<byte>(port), mapperIO.get());
733 }
734
735 mapperIO.reset();
736 }
737}
738
739string MSXMotherBoard::getUserName(const string& hwName)
740{
741 auto& s = userNames[hwName];
742 unsigned n = 0;
743 string userName;
744 do {
745 userName = strCat("untitled", ++n);
746 } while (contains(s, userName));
747 s.push_back(userName);
748 return userName;
749}
750
751void MSXMotherBoard::freeUserName(const string& hwName, const string& userName)
752{
753 auto& s = userNames[hwName];
754 move_pop_back(s, rfind_unguarded(s, userName));
755}
756
757void MSXMotherBoard::registerMediaInfo(std::string_view name, MediaInfoProvider& provider)
758{
759 machineMediaInfo->registerProvider(name, provider);
760}
761
763{
764 machineMediaInfo->unregisterProvider(provider);
765}
766
767
768// AddRemoveUpdate
769
771 : motherBoard(motherBoard_)
772{
773 motherBoard.getReactor().getGlobalCliComm().update(
774 CliComm::HARDWARE, motherBoard.getMachineID(), "add");
775}
776
778{
779 motherBoard.getReactor().getGlobalCliComm().update(
780 CliComm::HARDWARE, motherBoard.getMachineID(), "remove");
781}
782
783
784// ResetCmd
786 : RecordedCommand(motherBoard_.getCommandController(),
787 motherBoard_.getStateChangeDistributor(),
788 motherBoard_.getScheduler(),
789 "reset")
790 , motherBoard(motherBoard_)
791{
792}
793
794void ResetCmd::execute(std::span<const TclObject> /*tokens*/, TclObject& /*result*/,
795 EmuTime::param /*time*/)
796{
797 motherBoard.doReset();
798}
799
800string ResetCmd::help(std::span<const TclObject> /*tokens*/) const
801{
802 return "Resets the MSX.";
803}
804
805
806// LoadMachineCmd
808 : Command(motherBoard_.getCommandController(), "load_machine")
809 , motherBoard(motherBoard_)
810{
811 // The load_machine command should always directly follow a
812 // create_machine command:
813 // - It's not allowed to use load_machine on a machine that has
814 // already a machine configuration loaded earlier.
815 // - We also disallow executing most machine-specific commands on an
816 // 'empty machine' (an 'empty machine', is a machine returned by
817 // create_machine before the load_machine command is executed, so a
818 // machine without a machine configuration). The only exception is
819 // this load_machine command and machine_info.
820 //
821 // So if the only allowed command on an empty machine is
822 // 'load_machine', (and an empty machine by itself isn't very useful),
823 // then why isn't create_machine and load_machine merged into a single
824 // command? The only reason for this is that load_machine sends out
825 // events (machine specific) and maybe you already want to know the ID
826 // of the new machine (this is returned by create_machine) before those
827 // events will be send.
828 //
829 // Why not allow all commands on an empty machine? In the past we did
830 // allow this, though it often was the source of bugs. We could in each
831 // command (when needed) check for an empty machine and then return
832 // some dummy/empty result or some error. But because I can't think of
833 // any really useful command for an empty machine, it seemed easier to
834 // just disallow most commands.
836}
837
838void LoadMachineCmd::execute(std::span<const TclObject> tokens, TclObject& result)
839{
840 checkNumArgs(tokens, 2, "machine");
841 if (motherBoard.getMachineConfig()) {
842 throw CommandException("Already loaded a config in this machine.");
843 }
844 result = motherBoard.loadMachine(string(tokens[1].getString()));
845}
846
847string LoadMachineCmd::help(std::span<const TclObject> /*tokens*/) const
848{
849 return "Load a msx machine configuration into an empty machine.";
850}
851
852void LoadMachineCmd::tabCompletion(std::vector<string>& tokens) const
853{
854 completeString(tokens, Reactor::getHwConfigs("machines"));
855}
856
857
858// ListExtCmd
860 : Command(motherBoard_.getCommandController(), "list_extensions")
861 , motherBoard(motherBoard_)
862{
863}
864
865void ListExtCmd::execute(std::span<const TclObject> /*tokens*/, TclObject& result)
866{
867 result.addListElements(
868 view::transform(motherBoard.getExtensions(),
869 [&](auto& e) { return e->getName(); }));
870}
871
872string ListExtCmd::help(std::span<const TclObject> /*tokens*/) const
873{
874 return "Return a list of all inserted extensions.";
875}
876
877
878// ExtCmd
879ExtCmd::ExtCmd(MSXMotherBoard& motherBoard_, std::string commandName_)
880 : RecordedCommand(motherBoard_.getCommandController(),
881 motherBoard_.getStateChangeDistributor(),
882 motherBoard_.getScheduler(),
883 commandName_)
884 , motherBoard(motherBoard_)
885 , commandName(std::move(commandName_))
886{
887}
888
889void ExtCmd::execute(std::span<const TclObject> tokens, TclObject& result,
890 EmuTime::param /*time*/)
891{
892 checkNumArgs(tokens, Between{2, 3}, "extension");
893 if (tokens.size() == 3 && tokens[1].getString() != "insert") {
894 throw SyntaxError();
895 }
896 try {
897 auto name = tokens[tokens.size() - 1].getString();
898 auto slotName = (commandName.size() == 4)
899 ? std::string_view(&commandName[3], 1)
900 : "any";
901 auto extension = motherBoard.loadExtension(name, slotName);
902 if (slotName != "any") {
903 auto& manager = motherBoard.getSlotManager();
904 if (const auto* extConf = manager.getConfigForSlot(commandName[3] - 'a')) {
905 // still a cartridge inserted, (try to) remove it now
906 motherBoard.removeExtension(*extConf);
907 }
908 }
909 result = motherBoard.insertExtension(name, std::move(extension));
910 } catch (MSXException& e) {
911 throw CommandException(std::move(e).getMessage());
912 }
913}
914
915string ExtCmd::help(std::span<const TclObject> /*tokens*/) const
916{
917 return "Insert a hardware extension.";
918}
919
920void ExtCmd::tabCompletion(std::vector<string>& tokens) const
921{
922 completeString(tokens, Reactor::getHwConfigs("extensions"));
923}
924
925
926// RemoveExtCmd
928 : RecordedCommand(motherBoard_.getCommandController(),
929 motherBoard_.getStateChangeDistributor(),
930 motherBoard_.getScheduler(),
931 "remove_extension")
932 , motherBoard(motherBoard_)
933{
934}
935
936void RemoveExtCmd::execute(std::span<const TclObject> tokens, TclObject& /*result*/,
937 EmuTime::param /*time*/)
938{
939 checkNumArgs(tokens, 2, "extension");
940 std::string_view extName = tokens[1].getString();
941 HardwareConfig* extension = motherBoard.findExtension(extName);
942 if (!extension) {
943 throw CommandException("No such extension: ", extName);
944 }
945 try {
946 motherBoard.removeExtension(*extension);
947 } catch (MSXException& e) {
948 throw CommandException("Can't remove extension '", extName,
949 "': ", e.getMessage());
950 }
951}
952
953string RemoveExtCmd::help(std::span<const TclObject> /*tokens*/) const
954{
955 return "Remove an extension from the MSX machine.";
956}
957
958void RemoveExtCmd::tabCompletion(std::vector<string>& tokens) const
959{
960 if (tokens.size() == 2) {
962 motherBoard.getExtensions(),
963 [](auto& e) -> std::string_view { return e->getName(); }));
964 }
965}
966
967
968// MachineNameInfo
969
971 : InfoTopic(motherBoard_.getMachineInfoCommand(), "config_name")
972 , motherBoard(motherBoard_)
973{
974}
975
976void MachineNameInfo::execute(std::span<const TclObject> /*tokens*/,
977 TclObject& result) const
978{
979 result = motherBoard.getMachineName();
980}
981
982string MachineNameInfo::help(std::span<const TclObject> /*tokens*/) const
983{
984 return "Returns the configuration name for this machine.";
985}
986
987// MachineTypeInfo
988
990 : InfoTopic(motherBoard_.getMachineInfoCommand(), "type")
991 , motherBoard(motherBoard_)
992{
993}
994
995void MachineTypeInfo::execute(std::span<const TclObject> /*tokens*/,
996 TclObject& result) const
997{
998 result = motherBoard.getMachineType();
999}
1000
1001string MachineTypeInfo::help(std::span<const TclObject> /*tokens*/) const
1002{
1003 return "Returns the machine type for this machine.";
1004}
1005
1006
1007// MachineExtensionInfo
1008
1010 : InfoTopic(motherBoard_.getMachineInfoCommand(), "extension")
1011 , motherBoard(motherBoard_)
1012{
1013}
1014
1015void MachineExtensionInfo::execute(std::span<const TclObject> tokens,
1016 TclObject& result) const
1017{
1018 checkNumArgs(tokens, Between{2, 3}, Prefix{2}, "?extension-instance-name?");
1019 if (tokens.size() == 2) {
1020 result.addListElements(
1021 view::transform(motherBoard.getExtensions(),
1022 [&](auto& e) { return e->getName(); }));
1023 } else if (tokens.size() == 3) {
1024 std::string_view extName = tokens[2].getString();
1025 HardwareConfig* extension = motherBoard.findExtension(extName);
1026 if (!extension) {
1027 throw CommandException("No such extension: ", extName);
1028 }
1029 if (extension->getType() == HardwareConfig::Type::EXTENSION) {
1030 // A 'true' extension, as specified in an XML file
1031 result.addDictKeyValue("config", extension->getConfigName());
1032 } else {
1033 assert(extension->getType() == HardwareConfig::Type::ROM);
1034 // A ROM cartridge, peek into the internal config for the original filename
1035 const auto& filename = extension->getConfig()
1036 .getChild("devices").getChild("primary").getChild("secondary")
1037 .getChild("ROM").getChild("rom").getChildData("filename");
1038 result.addDictKeyValue("rom", filename);
1039 }
1040 TclObject deviceList;
1041 deviceList.addListElements(
1042 view::transform(extension->getDevices(),
1043 [&](auto& e) { return e->getName(); }));
1044 result.addDictKeyValue("devices", deviceList);
1045 }
1046}
1047
1048string MachineExtensionInfo::help(std::span<const TclObject> /*tokens*/) const
1049{
1050 return "Returns information about the given extension instance.";
1051}
1052
1053void MachineExtensionInfo::tabCompletion(std::vector<string>& tokens) const
1054{
1055 if (tokens.size() == 3) {
1057 motherBoard.getExtensions(),
1058 [](auto& e) -> std::string_view { return e->getName(); }));
1059 }
1060}
1061
1062
1063// MachineMediaInfo
1064
1066 : InfoTopic(motherBoard_.getMachineInfoCommand(), "media")
1067{
1068}
1069
1070void MachineMediaInfo::execute(std::span<const TclObject> tokens,
1071 TclObject& result) const
1072{
1073 checkNumArgs(tokens, Between{2, 3}, Prefix{2}, "?media-slot-name?");
1074 if (tokens.size() == 2) {
1075 result.addListElements(
1076 view::transform(providers, &ProviderInfo::name));
1077 } else if (tokens.size() == 3) {
1078 auto name = tokens[2].getString();
1079 if (auto it = ranges::find(providers, name, &ProviderInfo::name);
1080 it != providers.end()) {
1081 it->provider->getMediaInfo(result);
1082 } else {
1083 throw CommandException("No info about media slot ", name);
1084 }
1085 }
1086}
1087
1088string MachineMediaInfo::help(std::span<const TclObject> /*tokens*/) const
1089{
1090 return "Returns information about the given media slot.";
1091}
1092
1093void MachineMediaInfo::tabCompletion(std::vector<string>& tokens) const
1094{
1095 if (tokens.size() == 3) {
1097 providers, &ProviderInfo::name));
1098 }
1099}
1100
1101void MachineMediaInfo::registerProvider(std::string_view name, MediaInfoProvider& provider)
1102{
1103 assert(!contains(providers, name, &ProviderInfo::name));
1104 assert(!contains(providers, &provider, &ProviderInfo::provider));
1105 providers.emplace_back(name, &provider);
1106}
1107
1109{
1110 move_pop_back(providers,
1111 rfind_unguarded(providers, &provider, &ProviderInfo::provider));
1112}
1113
1114// DeviceInfo
1115
1117 : InfoTopic(motherBoard_.getMachineInfoCommand(), "device")
1118 , motherBoard(motherBoard_)
1119{
1120}
1121
1122void DeviceInfo::execute(std::span<const TclObject> tokens, TclObject& result) const
1123{
1124 checkNumArgs(tokens, Between{2, 3}, Prefix{2}, "?device?");
1125 switch (tokens.size()) {
1126 case 2:
1127 result.addListElements(
1128 view::transform(motherBoard.availableDevices,
1129 [](auto& d) { return d->getName(); }));
1130 break;
1131 case 3: {
1132 std::string_view deviceName = tokens[2].getString();
1133 MSXDevice* device = motherBoard.findDevice(deviceName);
1134 if (!device) {
1135 throw CommandException("No such device: ", deviceName);
1136 }
1137 device->getDeviceInfo(result);
1138 break;
1139 }
1140 }
1141}
1142
1143string DeviceInfo::help(std::span<const TclObject> /*tokens*/) const
1144{
1145 return "Without any arguments, returns the list of used device names.\n"
1146 "With a device name as argument, returns the type (and for some "
1147 "devices the subtype) of the given device.";
1148}
1149
1150void DeviceInfo::tabCompletion(std::vector<string>& tokens) const
1151{
1152 if (tokens.size() == 3) {
1154 motherBoard.availableDevices,
1155 [](auto& d) -> std::string_view { return d->getName(); }));
1156 }
1157}
1158
1159
1160// FastForwardHelper
1161
1163 : Schedulable(motherBoard_.getScheduler())
1164 , motherBoard(motherBoard_)
1165{
1166}
1167
1168void FastForwardHelper::setTarget(EmuTime::param targetTime)
1169{
1170 setSyncPoint(targetTime);
1171}
1172
1173void FastForwardHelper::executeUntil(EmuTime::param /*time*/)
1174{
1175 motherBoard.exitCPULoopSync();
1176}
1177
1178
1179// class JoyPortDebuggable
1180
1182 : SimpleDebuggable(motherBoard_, "joystickports", "MSX Joystick Ports", 2)
1183{
1184}
1185
1186byte JoyPortDebuggable::read(unsigned address, EmuTime::param time)
1187{
1188 return getMotherBoard().getJoystickPort(address).read(time);
1189}
1190
1191void JoyPortDebuggable::write(unsigned /*address*/, byte /*value*/)
1192{
1193 // ignore
1194}
1195
1196
1197// class SettingObserver
1198
1200 : motherBoard(motherBoard_)
1201{
1202}
1203
1205{
1206 if (&setting == &motherBoard.powerSetting) {
1207 if (motherBoard.powerSetting.getBoolean()) {
1208 motherBoard.powerUp();
1209 } else {
1210 motherBoard.powerDown();
1211 }
1212 } else if (&setting == &motherBoard.suppressMessagesSetting) {
1213 motherBoard.msxCliComm->setSuppressMessages(motherBoard.suppressMessagesSetting.getBoolean());
1214 } else {
1216 }
1217}
1218
1219
1220// serialize
1221// version 1: initial version
1222// version 2: added reRecordCount
1223// version 3: removed reRecordCount (moved to ReverseManager)
1224// version 4: moved joystickportA/B from MSXPSG to here
1225// version 5: do serialize renShaTurbo
1226template<typename Archive>
1227void MSXMotherBoard::serialize(Archive& ar, unsigned version)
1228{
1229 // don't serialize:
1230 // machineID, userNames, availableDevices, addRemoveUpdate,
1231 // sharedStuffMap, msxCliComm, msxEventDistributor,
1232 // msxCommandController, slotManager, eventDelay,
1233 // debugger, msxMixer, panasonicMemory, ledStatus
1234
1235 // Scheduler must come early so that devices can query current time
1236 ar.serialize("scheduler", *scheduler);
1237 // MSXMixer has already set sync points, those are invalid now
1238 // the following call will fix this
1239 if constexpr (Archive::IS_LOADER) {
1240 msxMixer->reInit();
1241 }
1242
1243 ar.serialize("name", machineName);
1244 ar.serializeWithID("config", machineConfig2, std::ref(*this));
1245 assert(getMachineConfig() == machineConfig2.get());
1246 ar.serializeWithID("extensions", extensions, std::ref(*this));
1247
1248 if (mapperIO) ar.serialize("mapperIO", *mapperIO);
1249
1250 if (auto& devSwitch = getDeviceSwitch();
1251 devSwitch.hasRegisteredDevices()) {
1252 ar.serialize("deviceSwitch", devSwitch);
1253 }
1254
1255 if (getMachineConfig()) {
1256 ar.serialize("cpu", getCPU());
1257 }
1258 ar.serialize("cpuInterface", getCPUInterface());
1259
1260 if (auto* port = dynamic_cast<CassettePort*>(&getCassettePort())) {
1261 ar.serialize("cassetteport", *port);
1262 }
1263 if (ar.versionAtLeast(version, 4)) {
1264 if (auto* port = dynamic_cast<JoystickPort*>(
1265 joystickPort[0].get())) {
1266 ar.serialize("joystickportA", *port);
1267 }
1268 if (auto* port = dynamic_cast<JoystickPort*>(
1269 joystickPort[1].get())) {
1270 ar.serialize("joystickportB", *port);
1271 }
1272 }
1273 if (ar.versionAtLeast(version, 5)) {
1274 if (renShaTurbo) ar.serialize("renShaTurbo", *renShaTurbo);
1275 }
1276
1277 if constexpr (Archive::IS_LOADER) {
1278 powered = true; // must come before changing power setting
1279 powerSetting.setBoolean(true);
1281 msxMixer->unmute();
1282 }
1283
1284 if (version == 2) {
1285 assert(Archive::IS_LOADER);
1286 unsigned reRecordCount = 0; // silence warning
1287 ar.serialize("reRecordCount", reRecordCount);
1288 getReverseManager().setReRecordCount(reRecordCount);
1289 }
1290}
1292
1293} // namespace openmsx
BaseSetting * setting
Assign new value to some variable and restore the original value when this object goes out of scope.
AddRemoveUpdate(const AddRemoveUpdate &)=delete
AddRemoveUpdate & operator=(AddRemoveUpdate &&)=delete
AddRemoveUpdate(MSXMotherBoard &motherBoard)
AddRemoveUpdate(AddRemoveUpdate &&)=delete
AddRemoveUpdate & operator=(const AddRemoveUpdate &)=delete
bool getBoolean() const noexcept
Sent when the MSX resets or powers up.
Definition Event.hh:371
void setAllowedInEmptyMachine(bool value)
Definition Command.hh:67
static void completeString(std::vector< std::string > &tokens, ITER begin, ITER end, bool caseSensitive=true)
Definition Completer.hh:138
void checkNumArgs(std::span< const TclObject > tokens, unsigned exactly, const char *errMessage) const
Definition Completer.cc:181
static std::unique_ptr< MSXDeviceSwitch > createDeviceSwitch(const HardwareConfig &hwConf)
static std::unique_ptr< MSXMapperIO > createMapperIO(const HardwareConfig &hwConf)
DeviceInfo(MSXMotherBoard &motherBoard)
void execute(std::span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
string help(std::span< const TclObject > tokens) const override
Print help for this topic.
void tabCompletion(std::vector< string > &tokens) const override
Attempt tab completion for this command.
void distributeEvent(Event &&event)
Schedule the given event for delivery.
void tabCompletion(std::vector< std::string > &tokens) const override
Attempt tab completion for this command.
ExtCmd(MSXMotherBoard &motherBoard, std::string commandName)
void execute(std::span< const TclObject > tokens, TclObject &result, EmuTime::param time) override
This is like the execute() method of the Command class, it only has an extra time parameter.
std::string help(std::span< const TclObject > tokens) const override
Print help for this command.
void setTarget(EmuTime::param targetTime)
FastForwardHelper(MSXMotherBoard &motherBoard)
void update(UpdateType type, std::string_view name, std::string_view value) override
const std::string & getConfigName() const
static std::unique_ptr< HardwareConfig > createMachineConfig(MSXMotherBoard &motherBoard, std::string machineName)
const auto & getDevices() const
const std::string & getName() const
const XMLElement & getConfig() const
static std::unique_ptr< HardwareConfig > createExtensionConfig(MSXMotherBoard &motherBoard, std::string extensionName, std::string_view slotName)
void testRemove() const
Checks whether this HardwareConfig can be deleted.
void write(unsigned address, byte value) override
JoyPortDebuggable(MSXMotherBoard &motherBoard)
byte read(unsigned address, EmuTime::param time) override
virtual uint8_t read(EmuTime::param time)=0
void setLed(Led led, bool status)
Definition LedStatus.cc:41
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
ListExtCmd(MSXMotherBoard &motherBoard)
string help(std::span< const TclObject > tokens) const override
Print help for this command.
LoadMachineCmd(MSXMotherBoard &motherBoard)
string help(std::span< const TclObject > tokens) const override
Print help for this command.
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
void tabCompletion(std::vector< string > &tokens) const override
Attempt tab completion for this command.
void register_IO_Out(byte port, MSXDevice *device)
Devices can register their Out ports.
void register_IO_In(byte port, MSXDevice *device)
Devices can register their In ports.
void unregister_IO_In(byte port, MSXDevice *device)
void reset()
Reset (the slot state)
void unregister_IO_Out(byte port, MSXDevice *device)
void exitCPULoopSync()
See CPUCore::exitCPULoopSync()
Definition MSXCPU.cc:126
void doReset(EmuTime::param time)
Reset CPU.
Definition MSXCPU.cc:80
void setPaused(bool paused)
(un)pause CPU.
Definition MSXCPU.cc:365
void exitCPULoopAsync()
See CPUCore::exitCPULoopAsync()
Definition MSXCPU.cc:131
void update(UpdateType type, std::string_view name, std::string_view value) override
Definition MSXCliComm.cc:21
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition MSXDevice.hh:36
void getDeviceInfo(TclObject &result) const
Get device info.
Definition MSXDevice.cc:385
virtual const std::string & getName() const
Returns a human-readable name for this device.
Definition MSXDevice.cc:375
HardwareConfig * findExtension(std::string_view extensionName)
PluggingController & getPluggingController()
void activate(bool active)
void setMachineConfig(HardwareConfig *machineConfig)
RenShaTurbo & getRenShaTurbo()
void freeUserName(const std::string &hwName, const std::string &userName)
bool execute()
Run emulation.
EmuTime::param getCurrentTime() const
Convenience method: This is the same as getScheduler().getCurrentTime().
const HardwareConfig * getMachineConfig() const
MSXCPUInterface & getCPUInterface()
std::string getUserName(const std::string &hwName)
Keep track of which 'usernames' are in use.
std::unique_ptr< HardwareConfig > loadExtension(std::string_view extensionName, std::string_view slotName)
std::string loadMachine(const std::string &machine)
std::string_view getMachineName() const
void registerMediaInfo(std::string_view name, MediaInfoProvider &provider)
Register and unregister providers of media info, for the media info topic.
MSXDevice * findDevice(std::string_view name)
Find a MSXDevice by name.
CommandController & getCommandController()
void pause()
Pause MSX machine.
std::string insertExtension(std::string_view name, std::unique_ptr< HardwareConfig > extension)
void fastForward(EmuTime::param time, bool fast)
Run emulation until a certain time in fast forward mode.
void exitCPULoopAsync()
See CPU::exitCPULoopAsync().
MSXMotherBoard(const MSXMotherBoard &)=delete
void unregisterMediaInfo(MediaInfoProvider &provider)
MSXDeviceSwitch & getDeviceSwitch()
void serialize(Archive &ar, unsigned version)
CartridgeSlotManager & getSlotManager()
void removeDevice(MSXDevice &device)
std::string_view getMachineID() const
void removeExtension(const HardwareConfig &extension)
ReverseManager & getReverseManager()
JoystickPortIf & getJoystickPort(unsigned port)
std::string_view getMachineType() const
const Extensions & getExtensions() const
CassettePortInterface & getCassettePort()
void addDevice(MSXDevice &device)
All MSXDevices should be registered by the MotherBoard.
PanasonicMemory & getPanasonicMemory()
MSXMapperIO & createMapperIO()
All memory mappers in one MSX machine share the same four (logical) memory mapper registers.
InfoCommand & getMachineInfoCommand()
Send when a machine is (de)activated.
Definition Event.hh:393
void execute(std::span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
string help(std::span< const TclObject > tokens) const override
Print help for this topic.
void tabCompletion(std::vector< string > &tokens) const override
Attempt tab completion for this topic.
MachineExtensionInfo(MSXMotherBoard &motherBoard)
void unregisterProvider(MediaInfoProvider &provider)
void registerProvider(std::string_view name, MediaInfoProvider &provider)
string help(std::span< const TclObject > tokens) const override
Print help for this topic.
void execute(std::span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
MachineMediaInfo(MSXMotherBoard &motherBoard)
void tabCompletion(std::vector< string > &tokens) const override
Attempt tab completion for this topic.
void execute(std::span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
MachineNameInfo(MSXMotherBoard &motherBoard)
string help(std::span< const TclObject > tokens) const override
Print help for this topic.
string help(std::span< const TclObject > tokens) const override
Print help for this topic.
void execute(std::span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
MachineTypeInfo(MSXMotherBoard &motherBoard)
Generic Gang-of-Four Observer class, templatized edition.
Definition Observer.hh:10
Central administration of Connectors and Pluggables.
Contains the main loop of openMSX.
Definition Reactor.hh:72
GlobalSettings & getGlobalSettings()
Definition Reactor.hh:114
GlobalCliComm & getGlobalCliComm()
Definition Reactor.hh:87
RTScheduler & getRTScheduler()
Definition Reactor.hh:85
EventDistributor & getEventDistributor()
Definition Reactor.hh:86
static std::vector< std::string > getHwConfigs(std::string_view type)
Definition Reactor.cc:349
Commands that directly influence the MSX state should send and events so that they can be recorded by...
RemoveExtCmd(MSXMotherBoard &motherBoard)
void tabCompletion(std::vector< string > &tokens) const override
Attempt tab completion for this command.
void execute(std::span< const TclObject > tokens, TclObject &result, EmuTime::param time) override
This is like the execute() method of the Command class, it only has an extra time parameter.
string help(std::span< const TclObject > tokens) const override
Print help for this command.
Ren-Sha Turbo is the autofire in several MSX 2+ models and in the MSX turbo R.
string help(std::span< const TclObject > tokens) const override
Print help for this command.
void execute(std::span< const TclObject > tokens, TclObject &result, EmuTime::param time) override
This is like the execute() method of the Command class, it only has an extra time parameter.
ResetCmd(MSXMotherBoard &motherBoard)
void setReRecordCount(unsigned count)
Every class that wants to get scheduled at some point must inherit from this class.
void setSyncPoint(EmuTime::param timestamp)
SettingObserver(MSXMotherBoard &motherBoard)
void update(const Setting &setting) noexcept override
MSXMotherBoard & getMotherBoard() const
void detach(Observer< T > &observer)
Definition Subject.hh:60
void attach(Observer< T > &observer)
Definition Subject.hh:54
void addListElements(ITER first, ITER last)
Definition TclObject.hh:132
void addDictKeyValue(const Key &key, const Value &value)
Definition TclObject.hh:145
const XMLElement * findChild(std::string_view childName) const
Definition XMLElement.cc:21
const XMLElement & getChild(std::string_view childName) const
Definition XMLElement.cc:55
std::string_view getChildData(std::string_view childName) const
Definition XMLElement.cc:64
This file implemented 3 utility functions:
Definition Autofire.cc:11
std::variant< KeyUpEvent, KeyDownEvent, MouseMotionEvent, MouseButtonUpEvent, MouseButtonDownEvent, MouseWheelEvent, JoystickAxisMotionEvent, JoystickHatEvent, JoystickButtonUpEvent, JoystickButtonDownEvent, OsdControlReleaseEvent, OsdControlPressEvent, WindowEvent, TextEvent, FileDropEvent, QuitEvent, FinishFrameEvent, CliCommandEvent, GroupEvent, BootEvent, FrameDrawnEvent, BreakEvent, SwitchRendererEvent, TakeReverseSnapshotEvent, AfterTimedEvent, MachineLoadedEvent, MachineActivatedEvent, MachineDeactivatedEvent, MidiInReaderEvent, MidiInWindowsEvent, MidiInCoreMidiEvent, MidiInCoreMidiVirtualEvent, MidiInALSAEvent, Rs232TesterEvent, Rs232NetEvent, ImGuiDelayedActionEvent, ImGuiActiveEvent > Event
Definition Event.hh:446
auto find(InputRange &&range, const T &value)
Definition ranges.hh:160
STL namespace.
constexpr auto transform(Range &&range, UnaryOp op)
Definition view.hh:520
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
Definition stl.hh:134
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.
Definition stl.hh:109
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition stl.hh:32
std::string strCat()
Definition strCat.hh:703
#define UNREACHABLE
constexpr auto end(const zstring_view &x)