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// Bitmap mode, sprites enabled.
53static constexpr std::array<int16_t, 31 + 3> slotsSpritesOn = {
54 28, 92, 162, 170, 188, 220, 252, 316, 348, 380,
55 444, 476, 508, 572, 604, 636, 700, 732, 764, 828,
56 860, 892, 956, 988, 1020, 1084, 1116, 1148, 1212, 1264,
57 1330,
58 1368+28, 1368+92, 1368+162,
59};
60
61// Character mode, sprites enabled.
62static constexpr std::array<int16_t, 31 + 3> slotsChar = {
63 32, 96, 166, 174, 188, 220, 252, 316, 348, 380,
64 444, 476, 508, 572, 604, 636, 700, 732, 764, 828,
65 860, 892, 956, 988, 1020, 1084, 1116, 1148, 1212, 1268,
66 1334,
67 1368+32, 1368+96, 1368+166,
68};
69
70// Text mode.
71static constexpr std::array<int16_t, 47 + 10> slotsText = {
72 2, 10, 18, 26, 34, 42, 50, 58, 66, 166,
73 174, 182, 190, 198, 206, 214, 222, 312, 408, 504,
74 600, 696, 792, 888, 984, 1080, 1176, 1206, 1214, 1222,
75 1230, 1238, 1246, 1254, 1262, 1270, 1278, 1286, 1294, 1302,
76 1310, 1318, 1326, 1336, 1346, 1354, 1362,
77 1368+ 2, 1368+10, 1368+18, 1368+26, 1368+ 34,
78 1368+42, 1368+50, 1368+58, 1368+66, 1368+166,
79};
80
81
82// TMS9918 (MSX1) cycle numbers translated to V99x8 cycles (multiplied by 4).
83// MSX1 screen off.
84static constexpr std::array<int16_t, 107 + 18> slotsMsx1ScreenOff = {
85 4, 12, 20, 28, 36, 44, 52, 60, 68, 76,
86 84, 92, 100, 108, 116, 124, 132, 140, 148, 156,
87 164, 172, 180, 188, 196, 204, 220, 236, 252, 268,
88 284, 300, 316, 332, 348, 364, 380, 396, 412, 428,
89 444, 460, 476, 492, 508, 524, 540, 556, 572, 588,
90 604, 620, 636, 652, 668, 684, 700, 716, 732, 748,
91 764, 780, 796, 812, 828, 844, 860, 876, 892, 908,
92 924, 940, 956, 972, 988, 1004, 1020, 1036, 1052, 1068,
93 1084, 1100, 1116, 1132, 1148, 1164, 1180, 1196, 1212, 1228,
94 1236, 1244, 1252, 1260, 1268, 1276, 1284, 1292, 1300, 1308,
95 1316, 1324, 1332, 1340, 1348, 1356, 1364,
96 1368+ 4, 1368+ 12, 1368+ 20, 1368+ 28, 1368+ 36,
97 1368+ 44, 1368+ 52, 1368+ 60, 1368+ 68, 1368+ 76,
98 1368+ 84, 1368+ 92, 1368+100, 1368+108, 1368+116,
99 1368+124, 1368+132, 1368+140,
100};
101
102// MSX1 graphic mode 1 and 2 (aka screen 1 and 2).
103static constexpr std::array<int16_t, 19 + 8> slotsMsx1Gfx12 = {
104 4, 12, 20, 28, 116, 124, 132, 140, 220, 348,
105 476, 604, 732, 860, 988, 1116, 1236, 1244, 1364,
106 1368+ 4, 1368+ 12, 1368+ 20, 1368+ 28, 1368+116,
107 1368+124, 1368+132, 1368+140,
108};
109
110// MSX1 graphic mode 3 (aka screen 3).
111static constexpr std::array<int16_t, 51 + 8> slotsMsx1Gfx3 = {
112 4, 12, 20, 28, 116, 124, 132, 140, 220, 228,
113 260, 292, 324, 348, 356, 388, 420, 452, 476, 484,
114 516, 548, 580, 604, 612, 644, 676, 708, 732, 740,
115 772, 804, 836, 860, 868, 900, 932, 964, 988, 996,
116 1028, 1060, 1092, 1116, 1124, 1156, 1188, 1220, 1236, 1244,
117 1364,
118 1368+ 4, 1368+ 12, 1368+ 20, 1368+ 28, 1368+116,
119 1368+124, 1368+132, 1368+140,
120};
121
122
123// MSX1 text mode 1 (aka screen 0 width 40).
124static constexpr std::array<int16_t, 91 + 18> slotsMsx1Text = {
125 4, 12, 20, 28, 36, 44, 52, 60, 68, 76,
126 84, 92, 100, 108, 116, 124, 132, 140, 148, 156,
127 164, 172, 180, 188, 196, 204, 212, 220, 228, 244,
128 268, 292, 316, 340, 364, 388, 412, 436, 460, 484,
129 508, 532, 556, 580, 604, 628, 652, 676, 700, 724,
130 748, 772, 796, 820, 844, 868, 892, 916, 940, 964,
131 988, 1012, 1036, 1060, 1084, 1108, 1132, 1156, 1180, 1196,
132 1204, 1212, 1220, 1228, 1236, 1244, 1252, 1260, 1268, 1276,
133 1284, 1292, 1300, 1308, 1316, 1324, 1332, 1340, 1348, 1356,
134 1364,
135 1368+ 4, 1368+ 12, 1368+ 20, 1368+ 28, 1368+ 36,
136 1368+ 44, 1368+ 52, 1368+ 60, 1368+ 68, 1368+ 76,
137 1368+ 84, 1368+ 92, 1368+100, 1368+108, 1368+116,
138 1368+124, 1368+132, 1368+140,
139};
140
141// Helper functions to transform the above tables into a format that is easier
142// (=faster) to work with.
143
145{
146 operator std::span<const uint8_t, NUM_DELTAS * TICKS>() const { return values; }
147
148protected:
149 std::array<uint8_t, NUM_DELTAS * TICKS> values = {};
150};
151
153{
154 constexpr CycleTable(bool msx1, std::span<const int16_t> slots)
155 {
156 // !!! Keep this in sync with the 'Delta' enum !!!
157 constexpr std::array<int, NUM_DELTAS> delta = {
158 0, 1, 16, 24, 28, 32, 40, 48, 64, 72, 88, 104, 120, 128, 136
159 };
160
161 size_t out = 0;
162 for (auto step : delta) {
163 int p = 0;
164 while (slots[p] < step) ++p;
165 for (auto i : xrange(TICKS)) {
166 if ((slots[p] - i) < step) ++p;
167 assert((slots[p] - i) >= step);
168 unsigned t = slots[p] - i;
169 if (msx1) {
170 if (step <= 40) assert(t < 256);
171 } else {
172 assert(t < 256);
173 }
174 values[out++] = narrow_cast<uint8_t>(t);
175 }
176 }
177 }
178};
179
181{
182};
183
184static constexpr CycleTable tabSpritesOn (false, slotsSpritesOn);
185static constexpr CycleTable tabSpritesOff (false, slotsSpritesOff);
186static constexpr CycleTable tabChar (false, slotsChar);
187static constexpr CycleTable tabText (false, slotsText);
188static constexpr CycleTable tabScreenOff (false, slotsScreenOff);
189static constexpr CycleTable tabMsx1Gfx12 (true, slotsMsx1Gfx12);
190static constexpr CycleTable tabMsx1Gfx3 (true, slotsMsx1Gfx3);
191static constexpr CycleTable tabMsx1Text (true, slotsMsx1Text);
192static constexpr CycleTable tabMsx1ScreenOff (true, slotsMsx1ScreenOff);
193static constexpr ZeroTable tabBroken;
194
195
196[[nodiscard]] static inline std::span<const uint8_t, NUM_DELTAS * TICKS> getTab(const VDP& vdp)
197{
198 if (vdp.getBrokenCmdTiming()) return tabBroken;
199 bool enabled = vdp.isDisplayEnabled();
200 bool sprites = vdp.spritesEnabledRegister();
201 auto mode = vdp.getDisplayMode();
202 bool bitmap = mode.isBitmapMode();
203 bool text = mode.isTextMode();
204 bool gfx3 = mode.getBase() == DisplayMode::GRAPHIC3;
205
206 if (vdp.isMSX1VDP()) {
207 if (!enabled) return tabMsx1ScreenOff;
208 return text ? tabMsx1Text
209 : (gfx3 ? tabMsx1Gfx3
210 : tabMsx1Gfx12);
211 // TODO undocumented modes
212 } else {
213 if (bitmap) {
214 return !enabled ? tabScreenOff
215 : sprites ? tabSpritesOn
216 : tabSpritesOff;
217 } else {
218 // 'enabled' or 'sprites' doesn't matter in V99x8 non-bitmap mode
219 // See: https://github.com/openMSX/openMSX/issues/1754
220 return text ? tabText
221 : tabChar;
222 }
223 }
224}
225
227 EmuTime::param frame_, EmuTime::param time, Delta delta,
228 const VDP& vdp)
229{
230 VDP::VDPClock frame(frame_);
231 unsigned ticks = frame.getTicksTill_fast(time) % TICKS;
232 auto tab = getTab(vdp);
233 return time + VDP::VDPClock::duration(tab[to_underlying(delta) + ticks]);
234}
235
237 EmuTime::param frame, EmuTime::param time, EmuTime::param limit,
238 const VDP& vdp)
239{
240 auto tab = getTab(vdp);
241 return {frame, time, limit, tab};
242}
243
244} // 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.
constexpr auto to_underlying(E e) noexcept
Definition stl.hh:468
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