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