VDPAccessSlots.cc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. #include "VDPAccessSlots.hh"
  2. namespace openmsx::VDPAccessSlots {
  3. // These tables must contain at least one value that is bigger or equal
  4. // to 1368+136. So we extend the data with some cyclic duplicates.
  5. // Screen rendering disabled (or vertical border).
  6. // This is correct (measured on real V9938) for bitmap and character mode.
  7. // TODO also correct for text mode? See 'vdp-timing-2.html for more details.
  8. constexpr int16_t slotsScreenOff[154 + 17] = {
  9. 0, 8, 16, 24, 32, 40, 48, 56, 64, 72,
  10. 80, 88, 96, 104, 112, 120, 164, 172, 180, 188,
  11. 196, 204, 212, 220, 228, 236, 244, 252, 260, 268,
  12. 276, 292, 300, 308, 316, 324, 332, 340, 348, 356,
  13. 364, 372, 380, 388, 396, 404, 420, 428, 436, 444,
  14. 452, 460, 468, 476, 484, 492, 500, 508, 516, 524,
  15. 532, 548, 556, 564, 572, 580, 588, 596, 604, 612,
  16. 620, 628, 636, 644, 652, 660, 676, 684, 692, 700,
  17. 708, 716, 724, 732, 740, 748, 756, 764, 772, 780,
  18. 788, 804, 812, 820, 828, 836, 844, 852, 860, 868,
  19. 876, 884, 892, 900, 908, 916, 932, 940, 948, 956,
  20. 964, 972, 980, 988, 996, 1004, 1012, 1020, 1028, 1036,
  21. 1044, 1060, 1068, 1076, 1084, 1092, 1100, 1108, 1116, 1124,
  22. 1132, 1140, 1148, 1156, 1164, 1172, 1188, 1196, 1204, 1212,
  23. 1220, 1228, 1268, 1276, 1284, 1292, 1300, 1308, 1316, 1324,
  24. 1334, 1344, 1352, 1360,
  25. 1368+ 0, 1368+ 8, 1368+16, 1368+ 24, 1368+ 32,
  26. 1368+ 40, 1368+ 48, 1368+56, 1368+ 64, 1368+ 72,
  27. 1368+ 80, 1368+ 88, 1368+96, 1368+104, 1368+112,
  28. 1368+120, 1368+164
  29. };
  30. // Bitmap mode, sprites disabled.
  31. constexpr int16_t slotsSpritesOff[88 + 16] = {
  32. 6, 14, 22, 30, 38, 46, 54, 62, 70, 78,
  33. 86, 94, 102, 110, 118, 162, 170, 182, 188, 214,
  34. 220, 246, 252, 278, 310, 316, 342, 348, 374, 380,
  35. 406, 438, 444, 470, 476, 502, 508, 534, 566, 572,
  36. 598, 604, 630, 636, 662, 694, 700, 726, 732, 758,
  37. 764, 790, 822, 828, 854, 860, 886, 892, 918, 950,
  38. 956, 982, 988, 1014, 1020, 1046, 1078, 1084, 1110, 1116,
  39. 1142, 1148, 1174, 1206, 1212, 1266, 1274, 1282, 1290, 1298,
  40. 1306, 1314, 1322, 1332, 1342, 1350, 1358, 1366,
  41. 1368+ 6, 1368+14, 1368+ 22, 1368+ 30, 1368+ 38,
  42. 1368+ 46, 1368+54, 1368+ 62, 1368+ 70, 1368+ 78,
  43. 1368+ 86, 1368+94, 1368+102, 1368+110, 1368+118,
  44. 1368+162,
  45. };
  46. // Character mode, sprites disabled.
  47. // TODO these are not actually measured! See 'vdp-timing-2.html'.
  48. // [166,1212] is likely correct
  49. // [1270,122] is an educated guess, the amount of slots is likely correct,
  50. // but they might be shifted a few cycles forwards or backwards.
  51. constexpr int16_t slotsCharSpritesOff[88 + 17] = {
  52. 2, 10, 18, 26, 34, 42, 50, 58, 66, 74,
  53. 82, 90, 98, 106, 114, 122, 166, 174, 188, 194,
  54. 220, 226, 252, 258, 290, 316, 322, 348, 354, 380,
  55. 386, 418, 444, 450, 476, 482, 508, 514, 546, 572,
  56. 578, 604, 610, 636, 642, 674, 700, 706, 732, 738,
  57. 764, 770, 802, 828, 834, 860, 866, 892, 898, 930,
  58. 956, 962, 988, 994, 1020, 1026, 1058, 1084, 1090, 1116,
  59. 1122, 1148, 1154, 1186, 1212, 1218, 1270, 1278, 1286, 1294,
  60. 1302, 1310, 1318, 1326, 1336, 1346, 1354, 1362,
  61. 1368+ 2, 1368+ 10, 1368+18, 1368+ 26, 1368+ 34,
  62. 1368+ 42, 1368+ 50, 1368+58, 1368+ 66, 1368+ 74,
  63. 1368+ 82, 1368+ 90, 1368+98, 1368+106, 1368+114,
  64. 1368+122, 1368+166,
  65. };
  66. // Bitmap mode, sprites enabled.
  67. constexpr int16_t slotsSpritesOn[31 + 3] = {
  68. 28, 92, 162, 170, 188, 220, 252, 316, 348, 380,
  69. 444, 476, 508, 572, 604, 636, 700, 732, 764, 828,
  70. 860, 892, 956, 988, 1020, 1084, 1116, 1148, 1212, 1264,
  71. 1330,
  72. 1368+28, 1368+92, 1368+162,
  73. };
  74. // Character mode, sprites enabled.
  75. constexpr int16_t slotsCharSpritesOn[31 + 3] = {
  76. 32, 96, 166, 174, 188, 220, 252, 316, 348, 380,
  77. 444, 476, 508, 572, 604, 636, 700, 732, 764, 828,
  78. 860, 892, 956, 988, 1020, 1084, 1116, 1148, 1212, 1268,
  79. 1334,
  80. 1368+32, 1368+96, 1368+166,
  81. };
  82. // Text mode.
  83. constexpr int16_t slotsText[47 + 10] = {
  84. 2, 10, 18, 26, 34, 42, 50, 58, 66, 166,
  85. 174, 182, 190, 198, 206, 214, 222, 312, 408, 504,
  86. 600, 696, 792, 888, 984, 1080, 1176, 1206, 1214, 1222,
  87. 1230, 1238, 1246, 1254, 1262, 1270, 1278, 1286, 1294, 1302,
  88. 1310, 1318, 1326, 1336, 1346, 1354, 1362,
  89. 1368+ 2, 1368+10, 1368+18, 1368+26, 1368+ 34,
  90. 1368+42, 1368+50, 1368+58, 1368+66, 1368+166,
  91. };
  92. // TMS9918 (MSX1) cycle numbers translated to V99x8 cycles (multiplied by 4).
  93. // MSX1 screen off.
  94. constexpr int16_t slotsMsx1ScreenOff[107 + 18] = {
  95. 4, 12, 20, 28, 36, 44, 52, 60, 68, 76,
  96. 84, 92, 100, 108, 116, 124, 132, 140, 148, 156,
  97. 164, 172, 180, 188, 196, 204, 220, 236, 252, 268,
  98. 284, 300, 316, 332, 348, 364, 380, 396, 412, 428,
  99. 444, 460, 476, 492, 508, 524, 540, 556, 572, 588,
  100. 604, 620, 636, 652, 668, 684, 700, 716, 732, 748,
  101. 764, 780, 796, 812, 828, 844, 860, 876, 892, 908,
  102. 924, 940, 956, 972, 988, 1004, 1020, 1036, 1052, 1068,
  103. 1084, 1100, 1116, 1132, 1148, 1164, 1180, 1196, 1212, 1228,
  104. 1236, 1244, 1252, 1260, 1268, 1276, 1284, 1292, 1300, 1308,
  105. 1316, 1324, 1332, 1340, 1348, 1356, 1364,
  106. 1368+ 4, 1368+ 12, 1368+ 20, 1368+ 28, 1368+ 36,
  107. 1368+ 44, 1368+ 52, 1368+ 60, 1368+ 68, 1368+ 76,
  108. 1368+ 84, 1368+ 92, 1368+100, 1368+108, 1368+116,
  109. 1368+124, 1368+132, 1368+140,
  110. };
  111. // MSX1 graphic mode 1 and 2 (aka screen 1 and 2).
  112. constexpr int16_t slotsMsx1Gfx12[19 + 8] = {
  113. 4, 12, 20, 28, 116, 124, 132, 140, 220, 348,
  114. 476, 604, 732, 860, 988, 1116, 1236, 1244, 1364,
  115. 1368+ 4, 1368+ 12, 1368+ 20, 1368+ 28, 1368+116,
  116. 1368+124, 1368+132, 1368+140,
  117. };
  118. // MSX1 graphic mode 3 (aka screen 3).
  119. constexpr int16_t slotsMsx1Gfx3[51 + 8] = {
  120. 4, 12, 20, 28, 116, 124, 132, 140, 220, 228,
  121. 260, 292, 324, 348, 356, 388, 420, 452, 476, 484,
  122. 516, 548, 580, 604, 612, 644, 676, 708, 732, 740,
  123. 772, 804, 836, 860, 868, 900, 932, 964, 988, 996,
  124. 1028, 1060, 1092, 1116, 1124, 1156, 1188, 1220, 1236, 1244,
  125. 1364,
  126. 1368+ 4, 1368+ 12, 1368+ 20, 1368+ 28, 1368+116,
  127. 1368+124, 1368+132, 1368+140,
  128. };
  129. // MSX1 text mode 1 (aka screen 0 width 40).
  130. constexpr int16_t slotsMsx1Text[91 + 18] = {
  131. 4, 12, 20, 28, 36, 44, 52, 60, 68, 76,
  132. 84, 92, 100, 108, 116, 124, 132, 140, 148, 156,
  133. 164, 172, 180, 188, 196, 204, 212, 220, 228, 244,
  134. 268, 292, 316, 340, 364, 388, 412, 436, 460, 484,
  135. 508, 532, 556, 580, 604, 628, 652, 676, 700, 724,
  136. 748, 772, 796, 820, 844, 868, 892, 916, 940, 964,
  137. 988, 1012, 1036, 1060, 1084, 1108, 1132, 1156, 1180, 1196,
  138. 1204, 1212, 1220, 1228, 1236, 1244, 1252, 1260, 1268, 1276,
  139. 1284, 1292, 1300, 1308, 1316, 1324, 1332, 1340, 1348, 1356,
  140. 1364,
  141. 1368+ 4, 1368+ 12, 1368+ 20, 1368+ 28, 1368+ 36,
  142. 1368+ 44, 1368+ 52, 1368+ 60, 1368+ 68, 1368+ 76,
  143. 1368+ 84, 1368+ 92, 1368+100, 1368+108, 1368+116,
  144. 1368+124, 1368+132, 1368+140,
  145. };
  146. // Helper functions to transform the above tables into a format that is easier
  147. // (=faster) to work with.
  148. struct AccessTable
  149. {
  150. operator const uint8_t*() const { return values; }
  151. protected:
  152. uint8_t values[NUM_DELTAS * TICKS] = {};
  153. };
  154. struct CycleTable : AccessTable
  155. {
  156. constexpr CycleTable(bool msx1, const int16_t* slots)
  157. {
  158. // !!! Keep this in sync with the 'Delta' enum !!!
  159. constexpr int delta[NUM_DELTAS] = {
  160. 0, 1, 16, 24, 28, 32, 40, 48, 64, 72, 88, 104, 120, 128, 136
  161. };
  162. size_t out = 0;
  163. for (auto step : delta) {
  164. int p = 0;
  165. while (slots[p] < step) ++p;
  166. for (int i = 0; i < TICKS; ++i) {
  167. if ((slots[p] - i) < step) ++p;
  168. assert((slots[p] - i) >= step);
  169. unsigned t = slots[p] - i;
  170. if (msx1) {
  171. if (step <= 40) assert(t < 256);
  172. } else {
  173. assert(t < 256);
  174. }
  175. values[out++] = t;
  176. }
  177. }
  178. }
  179. };
  180. struct ZeroTable : AccessTable
  181. {
  182. };
  183. constexpr CycleTable tabSpritesOn (false, slotsSpritesOn);
  184. constexpr CycleTable tabSpritesOff (false, slotsSpritesOff);
  185. constexpr CycleTable tabCharSpritesOn (false, slotsCharSpritesOn);
  186. constexpr CycleTable tabCharSpritesOff(false, slotsCharSpritesOff);
  187. constexpr CycleTable tabText (false, slotsText);
  188. constexpr CycleTable tabScreenOff (false, slotsScreenOff);
  189. constexpr CycleTable tabMsx1Gfx12 (true, slotsMsx1Gfx12);
  190. constexpr CycleTable tabMsx1Gfx3 (true, slotsMsx1Gfx3);
  191. constexpr CycleTable tabMsx1Text (true, slotsMsx1Text);
  192. constexpr CycleTable tabMsx1ScreenOff (true, slotsMsx1ScreenOff);
  193. constexpr ZeroTable tabBroken;
  194. static inline const uint8_t* getTab(const VDP& vdp)
  195. {
  196. if (vdp.getBrokenCmdTiming()) return tabBroken;
  197. bool enabled = vdp.isDisplayEnabled();
  198. bool sprites = vdp.spritesEnabledRegister();
  199. auto mode = vdp.getDisplayMode();
  200. bool bitmap = mode.isBitmapMode();
  201. bool text = mode.isTextMode();
  202. bool gfx3 = mode.getBase() == DisplayMode::GRAPHIC3;
  203. if (vdp.isMSX1VDP()) {
  204. if (!enabled) return tabMsx1ScreenOff;
  205. return text ? tabMsx1Text
  206. : (gfx3 ? tabMsx1Gfx3
  207. : tabMsx1Gfx12);
  208. // TODO undocumented modes
  209. } else {
  210. if (!enabled) return tabScreenOff;
  211. return bitmap ? (sprites ? tabSpritesOn
  212. : tabSpritesOff)
  213. : (text ? tabText
  214. : (sprites ? tabCharSpritesOn
  215. : tabCharSpritesOff));
  216. }
  217. }
  218. EmuTime getAccessSlot(
  219. EmuTime::param frame_, EmuTime::param time, Delta delta,
  220. const VDP& vdp)
  221. {
  222. VDP::VDPClock frame(frame_);
  223. unsigned ticks = frame.getTicksTill_fast(time) % TICKS;
  224. auto* tab = getTab(vdp);
  225. return time + VDP::VDPClock::duration(tab[delta + ticks]);
  226. }
  227. Calculator getCalculator(
  228. EmuTime::param frame, EmuTime::param time, EmuTime::param limit,
  229. const VDP& vdp)
  230. {
  231. auto* tab = getTab(vdp);
  232. return Calculator(frame, time, limit, tab);
  233. }
  234. } // namespace openmsx::VDPAccessSlots