VDPCmdEngine.hh 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #ifndef VDPCMDENGINE_HH
  2. #define VDPCMDENGINE_HH
  3. #include "VDP.hh"
  4. #include "VDPAccessSlots.hh"
  5. #include "BooleanSetting.hh"
  6. #include "Probe.hh"
  7. #include "TclCallback.hh"
  8. #include "serialize_meta.hh"
  9. #include "openmsx.hh"
  10. namespace openmsx {
  11. class VDPVRAM;
  12. class DisplayMode;
  13. class CommandController;
  14. /** VDP command engine by Alex Wulms.
  15. * Implements command execution unit of V9938/58.
  16. */
  17. class VDPCmdEngine
  18. {
  19. public:
  20. VDPCmdEngine(VDP& vdp, CommandController& commandController);
  21. /** Reinitialise Renderer state.
  22. * @param time The moment in time the reset occurs.
  23. */
  24. void reset(EmuTime::param time);
  25. /** Synchronises the command engine with the VDP.
  26. * Ideally this would be a private method, but the current
  27. * design doesn't allow that.
  28. * @param time The moment in emulated time to sync to.
  29. */
  30. inline void sync(EmuTime::param time) {
  31. if (CMD) sync2(time);
  32. }
  33. void sync2(EmuTime::param time);
  34. /** Steal a VRAM access slot from the CmdEngine.
  35. * Used when the CPU reads/writes VRAM.
  36. * @param time The moment in time the CPU read/write is performed.
  37. */
  38. void stealAccessSlot(EmuTime::param time) {
  39. if (!CMD) return;
  40. engineTime = time;
  41. nextAccessSlot(VDPAccessSlots::DELTA_1); // skip one slot
  42. assert(engineTime > time);
  43. }
  44. /** Gets the command engine status (part of S#2).
  45. * Bit 7 (TR) is set when the command engine is ready for
  46. * a pixel transfer.
  47. * Bit 4 (BD) is set when the boundary color is detected.
  48. * Bit 0 (CE) is set when a command is in progress.
  49. */
  50. inline byte getStatus(EmuTime::param time) {
  51. if (time >= statusChangeTime) {
  52. sync(time);
  53. }
  54. return status;
  55. }
  56. /** Use this method to transfer pixel(s) from VDP to CPU.
  57. * This method implements V9938 S#7.
  58. * @param time The moment in emulated time this read occurs.
  59. * @return Color value of the pixel.
  60. */
  61. inline byte readColor(EmuTime::param time) {
  62. sync(time);
  63. return COL;
  64. }
  65. inline void resetColor() {
  66. // Note: Real VDP always resets TR, but for such a short time
  67. // that the MSX won't notice it.
  68. // TODO: What happens on non-transfer commands?
  69. if (!CMD) status &= 0x7F;
  70. transfer = true;
  71. }
  72. /** Gets the X coordinate of a border detected by SRCH (intended behaviour,
  73. * as documented in the V9938 technical data book). However, real VDP
  74. * simply returns the current value of the ASX 'temporary source X' counter,
  75. * regardless of the command that is being executed or was executed most
  76. * recently
  77. * @param time The moment in emulated time this get occurs.
  78. */
  79. inline unsigned getBorderX(EmuTime::param time) {
  80. sync(time);
  81. return ASX;
  82. }
  83. /** Writes to a command register.
  84. * @param index The register [0..14] to write to.
  85. * @param value The new value for the specified register.
  86. * @param time The moment in emulated time this write occurs.
  87. */
  88. void setCmdReg(byte index, byte value, EmuTime::param time);
  89. /** Read the content of a command register. This method is meant to
  90. * be used by the debugger, there is no strict guarantee that the
  91. * returned value is the correct value at _exactly_ this moment in
  92. * time (IOW this method does not sync the complete CmdEngine)
  93. * @param index The register [0..14] to read from.
  94. */
  95. byte peekCmdReg(byte index) const;
  96. /** Informs the command engine of a VDP display mode change.
  97. * @param mode The new display mode.
  98. * @param cmdBit Are VDP commands allowed in non-bitmap mode.
  99. * @param time The moment in emulated time this change occurs.
  100. */
  101. void updateDisplayMode(DisplayMode mode, bool cmdBit, EmuTime::param time);
  102. /** Interface for logical operations.
  103. */
  104. template<typename Archive>
  105. void serialize(Archive& ar, unsigned version);
  106. private:
  107. void executeCommand(EmuTime::param time);
  108. void setStatusChangeTime(EmuTime::param t);
  109. void calcFinishTime(unsigned NX, unsigned NY, unsigned ticksPerPixel);
  110. void startAbrt(EmuTime::param time);
  111. void startPoint(EmuTime::param time);
  112. void startPset(EmuTime::param time);
  113. void startSrch(EmuTime::param time);
  114. void startLine(EmuTime::param time);
  115. template<typename Mode> void startLmmv(EmuTime::param time);
  116. template<typename Mode> void startLmmm(EmuTime::param time);
  117. template<typename Mode> void startLmcm(EmuTime::param time);
  118. template<typename Mode> void startLmmc(EmuTime::param time);
  119. template<typename Mode> void startHmmv(EmuTime::param time);
  120. template<typename Mode> void startHmmm(EmuTime::param time);
  121. template<typename Mode> void startYmmm(EmuTime::param time);
  122. template<typename Mode> void startHmmc(EmuTime::param time);
  123. template<typename Mode> void executePoint(EmuTime::param limit);
  124. template<typename Mode, typename LogOp> void executePset(EmuTime::param limit);
  125. template<typename Mode> void executeSrch(EmuTime::param limit);
  126. template<typename Mode, typename LogOp> void executeLine(EmuTime::param limit);
  127. template<typename Mode, typename LogOp> void executeLmmv(EmuTime::param limit);
  128. template<typename Mode, typename LogOp> void executeLmmm(EmuTime::param limit);
  129. template<typename Mode> void executeLmcm(EmuTime::param limit);
  130. template<typename Mode, typename LogOp> void executeLmmc(EmuTime::param limit);
  131. template<typename Mode> void executeHmmv(EmuTime::param limit);
  132. template<typename Mode> void executeHmmm(EmuTime::param limit);
  133. template<typename Mode> void executeYmmm(EmuTime::param limit);
  134. template<typename Mode> void executeHmmc(EmuTime::param limit);
  135. // Advance to the next access slot at or past the given time.
  136. inline void nextAccessSlot(EmuTime::param time) {
  137. engineTime = vdp.getAccessSlot(time, VDPAccessSlots::DELTA_0);
  138. }
  139. // Advance to the next access slot that is at least 'delta' cycles past
  140. // the current one.
  141. inline void nextAccessSlot(VDPAccessSlots::Delta delta) {
  142. engineTime = vdp.getAccessSlot(engineTime, delta);
  143. }
  144. inline VDPAccessSlots::Calculator getSlotCalculator(
  145. EmuTime::param limit) const {
  146. return vdp.getAccessSlotCalculator(engineTime, limit);
  147. }
  148. /** Finshed executing graphical operation.
  149. */
  150. void commandDone(EmuTime::param time);
  151. /** Report the VDP command specified in the registers.
  152. */
  153. void reportVdpCommand() const;
  154. /** The VDP this command engine is part of.
  155. */
  156. VDP& vdp;
  157. VDPVRAM& vram;
  158. /** Only call reportVdpCommand() when this setting is turned on
  159. */
  160. BooleanSetting cmdTraceSetting;
  161. TclCallback cmdInProgressCallback;
  162. Probe<bool> executingProbe;
  163. /** Time at which the next vram access slot is available.
  164. * Only valid when a command is executing.
  165. */
  166. EmuTime engineTime;
  167. /** Lower bound for the time when the status register will change, IOW
  168. * the status register will not change before this time.
  169. * Can also be EmuTime::zero -> status can change any moment
  170. * or EmuTime::infinity -> this command doesn't change the status
  171. */
  172. EmuTime statusChangeTime;
  173. /** Some commands execute multiple VRAM accesses per pixel
  174. * (e.g. LMMM does two reads and a write). This variable keeps
  175. * track of where in the (sub)command we are. */
  176. int phase;
  177. /** Current screen mode.
  178. * 0 -> SCREEN5, 1 -> SCREEN6, 2 -> SCREEN7, 3 -> SCREEN8,
  179. * 4 -> Non-BitMap mode (like SCREEN8 but non-planar addressing)
  180. * -1 -> other.
  181. */
  182. int scrMode;
  183. /** VDP command registers.
  184. */
  185. unsigned SX, SY, DX, DY, NX, NY; // registers that can be set by CPU
  186. unsigned ASX, ADX, ANX; // Temporary registers used in the VDP commands
  187. // Register ASX can be read (via status register 8/9)
  188. byte COL, ARG, CMD;
  189. /** When a command needs multiple VRAM accesses per pixel, the result
  190. * of intermediate reads is stored in these variables. */
  191. byte tmpSrc;
  192. byte tmpDst;
  193. /** The command engine status (part of S#2).
  194. * Bit 7 (TR) is set when the command engine is ready for
  195. * a pixel transfer.
  196. * Bit 4 (BD) is set when the boundary color is detected.
  197. * Bit 0 (CE) is set when a command is in progress.
  198. */
  199. byte status;
  200. /** Used in LMCM LMMC HMMC cmds, true when CPU has read or written
  201. * next byte.
  202. */
  203. bool transfer;
  204. /** Flag that indicated whether extended VRAM is available
  205. */
  206. const bool hasExtendedVRAM;
  207. };
  208. SERIALIZE_CLASS_VERSION(VDPCmdEngine, 3);
  209. } // namespace openmsx
  210. #endif