23static constexpr unsigned maxLength = 171;
24static constexpr EmuDuration d_(
unsigned x)
26 assert(x <= maxLength);
30static constexpr EDStorage d(
unsigned x) {
return d_(x); }
31using A = std::array<const EDStorage, 4>;
32using A2 = std::array<const A, 3>;
39static constexpr std::array LMMV_TIMING = {
40 A2{
A{ d( 8), d(11), d(15), d(30)},
A{d( 7), d(10), d(13), d(26)},
A{d( 7), d(10), d(13), d(25)}},
41 A2{
A{ d( 5), d( 7), d( 9), d(18)},
A{d( 5), d( 6), d( 8), d(17)},
A{d( 5), d( 6), d( 8), d(17)}},
42 A2{
A{ d(56), d(56), d(56), d(56)},
A{d(25), d(25), d(25), d(25)},
A{d( 9), d( 9), d( 9), d( 9)}},
43 A2{
A{ d(28), d(28), d(28), d(28)},
A{d(15), d(15), d(15), d(15)},
A{d( 6), d( 6), d( 6), d( 6)}}
45static constexpr std::array LMMM_TIMING = {
46 A2{
A{d (10),d (16),d( 32),d( 66)},
A{d( 8), d(14), d(28), d(57)},
A{d( 8), d(13), d(27), d(54)}},
47 A2{
A{d ( 6),d( 10),d( 20),d( 39)},
A{d( 5), d( 9), d(18), d(35)},
A{d( 5), d( 9), d(17), d(35)}},
48 A2{
A{d(115),d(115),d(115),d(115)},
A{d(52), d(52), d(52), d(52)},
A{d(18), d(18), d(18), d(18)}},
49 A2{
A{d( 57),d( 57),d( 57),d( 57)},
A{d(25), d(25), d(25), d(25)},
A{d( 9), d( 9), d( 9), d( 9)}}
51static constexpr std::array BMXL_TIMING = {
52 A2{
A{d( 38),d( 33),d( 32),d( 33)},
A{d(33), d(28), d(28), d(28)},
A{d(33), d(27), d(27), d(27)}},
53 A2{
A{d( 24),d( 20),d( 20),d (19)},
A{d(22), d(18), d(18), d(18)},
A{d(21), d(17), d(17), d(17)}},
54 A2{
A{d(171),d(171),d(171),d(171)},
A{d(82), d(82), d(82), d(82)},
A{d(29), d(29), d(29), d(29)}},
55 A2{
A{d(114),d(114),d(114),d(114)},
A{d(50), d(50), d(50), d(50)},
A{d(18), d(18), d(18), d(18)}}
57static constexpr std::array BMLX_TIMING = {
58 A2{
A{ d(10), d(16), d(32), d(66)},
A{d( 8), d(14), d(28), d(57)},
A{d( 8), d(13), d(27), d(54)}},
59 A2{
A{ d( 6), d(10), d(20), d(39)},
A{d( 5), d( 9), d(18), d(35)},
A{d( 5), d( 9), d(17), d(35)}},
60 A2{
A{ d(84), d(84), d(84), d(84)},
A{d(44), d(44), d(44), d(44)},
A{d(17), d(17), d(17), d(17)}},
61 A2{
A{ d(57), d(57), d(57), d(57)},
A{d(25), d(25), d(25), d(25)},
A{d( 9), d( 9), d( 9), d( 9)}}
63static constexpr std::array BMLL_TIMING = {
64 A2{
A{d( 33),d( 33),d( 33),d( 33)},
A{d(28), d(28), d(28), d(28)},
A{d(27), d(27), d(27), d(27)}},
65 A2{
A{d( 20),d( 20),d( 20),d( 20)},
A{d(18), d(18), d(18), d(18)},
A{d(18), d(18), d(18), d(18)}},
66 A2{
A{d(118),d(118),d(118),d(118)},
A{d(52), d(52), d(52), d(52)},
A{d(18), d(18), d(18), d(18)}},
67 A2{
A{d(118),d(118),d(118),d(118)},
A{d(52), d(52), d(52), d(52)},
A{d(18), d(18), d(18), d(18)}}
69static constexpr std::array CMMM_TIMING = {
70 A2{
A{ d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)}},
71 A2{
A{ d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)}},
72 A2{
A{ d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)}},
73 A2{
A{ d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)}}
75static constexpr std::array LINE_TIMING = {
76 A2{
A{ d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)}},
77 A2{
A{ d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)}},
78 A2{
A{ d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)}},
79 A2{
A{ d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)}}
81static constexpr std::array SRCH_TIMING = {
82 A2{
A{ d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)}},
83 A2{
A{ d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)}},
84 A2{
A{ d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)}},
85 A2{
A{ d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)},
A{d(24), d(24), d(24), d(24)}}
90 if (cmdEngine.getBrokenTiming()) [[unlikely]]
return {};
92 const auto& vdp = cmdEngine.getVDP();
93 auto mode = vdp.getDisplayMode();
94 unsigned idx1 = (mode ==
P1) ? 2 :
96 (vdp.isOverScan()) ? 0 : 1;
97 unsigned idx2 = vdp.isDisplayEnabled() ? (vdp.spritesEnabled() ? 0 : 1)
99 unsigned idx3 = vdp.getColorDepth();
100 return table[idx1][idx2][idx3];
113static std::array<std::array<MemBuffer<byte>, 16>, 4> logOpLUT;
116static constexpr auto bitLUT = [] {
117 std::array<std::array<std::array<std::array<byte, 2>, 2>, 16>, 8> result = {};
118 for (
auto op :
xrange(16)) {
120 for (
auto src :
xrange(2)) {
121 for (
auto dst :
xrange(2)) {
122 unsigned b = tmp & 1;
123 for (
auto bit :
xrange(8)) {
124 result[bit][op][src][dst] = narrow<byte>(b << bit);
135[[nodiscard]]
static constexpr byte func01(
unsigned op,
unsigned src,
unsigned dst)
137 if ((src & 0x03) == 0)
return dst & 0x03;
139 res |= bitLUT[0][op][(src & 0x01) >> 0][(dst & 0x01) >> 0];
140 res |= bitLUT[1][op][(src & 0x02) >> 1][(dst & 0x02) >> 1];
143[[nodiscard]]
static constexpr byte func23(
unsigned op,
unsigned src,
unsigned dst)
145 if ((src & 0x0C) == 0)
return dst & 0x0C;
147 res |= bitLUT[2][op][(src & 0x04) >> 2][(dst & 0x04) >> 2];
148 res |= bitLUT[3][op][(src & 0x08) >> 3][(dst & 0x08) >> 3];
151[[nodiscard]]
static constexpr byte func45(
unsigned op,
unsigned src,
unsigned dst)
153 if ((src & 0x30) == 0)
return dst & 0x30;
155 res |= bitLUT[4][op][(src & 0x10) >> 4][(dst & 0x10) >> 4];
156 res |= bitLUT[5][op][(src & 0x20) >> 5][(dst & 0x20) >> 5];
159[[nodiscard]]
static constexpr byte func67(
unsigned op,
unsigned src,
unsigned dst)
161 if ((src & 0xC0) == 0)
return dst & 0xC0;
163 res |= bitLUT[6][op][(src & 0x40) >> 6][(dst & 0x40) >> 6];
164 res |= bitLUT[7][op][(src & 0x80) >> 7][(dst & 0x80) >> 7];
168[[nodiscard]]
static constexpr byte func03(
unsigned op,
unsigned src,
unsigned dst)
170 if ((src & 0x0F) == 0)
return dst & 0x0F;
172 res |= bitLUT[0][op][(src & 0x01) >> 0][(dst & 0x01) >> 0];
173 res |= bitLUT[1][op][(src & 0x02) >> 1][(dst & 0x02) >> 1];
174 res |= bitLUT[2][op][(src & 0x04) >> 2][(dst & 0x04) >> 2];
175 res |= bitLUT[3][op][(src & 0x08) >> 3][(dst & 0x08) >> 3];
178[[nodiscard]]
static constexpr byte func47(
unsigned op,
unsigned src,
unsigned dst)
180 if ((src & 0xF0) == 0)
return dst & 0xF0;
182 res |= bitLUT[4][op][(src & 0x10) >> 4][(dst & 0x10) >> 4];
183 res |= bitLUT[5][op][(src & 0x20) >> 5][(dst & 0x20) >> 5];
184 res |= bitLUT[6][op][(src & 0x40) >> 6][(dst & 0x40) >> 6];
185 res |= bitLUT[7][op][(src & 0x80) >> 7][(dst & 0x80) >> 7];
189[[nodiscard]]
static constexpr byte func07(
unsigned op,
unsigned src,
unsigned dst)
193 res |= bitLUT[0][op][(src & 0x01) >> 0][(dst & 0x01) >> 0];
194 res |= bitLUT[1][op][(src & 0x02) >> 1][(dst & 0x02) >> 1];
195 res |= bitLUT[2][op][(src & 0x04) >> 2][(dst & 0x04) >> 2];
196 res |= bitLUT[3][op][(src & 0x08) >> 3][(dst & 0x08) >> 3];
197 res |= bitLUT[4][op][(src & 0x10) >> 4][(dst & 0x10) >> 4];
198 res |= bitLUT[5][op][(src & 0x20) >> 5][(dst & 0x20) >> 5];
199 res |= bitLUT[6][op][(src & 0x40) >> 6][(dst & 0x40) >> 6];
200 res |= bitLUT[7][op][(src & 0x80) >> 7][(dst & 0x80) >> 7];
204static constexpr void fillTableNoT(
unsigned op, std::span<byte, 256 * 256> table)
206 for (
auto dst :
xrange(256)) {
207 for (
auto src :
xrange(256)) {
208 table[dst * 256 + src] = func07(op, src, dst);
213static constexpr void fillTable2(
unsigned op, std::span<byte, 256 * 256> table)
215 for (
auto dst :
xrange(256)) {
216 for (
auto src :
xrange(256)) {
218 res |= func01(op, src, dst);
219 res |= func23(op, src, dst);
220 res |= func45(op, src, dst);
221 res |= func67(op, src, dst);
222 table[dst * 256 + src] = res;
227static constexpr void fillTable4(
unsigned op, std::span<byte, 256 * 256> table)
229 for (
auto dst :
xrange(256)) {
230 for (
auto src :
xrange(256)) {
232 res |= func03(op, src, dst);
233 res |= func47(op, src, dst);
234 table[dst * 256 + src] = res;
239static constexpr void fillTable8(
unsigned op, std::span<byte, 256 * 256> table)
241 for (
auto dst :
xrange(256)) {
243 table[dst * 256 + 0 ] = narrow_cast<byte>(dst);
245 for (
auto src :
xrange(1, 256)) {
246 table[dst * 256 + src] = func07(op, src, dst);
251[[nodiscard]]
static std::span<const byte, 256 * 256> getLogOpImpl(
unsigned mode,
unsigned op)
254 auto& lut = logOpLUT[mode][op];
256 lut.resize(256 * 256);
257 std::span<byte, 256 * 256> s{lut.data(), 256 * 256};
275 return std::span<byte, 256 * 256>{lut.data(), 256 * 256};
279static constexpr byte DIY = 0x08;
280static constexpr byte DIX = 0x04;
281static constexpr byte NEQ = 0x02;
282static constexpr byte MAJ = 0x01;
285inline unsigned V9990CmdEngine::V9990P1::getPitch(
unsigned width)
290inline unsigned V9990CmdEngine::V9990P1::addressOf(
291 unsigned x,
unsigned y,
unsigned pitch)
296 return (addr & 0x3FFFF) | ((x & 0x200) << 9);
299inline byte V9990CmdEngine::V9990P1::point(
300 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
302 return vram.readVRAMDirect(addressOf(x, y, pitch));
305inline byte V9990CmdEngine::V9990P1::shift(
306 byte value,
unsigned fromX,
unsigned toX)
308 int shift = 4 * (narrow<int>(toX & 1) - narrow<int>(fromX & 1));
309 return (shift > 0) ?
byte(value >> shift) :
byte(value << -shift);
312inline byte V9990CmdEngine::V9990P1::shiftMask(
unsigned x)
314 return (x & 1) ? 0x0F : 0xF0;
317inline std::span<const byte, 256 * 256> V9990CmdEngine::V9990P1::getLogOpLUT(
byte op)
322inline byte V9990CmdEngine::V9990P1::logOp(
323 std::span<const byte, 256 * 256> lut,
byte src,
byte dst)
325 return lut[256 * dst + src];
328inline void V9990CmdEngine::V9990P1::pset(
329 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
330 byte srcColor,
word mask, std::span<const byte, 256 * 256> lut,
byte )
332 unsigned addr = addressOf(x, y, pitch);
333 byte dstColor = vram.readVRAMDirect(addr);
334 byte newColor = logOp(lut, srcColor, dstColor);
335 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
336 byte mask2 = mask1 & shiftMask(x);
337 byte result = (dstColor & ~mask2) | (newColor & mask2);
338 vram.writeVRAMDirect(addr, result);
340inline void V9990CmdEngine::V9990P1::psetColor(
341 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
342 word color,
word mask, std::span<const byte, 256 * 256> lut,
byte )
344 unsigned addr = addressOf(x, y, pitch);
345 byte srcColor = narrow_cast<byte>((addr & 0x40000) ? (color >> 8) : (color & 0xFF));
346 byte dstColor = vram.readVRAMDirect(addr);
347 byte newColor = logOp(lut, srcColor, dstColor);
348 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
349 byte mask2 = mask1 & (0xF0 >> (4 * (x & 1)));
350 byte result = (dstColor & ~mask2) | (newColor & mask2);
351 vram.writeVRAMDirect(addr, result);
355inline unsigned V9990CmdEngine::V9990P2::getPitch(
unsigned width)
360inline unsigned V9990CmdEngine::V9990P2::addressOf(
361 unsigned x,
unsigned y,
unsigned pitch)
367inline byte V9990CmdEngine::V9990P2::point(
368 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
370 return vram.readVRAMDirect(addressOf(x, y, pitch));
373inline byte V9990CmdEngine::V9990P2::shift(
374 byte value,
unsigned fromX,
unsigned toX)
376 int shift = 4 * (narrow<int>(toX & 1) - narrow<int>(fromX & 1));
377 return (shift > 0) ?
byte(value >> shift) :
byte(value << -shift);
380inline byte V9990CmdEngine::V9990P2::shiftMask(
unsigned x)
382 return (x & 1) ? 0x0F : 0xF0;
385inline std::span<const byte, 256 * 256> V9990CmdEngine::V9990P2::getLogOpLUT(
byte op)
390inline byte V9990CmdEngine::V9990P2::logOp(
391 std::span<const byte, 256 * 256> lut,
byte src,
byte dst)
393 return lut[256 * dst + src];
396inline void V9990CmdEngine::V9990P2::pset(
397 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
398 byte srcColor,
word mask, std::span<const byte, 256 * 256> lut,
byte )
400 unsigned addr = addressOf(x, y, pitch);
401 byte dstColor = vram.readVRAMDirect(addr);
402 byte newColor = logOp(lut, srcColor, dstColor);
403 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
404 byte mask2 = mask1 & shiftMask(x);
405 byte result = (dstColor & ~mask2) | (newColor & mask2);
406 vram.writeVRAMDirect(addr, result);
409inline void V9990CmdEngine::V9990P2::psetColor(
410 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
411 word color,
word mask, std::span<const byte, 256 * 256> lut,
byte )
413 unsigned addr = addressOf(x, y, pitch);
414 byte srcColor = narrow_cast<byte>((addr & 0x40000) ? (color >> 8) : (color & 0xFF));
415 byte dstColor = vram.readVRAMDirect(addr);
416 byte newColor = logOp(lut, srcColor, dstColor);
417 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
418 byte mask2 = mask1 & (0xF0 >> (4 * (x & 1)));
419 byte result = (dstColor & ~mask2) | (newColor & mask2);
420 vram.writeVRAMDirect(addr, result);
424inline unsigned V9990CmdEngine::V9990Bpp2::getPitch(
unsigned width)
429inline unsigned V9990CmdEngine::V9990Bpp2::addressOf(
430 unsigned x,
unsigned y,
unsigned pitch)
435inline byte V9990CmdEngine::V9990Bpp2::point(
436 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
438 return vram.readVRAMDirect(addressOf(x, y, pitch));
441inline byte V9990CmdEngine::V9990Bpp2::shift(
442 byte value,
unsigned fromX,
unsigned toX)
444 int shift = 2 * (narrow<int>(toX & 3) - narrow<int>(fromX & 3));
445 return (shift > 0) ?
byte(value >> shift) :
byte(value << -shift);
448inline byte V9990CmdEngine::V9990Bpp2::shiftMask(
unsigned x)
450 return 0xC0 >> (2 * (x & 3));
453inline std::span<const byte, 256 * 256> V9990CmdEngine::V9990Bpp2::getLogOpLUT(
byte op)
458inline byte V9990CmdEngine::V9990Bpp2::logOp(
459 std::span<const byte, 256 * 256> lut,
byte src,
byte dst)
461 return lut[256 * dst + src];
464inline void V9990CmdEngine::V9990Bpp2::pset(
465 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
466 byte srcColor,
word mask, std::span<const byte, 256 * 256> lut,
byte )
468 unsigned addr = addressOf(x, y, pitch);
469 byte dstColor = vram.readVRAMDirect(addr);
470 byte newColor = logOp(lut, srcColor, dstColor);
471 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
472 byte mask2 = mask1 & shiftMask(x);
473 byte result = (dstColor & ~mask2) | (newColor & mask2);
474 vram.writeVRAMDirect(addr, result);
477inline void V9990CmdEngine::V9990Bpp2::psetColor(
478 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
479 word color,
word mask, std::span<const byte, 256 * 256> lut,
byte )
481 unsigned addr = addressOf(x, y, pitch);
482 byte srcColor = narrow_cast<byte>((addr & 0x40000) ? (color >> 8) : (color & 0xFF));
483 byte dstColor = vram.readVRAMDirect(addr);
484 byte newColor = logOp(lut, srcColor, dstColor);
485 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
486 byte mask2 = mask1 & (0xC0 >> (2 * (x & 3)));
487 byte result = (dstColor & ~mask2) | (newColor & mask2);
488 vram.writeVRAMDirect(addr, result);
492inline unsigned V9990CmdEngine::V9990Bpp4::getPitch(
unsigned width)
497inline unsigned V9990CmdEngine::V9990Bpp4::addressOf(
498 unsigned x,
unsigned y,
unsigned pitch)
503inline byte V9990CmdEngine::V9990Bpp4::point(
504 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
506 return vram.readVRAMDirect(addressOf(x, y, pitch));
509inline byte V9990CmdEngine::V9990Bpp4::shift(
510 byte value,
unsigned fromX,
unsigned toX)
512 int shift = 4 * (narrow<int>(toX & 1) - narrow<int>(fromX & 1));
513 return (shift > 0) ?
byte(value >> shift) :
byte(value << -shift);
516inline byte V9990CmdEngine::V9990Bpp4::shiftMask(
unsigned x)
518 return (x & 1) ? 0x0F : 0xF0;
521inline std::span<const byte, 256 * 256> V9990CmdEngine::V9990Bpp4::getLogOpLUT(
byte op)
526inline byte V9990CmdEngine::V9990Bpp4::logOp(
527 std::span<const byte, 256 * 256> lut,
byte src,
byte dst)
529 return lut[256 * dst + src];
532inline void V9990CmdEngine::V9990Bpp4::pset(
533 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
534 byte srcColor,
word mask, std::span<const byte, 256 * 256> lut,
byte )
536 unsigned addr = addressOf(x, y, pitch);
537 byte dstColor = vram.readVRAMDirect(addr);
538 byte newColor = logOp(lut, srcColor, dstColor);
539 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
540 byte mask2 = mask1 & shiftMask(x);
541 byte result = (dstColor & ~mask2) | (newColor & mask2);
542 vram.writeVRAMDirect(addr, result);
545inline void V9990CmdEngine::V9990Bpp4::psetColor(
546 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
547 word color,
word mask, std::span<const byte, 256 * 256> lut,
byte )
549 unsigned addr = addressOf(x, y, pitch);
550 byte srcColor = narrow_cast<byte>((addr & 0x40000) ? (color >> 8) : (color & 0xFF));
551 byte dstColor = vram.readVRAMDirect(addr);
552 byte newColor = logOp(lut, srcColor, dstColor);
553 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
554 byte mask2 = mask1 & (0xF0 >> (4 * (x & 1)));
555 byte result = (dstColor & ~mask2) | (newColor & mask2);
556 vram.writeVRAMDirect(addr, result);
560inline unsigned V9990CmdEngine::V9990Bpp8::getPitch(
unsigned width)
565inline unsigned V9990CmdEngine::V9990Bpp8::addressOf(
566 unsigned x,
unsigned y,
unsigned pitch)
571inline byte V9990CmdEngine::V9990Bpp8::point(
572 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
574 return vram.readVRAMDirect(addressOf(x, y, pitch));
577inline byte V9990CmdEngine::V9990Bpp8::shift(
578 byte value,
unsigned ,
unsigned )
583inline byte V9990CmdEngine::V9990Bpp8::shiftMask(
unsigned )
588inline std::span<const byte, 256 * 256> V9990CmdEngine::V9990Bpp8::getLogOpLUT(
byte op)
593inline byte V9990CmdEngine::V9990Bpp8::logOp(
594 std::span<const byte, 256 * 256> lut,
byte src,
byte dst)
596 return lut[256 * dst + src];
599inline void V9990CmdEngine::V9990Bpp8::pset(
600 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
601 byte srcColor,
word mask, std::span<const byte, 256 * 256> lut,
byte )
603 unsigned addr = addressOf(x, y, pitch);
604 byte dstColor = vram.readVRAMDirect(addr);
605 byte newColor = logOp(lut, srcColor, dstColor);
606 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
607 byte result = (dstColor & ~mask1) | (newColor & mask1);
608 vram.writeVRAMDirect(addr, result);
611inline void V9990CmdEngine::V9990Bpp8::psetColor(
612 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
613 word color,
word mask, std::span<const byte, 256 * 256> lut,
byte )
615 unsigned addr = addressOf(x, y, pitch);
616 byte srcColor = narrow_cast<byte>((addr & 0x40000) ? (color >> 8) : (color & 0xFF));
617 byte dstColor = vram.readVRAMDirect(addr);
618 byte newColor = logOp(lut, srcColor, dstColor);
619 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
620 byte result = (dstColor & ~mask1) | (newColor & mask1);
621 vram.writeVRAMDirect(addr, result);
625inline unsigned V9990CmdEngine::V9990Bpp16::getPitch(
unsigned width)
631inline unsigned V9990CmdEngine::V9990Bpp16::addressOf(
632 unsigned x,
unsigned y,
unsigned pitch)
635 return ((x & (pitch - 1)) + y * pitch) & 0x3FFFF;
638inline word V9990CmdEngine::V9990Bpp16::point(
639 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
641 unsigned addr = addressOf(x, y, pitch);
642 return word(vram.readVRAMDirect(addr + 0x00000) +
643 vram.readVRAMDirect(addr + 0x40000) * 256);
646inline word V9990CmdEngine::V9990Bpp16::shift(
647 word value,
unsigned ,
unsigned )
652inline word V9990CmdEngine::V9990Bpp16::shiftMask(
unsigned )
657inline std::span<const byte, 256 * 256> V9990CmdEngine::V9990Bpp16::getLogOpLUT(
byte op)
662inline word V9990CmdEngine::V9990Bpp16::logOp(
663 std::span<const byte, 256 * 256> lut,
word src,
word dst,
bool transp)
665 if (transp && (src == 0))
return dst;
666 return word((lut[((dst & 0x00FF) << 8) + ((src & 0x00FF) >> 0)] << 0) +
667 (lut[((dst & 0xFF00) << 0) + ((src & 0xFF00) >> 8)] << 8));
670inline void V9990CmdEngine::V9990Bpp16::pset(
671 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
672 word srcColor,
word mask, std::span<const byte, 256 * 256> lut,
byte op)
674 unsigned addr = addressOf(x, y, pitch);
675 auto dstColor =
word(vram.readVRAMDirect(addr + 0x00000) +
676 vram.readVRAMDirect(addr + 0x40000) * 256);
677 word newColor = logOp(lut, srcColor, dstColor, (op & 0x10) != 0);
678 word result = (dstColor & ~mask) | (newColor & mask);
679 vram.writeVRAMDirect(addr + 0x00000, narrow_cast<byte>(result & 0xFF));
680 vram.writeVRAMDirect(addr + 0x40000, narrow_cast<byte>(result >> 8));
683inline void V9990CmdEngine::V9990Bpp16::psetColor(
684 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
685 word srcColor,
word mask, std::span<const byte, 256 * 256> lut,
byte op)
687 unsigned addr = addressOf(x, y, pitch);
688 auto dstColor =
word(vram.readVRAMDirect(addr + 0x00000) +
689 vram.readVRAMDirect(addr + 0x40000) * 256);
690 word newColor = logOp(lut, srcColor, dstColor, (op & 0x10) != 0);
691 word result = (dstColor & ~mask) | (newColor & mask);
692 vram.writeVRAMDirect(addr + 0x00000, narrow_cast<byte>(result & 0xFF));
693 vram.writeVRAMDirect(addr + 0x40000, narrow_cast<byte>(result >> 8));
701 : settings(settings_), vdp(vdp_), vram(vdp.getVRAM()), engineTime(time_)
706 "V9990 command tracing on/off",
false);
709 update(cmdTimingSetting);
710 cmdTimingSetting.
attach(*
this);
715 srcAddress = dstAddress = nbBytes = 0;
716 ASX = ADX = ANX = ANY = 0;
717 SX = SY = DX = DY = NX = NY = 0;
718 WM = fgCol = bgCol = 0;
720 data = bitsLeft = partial = 0;
733 endAfterRead =
false;
741 SX =
word((SX & 0x0700) | ((value & 0xFF) << 0));
744 SX =
word((SX & 0x00FF) | ((value & 0x07) << 8));
747 SY =
word((SY & 0x0F00) | ((value & 0xFF) << 0));
750 SY =
word((SY & 0x00FF) | ((value & 0x0F) << 8));
753 DX =
word((DX & 0x0700) | ((value & 0xFF) << 0));
756 DX =
word((DX & 0x00FF) | ((value & 0x07) << 8));
759 DY =
word((DY & 0x0F00) | ((value & 0xFF) << 0));
762 DY =
word((DY & 0x00FF) | ((value & 0x0F) << 8));
765 NX =
word((NX & 0x0F00) | ((value & 0xFF) << 0));
768 NX =
word((NX & 0x00FF) | ((value & 0x0F) << 8));
771 NY =
word((NY & 0x0F00) | ((value & 0xFF) << 0));
774 NY =
word((NY & 0x00FF) | ((value & 0x0F) << 8));
783 WM =
word((WM & 0xFF00) | (value << 0));
786 WM =
word((WM & 0x00FF) | (value << 8));
789 fgCol =
word((fgCol & 0xFF00) | (value << 0));
792 fgCol =
word((fgCol & 0x00FF) | (value << 8));
795 bgCol =
word((bgCol & 0xFF00) | (value << 0));
798 bgCol =
word((bgCol & 0x00FF) | (value << 8));
802 if (cmdTraceSetting->getBoolean()) {
803 reportV9990Command();
811 switch (cmdMode | (CMD >> 4)) {
812 case 0x00:
case 0x10:
case 0x20:
case 0x30:
case 0x40:
case 0x50:
813 startSTOP(time);
break;
815 case 0x01:
case 0x11:
case 0x21:
case 0x31:
case 0x41:
816 startLMMC (time);
break;
818 startLMMC16(time);
break;
820 case 0x02:
case 0x12:
case 0x22:
case 0x32:
case 0x42:
case 0x52:
821 startLMMV(time);
break;
823 case 0x03:
case 0x13:
case 0x23:
case 0x33:
case 0x43:
824 startLMCM (time);
break;
826 startLMCM16(time);
break;
828 case 0x04:
case 0x14:
case 0x24:
case 0x34:
case 0x44:
case 0x54:
829 startLMMM(time);
break;
831 case 0x05:
case 0x15:
case 0x25:
case 0x35:
case 0x45:
case 0x55:
832 startCMMC(time);
break;
834 case 0x06:
case 0x16:
case 0x26:
case 0x36:
case 0x46:
case 0x56:
835 startCMMK(time);
break;
837 case 0x07:
case 0x17:
case 0x27:
case 0x37:
case 0x47:
case 0x57:
838 startCMMM(time);
break;
840 case 0x08:
case 0x18:
case 0x28:
case 0x38:
case 0x48:
case 0x58:
841 startBMXL(time);
break;
843 case 0x09:
case 0x19:
case 0x29:
case 0x39:
case 0x49:
case 0x59:
844 startBMLX(time);
break;
846 case 0x0A:
case 0x1A:
case 0x2A:
case 0x3A:
case 0x4A:
847 startBMLL (time);
break;
849 startBMLL16(time);
break;
851 case 0x0B:
case 0x1B:
case 0x2B:
case 0x3B:
case 0x4B:
case 0x5B:
852 startLINE(time);
break;
854 case 0x0C:
case 0x1C:
case 0x2C:
case 0x3C:
case 0x4C:
case 0x5C:
855 startSRCH(time);
break;
857 case 0x0D: startPOINT<V9990P1 >(time);
break;
858 case 0x1D: startPOINT<V9990P2 >(time);
break;
859 case 0x2D: startPOINT<V9990Bpp2 >(time);
break;
860 case 0x3D: startPOINT<V9990Bpp4 >(time);
break;
861 case 0x4D: startPOINT<V9990Bpp8 >(time);
break;
862 case 0x5D: startPOINT<V9990Bpp16>(time);
break;
864 case 0x0E: startPSET<V9990P1 >(time);
break;
865 case 0x1E: startPSET<V9990P2 >(time);
break;
866 case 0x2E: startPSET<V9990Bpp2 >(time);
break;
867 case 0x3E: startPSET<V9990Bpp4 >(time);
break;
868 case 0x4E: startPSET<V9990Bpp8 >(time);
break;
869 case 0x5E: startPSET<V9990Bpp16>(time);
break;
871 case 0x0F:
case 0x1F:
case 0x2F:
case 0x3F:
case 0x4F:
case 0x5F:
872 startADVN(time);
break;
886void V9990CmdEngine::setCommandMode()
889 if (dispMode ==
P1) {
891 }
else if (dispMode ==
P2) {
919void V9990CmdEngine::reportV9990Command()
const
921 static constexpr std::array<std::string_view, 16> COMMANDS = {
922 "STOP",
"LMMC",
"LMMV",
"LMCM",
923 "LMMM",
"CMMC",
"CMMK",
"CMMM",
924 "BMXL",
"BMLX",
"BMLL",
"LINE",
925 "SRCH",
"POINT",
"PSET",
"ADVN"
927 std::cerr <<
"V9990Cmd " << COMMANDS[CMD >> 4]
928 <<
" SX=" << std::dec << SX
929 <<
" SY=" << std::dec << SY
930 <<
" DX=" << std::dec << DX
931 <<
" DY=" << std::dec << DY
932 <<
" NX=" << std::dec << NX
933 <<
" NY=" << std::dec << NY
934 <<
" ARG=" << std::hex << int(ARG)
935 <<
" LOG=" << std::hex << int(LOG)
936 <<
" WM=" << std::hex << WM
937 <<
" FC=" << std::hex << fgCol
938 <<
" BC=" << std::hex << bgCol
939 <<
" CMD=" << std::hex << int(CMD)
943void V9990CmdEngine::update(
const Setting&
setting)
noexcept
945 brokenTiming = checked_cast<const EnumSetting<bool>&>(
setting).getEnum();
949void V9990CmdEngine::startSTOP(EmuTime::param time)
954void V9990CmdEngine::executeSTOP(EmuTime::param )
960void V9990CmdEngine::startLMMC(EmuTime::param )
962 ANX = getWrappedNX();
963 ANY = getWrappedNY();
966void V9990CmdEngine::startLMMC16(EmuTime::param time)
973void V9990CmdEngine::executeLMMC<V9990CmdEngine::V9990Bpp16>(EmuTime::param limit)
975 if (!(status & TR)) {
982 auto value =
word((data << 8) | partial);
983 unsigned pitch = V9990Bpp16::getPitch(vdp.getImageWidth());
984 auto lut = V9990Bpp16::getLogOpLUT(LOG);
985 V9990Bpp16::pset(vram, DX, DY, pitch, value, WM, lut, LOG);
986 word dx = (ARG & DIX) ?
word(-1) : 1;
989 word dy = (ARG & DIY) ?
word(-1) : 1;
995 ANX = getWrappedNX();
1002template<
typename Mode>
1003void V9990CmdEngine::executeLMMC(EmuTime::param limit)
1005 if (!(status &
TR)) {
1008 auto lut = Mode::getLogOpLUT(LOG);
1009 for (
int i = 0; (ANY > 0) && (i < Mode::PIXELS_PER_BYTE); ++i) {
1010 byte d = Mode::shift(data, i, DX);
1011 Mode::pset(vram, DX, DY, pitch, d, WM, lut, LOG);
1013 word dx = (ARG & DIX) ?
word(-1) : 1;
1016 word dy = (ARG & DIY) ?
word(-1) : 1;
1017 DX -=
word(NX * dx);
1030void V9990CmdEngine::startLMMV(EmuTime::param time)
1033 ANX = getWrappedNX();
1034 ANY = getWrappedNY();
1037template<
typename Mode>
1038void V9990CmdEngine::executeLMMV(EmuTime::param limit)
1042 auto delta = getTiming(*
this, LMMV_TIMING);
1044 word dx = (ARG & DIX) ?
word(-1) : 1;
1045 word dy = (ARG & DIY) ?
word(-1) : 1;
1046 auto lut = Mode::getLogOpLUT(LOG);
1047 while (engineTime < limit) {
1048 engineTime += delta;
1049 Mode::psetColor(vram, DX, DY, pitch, fgCol, WM, lut, LOG);
1053 DX -=
word(NX * dx);
1056 cmdReady(engineTime);
1059 ANX = getWrappedNX();
1066void V9990CmdEngine::startLMCM(EmuTime::param )
1068 ANX = getWrappedNX();
1069 ANY = getWrappedNY();
1071 endAfterRead =
false;
1073void V9990CmdEngine::startLMCM16(EmuTime::param time)
1079template<
typename Mode>
1080void V9990CmdEngine::executeLMCM(EmuTime::param )
1082 if (!(status &
TR)) {
1084 if ((Mode::BITS_PER_PIXEL == 16) && bitsLeft) {
1090 using Type =
typename Mode::Type;
1092 for (
int i = 0; (ANY > 0) && (i < Mode::PIXELS_PER_BYTE); ++i) {
1093 auto src = Mode::point(vram, SX, SY, pitch);
1094 d |= Type(Mode::shift(src, SX, i) & Mode::shiftMask(i));
1096 word dx = (ARG & DIX) ?
word(-1) : 1;
1099 word dy = (ARG & DIY) ?
word(-1) : 1;
1100 SX -=
word(NX * dx);
1103 endAfterRead =
true;
1105 ANX = getWrappedNX();
1109 if constexpr (Mode::BITS_PER_PIXEL == 16) {
1113 data = narrow_cast<byte>(tmp & 0xff);
1114 partial = narrow_cast<byte>(tmp >> 8);
1123void V9990CmdEngine::startLMMM(EmuTime::param time)
1126 ANX = getWrappedNX();
1127 ANY = getWrappedNY();
1130template<
typename Mode>
1131void V9990CmdEngine::executeLMMM(EmuTime::param limit)
1135 auto delta = getTiming(*
this, LMMM_TIMING);
1137 word dx = (ARG & DIX) ?
word(-1) : 1;
1138 word dy = (ARG & DIY) ?
word(-1) : 1;
1139 auto lut = Mode::getLogOpLUT(LOG);
1140 while (engineTime < limit) {
1141 engineTime += delta;
1142 auto src = Mode::point(vram, SX, SY, pitch);
1143 src = Mode::shift(src, SX, DX);
1144 Mode::pset(vram, DX, DY, pitch, src, WM, lut, LOG);
1149 DX -=
word(NX * dx);
1150 SX -=
word(NX * dx);
1154 cmdReady(engineTime);
1157 ANX = getWrappedNX();
1164void V9990CmdEngine::startCMMC(EmuTime::param )
1166 ANX = getWrappedNX();
1167 ANY = getWrappedNY();
1171template<
typename Mode>
1172void V9990CmdEngine::executeCMMC(EmuTime::param limit)
1174 if (!(status &
TR)) {
1178 word dx = (ARG & DIX) ?
word(-1) : 1;
1179 word dy = (ARG & DIY) ?
word(-1) : 1;
1180 auto lut = Mode::getLogOpLUT(LOG);
1181 for (
auto i :
xrange(8)) {
1183 bool bit = (data & 0x80) != 0;
1186 word src = bit ? fgCol : bgCol;
1187 Mode::psetColor(vram, DX, DY, pitch, src, WM, lut, LOG);
1191 DX -=
word(NX * dx);
1197 ANX = getWrappedNX();
1205void V9990CmdEngine::startCMMK(EmuTime::param time)
1207 std::cout <<
"V9990: CMMK not yet implemented\n";
1211void V9990CmdEngine::executeCMMK(EmuTime::param )
1217void V9990CmdEngine::startCMMM(EmuTime::param time)
1220 srcAddress = (SX & 0xFF) + ((SY & 0x7FF) << 8);
1221 ANX = getWrappedNX();
1222 ANY = getWrappedNY();
1226template<
typename Mode>
1227void V9990CmdEngine::executeCMMM(EmuTime::param limit)
1231 auto delta = getTiming(*
this, CMMM_TIMING);
1233 word dx = (ARG & DIX) ?
word(-1) : 1;
1234 word dy = (ARG & DIY) ?
word(-1) : 1;
1235 auto lut = Mode::getLogOpLUT(LOG);
1236 while (engineTime < limit) {
1237 engineTime += delta;
1239 data = vram.readVRAMBx(srcAddress++);
1243 bool bit = (data & 0x80) != 0;
1246 word color = bit ? fgCol : bgCol;
1247 Mode::psetColor(vram, DX, DY, pitch, color, WM, lut, LOG);
1251 DX -=
word(NX * dx);
1254 cmdReady(engineTime);
1257 ANX = getWrappedNX();
1264void V9990CmdEngine::startBMXL(EmuTime::param time)
1267 srcAddress = (SX & 0xFF) + ((SY & 0x7FF) << 8);
1268 ANX = getWrappedNX();
1269 ANY = getWrappedNY();
1273void V9990CmdEngine::executeBMXL<V9990CmdEngine::V9990Bpp16>(EmuTime::param limit)
1276 auto delta = getTiming(*
this, BMXL_TIMING) * 2;
1277 unsigned pitch = V9990Bpp16::getPitch(vdp.getImageWidth());
1278 word dx = (ARG & DIX) ?
word(-1) : 1;
1279 word dy = (ARG & DIY) ?
word(-1) : 1;
1280 auto lut = V9990Bpp16::getLogOpLUT(LOG);
1282 while (engineTime < limit) {
1283 engineTime += delta;
1284 auto src =
word(vram.readVRAMBx(srcAddress + 0) +
1285 vram.readVRAMBx(srcAddress + 1) * 256);
1287 V9990Bpp16::pset(vram, DX, DY, pitch, src, WM, lut, LOG);
1290 DX -=
word(NX * dx);
1293 cmdReady(engineTime);
1296 ANX = getWrappedNX();
1302template<
typename Mode>
1303void V9990CmdEngine::executeBMXL(EmuTime::param limit)
1305 auto delta = getTiming(*
this, BMXL_TIMING);
1307 word dx = (ARG & DIX) ?
word(-1) : 1;
1308 word dy = (ARG & DIY) ?
word(-1) : 1;
1309 auto lut = Mode::getLogOpLUT(LOG);
1311 while (engineTime < limit) {
1312 engineTime += delta;
1313 byte d = vram.readVRAMBx(srcAddress++);
1314 for (
int i = 0; (ANY > 0) && (i < Mode::PIXELS_PER_BYTE); ++i) {
1315 auto d2 = Mode::shift(d, i, DX);
1316 Mode::pset(vram, DX, DY, pitch, d2, WM, lut, LOG);
1319 DX -=
word(NX * dx);
1322 cmdReady(engineTime);
1325 ANX = getWrappedNX();
1333void V9990CmdEngine::startBMLX(EmuTime::param time)
1336 dstAddress = (DX & 0xFF) + ((DY & 0x7FF) << 8);
1337 ANX = getWrappedNX();
1338 ANY = getWrappedNY();
1342void V9990CmdEngine::executeBMLX<V9990CmdEngine::V9990Bpp16>(EmuTime::param limit)
1345 auto delta = getTiming(*
this, BMLX_TIMING);
1346 unsigned pitch = V9990Bpp16::getPitch(vdp.getImageWidth());
1347 word dx = (ARG & DIX) ?
word(-1) : 1;
1348 word dy = (ARG & DIY) ?
word(-1) : 1;
1350 while (engineTime < limit) {
1351 engineTime += delta;
1352 auto src = V9990Bpp16::point(vram, SX, SY, pitch);
1353 vram.writeVRAMBx(dstAddress++, narrow_cast<byte>(src & 0xFF));
1354 vram.writeVRAMBx(dstAddress++, narrow_cast<byte>(src >> 8));
1357 SX -=
word(NX * dx);
1360 cmdReady(engineTime);
1363 ANX = getWrappedNX();
1368template<
typename Mode>
1369void V9990CmdEngine::executeBMLX(EmuTime::param limit)
1372 auto delta = getTiming(*
this, BMLX_TIMING);
1374 word dx = (ARG & DIX) ?
word(-1) : 1;
1375 word dy = (ARG & DIY) ?
word(-1) : 1;
1377 while (engineTime < limit) {
1378 engineTime += delta;
1380 for (
auto i :
xrange(Mode::PIXELS_PER_BYTE)) {
1381 auto src = Mode::point(vram, SX, SY, pitch);
1382 d |=
byte(Mode::shift(src, SX, i) & Mode::shiftMask(i));
1385 SX -=
word(NX * dx);
1388 vram.writeVRAMBx(dstAddress++, d);
1389 cmdReady(engineTime);
1392 ANX = getWrappedNX();
1396 vram.writeVRAMBx(dstAddress++, d);
1401void V9990CmdEngine::startBMLL(EmuTime::param time)
1404 srcAddress = (SX & 0xFF) + ((SY & 0x7FF) << 8);
1405 dstAddress = (DX & 0xFF) + ((DY & 0x7FF) << 8);
1406 nbBytes = (NX & 0xFF) + ((NY & 0x7FF) << 8);
1411void V9990CmdEngine::startBMLL16(EmuTime::param time)
1422void V9990CmdEngine::executeBMLL<V9990CmdEngine::V9990Bpp16>(EmuTime::param limit)
1426 auto delta = getTiming(*
this, BMLL_TIMING) * 2;
1427 auto lut = V9990Bpp16::getLogOpLUT(LOG);
1428 bool transp = (LOG & 0x10) != 0;
1429 while (engineTime < limit) {
1430 engineTime += delta;
1432 auto srcColor =
word(vram.readVRAMDirect(srcAddress + 0x00000) +
1433 vram.readVRAMDirect(srcAddress + 0x40000) * 256);
1434 auto dstColor =
word(vram.readVRAMDirect(dstAddress + 0x00000) +
1435 vram.readVRAMDirect(dstAddress + 0x40000) * 256);
1436 word newColor = V9990Bpp16::logOp(lut, srcColor, dstColor, transp);
1437 word result = (dstColor & ~WM) | (newColor & WM);
1438 vram.writeVRAMDirect(dstAddress + 0x00000, narrow_cast<byte>(result & 0xFF));
1439 vram.writeVRAMDirect(dstAddress + 0x40000, narrow_cast<byte>(result >> 8));
1440 srcAddress = (srcAddress + 1) & 0x3FFFF;
1441 dstAddress = (dstAddress + 1) & 0x3FFFF;
1443 cmdReady(engineTime);
1449template<
typename Mode>
1450void V9990CmdEngine::executeBMLL(EmuTime::param limit)
1453 auto delta = getTiming(*
this, BMLL_TIMING);
1454 auto lut = Mode::getLogOpLUT(LOG);
1455 while (engineTime < limit) {
1456 engineTime += delta;
1458 byte srcColor = vram.readVRAMBx(srcAddress);
1460 byte dstColor = vram.readVRAMDirect(addr);
1461 byte newColor = Mode::logOp(lut, srcColor, dstColor);
1462 byte mask = narrow_cast<byte>((addr & 0x40000) ? (WM >> 8) : (WM & 0xFF));
1463 byte result = (dstColor & ~mask) | (newColor & mask);
1464 vram.writeVRAMDirect(addr, result);
1465 srcAddress = (srcAddress + 1) & 0x7FFFF;
1466 dstAddress = (dstAddress + 1) & 0x7FFFF;
1468 cmdReady(engineTime);
1475void V9990CmdEngine::startLINE(EmuTime::param time)
1478 ASX =
word((NX - 1) / 2);
1483template<
typename Mode>
1484void V9990CmdEngine::executeLINE(EmuTime::param limit)
1486 auto delta = getTiming(*
this, LINE_TIMING);
1488 unsigned pitch = Mode::getPitch(width);
1490 word TX = (ARG & DIX) ?
word(-1) : 1;
1491 word TY = (ARG & DIY) ?
word(-1) : 1;
1492 auto lut = Mode::getLogOpLUT(LOG);
1494 if ((ARG & MAJ) == 0) {
1496 while (engineTime < limit) {
1497 engineTime += delta;
1498 Mode::psetColor(vram, ADX, DY, pitch, fgCol, WM, lut, LOG);
1507 if (ANX++ == NX || (ADX & width)) {
1508 cmdReady(engineTime);
1514 while (engineTime < limit) {
1515 engineTime += delta;
1516 Mode::psetColor(vram, ADX, DY, pitch, fgCol, WM, lut, LOG);
1524 if (ANX++ == NX || (ADX & width)) {
1525 cmdReady(engineTime);
1533void V9990CmdEngine::startSRCH(EmuTime::param time)
1539template<
typename Mode>
1540void V9990CmdEngine::executeSRCH(EmuTime::param limit)
1542 using Type =
typename Mode::Type;
1543 auto delta = getTiming(*
this, SRCH_TIMING);
1545 unsigned pitch = Mode::getPitch(width);
1546 Type mask = (1 << Mode::BITS_PER_PIXEL) -1;
1548 word TX = (ARG & DIX) ?
word(-1) : 1;
1549 bool AEQ = (ARG & NEQ) != 0;
1551 while (engineTime < limit) {
1552 engineTime += delta;
1556 if constexpr (Mode::BITS_PER_PIXEL == 16) {
1557 value = Mode::point(vram, ASX, SY, pitch);
1558 col =
static_cast<Type
>(fgCol);
1559 mask2 =
static_cast<Type
>(~0);
1562 unsigned addr = Mode::addressOf(ASX, SY, pitch);
1563 value = vram.readVRAMDirect(addr);
1564 col = narrow_cast<byte>((addr & 0x40000) ? (fgCol >> 8) : (fgCol & 0xFF));
1565 mask2 = Mode::shift(mask, 3, ASX);
1567 if (((value & mask2) == (col & mask2)) ^ AEQ) {
1569 cmdReady(engineTime);
1576 cmdReady(engineTime);
1584template<
typename Mode>
1585void V9990CmdEngine::startPOINT(EmuTime::param )
1588 auto d = Mode::point(vram, SX, SY, pitch);
1590 if constexpr (Mode::BITS_PER_PIXEL != 16) {
1592 endAfterRead =
true;
1597 data = narrow_cast<byte>(tmp & 0xff);
1598 partial = narrow_cast<byte>(tmp >> 8);
1599 endAfterRead =
false;
1604template<
typename Mode>
1605void V9990CmdEngine::executePOINT(EmuTime::param )
1607 if (status &
TR)
return;
1609 assert(Mode::BITS_PER_PIXEL == 16);
1612 endAfterRead =
true;
1616template<
typename Mode>
1617void V9990CmdEngine::startPSET(EmuTime::param time)
1620 auto lut = Mode::getLogOpLUT(LOG);
1621 Mode::psetColor(vram, DX, DY, pitch, fgCol, WM, lut, LOG);
1628void V9990CmdEngine::executePSET(EmuTime::param )
1634void V9990CmdEngine::startADVN(EmuTime::param time)
1636 std::cout <<
"V9990: ADVN not yet implemented\n";
1640void V9990CmdEngine::executeADVN(EmuTime::param )
1650 switch (cmdMode | (CMD >> 4)) {
1651 case 0x00:
case 0x10:
case 0x20:
case 0x30:
case 0x40:
case 0x50:
1652 executeSTOP(time);
break;
1654 case 0x01: executeLMMC<V9990P1 >(time);
break;
1655 case 0x11: executeLMMC<V9990P2 >(time);
break;
1656 case 0x21: executeLMMC<V9990Bpp2 >(time);
break;
1657 case 0x31: executeLMMC<V9990Bpp4 >(time);
break;
1658 case 0x41: executeLMMC<V9990Bpp8 >(time);
break;
1659 case 0x51: executeLMMC<V9990Bpp16>(time);
break;
1661 case 0x02: executeLMMV<V9990P1 >(time);
break;
1662 case 0x12: executeLMMV<V9990P2 >(time);
break;
1663 case 0x22: executeLMMV<V9990Bpp2 >(time);
break;
1664 case 0x32: executeLMMV<V9990Bpp4 >(time);
break;
1665 case 0x42: executeLMMV<V9990Bpp8 >(time);
break;
1666 case 0x52: executeLMMV<V9990Bpp16>(time);
break;
1668 case 0x03: executeLMCM<V9990P1 >(time);
break;
1669 case 0x13: executeLMCM<V9990P2 >(time);
break;
1670 case 0x23: executeLMCM<V9990Bpp2 >(time);
break;
1671 case 0x33: executeLMCM<V9990Bpp4 >(time);
break;
1672 case 0x43: executeLMCM<V9990Bpp8 >(time);
break;
1673 case 0x53: executeLMCM<V9990Bpp16>(time);
break;
1675 case 0x04: executeLMMM<V9990P1 >(time);
break;
1676 case 0x14: executeLMMM<V9990P2 >(time);
break;
1677 case 0x24: executeLMMM<V9990Bpp2 >(time);
break;
1678 case 0x34: executeLMMM<V9990Bpp4 >(time);
break;
1679 case 0x44: executeLMMM<V9990Bpp8 >(time);
break;
1680 case 0x54: executeLMMM<V9990Bpp16>(time);
break;
1682 case 0x05: executeCMMC<V9990P1 >(time);
break;
1683 case 0x15: executeCMMC<V9990P2 >(time);
break;
1684 case 0x25: executeCMMC<V9990Bpp2 >(time);
break;
1685 case 0x35: executeCMMC<V9990Bpp4 >(time);
break;
1686 case 0x45: executeCMMC<V9990Bpp8 >(time);
break;
1687 case 0x55: executeCMMC<V9990Bpp16>(time);
break;
1689 case 0x06:
case 0x16:
case 0x26:
case 0x36:
case 0x46:
case 0x56:
1690 executeCMMK(time);
break;
1692 case 0x07: executeCMMM<V9990P1 >(time);
break;
1693 case 0x17: executeCMMM<V9990P2 >(time);
break;
1694 case 0x27: executeCMMM<V9990Bpp2 >(time);
break;
1695 case 0x37: executeCMMM<V9990Bpp4 >(time);
break;
1696 case 0x47: executeCMMM<V9990Bpp8 >(time);
break;
1697 case 0x57: executeCMMM<V9990Bpp16>(time);
break;
1699 case 0x08: executeBMXL<V9990P1 >(time);
break;
1700 case 0x18: executeBMXL<V9990P2 >(time);
break;
1701 case 0x28: executeBMXL<V9990Bpp2 >(time);
break;
1702 case 0x38: executeBMXL<V9990Bpp4 >(time);
break;
1703 case 0x48: executeBMXL<V9990Bpp8 >(time);
break;
1704 case 0x58: executeBMXL<V9990Bpp16>(time);
break;
1706 case 0x09: executeBMLX<V9990P1 >(time);
break;
1707 case 0x19: executeBMLX<V9990P2 >(time);
break;
1708 case 0x29: executeBMLX<V9990Bpp2 >(time);
break;
1709 case 0x39: executeBMLX<V9990Bpp4 >(time);
break;
1710 case 0x49: executeBMLX<V9990Bpp8 >(time);
break;
1711 case 0x59: executeBMLX<V9990Bpp16>(time);
break;
1713 case 0x0A: executeBMLL<V9990P1 >(time);
break;
1714 case 0x1A: executeBMLL<V9990P2 >(time);
break;
1715 case 0x2A: executeBMLL<V9990Bpp2 >(time);
break;
1716 case 0x3A: executeBMLL<V9990Bpp4 >(time);
break;
1717 case 0x4A: executeBMLL<V9990Bpp8 >(time);
break;
1718 case 0x5A: executeBMLL<V9990Bpp16>(time);
break;
1720 case 0x0B: executeLINE<V9990P1 >(time);
break;
1721 case 0x1B: executeLINE<V9990P2 >(time);
break;
1722 case 0x2B: executeLINE<V9990Bpp2 >(time);
break;
1723 case 0x3B: executeLINE<V9990Bpp4 >(time);
break;
1724 case 0x4B: executeLINE<V9990Bpp8 >(time);
break;
1725 case 0x5B: executeLINE<V9990Bpp16>(time);
break;
1727 case 0x0C: executeSRCH<V9990P1 >(time);
break;
1728 case 0x1C: executeSRCH<V9990P2 >(time);
break;
1729 case 0x2C: executeSRCH<V9990Bpp2 >(time);
break;
1730 case 0x3C: executeSRCH<V9990Bpp4 >(time);
break;
1731 case 0x4C: executeSRCH<V9990Bpp8 >(time);
break;
1732 case 0x5C: executeSRCH<V9990Bpp16>(time);
break;
1734 case 0x0D: executePOINT<V9990P1 >(time);
break;
1735 case 0x1D: executePOINT<V9990P2 >(time);
break;
1736 case 0x2D: executePOINT<V9990Bpp2 >(time);
break;
1737 case 0x3D: executePOINT<V9990Bpp4 >(time);
break;
1738 case 0x4D: executePOINT<V9990Bpp8 >(time);
break;
1739 case 0x5D: executePOINT<V9990Bpp16>(time);
break;
1741 case 0x0E:
case 0x1E:
case 0x2E:
case 0x3E:
case 0x4E:
case 0x5E:
1742 executePSET(time);
break;
1744 case 0x0F:
case 0x1F:
case 0x2F:
case 0x3F:
case 0x4F:
case 0x5F:
1745 executeADVN(time);
break;
1767 endAfterRead =
false;
1777 return (status &
TR) ? data : 0xFF;
1780void V9990CmdEngine::cmdReady(EmuTime::param )
1783 status &= ~(
CE |
TR);
1809 delta = getTiming(*
this, LMMV_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1812 delta = getTiming(*
this, LMMM_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1815 delta = getTiming(*
this, CMMM_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1818 delta = getTiming(*
this, BMXL_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1821 delta = getTiming(*
this, BMLX_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1830 delta = getTiming(*
this, BMLL_TIMING) * nbBytes;
1834 delta = getTiming(*
this, LINE_TIMING) * (NX - ANX);
1839 delta = getTiming(*
this, SRCH_TIMING);
1850 return engineTime + delta;
1855template<
typename Archive>
1859 if (ar.versionAtLeast(version, 2)) {
1860 ar.serialize(
"time", engineTime);
1867 ar.serialize(
"srcAddress", srcAddress,
1868 "dstAddress", dstAddress,
1889 "bitsLeft", bitsLeft,
1891 "endAfterRead", endAfterRead);
1893 if constexpr (Archive::IS_LOADER) {
static constexpr EmuDuration duration(unsigned ticks)
Calculates the duration of the given number of ticks at this clock's frequency.
constexpr uint64_t length() const
static constexpr EmuDuration zero()
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
CommandController & getCommandController() const
std::shared_ptr< T > getSharedStuff(std::string_view name, Args &&...args)
Some MSX device parts are shared between several MSX devices (e.g.
Class containing all settings for renderers.
EnumSetting< bool > & getCmdTimingSetting()
CmdTiming [real, broken].
void detach(Observer< T > &observer)
void attach(Observer< T > &observer)
void sync(EmuTime::param time)
Synchronizes the command engine with the V9990.
void serialize(Archive &ar, unsigned version)
byte peekCmdData(EmuTime::param time) const
read the command data byte (without side-effects)
void reset(EmuTime::param time)
Re-initialise the command engine's state.
void setCmdData(byte value, EmuTime::param time)
set the data byte
void setCmdReg(byte reg, byte val, EmuTime::param time)
Set a value to one of the command registers.
byte getCmdData(EmuTime::param time)
read the command data byte
V9990CmdEngine(V9990 &vdp, EmuTime::param time, RenderSettings &settings)
Constructor.
EmuTime estimateCmdEnd() const
Calculate an (under-)estimation for when the command will finish.
void sync2(EmuTime::param time)
static unsigned transformP2(unsigned address)
static unsigned transformBx(unsigned address)
static unsigned transformP1(unsigned address)
Implementation of the Yamaha V9990 VDP as used in the GFX9000 cartridge by Sunrise.
void cmdReady()
Command execution ready.
V9990DisplayMode getDisplayMode() const
Return the current display mode.
unsigned getImageWidth() const
Return the image width.
V9990ColorMode getColorMode() const
Return the current color mode.
This file implemented 3 utility functions:
uint8_t byte
8 bit unsigned integer
std::span< const A2, 4 > TimingTable
std::conditional_t<(MAX > detail::max32), EmuDuration, std::conditional_t<(MAX > detail::max16), EmuDuration32, std::conditional_t<(MAX > detail::max8), EmuDuration16, EmuDuration8 > > > EmuDurationStorageFor
uint16_t word
16 bit unsigned integer
EmuDurationStorageFor< d_(maxLength).length()> EDStorage
std::array< const EDStorage, 4 > A
std::array< const A, 3 > A2
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)