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