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;
375 std::unique_ptr<HardwareConfig> extension;
378 *
this,
string(name), slotName);
381 "Extension \"", name,
"\" not found: ",
e.getMessage());
384 "Error in \"", name,
"\" extension: ",
e.getMessage());
390 std::string_view name, std::unique_ptr<HardwareConfig> extension)
393 extension->parseSlots();
394 extension->createDevices();
397 "Error in \"", name,
"\" extension: ",
e.getMessage());
399 string result = extension->getName();
400 extensions.push_back(std::move(extension));
408 return (it !=
end(extensions)) ? it->get() :
nullptr;
416 [](
auto&
e) {
return e.get(); });
417 extensions.erase(it);
428 if (!pluggingController) {
429 pluggingController = make_unique<PluggingController>(*
this);
431 return *pluggingController;
444 return *msxCpuInterface;
449 if (!panasonicMemory) {
450 panasonicMemory = make_unique<PanasonicMemory>(*
this);
452 return *panasonicMemory;
460 return *deviceSwitch;
470 cassettePort = make_unique<DummyCassettePort>();
473 return *cassettePort;
479 if (!joystickPort[0]) {
483 "JoystickPorts",
"AB");
484 if (ports !=
one_of(
"AB",
"",
"A",
"B")) {
486 "Invalid JoystickPorts specification, "
487 "should be one of '', 'A', 'B' or 'AB'.");
490 if (ports ==
one_of(
"AB",
"A")) {
491 joystickPort[0] = make_unique<JoystickPort>(
492 ctrl,
"joyporta",
"MSX Joystick port A");
494 joystickPort[0] = make_unique<DummyJoystickPort>();
496 if (ports ==
one_of(
"AB",
"B")) {
497 joystickPort[1] = make_unique<JoystickPort>(
498 ctrl,
"joyportb",
"MSX Joystick port B");
500 joystickPort[1] = make_unique<DummyJoystickPort>();
502 joyPortDebuggable = make_unique<JoyPortDebuggable>(*
this);
504 return *joystickPort[port];
511 renShaTurbo = make_unique<RenShaTurbo>(
522 ledStatus = make_unique<LedStatus>(
524 *msxCommandController,
532 return *msxCommandController;
537 return msxCommandController->getMachineInfoCommand();
542 return scheduler->getCurrentTime();
566 fastForwardHelper->setTarget(time);
593 availableDevices.push_back(&device);
603 if (!powered)
return;
608 for (
auto& d : availableDevices) {
615 Event::create<BootEvent>());
621 for (
auto& d : availableDevices) {
622 result &= d->readIRQVector();
645 for (
auto& d : availableDevices) {
653 Event::create<BootEvent>());
656void MSXMotherBoard::powerDown()
658 if (!powered)
return;
671 for (
auto& d : availableDevices) {
679 auto event = active ? Event::create<MachineActivatedEvent>()
680 : Event::create<MachineDeactivatedEvent>();
681 msxEventDistributor->distributeEvent(event, scheduler->getCurrentTime());
702 return (it !=
end(availableDevices)) ? *it :
nullptr;
707 if (mapperIOCounter == 0) {
727 assert(mapperIOCounter);
729 if (mapperIOCounter == 0) {
746 auto& s = userNames[hwName];
750 userName =
strCat(
"untitled", ++n);
752 s.push_back(userName);
758 auto& s = userNames[hwName];
764 machineMediaInfo->registerProvider(name, provider);
769 machineMediaInfo->unregisterProvider(provider);
776 : motherBoard(motherBoard_)
792 motherBoard_.getStateChangeDistributor(),
793 motherBoard_.getScheduler(),
795 , motherBoard(motherBoard_)
807 return "Resets the MSX.";
813 :
Command(motherBoard_.getCommandController(),
"load_machine")
814 , motherBoard(motherBoard_)
849 result = motherBoard.
loadMachine(
string(tokens[1].getString()));
854 return "Load a msx machine configuration into an empty machine.";
865 :
Command(motherBoard_.getCommandController(),
"list_extensions")
866 , motherBoard(motherBoard_)
874 [&](
auto&
e) { return e->getName(); }));
879 return "Return a list of all inserted extensions.";
886 motherBoard_.getStateChangeDistributor(),
887 motherBoard_.getScheduler(),
889 , motherBoard(motherBoard_)
890 , commandName(
std::move(commandName_))
899 auto slotName = (commandName.size() == 4)
900 ? std::string_view(&commandName[3], 1)
903 tokens[1].getString(), slotName);
911 return "Insert a hardware extension.";
923 motherBoard_.getStateChangeDistributor(),
924 motherBoard_.getScheduler(),
926 , motherBoard(motherBoard_)
934 std::string_view extName = tokens[1].getString();
943 "': ",
e.getMessage());
949 return "Remove an extension from the MSX machine.";
954 if (tokens.size() == 2) {
957 [](
auto&
e) -> std::string_view { return e->getName(); }));
965 :
InfoTopic(motherBoard_.getMachineInfoCommand(),
"config_name")
966 , motherBoard(motherBoard_)
978 return "Returns the configuration name for this machine.";
984 :
InfoTopic(motherBoard_.getMachineInfoCommand(),
"type")
985 , motherBoard(motherBoard_)
997 return "Returns the machine type for this machine.";
1004 :
InfoTopic(motherBoard_.getMachineInfoCommand(),
"extension")
1005 , motherBoard(motherBoard_)
1013 if (tokens.size() == 2) {
1016 [&](
auto&
e) { return e->getName(); }));
1017 }
else if (tokens.size() == 3) {
1018 std::string_view extName = tokens[2].getString();
1029 const auto& filename = extension->
getConfig()
1037 [&](
auto&
e) { return e->getName(); }));
1044 return "Returns information about the given extension instance.";
1049 if (tokens.size() == 3) {
1052 [](
auto&
e) -> std::string_view { return e->getName(); }));
1060 :
InfoTopic(motherBoard_.getMachineInfoCommand(),
"media")
1068 if (tokens.size() == 2) {
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);
1084 return "Returns information about the given media slot.";
1089 if (tokens.size() == 3) {
1091 providers, &ProviderInfo::name));
1097 assert(!
contains(providers, name, &ProviderInfo::name));
1098 assert(!
contains(providers, &provider, &ProviderInfo::provider));
1099 providers.push_back(ProviderInfo{name, &provider});
1111 :
InfoTopic(motherBoard_.getMachineInfoCommand(),
"device")
1112 , motherBoard(motherBoard_)
1119 switch (tokens.size()) {
1123 [](
auto& d) { return d->getName(); }));
1126 std::string_view deviceName = tokens[2].getString();
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.";
1146 if (tokens.size() == 3) {
1148 motherBoard.availableDevices,
1149 [](
auto& d) -> std::string_view { return d->getName(); }));
1158 , motherBoard(motherBoard_)
1167void FastForwardHelper::executeUntil(EmuTime::param )
1194 : motherBoard(motherBoard_)
1200 if (&
setting == &motherBoard.powerSetting) {
1201 if (motherBoard.powerSetting.getBoolean()) {
1202 motherBoard.powerUp();
1204 motherBoard.powerDown();
1206 }
else if (&
setting == &motherBoard.suppressMessagesSetting) {
1207 motherBoard.msxCliComm->setSuppressMessages(motherBoard.suppressMessagesSetting.getBoolean());
1220template<
typename Archive>
1230 ar.serialize(
"scheduler", *scheduler);
1233 if constexpr (Archive::IS_LOADER) {
1237 ar.serialize(
"name", machineName);
1238 ar.serializeWithID(
"config", machineConfig2, std::ref(*
this));
1240 ar.serializeWithID(
"extensions", extensions, std::ref(*
this));
1242 if (mapperIO) ar.serialize(
"mapperIO", *mapperIO);
1246 ar.serialize(
"deviceSwitch", devSwitch);
1250 ar.serialize(
"cpu",
getCPU());
1255 ar.serialize(
"cassetteport", *port);
1257 if (ar.versionAtLeast(version, 4)) {
1259 joystickPort[0].
get())) {
1260 ar.serialize(
"joystickportA", *port);
1263 joystickPort[1].
get())) {
1264 ar.serialize(
"joystickportB", *port);
1267 if (ar.versionAtLeast(version, 5)) {
1268 if (renShaTurbo) ar.serialize(
"renShaTurbo", *renShaTurbo);
1271 if constexpr (Archive::IS_LOADER) {
1279 assert(Archive::IS_LOADER);
1280 unsigned reRecordCount = 0;
1281 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
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 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)
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::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)
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 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:
const T & get(const Event &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.
std::string strCat(Ts &&...ts)
constexpr auto end(const zstring_view &x)