54using std::make_unique;
75 EmuTime::param time)
override;
76 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
86 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
87 void tabCompletion(std::vector<string>& tokens)
const override;
97 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
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;
118 void execute(std::span<const TclObject> tokens,
120 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
129 void execute(std::span<const TclObject> tokens,
131 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
140 void execute(std::span<const TclObject> tokens,
142 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
143 void tabCompletion(std::vector<string>& tokens)
const override;
153 assert(providers.empty());
155 void execute(std::span<const TclObject> tokens,
157 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
158 void tabCompletion(std::vector<string>& tokens)
const override;
162 struct ProviderInfo {
163 std::string_view name;
167 std::vector<ProviderInfo> providers;
174 void execute(std::span<const TclObject> tokens,
176 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
177 void tabCompletion(std::vector<string>& tokens)
const override;
186 void setTarget(EmuTime::param targetTime);
188 void executeUntil(EmuTime::param time)
override;
196 [[nodiscard]]
byte read(
unsigned address, EmuTime::param time)
override;
197 void write(
unsigned address,
byte value)
override;
210static unsigned machineIDCounter = 0;
214 , machineID(
strCat(
"machine", ++machineIDCounter))
215 , msxCliComm(make_unique<
MSXCliComm>(*this, reactor.getGlobalCliComm()))
219 reactor.getGlobalCommandController(), reactor,
220 *this, *msxEventDistributor, machineID))
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.",
234 , powerSetting(reactor.getGlobalSettings().getPowerSetting())
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);
255 addRemoveUpdate = make_unique<AddRemoveUpdate>(*
this);
260 eventDelay = make_unique<EventDelay>(
261 *scheduler, *msxCommandController,
264 realTime = make_unique<RealTime>(
267 powerSetting.
attach(*settingObserver);
268 suppressMessagesSetting.
attach(*settingObserver);
273 suppressMessagesSetting.
detach(*settingObserver);
274 powerSetting.
detach(*settingObserver);
277 assert(mapperIOCounter == 0);
278 assert(availableDevices.empty());
279 assert(extensions.empty());
280 assert(!machineConfig2);
284void MSXMotherBoard::deleteMachine()
286 while (!extensions.empty()) {
289 }
catch (MSXException& e) {
290 std::cerr <<
"Internal error: failed to remove "
291 "extension while deleting a machine: "
292 << e.getMessage() <<
'\n';
297 machineConfig2.reset();
298 machineConfig =
nullptr;
304 machineConfig = machineConfig_;
308 msxCpu = make_unique<MSXCPU>(*
this);
309 msxCpuInterface = make_unique<MSXCPUInterface>(*
this);
315 if (
const auto* info = machine->getConfig().findChild(
"info")) {
316 if (
const auto* type = info->findChild(
"type")) {
317 return type->getData();
336 return devices.
findChild(
"T7775") !=
nullptr ||
344 assert(machineName.empty());
345 assert(extensions.empty());
346 assert(!machineConfig2);
353 throw MSXException(
"Machine \"", machine,
"\" not found: ",
356 throw MSXException(
"Error in \"", machine,
"\" machine: ",
363 throw MSXException(
"Error in \"", machine,
"\" machine: ",
369 machineName = machine;
377 *
this,
string(name), slotName);
380 "Extension \"", name,
"\" not found: ", e.getMessage());
383 "Error in \"", name,
"\" extension: ", e.getMessage());
388 std::string_view name, std::unique_ptr<HardwareConfig> extension)
391 extension->parseSlots();
392 extension->createDevices();
395 "Error in \"", name,
"\" extension: ", e.getMessage());
397 string result = extension->getName();
398 extensions.push_back(std::move(extension));
406 return (it !=
end(extensions)) ? it->get() :
nullptr;
414 [](
auto& e) {
return e.get(); });
415 extensions.erase(it);
426 if (!pluggingController) {
427 pluggingController = make_unique<PluggingController>(*
this);
429 return *pluggingController;
442 return *msxCpuInterface;
447 if (!panasonicMemory) {
448 panasonicMemory = make_unique<PanasonicMemory>(*
this);
450 return *panasonicMemory;
458 return *deviceSwitch;
468 cassettePort = make_unique<DummyCassettePort>();
471 return *cassettePort;
477 if (!joystickPort[0]) {
481 "JoystickPorts",
"AB");
482 if (ports !=
one_of(
"AB",
"",
"A",
"B")) {
484 "Invalid JoystickPorts specification, "
485 "should be one of '', 'A', 'B' or 'AB'.");
488 if (ports ==
one_of(
"AB",
"A")) {
489 joystickPort[0] = make_unique<JoystickPort>(
490 ctrl,
"joyporta",
"MSX Joystick port A");
492 joystickPort[0] = make_unique<DummyJoystickPort>();
494 if (ports ==
one_of(
"AB",
"B")) {
495 joystickPort[1] = make_unique<JoystickPort>(
496 ctrl,
"joyportb",
"MSX Joystick port B");
498 joystickPort[1] = make_unique<DummyJoystickPort>();
500 joyPortDebuggable = make_unique<JoyPortDebuggable>(*
this);
502 return *joystickPort[port];
509 renShaTurbo = make_unique<RenShaTurbo>(
520 ledStatus = make_unique<LedStatus>(
522 *msxCommandController,
530 return *msxCommandController;
535 return msxCommandController->getMachineInfoCommand();
540 return scheduler->getCurrentTime();
564 fastForwardHelper->setTarget(time);
591 availableDevices.push_back(&device);
601 if (!powered)
return;
606 for (
auto& d : availableDevices) {
618 for (
auto& d : availableDevices) {
619 result &= d->readIRQVector();
642 for (
auto& d : availableDevices) {
652void MSXMotherBoard::powerDown()
654 if (!powered)
return;
667 for (
auto& d : availableDevices) {
677 msxEventDistributor->distributeEvent(event, scheduler->getCurrentTime());
698 return (it !=
end(availableDevices)) ? *it :
nullptr;
703 if (mapperIOCounter == 0) {
723 assert(mapperIOCounter);
725 if (mapperIOCounter == 0) {
742 auto& s = userNames[hwName];
746 userName =
strCat(
"untitled", ++n);
748 s.push_back(userName);
754 auto& s = userNames[hwName];
760 machineMediaInfo->registerProvider(name, provider);
765 machineMediaInfo->unregisterProvider(provider);
772 : motherBoard(motherBoard_)
788 motherBoard_.getStateChangeDistributor(),
789 motherBoard_.getScheduler(),
791 , motherBoard(motherBoard_)
803 return "Resets the MSX.";
809 :
Command(motherBoard_.getCommandController(),
"load_machine")
810 , motherBoard(motherBoard_)
845 result = motherBoard.
loadMachine(
string(tokens[1].getString()));
850 return "Load a msx machine configuration into an empty machine.";
861 :
Command(motherBoard_.getCommandController(),
"list_extensions")
862 , motherBoard(motherBoard_)
870 [&](
auto& e) { return e->getName(); }));
875 return "Return a list of all inserted extensions.";
882 motherBoard_.getStateChangeDistributor(),
883 motherBoard_.getScheduler(),
885 , motherBoard(motherBoard_)
886 , commandName(
std::move(commandName_))
894 if (tokens.size() == 3 && tokens[1].getString() !=
"insert") {
898 auto name = tokens[tokens.size() - 1].getString();
899 auto slotName = (commandName.size() == 4)
900 ? std::string_view(&commandName[3], 1)
903 if (slotName !=
"any") {
905 if (
const auto* extConf = manager.getConfigForSlot(commandName[3] -
'a')) {
918 return "Insert a hardware extension.";
930 motherBoard_.getStateChangeDistributor(),
931 motherBoard_.getScheduler(),
933 , motherBoard(motherBoard_)
941 std::string_view extName = tokens[1].getString();
950 "': ", e.getMessage());
956 return "Remove an extension from the MSX machine.";
961 if (tokens.size() == 2) {
964 [](
auto& e) -> std::string_view { return e->getName(); }));
972 :
InfoTopic(motherBoard_.getMachineInfoCommand(),
"config_name")
973 , motherBoard(motherBoard_)
985 return "Returns the configuration name for this machine.";
991 :
InfoTopic(motherBoard_.getMachineInfoCommand(),
"type")
992 , motherBoard(motherBoard_)
1004 return "Returns the machine type for this machine.";
1011 :
InfoTopic(motherBoard_.getMachineInfoCommand(),
"extension")
1012 , motherBoard(motherBoard_)
1020 if (tokens.size() == 2) {
1023 [&](
auto& e) { return e->getName(); }));
1024 }
else if (tokens.size() == 3) {
1025 std::string_view extName = tokens[2].getString();
1036 const auto& filename = extension->
getConfig()
1044 [&](
auto& e) { return e->getName(); }));
1051 return "Returns information about the given extension instance.";
1056 if (tokens.size() == 3) {
1059 [](
auto& e) -> std::string_view { return e->getName(); }));
1067 :
InfoTopic(motherBoard_.getMachineInfoCommand(),
"media")
1075 if (tokens.size() == 2) {
1078 }
else if (tokens.size() == 3) {
1079 auto name = tokens[2].getString();
1080 if (
auto it =
ranges::find(providers, name, &ProviderInfo::name);
1081 it != providers.end()) {
1082 it->provider->getMediaInfo(result);
1091 return "Returns information about the given media slot.";
1096 if (tokens.size() == 3) {
1098 providers, &ProviderInfo::name));
1104 assert(!
contains(providers, name, &ProviderInfo::name));
1105 assert(!
contains(providers, &provider, &ProviderInfo::provider));
1106 providers.push_back(ProviderInfo{name, &provider});
1118 :
InfoTopic(motherBoard_.getMachineInfoCommand(),
"device")
1119 , motherBoard(motherBoard_)
1126 switch (tokens.size()) {
1130 [](
auto& d) { return d->getName(); }));
1133 std::string_view deviceName = tokens[2].getString();
1146 return "Without any arguments, returns the list of used device names.\n"
1147 "With a device name as argument, returns the type (and for some "
1148 "devices the subtype) of the given device.";
1153 if (tokens.size() == 3) {
1155 motherBoard.availableDevices,
1156 [](
auto& d) -> std::string_view { return d->getName(); }));
1165 , motherBoard(motherBoard_)
1174void FastForwardHelper::executeUntil(EmuTime::param )
1201 : motherBoard(motherBoard_)
1207 if (&
setting == &motherBoard.powerSetting) {
1208 if (motherBoard.powerSetting.getBoolean()) {
1209 motherBoard.powerUp();
1211 motherBoard.powerDown();
1213 }
else if (&
setting == &motherBoard.suppressMessagesSetting) {
1214 motherBoard.msxCliComm->setSuppressMessages(motherBoard.suppressMessagesSetting.getBoolean());
1227template<
typename Archive>
1237 ar.serialize(
"scheduler", *scheduler);
1240 if constexpr (Archive::IS_LOADER) {
1244 ar.serialize(
"name", machineName);
1245 ar.serializeWithID(
"config", machineConfig2, std::ref(*
this));
1247 ar.serializeWithID(
"extensions", extensions, std::ref(*
this));
1249 if (mapperIO) ar.serialize(
"mapperIO", *mapperIO);
1253 ar.serialize(
"deviceSwitch", devSwitch);
1257 ar.serialize(
"cpu",
getCPU());
1262 ar.serialize(
"cassetteport", *port);
1264 if (ar.versionAtLeast(version, 4)) {
1266 joystickPort[0].get())) {
1267 ar.serialize(
"joystickportA", *port);
1270 joystickPort[1].get())) {
1271 ar.serialize(
"joystickportB", *port);
1274 if (ar.versionAtLeast(version, 5)) {
1275 if (renShaTurbo) ar.serialize(
"renShaTurbo", *renShaTurbo);
1278 if constexpr (Archive::IS_LOADER) {
1286 assert(Archive::IS_LOADER);
1287 unsigned reRecordCount = 0;
1288 ar.serialize(
"reRecordCount", reRecordCount);
Assign new value to some variable and restore the original value when this object goes out of scope.
AddRemoveUpdate(const AddRemoveUpdate &)=delete
AddRemoveUpdate(MSXMotherBoard &motherBoard)
AddRemoveUpdate & operator=(const AddRemoveUpdate &)=delete
bool getBoolean() const noexcept
Sent when the MSX resets or powers up.
void setAllowedInEmptyMachine(bool value)
static void completeString(std::vector< std::string > &tokens, ITER begin, ITER end, bool caseSensitive=true)
void checkNumArgs(std::span< const TclObject > tokens, unsigned exactly, const char *errMessage) const
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)
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()
void doReset(EmuTime::param time)
Reset CPU.
void setPaused(bool paused)
(un)pause CPU.
void exitCPULoopAsync()
See CPUCore::exitCPULoopAsync()
void update(UpdateType type, std::string_view name, std::string_view value) override
bool hasRegisteredDevices() const
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
void getDeviceInfo(TclObject &result) const
Get device info.
virtual const std::string & getName() const
Returns a human-readable name for this device.
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::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)
MSXCliComm & getMSXCliComm()
LedStatus & getLedStatus()
bool hasToshibaEngine() const
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.
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 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.
Central administration of Connectors and Pluggables.
Contains the main loop of openMSX.
GlobalSettings & getGlobalSettings()
GlobalCliComm & getGlobalCliComm()
RTScheduler & getRTScheduler()
EventDistributor & getEventDistributor()
static std::vector< std::string > getHwConfigs(std::string_view type)
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)
void attach(Observer< T > &observer)
void addListElements(ITER first, ITER last)
void addDictKeyValue(const Key &key, const Value &value)
const XMLElement * findChild(std::string_view childName) const
const XMLElement & getChild(std::string_view childName) const
std::string_view getChildData(std::string_view childName) const
This file implemented 3 utility functions:
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
auto find(InputRange &&range, const T &value)
constexpr auto transform(Range &&range, UnaryOp op)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
auto rfind_unguarded(RANGE &range, const VAL &val, Proj proj={})
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
constexpr auto end(const zstring_view &x)