OXYGENHUB
◆ main openmsx / src / MSXMotherBoard.hh
12.9 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#ifndef MSXMOTHERBOARD_HH
2
#define MSXMOTHERBOARD_HH
3
4
#include "BooleanSetting.hh"
5
#include "EmuTime.hh"
6
#include "RecordedCommand.hh"
7
#include "VideoSourceSetting.hh"
8
#include "hash_map.hh"
9
#include "serialize_meta.hh"
10
#include "xxhash.hh"
11
12
#include <array>
13
#include <cassert>
14
#include <cstdint>
15
#include <memory>
16
#include <string_view>
17
#include <vector>
18
19
namespace openmsx {
20
21
class AddRemoveUpdate;
22
class CartridgeSlotManager;
23
class CassettePortInterface;
24
class CommandController;
25
class Debugger;
26
class DeviceInfo;
27
class EventDelay;
28
class ExtCmd;
29
class FastForwardHelper;
30
class HardwareConfig;
31
class InfoCommand;
32
class JoyPortDebuggable;
33
class JoystickPortIf;
34
class Keyboard;
35
class LedStatus;
36
class ListExtCmd;
37
class LoadMachineCmd;
38
class MachineExtensionInfo;
39
class MachineMediaInfo;
40
class MachineNameInfo;
41
class MachineTypeInfo;
42
class MSXCliComm;
43
class MSXCommandController;
44
class MSXCPU;
45
class MSXCPUInterface;
46
class MSXDevice;
47
class MSXDeviceSwitch;
48
class MSXEventDistributor;
49
class MSXMapperIO;
50
class MSXMixer;
51
class PanasonicMemory;
52
class PluggingController;
53
class Reactor;
54
class RealTime;
55
class RemoveExtCmd;
56
class RenShaTurbo;
57
class ResetCmd;
58
class StoreSetupCmd;
59
class ReverseManager;
60
class SettingObserver;
61
class Scheduler;
62
class StateChangeDistributor;
63
64
class MediaProvider
65
{
66
public:
67
	MediaProvider(const MediaProvider&) = delete;
68
	MediaProvider(MediaProvider&&) = delete;
69
	MediaProvider& operator=(const MediaProvider&) = delete;
70
	MediaProvider& operator=(MediaProvider&&) = delete;
71
72
	/** This method gets called when information is required on the
73
	 * media inserted in the media slot of the provider. The provider
74
	 * must attach the info as a dictionary to the given TclObject.
75
	 */
76
	virtual void getMediaInfo(TclObject& result) = 0;
77
78
	/** Insert media, based on the result from a previous getMediaInfo() call.
79
	 */
80
	virtual void setMedia(const TclObject& info, EmuTime time) = 0;
81
82
protected:
83
	MediaProvider() = default;
84
	~MediaProvider() = default;
85
};
86
87
struct MediaProviderInfo {
88
	std::string_view name;
89
	MediaProvider* provider;
90
};
91
92
// the order must be kept as it is, it's from shallow to deep
93
enum class SetupDepth : uint8_t { NONE, MACHINE, EXTENSIONS,
94
	CONNECTORS, MEDIA, COMPLETE_STATE,
95
	NUM /* must be last, for being able to use array_from_enum_index */};
96
97
class MSXMotherBoard final
98
{
99
public:
100
	MSXMotherBoard(const MSXMotherBoard&) = delete;
101
	MSXMotherBoard(MSXMotherBoard&&) = delete;
102
	MSXMotherBoard& operator=(const MSXMotherBoard&) = delete;
103
	MSXMotherBoard& operator=(MSXMotherBoard&&) = delete;
104
105
	explicit MSXMotherBoard(Reactor& reactor);
106
	~MSXMotherBoard();
107
108
	[[nodiscard]] std::string_view getMachineID()   const { return machineID; }
109
	[[nodiscard]] std::string_view getMachineName() const { return machineName; }
110
111
	/** Run emulation.
112
	 * @return True if emulation steps were done,
113
	 *   false if emulation is suspended.
114
	 */
115
	[[nodiscard]] bool execute();
116
117
	/** Run emulation until a certain time in fast forward mode.
118
	 */
119
	void fastForward(EmuTime time, bool fast);
120
121
	/** See CPU::exitCPULoopAsync(). */
122
	void exitCPULoopAsync();
123
	void exitCPULoopSync();
124
125
	/** Pause MSX machine. Only CPU is paused, other devices continue
126
	  * running. Used by turbor hardware pause.
127
	  */
128
	void pause();
129
	void unpause();
130
131
	void powerUp();
132
	void powerDown();
133
	[[nodiscard]] bool isPowered() const { return powered; }
134
135
	void doReset();
136
	void activate(bool active);
137
	[[nodiscard]] bool isActive() const { return active; }
138
	[[nodiscard]] bool isFastForwarding() const { return fastForwarding; }
139
140
	[[nodiscard]] uint8_t readIRQVector() const;
141
142
	[[nodiscard]] const HardwareConfig* getMachineConfig() const { return machineConfig; }
143
	[[nodiscard]] HardwareConfig* getMachineConfig() { return machineConfig; }
144
	void setMachineConfig(HardwareConfig* machineConfig);
145
	[[nodiscard]] std::string_view getMachineType() const;
146
	[[nodiscard]] bool isTurboR() const;
147
	[[nodiscard]] bool hasToshibaEngine() const;
148
149
	std::string loadMachine(const std::string& machine);
150
151
	void storeAsSetup(const std::string& filename, SetupDepth depth);
152
153
	using Extensions = std::vector<std::unique_ptr<HardwareConfig>>;
154
	[[nodiscard]] const Extensions& getExtensions() const { return extensions; }
155
	[[nodiscard]] HardwareConfig* findExtension(std::string_view extensionName);
156
	std::unique_ptr<HardwareConfig> loadExtension(std::string_view extensionName, std::string_view slotName);
157
	std::string insertExtension(std::string_view name,
158
	                            std::unique_ptr<HardwareConfig> extension);
159
	void removeExtension(const HardwareConfig& extension);
160
161
	// The following classes are unique per MSX machine
162
	[[nodiscard]] MSXCliComm& getMSXCliComm();
163
	[[nodiscard]] MSXCommandController& getMSXCommandController() { return *msxCommandController; }
164
	[[nodiscard]] Scheduler& getScheduler() { return *scheduler; }
165
	[[nodiscard]] MSXEventDistributor& getMSXEventDistributor() { return *msxEventDistributor; }
166
	[[nodiscard]] StateChangeDistributor& getStateChangeDistributor() { return *stateChangeDistributor; }
167
	[[nodiscard]] CartridgeSlotManager& getSlotManager() { return *slotManager; }
168
	[[nodiscard]] RealTime& getRealTime() { return *realTime; }
169
	[[nodiscard]] Debugger& getDebugger() { return *debugger; }
170
	[[nodiscard]] MSXMixer& getMSXMixer() { return *msxMixer; }
171
	[[nodiscard]] PluggingController& getPluggingController();
172
	[[nodiscard]] MSXCPU& getCPU();
173
	[[nodiscard]] MSXCPUInterface& getCPUInterface();
174
	[[nodiscard]] PanasonicMemory& getPanasonicMemory();
175
	[[nodiscard]] MSXDeviceSwitch& getDeviceSwitch();
176
	[[nodiscard]] CassettePortInterface& getCassettePort();
177
	[[nodiscard]] JoystickPortIf& getJoystickPort(unsigned port);
178
	[[nodiscard]] RenShaTurbo& getRenShaTurbo();
179
	[[nodiscard]] LedStatus& getLedStatus();
180
	[[nodiscard]] ReverseManager& getReverseManager() { return *reverseManager; }
181
	[[nodiscard]] Reactor& getReactor() { return reactor; }
182
	[[nodiscard]] VideoSourceSetting& getVideoSource() { return videoSourceSetting; }
183
	[[nodiscard]] BooleanSetting& suppressMessages() { return suppressMessagesSetting; }
184
185
	// convenience methods
186
	[[nodiscard]] CommandController& getCommandController();
187
	[[nodiscard]] InfoCommand& getMachineInfoCommand();
188
189
	/** Convenience method:
190
	  * This is the same as getScheduler().getCurrentTime(). */
191
	[[nodiscard]] EmuTime getCurrentTime() const;
192
193
	/** All MSXDevices should be registered by the MotherBoard.
194
	 */
195
	void addDevice(MSXDevice& device);
196
	void removeDevice(MSXDevice& device);
197
198
	/** Find a MSXDevice by name
199
	  * @param name The name of the device as returned by
200
	  *             MSXDevice::getName()
201
	  * @return A pointer to the device or nullptr if the device could not
202
	  *         be found.
203
	  */
204
	[[nodiscard]] MSXDevice* findDevice(std::string_view name);
205
206
	/** Some MSX device parts are shared between several MSX devices
207
	  * (e.g. all memory mappers share IO ports 0xFC-0xFF). But this
208
	  * sharing is limited to one MSX machine. This method offers the
209
	  * storage to implement per-machine reference counted objects.
210
	  * TODO This doesn't play nicely with savestates. For example memory
211
	  *      mappers don't use this mechanism anymore because of this.
212
	  *      Maybe this method can be removed when savestates are finished.
213
	  */
214
	template<typename T, typename ... Args>
215
	[[nodiscard]] std::shared_ptr<T> getSharedStuff(std::string_view name, Args&& ...args)
216
	{
217
		auto& weak = sharedStuffMap[name];
218
		auto shared = std::static_pointer_cast<T>(weak.lock());
219
		if (shared) return shared;
220
221
		shared = std::make_shared<T>(std::forward<Args>(args)...);
222
		weak = shared;
223
		return shared;
224
	}
225
226
	/** All memory mappers in one MSX machine share the same four (logical)
227
	 * memory mapper registers. These two methods handle this sharing.
228
	 */
229
	[[nodiscard]] MSXMapperIO& createMapperIO();
230
	[[nodiscard]] MSXMapperIO& getMapperIO() const
231
	{
232
		assert(mapperIOCounter);
233
		return *mapperIO;
234
	}
235
	void destroyMapperIO();
236
237
	/** Keep track of which 'usernames' are in use.
238
	 * For example to be able to use several fmpac extensions at once, each
239
	 * with its own SRAM file, we need to generate unique filenames. We
240
	 * also want to reuse existing filenames as much as possible.
241
	 * ATM the usernames always have the format 'untitled[N]'. In the future
242
	 * we might allow really user specified names.
243
	 */
244
	[[nodiscard]] std::string getUserName(const std::string& hwName);
245
	void freeUserName(const std::string& hwName, const std::string& userName);
246
247
	/** Register and unregister providers of media info, for the media info
248
	 * topic.
249
	 */
250
	void registerMediaProvider(std::string_view name, MediaProvider& provider);
251
	void unregisterMediaProvider(MediaProvider& provider);
252
	[[nodiscard]] const auto& getMediaProviders() const { return mediaProviders; }
253
	[[nodiscard]] MediaProvider* findMediaProvider(std::string_view name) const;
254
255
	void registerKeyboard(Keyboard& keyboard) {
256
		// Typically there's only 1 keyboard, but we shouldn't crash on
257
		// configurations that artificially use 2 MSXPPI devices.
258
		keyboards.push_back(&keyboard);
259
	}
260
	void unregisterKeyboard(Keyboard& keyboard) {
261
		auto it = find_unguarded(keyboards, &keyboard);
262
		keyboards.erase(it);
263
	}
264
	[[nodiscard]] Keyboard* getKeyboard() const {
265
		// Typically there's exactly 1 keyboard, except for early during
266
		// machine construction, or on artificial machine configs
267
		// without MSXPPI (they don't make sense, but we shouldn't crash
268
		// on it).
269
		return keyboards.empty() ? nullptr : keyboards.front();
270
	}
271
272
	template<typename Archive>
273
	void serialize(Archive& ar, unsigned version);
274
275
private:
276
	void deleteMachine();
277
278
private:
279
	Reactor& reactor;
280
	std::string machineID;
281
	std::string machineName;
282
283
	std::vector<MSXDevice*> availableDevices; // no ownership, no order
284
285
	hash_map<std::string_view, std::weak_ptr<void>,      XXHasher> sharedStuffMap;
286
	hash_map<std::string, std::vector<std::string>, XXHasher> userNames;
287
288
	std::unique_ptr<MSXMapperIO> mapperIO;
289
	unsigned mapperIOCounter = 0;
290
291
	// These two should normally be the same, only during savestate loading
292
	// machineConfig will already be filled in, but machineConfig2 not yet.
293
	// This is important when an exception happens during loading of
294
	// machineConfig2 (otherwise machineConfig2 gets deleted twice).
295
	// See also HardwareConfig::serialize() and setMachineConfig()
296
	std::unique_ptr<HardwareConfig> machineConfig2;
297
	HardwareConfig* machineConfig = nullptr;
298
299
	Extensions extensions; // order matters: later extension might depend on earlier ones
300
301
	// order of unique_ptr's is important!
302
	std::unique_ptr<AddRemoveUpdate> addRemoveUpdate;
303
	std::unique_ptr<MSXCliComm> msxCliComm;
304
	std::unique_ptr<MSXEventDistributor> msxEventDistributor;
305
	std::unique_ptr<StateChangeDistributor> stateChangeDistributor;
306
	std::unique_ptr<MSXCommandController> msxCommandController;
307
	std::unique_ptr<Scheduler> scheduler;
308
	std::unique_ptr<EventDelay> eventDelay;
309
	std::unique_ptr<RealTime> realTime;
310
	std::unique_ptr<Debugger> debugger;
311
	std::unique_ptr<MSXMixer> msxMixer;
312
	// machineMediaInfo must be BEFORE PluggingController!
313
	std::vector<MediaProviderInfo> mediaProviders; // unsorted, there will only be a few
314
	std::unique_ptr<MachineMediaInfo> machineMediaInfo;
315
	std::unique_ptr<PluggingController> pluggingController;
316
	std::unique_ptr<MSXCPU> msxCpu;
317
	std::unique_ptr<MSXCPUInterface> msxCpuInterface;
318
	std::unique_ptr<PanasonicMemory> panasonicMemory;
319
	std::unique_ptr<MSXDeviceSwitch> deviceSwitch;
320
	std::unique_ptr<CassettePortInterface> cassettePort;
321
	std::array<std::unique_ptr<JoystickPortIf>, 2> joystickPort;
322
	std::unique_ptr<JoyPortDebuggable> joyPortDebuggable;
323
	std::unique_ptr<RenShaTurbo> renShaTurbo;
324
	std::unique_ptr<LedStatus> ledStatus;
325
	VideoSourceSetting videoSourceSetting;
326
	BooleanSetting suppressMessagesSetting;
327
328
	std::unique_ptr<CartridgeSlotManager> slotManager;
329
	std::unique_ptr<ReverseManager> reverseManager;
330
	std::unique_ptr<ResetCmd>     resetCommand;
331
	std::unique_ptr<LoadMachineCmd> loadMachineCommand;
332
	std::unique_ptr<ListExtCmd>   listExtCommand;
333
	std::unique_ptr<ExtCmd>       extCommand;
334
	std::unique_ptr<RemoveExtCmd> removeExtCommand;
335
	std::unique_ptr<StoreSetupCmd> storeSetupCommand;
336
	std::unique_ptr<MachineNameInfo> machineNameInfo;
337
	std::unique_ptr<MachineTypeInfo> machineTypeInfo;
338
	std::unique_ptr<MachineExtensionInfo> machineExtensionInfo;
339
	std::unique_ptr<DeviceInfo>   deviceInfo;
340
	friend class DeviceInfo;
341
342
	std::unique_ptr<FastForwardHelper> fastForwardHelper;
343
344
	std::unique_ptr<SettingObserver> settingObserver;
345
	friend class SettingObserver;
346
	BooleanSetting& powerSetting;
347
348
	std::vector<Keyboard*> keyboards; // typically contains exactly 1 item
349
350
	bool powered = false;
351
	bool active = false;
352
	bool fastForwarding = false;
353
};
354
SERIALIZE_CLASS_VERSION(MSXMotherBoard, 5);
355
356
class ExtCmd final : public RecordedCommand
357
{
358
public:
359
	ExtCmd(MSXMotherBoard& motherBoard, std::string commandName);
360
	void execute(std::span<const TclObject> tokens, TclObject& result,
361
	             EmuTime time) override;
362
	[[nodiscard]] std::string help(std::span<const TclObject> tokens) const override;
363
	void tabCompletion(std::vector<std::string>& tokens) const override;
364
private:
365
	MSXMotherBoard& motherBoard;
366
	std::string commandName;
367
};
368
369
} // namespace openmsx
370
371
#endif