openMSX
VDPAccessSlots.cc
Go to the documentation of this file.
1#include "VDPAccessSlots.hh"
2
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.
11constexpr 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.
35constexpr 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.
56constexpr 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.
73constexpr 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.
82constexpr 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.
91constexpr 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.
104constexpr 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).
123constexpr 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).
131constexpr 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).
144constexpr 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
168protected:
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 (auto i : xrange(TICKS)) {
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
208constexpr CycleTable tabText (false, slotsText);
215
216
217[[nodiscard]] 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
237 : (text ? tabText
238 : (sprites ? tabCharSpritesOn
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 const 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 const auto* tab = getTab(vdp);
258 return {frame, time, limit, tab};
259}
260
261} // namespace openmsx::VDPAccessSlots
TclObject t
static constexpr EmuDuration duration(unsigned ticks)
Calculates the duration of the given number of ticks at this clock's frequency.
Definition: Clock.hh:35
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
constexpr bool isBitmapMode() const
Is the current mode a bitmap mode? Graphic4 and higher are bitmap modes.
Definition: DisplayMode.hh:130
VDP-VRAM access slot calculator, meant to be used in the inner loops of the VDPCmdEngine commands.
Unified implementation of MSX Video Display Processors (VDPs).
Definition: VDP.hh:63
bool getBrokenCmdTiming() const
Value of the cmdTiming setting, true means commands have infinite speed.
Definition: VDP.hh:598
bool spritesEnabledRegister() const
Still faster variant (just looks at the sprite-enabled-bit).
Definition: VDP.hh:273
DisplayMode getDisplayMode() const
Get the display mode the VDP is in.
Definition: VDP.hh:141
bool isMSX1VDP() const
Is this an MSX1 VDP?
Definition: VDP.hh:93
bool isDisplayEnabled() const
Is the display enabled? Both the regular border and forced blanking by clearing the display enable bi...
Definition: VDP.hh:248
constexpr auto step
Definition: eeprom.cc:9
constexpr int16_t slotsScreenOff[154+17]
constexpr int16_t slotsText[47+10]
constexpr int16_t slotsCharSpritesOff[88+17]
constexpr int16_t slotsMsx1Gfx12[19+8]
constexpr ZeroTable tabBroken
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'.
constexpr int16_t slotsCharSpritesOn[31+3]
constexpr int16_t slotsMsx1Gfx3[51+8]
constexpr int16_t slotsMsx1ScreenOff[107+18]
constexpr CycleTable tabMsx1Gfx3(true, slotsMsx1Gfx3)
constexpr int16_t slotsSpritesOn[31+3]
constexpr int16_t slotsMsx1Text[91+18]
constexpr CycleTable tabText(false, slotsText)
constexpr CycleTable tabSpritesOff(false, slotsSpritesOff)
constexpr CycleTable tabScreenOff(false, slotsScreenOff)
constexpr CycleTable tabMsx1Gfx12(true, slotsMsx1Gfx12)
constexpr CycleTable tabCharSpritesOff(false, slotsCharSpritesOff)
constexpr int16_t slotsSpritesOff[88+16]
constexpr CycleTable tabCharSpritesOn(false, slotsCharSpritesOn)
constexpr CycleTable tabMsx1ScreenOff(true, slotsMsx1ScreenOff)
constexpr CycleTable tabMsx1Text(true, slotsMsx1Text)
constexpr CycleTable tabSpritesOn(false, slotsSpritesOn)
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.
uint8_t values[NUM_DELTAS *TICKS]
constexpr CycleTable(bool msx1, const int16_t *slots)
constexpr auto xrange(T e)
Definition: xrange.hh:133