MSXDevice.hh 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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 save 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. /** Invalidate CPU memory-mapping cache.
  176. * This is a shortcut to the MSXCPU::invalidateMemCache() method,
  177. * see that method for more details.
  178. */
  179. void invalidateMemCache(word start, unsigned size);
  180. /** Get the mother board this device belongs to
  181. */
  182. MSXMotherBoard& getMotherBoard() const;
  183. /** Get the configuration section for this device.
  184. * This was passed as a constructor argument.
  185. */
  186. const XMLElement& getDeviceConfig() const {
  187. return *deviceConfig.getXML();
  188. }
  189. const DeviceConfig& getDeviceConfig2() const { // TODO
  190. return deviceConfig;
  191. }
  192. /** Get the device references that are specified for this device
  193. */
  194. const Devices& getReferences() const;
  195. // convenience functions, these delegate to MSXMotherBoard
  196. EmuTime::param getCurrentTime() const;
  197. MSXCPU& getCPU() const;
  198. MSXCPUInterface& getCPUInterface() const;
  199. Scheduler& getScheduler() const;
  200. CliComm& getCliComm() const;
  201. Reactor& getReactor() const;
  202. CommandController& getCommandController() const;
  203. PluggingController& getPluggingController() const;
  204. LedStatus& getLedStatus() const;
  205. template<typename Archive>
  206. void serialize(Archive& ar, unsigned version);
  207. protected:
  208. /** Every MSXDevice has a config entry; this constructor gets
  209. * some device properties from that config entry.
  210. * @param config config entry for this device.
  211. * @param name The name for the MSXDevice (will be made unique)
  212. */
  213. MSXDevice(const DeviceConfig& config, const std::string& name);
  214. explicit MSXDevice(const DeviceConfig& config);
  215. /** Constructing a MSXDevice is a 2-step process, after the constructor
  216. * is called this init() method must be called. The reason is exception
  217. * safety (init() might throw and we use the destructor to clean up
  218. * some stuff, this is more difficult when everything is done in the
  219. * constrcutor).
  220. * This is also a non-public method. This means you can only construct
  221. * MSXDevices via DeviceFactory.
  222. * In rare cases you need to override this method, for example when you
  223. * need to access the referenced devices already during construction
  224. * of this device (e.g. ADVram)
  225. */
  226. friend class DeviceFactory;
  227. virtual void init();
  228. /** @see getDeviceInfo()
  229. * Default implementation does nothing. Subclasses can override this
  230. * method to add extra info (like subtypes).
  231. */
  232. virtual void getExtraDeviceInfo(TclObject& result) const;
  233. public:
  234. // public to allow non-MSXDevices to use these same arrays
  235. static byte unmappedRead [0x10000]; // Read only
  236. static byte unmappedWrite[0x10000]; // Write only
  237. private:
  238. void initName(const std::string& name);
  239. void staticInit();
  240. void lockDevices();
  241. void unlockDevices();
  242. void registerSlots();
  243. void unregisterSlots();
  244. void registerPorts();
  245. void unregisterPorts();
  246. using MemRegions = std::vector<std::pair<unsigned, unsigned>>;
  247. MemRegions memRegions;
  248. std::vector<byte> inPorts;
  249. std::vector<byte> outPorts;
  250. DeviceConfig deviceConfig;
  251. std::string deviceName;
  252. Devices references;
  253. Devices referencedBy;
  254. int ps;
  255. int ss;
  256. };
  257. REGISTER_BASE_NAME_HELPER(MSXDevice, "Device");
  258. #define REGISTER_MSXDEVICE(CLASS, NAME) \
  259. REGISTER_POLYMORPHIC_INITIALIZER(MSXDevice, CLASS, NAME);
  260. } // namespace openmsx
  261. #endif