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