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