MSXDevice.hh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #ifndef MSXDEVICE_HH
  2. #define MSXDEVICE_HH
  3. #include "DeviceConfig.hh"
  4. #include "EmuTime.hh"
  5. #include "openmsx.hh"
  6. #include "serialize_meta.hh"
  7. #include <string>
  8. #include <vector>
  9. #include <utility> // for pair
  10. namespace openmsx {
  11. class XMLElement;
  12. class MSXMotherBoard;
  13. class MSXCPU;
  14. class MSXCPUInterface;
  15. class Scheduler;
  16. class CliComm;
  17. class Reactor;
  18. class CommandController;
  19. class LedStatus;
  20. class PluggingController;
  21. class HardwareConfig;
  22. class TclObject;
  23. /** An MSXDevice is an emulated hardware component connected to the bus
  24. * of the emulated MSX. There is no communication among devices, only
  25. * between devices and the CPU.
  26. */
  27. class MSXDevice
  28. {
  29. public:
  30. MSXDevice(const MSXDevice&) = delete;
  31. MSXDevice& operator=(const MSXDevice&) = delete;
  32. using Devices = std::vector<MSXDevice*>;
  33. virtual ~MSXDevice() = 0;
  34. /** Returns the hardwareconfig this device belongs to.
  35. */
  36. const HardwareConfig& getHardwareConfig() const {
  37. return deviceConfig.getHardwareConfig();
  38. }
  39. /** Checks whether this device can be removed (no other device has a
  40. * reference to it). Throws an exception if it can't be removed.
  41. */
  42. void testRemove(Devices alreadyRemoved) const;
  43. /**
  44. * This method is called on reset.
  45. * Default implementation does nothing.
  46. */
  47. virtual void reset(EmuTime::param time);
  48. /**
  49. * Gets IRQ vector used in IM2. This method only exists to support
  50. * YamahaSfg05. There is no way for several devices to coordinate which
  51. * vector is actually send to the CPU. But this IM is anyway not really
  52. * supported in the MSX standard.
  53. * Default implementation returns 0xFF.
  54. */
  55. virtual byte readIRQVector();
  56. /**
  57. * This method is called when MSX is powered down. The default
  58. * implementation does nothing, this is usually ok. Typically devices
  59. * that need to turn off LEDs need to reimplement this method.
  60. * @param time The moment in time the power down occurs.
  61. */
  62. virtual void powerDown(EmuTime::param time);
  63. /**
  64. * This method is called when MSX is powered up. The default
  65. * implementation calls reset(), this is usually ok.
  66. * @param time The moment in time the power up occurs.
  67. */
  68. virtual void powerUp(EmuTime::param time);
  69. /**
  70. * Returns a human-readable name for this device.
  71. * Default implementation is normally ok.
  72. */
  73. virtual std::string getName() const;
  74. /** Returns list of name(s) of this device.
  75. * This is normally the same as getName() (but formatted as a Tcl list)
  76. * except for multi-{mem,io}-devices.
  77. */
  78. virtual void getNameList(TclObject& result) const;
  79. /** Get device info.
  80. * Used by the 'machine_info device' command.
  81. */
  82. void getDeviceInfo(TclObject& result) const;
  83. /** Returns the range where this device is visible in memory.
  84. * This is the union of the "mem" tags inside the device tag in
  85. * hardwareconfig.xml (though practically always there is only one
  86. * "mem" tag). Information on possible holes in this range (when there
  87. * are multiple "mem" tags) is not returned by this method.
  88. */
  89. void getVisibleMemRegion(unsigned& base, unsigned& size) const;
  90. // IO
  91. /**
  92. * Read a byte from an IO port at a certain time from this device.
  93. * The default implementation returns 255.
  94. */
  95. virtual byte readIO(word port, EmuTime::param time);
  96. /**
  97. * Write a byte to a given IO port at a certain time to this
  98. * device.
  99. * The default implementation ignores the write (does nothing)
  100. */
  101. virtual void writeIO(word port, byte value, EmuTime::param time);
  102. /**
  103. * Read a byte from a given IO port. Reading via this method has no
  104. * side effects (doesn't change the device status). If safe reading
  105. * is not possible this method returns 0xFF.
  106. * This method is not used by the emulation. It can however be used
  107. * by a debugger.
  108. * The default implementation just returns 0xFF.
  109. */
  110. virtual byte peekIO(word port, EmuTime::param time) const;
  111. // Memory
  112. /**
  113. * Read a byte from a location at a certain time from this
  114. * device.
  115. * The default implementation returns 255.
  116. */
  117. virtual byte readMem(word address, EmuTime::param time);
  118. /**
  119. * Write a given byte to a given location at a certain time
  120. * to this device.
  121. * The default implementation ignores the write (does nothing).
  122. */
  123. virtual void writeMem(word address, byte value, EmuTime::param time);
  124. /**
  125. * Test that the memory in the interval [start, start +
  126. * CacheLine::SIZE) is cacheable for reading. If it is, a pointer to a
  127. * buffer containing this interval must be returned. If not, a null
  128. * pointer must be returned.
  129. * Cacheable for reading means the data may be read directly
  130. * from the buffer, thus bypassing the readMem() method, and
  131. * thus also ignoring EmuTime.
  132. * The default implementation always returns a null pointer.
  133. * The start of the interval is CacheLine::SIZE aligned.
  134. */
  135. virtual const byte* getReadCacheLine(word start) const;
  136. /**
  137. * Test that the memory in the interval [start, start +
  138. * CacheLine::SIZE) is cacheable for writing. If it is, a pointer to a
  139. * buffer containing this interval must be returned. If not, a null
  140. * pointer must be returned.
  141. * Cacheable for writing means the data may be written directly
  142. * to the buffer, thus bypassing the writeMem() method, and
  143. * thus also ignoring EmuTime.
  144. * The default implementation always returns a null pointer.
  145. * The start of the interval is CacheLine::SIZE aligned.
  146. */
  147. virtual byte* getWriteCacheLine(word start) const;
  148. /**
  149. * Read a byte from a given memory location. Reading memory
  150. * via this method has no side effects (doesn't change the
  151. * device status). If save reading is not possible this
  152. * method returns 0xFF.
  153. * This method is not used by the emulation. It can however
  154. * be used by a debugger.
  155. * The default implementation uses the cache mechanism
  156. * (getReadCacheLine() method). If a certain region is not
  157. * cacheable you cannot read it by default, Override this
  158. * method if you want to improve this behaviour.
  159. */
  160. virtual byte peekMem(word address, EmuTime::param time) const;
  161. /** Global writes.
  162. * Some devices violate the MSX standard by ignoring the SLOT-SELECT
  163. * signal; they react to writes to a certain address in _any_ slot.
  164. * Luckily the only known example so far is 'Super Lode Runner'.
  165. * This method is triggered for such 'global' writes.
  166. * You need to register each address for which you want this method
  167. * to be triggered.
  168. */
  169. virtual void globalWrite(word address, byte value, EmuTime::param time);
  170. /** Global reads. Similar to globalWrite() but then for reads.
  171. * 'Carnivore2' is an example of a device that monitors the MSX bus
  172. * for reads in any slot.
  173. */
  174. virtual void globalRead(word address, EmuTime::param time);
  175. /** Calls MSXCPUInterface::invalidateXXCache() for the specific (part
  176. * of) the slot that this device is located in.
  177. */
  178. void invalidateDeviceRWCache() { invalidateDeviceRWCache(0x0000, 0x10000); }
  179. void invalidateDeviceRCache() { invalidateDeviceRCache (0x0000, 0x10000); }
  180. void invalidateDeviceWCache() { invalidateDeviceWCache (0x0000, 0x10000); }
  181. void invalidateDeviceRWCache(unsigned start, unsigned size);
  182. void invalidateDeviceRCache (unsigned start, unsigned size);
  183. void invalidateDeviceWCache (unsigned start, unsigned size);
  184. /** Calls MSXCPUInterface::fillXXCache() for the specific (part of) the
  185. * slot that this device is located in.
  186. */
  187. void fillDeviceRWCache(unsigned start, unsigned size, byte* rwData);
  188. void fillDeviceRWCache(unsigned start, unsigned size, const byte* rData, byte* wData);
  189. void fillDeviceRCache (unsigned start, unsigned size, const byte* rData);
  190. void fillDeviceWCache (unsigned start, unsigned size, byte* wData);
  191. /** Get the mother board this device belongs to
  192. */
  193. MSXMotherBoard& getMotherBoard() const;
  194. /** Get the configuration section for this device.
  195. * This was passed as a constructor argument.
  196. */
  197. const XMLElement& getDeviceConfig() const {
  198. return *deviceConfig.getXML();
  199. }
  200. const DeviceConfig& getDeviceConfig2() const { // TODO
  201. return deviceConfig;
  202. }
  203. /** Get the device references that are specified for this device
  204. */
  205. const Devices& getReferences() const;
  206. // convenience functions, these delegate to MSXMotherBoard
  207. EmuTime::param getCurrentTime() const;
  208. MSXCPU& getCPU() const;
  209. MSXCPUInterface& getCPUInterface() const;
  210. Scheduler& getScheduler() const;
  211. CliComm& getCliComm() const;
  212. Reactor& getReactor() const;
  213. CommandController& getCommandController() const;
  214. PluggingController& getPluggingController() const;
  215. LedStatus& getLedStatus() const;
  216. template<typename Archive>
  217. void serialize(Archive& ar, unsigned version);
  218. protected:
  219. /** Every MSXDevice has a config entry; this constructor gets
  220. * some device properties from that config entry.
  221. * @param config config entry for this device.
  222. * @param name The name for the MSXDevice (will be made unique)
  223. */
  224. MSXDevice(const DeviceConfig& config, const std::string& name);
  225. explicit MSXDevice(const DeviceConfig& config);
  226. /** Constructing a MSXDevice is a 2-step process, after the constructor
  227. * is called this init() method must be called. The reason is exception
  228. * safety (init() might throw and we use the destructor to clean up
  229. * some stuff, this is more difficult when everything is done in the
  230. * constructor).
  231. * This is also a non-public method. This means you can only construct
  232. * MSXDevices via DeviceFactory.
  233. * In rare cases you need to override this method, for example when you
  234. * need to access the referenced devices already during construction
  235. * of this device (e.g. ADVram)
  236. */
  237. friend class DeviceFactory;
  238. virtual void init();
  239. /** The 'base' and 'size' attribute values need to be at least aligned
  240. * to CacheLine::SIZE. Though some devices may need a stricter
  241. * alignment. In that case they must override this method.
  242. */
  243. virtual unsigned getBaseSizeAlignment() const;
  244. /** By default we don't allow unaligned <mem> specifications in the
  245. * config file. Though for a machine like 'Victor HC-95A' is it useful
  246. * to model it with combinations of unaligned devices. So we do allow
  247. * it for a select few devices: devices that promise to not call any
  248. * of the 'fillDeviceXXXCache()' methods.
  249. */
  250. virtual bool allowUnaligned() const { return false; }
  251. /** @see getDeviceInfo()
  252. * Default implementation does nothing. Subclasses can override this
  253. * method to add extra info (like subtypes).
  254. */
  255. virtual void getExtraDeviceInfo(TclObject& result) const;
  256. public:
  257. // public to allow non-MSXDevices to use these same arrays
  258. static inline byte unmappedRead [0x10000]; // Read only
  259. static inline byte unmappedWrite[0x10000]; // Write only
  260. private:
  261. template<typename Action, typename... Args>
  262. void clip(unsigned start, unsigned size, Action action, Args... args);
  263. void initName(const std::string& name);
  264. void staticInit();
  265. void lockDevices();
  266. void unlockDevices();
  267. void registerSlots();
  268. void unregisterSlots();
  269. void registerPorts();
  270. void unregisterPorts();
  271. private:
  272. using MemRegions = std::vector<std::pair<unsigned, unsigned>>;
  273. MemRegions memRegions;
  274. std::vector<byte> inPorts;
  275. std::vector<byte> outPorts;
  276. DeviceConfig deviceConfig;
  277. std::string deviceName;
  278. Devices references;
  279. Devices referencedBy;
  280. int ps;
  281. int ss;
  282. };
  283. REGISTER_BASE_NAME_HELPER(MSXDevice, "Device");
  284. #define REGISTER_MSXDEVICE(CLASS, NAME) \
  285. REGISTER_POLYMORPHIC_INITIALIZER(MSXDevice, CLASS, NAME);
  286. } // namespace openmsx
  287. #endif