33 {{ d( 8), d(11), d(15), d(30)}, {d( 7), d(10), d(13), d(26)}, {d( 7), d(10), d(13), d(25)}},
34 {{ d( 5), d( 7), d( 9), d(18)}, {d( 5), d( 6), d( 8), d(17)}, {d( 5), d( 6), d( 8), d(17)}},
35 {{ d(56), d(56), d(56), d(56)}, {d(25), d(25), d(25), d(25)}, {d( 9), d( 9), d( 9), d( 9)}},
36 {{ d(28), d(28), d(28), d(28)}, {d(15), d(15), d(15), d(15)}, {d( 6), d( 6), d( 6), d( 6)}}
39 {{d (10),d (16),d( 32),d( 66)}, {d( 8), d(14), d(28), d(57)}, {d( 8), d(13), d(27), d(54)}},
40 {{d ( 6),d( 10),d( 20),d( 39)}, {d( 5), d( 9), d(18), d(35)}, {d( 5), d( 9), d(17), d(35)}},
41 {{d(115),d(115),d(115),d(115)}, {d(52), d(52), d(52), d(52)}, {d(18), d(18), d(18), d(18)}},
42 {{d( 57),d( 57),d( 57),d( 57)}, {d(25), d(25), d(25), d(25)}, {d( 9), d( 9), d( 9), d( 9)}}
45 {{d( 38),d( 33),d( 32),d( 33)}, {d(33), d(28), d(28), d(28)}, {d(33), d(27), d(27), d(27)}},
46 {{d( 24),d( 20),d( 20),d (19)}, {d(22), d(18), d(18), d(18)}, {d(21), d(17), d(17), d(17)}},
47 {{d(171),d(171),d(171),d(171)}, {d(82), d(82), d(82), d(82)}, {d(29), d(29), d(29), d(29)}},
48 {{d(114),d(114),d(114),d(114)}, {d(50), d(50), d(50), d(50)}, {d(18), d(18), d(18), d(18)}}
51 {{ d(10), d(16), d(32), d(66)}, {d( 8), d(14), d(28), d(57)}, {d( 8), d(13), d(27), d(54)}},
52 {{ d( 6), d(10), d(20), d(39)}, {d( 5), d( 9), d(18), d(35)}, {d( 5), d( 9), d(17), d(35)}},
53 {{ d(84), d(84), d(84), d(84)}, {d(44), d(44), d(44), d(44)}, {d(17), d(17), d(17), d(17)}},
54 {{ d(57), d(57), d(57), d(57)}, {d(25), d(25), d(25), d(25)}, {d( 9), d( 9), d( 9), d( 9)}}
57 {{d( 33),d( 33),d( 33),d( 33)}, {d(28), d(28), d(28), d(28)}, {d(27), d(27), d(27), d(27)}},
58 {{d( 20),d( 20),d( 20),d( 20)}, {d(18), d(18), d(18), d(18)}, {d(18), d(18), d(18), d(18)}},
59 {{d(118),d(118),d(118),d(118)}, {d(52), d(52), d(52), d(52)}, {d(18), d(18), d(18), d(18)}},
60 {{d(118),d(118),d(118),d(118)}, {d(52), d(52), d(52), d(52)}, {d(18), d(18), d(18), d(18)}}
63 {{ d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}},
64 {{ d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}},
65 {{ d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}},
66 {{ d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}}
69 {{ d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}},
70 {{ d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}},
71 {{ d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}},
72 {{ d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}}
75 {{ d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}},
76 {{ d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}},
77 {{ d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}},
78 {{ d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}, {d(24), d(24), d(24), d(24)}}
83 if (
unlikely(cmdEngine.getBrokenTiming()))
return EmuDuration();
85 const auto& vdp = cmdEngine.getVDP();
86 auto mode = vdp.getDisplayMode();
87 unsigned idx1 = (mode ==
P1) ? 2 :
89 (vdp.isOverScan()) ? 0 : 1;
90 unsigned idx2 = vdp.isDisplayEnabled() ? (vdp.spritesEnabled() ? 0 : 1)
92 unsigned idx3 = vdp.getColorDepth();
93 return table[idx1][idx2][idx3];
106 static MemBuffer<byte> logOpLUT[4][16];
109 static constexpr
auto bitLUT = [] {
110 std::array<std::array<std::array<std::array<byte, 2>, 2>, 16>, 8> result = {};
111 for (
auto op :
xrange(16)) {
113 for (
auto src :
xrange(2)) {
114 for (
auto dst :
xrange(2)) {
115 unsigned b = tmp & 1;
116 for (
auto bit :
xrange(8)) {
117 result[bit][op][src][dst] = b << bit;
128 [[nodiscard]]
static constexpr
byte func01(
unsigned op,
unsigned src,
unsigned dst)
130 if ((src & 0x03) == 0)
return dst & 0x03;
132 res |= bitLUT[0][op][(src & 0x01) >> 0][(dst & 0x01) >> 0];
133 res |= bitLUT[1][op][(src & 0x02) >> 1][(dst & 0x02) >> 1];
136 [[nodiscard]]
static constexpr
byte func23(
unsigned op,
unsigned src,
unsigned dst)
138 if ((src & 0x0C) == 0)
return dst & 0x0C;
140 res |= bitLUT[2][op][(src & 0x04) >> 2][(dst & 0x04) >> 2];
141 res |= bitLUT[3][op][(src & 0x08) >> 3][(dst & 0x08) >> 3];
144 [[nodiscard]]
static constexpr
byte func45(
unsigned op,
unsigned src,
unsigned dst)
146 if ((src & 0x30) == 0)
return dst & 0x30;
148 res |= bitLUT[4][op][(src & 0x10) >> 4][(dst & 0x10) >> 4];
149 res |= bitLUT[5][op][(src & 0x20) >> 5][(dst & 0x20) >> 5];
152 [[nodiscard]]
static constexpr
byte func67(
unsigned op,
unsigned src,
unsigned dst)
154 if ((src & 0xC0) == 0)
return dst & 0xC0;
156 res |= bitLUT[6][op][(src & 0x40) >> 6][(dst & 0x40) >> 6];
157 res |= bitLUT[7][op][(src & 0x80) >> 7][(dst & 0x80) >> 7];
161 [[nodiscard]]
static constexpr
byte func03(
unsigned op,
unsigned src,
unsigned dst)
163 if ((src & 0x0F) == 0)
return dst & 0x0F;
165 res |= bitLUT[0][op][(src & 0x01) >> 0][(dst & 0x01) >> 0];
166 res |= bitLUT[1][op][(src & 0x02) >> 1][(dst & 0x02) >> 1];
167 res |= bitLUT[2][op][(src & 0x04) >> 2][(dst & 0x04) >> 2];
168 res |= bitLUT[3][op][(src & 0x08) >> 3][(dst & 0x08) >> 3];
171 [[nodiscard]]
static constexpr
byte func47(
unsigned op,
unsigned src,
unsigned dst)
173 if ((src & 0xF0) == 0)
return dst & 0xF0;
175 res |= bitLUT[4][op][(src & 0x10) >> 4][(dst & 0x10) >> 4];
176 res |= bitLUT[5][op][(src & 0x20) >> 5][(dst & 0x20) >> 5];
177 res |= bitLUT[6][op][(src & 0x40) >> 6][(dst & 0x40) >> 6];
178 res |= bitLUT[7][op][(src & 0x80) >> 7][(dst & 0x80) >> 7];
182 [[nodiscard]]
static constexpr
byte func07(
unsigned op,
unsigned src,
unsigned dst)
186 res |= bitLUT[0][op][(src & 0x01) >> 0][(dst & 0x01) >> 0];
187 res |= bitLUT[1][op][(src & 0x02) >> 1][(dst & 0x02) >> 1];
188 res |= bitLUT[2][op][(src & 0x04) >> 2][(dst & 0x04) >> 2];
189 res |= bitLUT[3][op][(src & 0x08) >> 3][(dst & 0x08) >> 3];
190 res |= bitLUT[4][op][(src & 0x10) >> 4][(dst & 0x10) >> 4];
191 res |= bitLUT[5][op][(src & 0x20) >> 5][(dst & 0x20) >> 5];
192 res |= bitLUT[6][op][(src & 0x40) >> 6][(dst & 0x40) >> 6];
193 res |= bitLUT[7][op][(src & 0x80) >> 7][(dst & 0x80) >> 7];
197 static constexpr
void fillTableNoT(
unsigned op,
byte*
table)
199 for (
auto dst :
xrange(256)) {
200 for (
auto src :
xrange(256)) {
201 table[dst * 256 + src] = func07(op, src, dst);
206 static constexpr
void fillTable2(
unsigned op,
byte*
table)
208 for (
auto dst :
xrange(256)) {
209 for (
auto src :
xrange(256)) {
211 res |= func01(op, src, dst);
212 res |= func23(op, src, dst);
213 res |= func45(op, src, dst);
214 res |= func67(op, src, dst);
215 table[dst * 256 + src] = res;
220 static constexpr
void fillTable4(
unsigned op,
byte*
table)
222 for (
auto dst :
xrange(256)) {
223 for (
auto src :
xrange(256)) {
225 res |= func03(op, src, dst);
226 res |= func47(op, src, dst);
227 table[dst * 256 + src] = res;
232 static constexpr
void fillTable8(
unsigned op,
byte*
table)
234 for (
auto dst :
xrange(256)) {
236 table[dst * 256 + 0 ] = dst;
238 for (
auto src :
xrange(1, 256)) {
239 table[dst * 256 + src] = func07(op, src, dst);
244 [[nodiscard]]
static const byte* getLogOpImpl(
unsigned mode,
unsigned op)
247 if (!logOpLUT[mode][op].data()) {
248 logOpLUT[mode][op].
resize(256 * 256);
251 fillTableNoT(op, logOpLUT[mode][op].data());
254 fillTable2 (op, logOpLUT[mode][op].data());
257 fillTable4 (op, logOpLUT[mode][op].data());
260 fillTable8 (op, logOpLUT[mode][op].data());
266 return logOpLUT[mode][op].
data();
270 constexpr
byte DIY = 0x08;
271 constexpr
byte DIX = 0x04;
272 constexpr
byte NEQ = 0x02;
273 constexpr
byte MAJ = 0x01;
276 inline unsigned V9990CmdEngine::V9990P1::getPitch(
unsigned width)
281 inline unsigned V9990CmdEngine::V9990P1::addressOf(
282 unsigned x,
unsigned y,
unsigned pitch)
287 return (addr & 0x3FFFF) | ((
x & 0x200) << 9);
290 inline byte V9990CmdEngine::V9990P1::point(
291 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
293 return vram.readVRAMDirect(addressOf(
x, y, pitch));
296 inline byte V9990CmdEngine::V9990P1::shift(
297 byte value,
unsigned fromX,
unsigned toX)
299 int shift = 4 * ((toX & 1) - (fromX & 1));
300 return (shift > 0) ? (value >> shift) : (value << -shift);
303 inline byte V9990CmdEngine::V9990P1::shiftMask(
unsigned x)
305 return (
x & 1) ? 0x0F : 0xF0;
308 inline const byte* V9990CmdEngine::V9990P1::getLogOpLUT(
byte op)
313 inline byte V9990CmdEngine::V9990P1::logOp(
314 const byte* lut,
byte src,
byte dst)
316 return lut[256 * dst + src];
319 inline void V9990CmdEngine::V9990P1::pset(
320 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
321 byte srcColor,
word mask,
const byte* lut,
byte )
323 unsigned addr = addressOf(
x, y, pitch);
324 byte dstColor = vram.readVRAMDirect(addr);
325 byte newColor = logOp(lut, srcColor, dstColor);
326 byte mask1 = (addr & 0x40000) ? (
mask >> 8) : (
mask & 0xFF);
327 byte mask2 = mask1 & shiftMask(
x);
328 byte result = (dstColor & ~mask2) | (newColor & mask2);
329 vram.writeVRAMDirect(addr, result);
331 inline void V9990CmdEngine::V9990P1::psetColor(
332 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
335 unsigned addr = addressOf(
x, y, pitch);
336 byte srcColor = (addr & 0x40000) ? (color >> 8) : (color & 0xFF);
337 byte dstColor = vram.readVRAMDirect(addr);
338 byte newColor = logOp(lut, srcColor, dstColor);
339 byte mask1 = (addr & 0x40000) ? (
mask >> 8) : (
mask & 0xFF);
340 byte mask2 = mask1 & (0xF0 >> (4 * (
x & 1)));
341 byte result = (dstColor & ~mask2) | (newColor & mask2);
342 vram.writeVRAMDirect(addr, result);
346 inline unsigned V9990CmdEngine::V9990P2::getPitch(
unsigned width)
351 inline unsigned V9990CmdEngine::V9990P2::addressOf(
352 unsigned x,
unsigned y,
unsigned pitch)
358 inline byte V9990CmdEngine::V9990P2::point(
359 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
361 return vram.readVRAMDirect(addressOf(
x, y, pitch));
364 inline byte V9990CmdEngine::V9990P2::shift(
365 byte value,
unsigned fromX,
unsigned toX)
367 int shift = 4 * ((toX & 1) - (fromX & 1));
368 return (shift > 0) ? (value >> shift) : (value << -shift);
371 inline byte V9990CmdEngine::V9990P2::shiftMask(
unsigned x)
373 return (
x & 1) ? 0x0F : 0xF0;
376 inline const byte* V9990CmdEngine::V9990P2::getLogOpLUT(
byte op)
381 inline byte V9990CmdEngine::V9990P2::logOp(
382 const byte* lut,
byte src,
byte dst)
384 return lut[256 * dst + src];
387 inline void V9990CmdEngine::V9990P2::pset(
388 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
389 byte srcColor,
word mask,
const byte* lut,
byte )
391 unsigned addr = addressOf(
x, y, pitch);
392 byte dstColor = vram.readVRAMDirect(addr);
393 byte newColor = logOp(lut, srcColor, dstColor);
394 byte mask1 = (addr & 0x40000) ? (
mask >> 8) : (
mask & 0xFF);
395 byte mask2 = mask1 & shiftMask(
x);
396 byte result = (dstColor & ~mask2) | (newColor & mask2);
397 vram.writeVRAMDirect(addr, result);
400 inline void V9990CmdEngine::V9990P2::psetColor(
401 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
404 unsigned addr = addressOf(
x, y, pitch);
405 byte srcColor = (addr & 0x40000) ? (color >> 8) : (color & 0xFF);
406 byte dstColor = vram.readVRAMDirect(addr);
407 byte newColor = logOp(lut, srcColor, dstColor);
408 byte mask1 = (addr & 0x40000) ? (
mask >> 8) : (
mask & 0xFF);
409 byte mask2 = mask1 & (0xF0 >> (4 * (
x & 1)));
410 byte result = (dstColor & ~mask2) | (newColor & mask2);
411 vram.writeVRAMDirect(addr, result);
415 inline unsigned V9990CmdEngine::V9990Bpp2::getPitch(
unsigned width)
420 inline unsigned V9990CmdEngine::V9990Bpp2::addressOf(
421 unsigned x,
unsigned y,
unsigned pitch)
426 inline byte V9990CmdEngine::V9990Bpp2::point(
427 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
429 return vram.readVRAMDirect(addressOf(
x, y, pitch));
432 inline byte V9990CmdEngine::V9990Bpp2::shift(
433 byte value,
unsigned fromX,
unsigned toX)
435 int shift = 2 * ((toX & 3) - (fromX & 3));
436 return (shift > 0) ? (value >> shift) : (value << -shift);
439 inline byte V9990CmdEngine::V9990Bpp2::shiftMask(
unsigned x)
441 return 0xC0 >> (2 * (
x & 3));
444 inline const byte* V9990CmdEngine::V9990Bpp2::getLogOpLUT(
byte op)
449 inline byte V9990CmdEngine::V9990Bpp2::logOp(
450 const byte* lut,
byte src,
byte dst)
452 return lut[256 * dst + src];
455 inline void V9990CmdEngine::V9990Bpp2::pset(
456 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
457 byte srcColor,
word mask,
const byte* lut,
byte )
459 unsigned addr = addressOf(
x, y, pitch);
460 byte dstColor = vram.readVRAMDirect(addr);
461 byte newColor = logOp(lut, srcColor, dstColor);
462 byte mask1 = (addr & 0x40000) ? (
mask >> 8) : (
mask & 0xFF);
463 byte mask2 = mask1 & shiftMask(
x);
464 byte result = (dstColor & ~mask2) | (newColor & mask2);
465 vram.writeVRAMDirect(addr, result);
468 inline void V9990CmdEngine::V9990Bpp2::psetColor(
469 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
472 unsigned addr = addressOf(
x, y, pitch);
473 byte srcColor = (addr & 0x40000) ? (color >> 8) : (color & 0xFF);
474 byte dstColor = vram.readVRAMDirect(addr);
475 byte newColor = logOp(lut, srcColor, dstColor);
476 byte mask1 = (addr & 0x40000) ? (
mask >> 8) : (
mask & 0xFF);
477 byte mask2 = mask1 & (0xC0 >> (2 * (
x & 3)));
478 byte result = (dstColor & ~mask2) | (newColor & mask2);
479 vram.writeVRAMDirect(addr, result);
483 inline unsigned V9990CmdEngine::V9990Bpp4::getPitch(
unsigned width)
488 inline unsigned V9990CmdEngine::V9990Bpp4::addressOf(
489 unsigned x,
unsigned y,
unsigned pitch)
494 inline byte V9990CmdEngine::V9990Bpp4::point(
495 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
497 return vram.readVRAMDirect(addressOf(
x, y, pitch));
500 inline byte V9990CmdEngine::V9990Bpp4::shift(
501 byte value,
unsigned fromX,
unsigned toX)
503 int shift = 4 * ((toX & 1) - (fromX & 1));
504 return (shift > 0) ? (value >> shift) : (value << -shift);
507 inline byte V9990CmdEngine::V9990Bpp4::shiftMask(
unsigned x)
509 return (
x & 1) ? 0x0F : 0xF0;
512 inline const byte* V9990CmdEngine::V9990Bpp4::getLogOpLUT(
byte op)
517 inline byte V9990CmdEngine::V9990Bpp4::logOp(
518 const byte* lut,
byte src,
byte dst)
520 return lut[256 * dst + src];
523 inline void V9990CmdEngine::V9990Bpp4::pset(
524 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
525 byte srcColor,
word mask,
const byte* lut,
byte )
527 unsigned addr = addressOf(
x, y, pitch);
528 byte dstColor = vram.readVRAMDirect(addr);
529 byte newColor = logOp(lut, srcColor, dstColor);
530 byte mask1 = (addr & 0x40000) ? (
mask >> 8) : (
mask & 0xFF);
531 byte mask2 = mask1 & shiftMask(
x);
532 byte result = (dstColor & ~mask2) | (newColor & mask2);
533 vram.writeVRAMDirect(addr, result);
536 inline void V9990CmdEngine::V9990Bpp4::psetColor(
537 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
540 unsigned addr = addressOf(
x, y, pitch);
541 byte srcColor = (addr & 0x40000) ? (color >> 8) : (color & 0xFF);
542 byte dstColor = vram.readVRAMDirect(addr);
543 byte newColor = logOp(lut, srcColor, dstColor);
544 byte mask1 = (addr & 0x40000) ? (
mask >> 8) : (
mask & 0xFF);
545 byte mask2 = mask1 & (0xF0 >> (4 * (
x & 1)));
546 byte result = (dstColor & ~mask2) | (newColor & mask2);
547 vram.writeVRAMDirect(addr, result);
551 inline unsigned V9990CmdEngine::V9990Bpp8::getPitch(
unsigned width)
556 inline unsigned V9990CmdEngine::V9990Bpp8::addressOf(
557 unsigned x,
unsigned y,
unsigned pitch)
562 inline byte V9990CmdEngine::V9990Bpp8::point(
563 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
565 return vram.readVRAMDirect(addressOf(
x, y, pitch));
568 inline byte V9990CmdEngine::V9990Bpp8::shift(
569 byte value,
unsigned ,
unsigned )
574 inline byte V9990CmdEngine::V9990Bpp8::shiftMask(
unsigned )
579 inline const byte* V9990CmdEngine::V9990Bpp8::getLogOpLUT(
byte op)
584 inline byte V9990CmdEngine::V9990Bpp8::logOp(
585 const byte* lut,
byte src,
byte dst)
587 return lut[256 * dst + src];
590 inline void V9990CmdEngine::V9990Bpp8::pset(
591 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
592 byte srcColor,
word mask,
const byte* lut,
byte )
594 unsigned addr = addressOf(
x, y, pitch);
595 byte dstColor = vram.readVRAMDirect(addr);
596 byte newColor = logOp(lut, srcColor, dstColor);
597 byte mask1 = (addr & 0x40000) ? (
mask >> 8) : (
mask & 0xFF);
598 byte result = (dstColor & ~mask1) | (newColor & mask1);
599 vram.writeVRAMDirect(addr, result);
602 inline void V9990CmdEngine::V9990Bpp8::psetColor(
603 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
606 unsigned addr = addressOf(
x, y, pitch);
607 byte srcColor = (addr & 0x40000) ? (color >> 8) : (color & 0xFF);
608 byte dstColor = vram.readVRAMDirect(addr);
609 byte newColor = logOp(lut, srcColor, dstColor);
610 byte mask1 = (addr & 0x40000) ? (
mask >> 8) : (
mask & 0xFF);
611 byte result = (dstColor & ~mask1) | (newColor & mask1);
612 vram.writeVRAMDirect(addr, result);
616 inline unsigned V9990CmdEngine::V9990Bpp16::getPitch(
unsigned width)
622 inline unsigned V9990CmdEngine::V9990Bpp16::addressOf(
623 unsigned x,
unsigned y,
unsigned pitch)
626 return ((
x & (pitch - 1)) + y * pitch) & 0x3FFFF;
629 inline word V9990CmdEngine::V9990Bpp16::point(
630 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
632 unsigned addr = addressOf(
x, y, pitch);
633 return vram.readVRAMDirect(addr + 0x00000) +
634 vram.readVRAMDirect(addr + 0x40000) * 256;
637 inline word V9990CmdEngine::V9990Bpp16::shift(
638 word value,
unsigned ,
unsigned )
643 inline word V9990CmdEngine::V9990Bpp16::shiftMask(
unsigned )
648 inline const byte* V9990CmdEngine::V9990Bpp16::getLogOpLUT(
byte op)
653 inline word V9990CmdEngine::V9990Bpp16::logOp(
654 const byte* lut,
word src,
word dst,
bool transp)
656 if (transp && (src == 0))
return dst;
657 return (lut[((dst & 0x00FF) << 8) + ((src & 0x00FF) >> 0)] << 0) +
658 (lut[((dst & 0xFF00) << 0) + ((src & 0xFF00) >> 8)] << 8);
661 inline void V9990CmdEngine::V9990Bpp16::pset(
662 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
665 unsigned addr = addressOf(
x, y, pitch);
666 word dstColor = vram.readVRAMDirect(addr + 0x00000) +
667 vram.readVRAMDirect(addr + 0x40000) * 256;
668 word newColor = logOp(lut, srcColor, dstColor, (op & 0x10) != 0);
670 vram.writeVRAMDirect(addr + 0x00000, result & 0xFF);
671 vram.writeVRAMDirect(addr + 0x40000, result >> 8);
674 inline void V9990CmdEngine::V9990Bpp16::psetColor(
675 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
678 unsigned addr = addressOf(
x, y, pitch);
679 word dstColor = vram.readVRAMDirect(addr + 0x00000) +
680 vram.readVRAMDirect(addr + 0x40000) * 256;
681 word newColor = logOp(lut, srcColor, dstColor, (op & 0x10) != 0);
683 vram.writeVRAMDirect(addr + 0x00000, result & 0xFF);
684 vram.writeVRAMDirect(addr + 0x40000, result >> 8);
692 : settings(settings_), vdp(vdp_), vram(vdp.getVRAM()), engineTime(time_)
697 "V9990 command tracing on/off",
false);
700 update(cmdTimingSetting);
701 cmdTimingSetting.
attach(*
this);
706 srcAddress = dstAddress = nbBytes = 0;
707 ASX = ADX = ANX = ANY = 0;
708 SX = SY = DX = DY = NX = NY = 0;
709 WM = fgCol = bgCol = 0;
711 data = bitsLeft = partial = 0;
724 endAfterRead =
false;
732 SX = (SX & 0x0700) | value;
735 SX = (SX & 0x00FF) | ((value & 0x07) << 8);
738 SY = (SY & 0x0F00) | value;
741 SY = (SY & 0x00FF) | ((value & 0x0F) << 8);
744 DX = (DX & 0x0700) | value;
747 DX = (DX & 0x00FF) | ((value & 0x07) << 8);
750 DY = (DY & 0x0F00) | value;
753 DY = (DY & 0x00FF) | ((value & 0x0F) << 8);
756 NX = (NX & 0x0F00) | value;
759 NX = (NX & 0x00FF) | ((value & 0x0F) << 8);
762 NY = (NY & 0x0F00) | value;
765 NY = (NY & 0x00FF) | ((value & 0x0F) << 8);
774 WM = (WM & 0xFF00) | value;
777 WM = (WM & 0x00FF) | (value << 8);
780 fgCol = (fgCol & 0xFF00) | value;
783 fgCol = (fgCol & 0x00FF) | (value << 8);
786 bgCol = (bgCol & 0xFF00) | value;
789 bgCol = (bgCol & 0x00FF) | (value << 8);
793 if (cmdTraceSetting->getBoolean()) {
794 reportV9990Command();
802 switch (cmdMode | (CMD >> 4)) {
803 case 0x00:
case 0x10:
case 0x20:
case 0x30:
case 0x40:
case 0x50:
804 startSTOP(time);
break;
806 case 0x01:
case 0x11:
case 0x21:
case 0x31:
case 0x41:
807 startLMMC (time);
break;
809 startLMMC16(time);
break;
811 case 0x02:
case 0x12:
case 0x22:
case 0x32:
case 0x42:
case 0x52:
812 startLMMV(time);
break;
814 case 0x03:
case 0x13:
case 0x23:
case 0x33:
case 0x43:
815 startLMCM (time);
break;
817 startLMCM16(time);
break;
819 case 0x04:
case 0x14:
case 0x24:
case 0x34:
case 0x44:
case 0x54:
820 startLMMM(time);
break;
822 case 0x05:
case 0x15:
case 0x25:
case 0x35:
case 0x45:
case 0x55:
823 startCMMC(time);
break;
825 case 0x06:
case 0x16:
case 0x26:
case 0x36:
case 0x46:
case 0x56:
826 startCMMK(time);
break;
828 case 0x07:
case 0x17:
case 0x27:
case 0x37:
case 0x47:
case 0x57:
829 startCMMM(time);
break;
831 case 0x08:
case 0x18:
case 0x28:
case 0x38:
case 0x48:
case 0x58:
832 startBMXL(time);
break;
834 case 0x09:
case 0x19:
case 0x29:
case 0x39:
case 0x49:
case 0x59:
835 startBMLX(time);
break;
837 case 0x0A:
case 0x1A:
case 0x2A:
case 0x3A:
case 0x4A:
838 startBMLL (time);
break;
840 startBMLL16(time);
break;
842 case 0x0B:
case 0x1B:
case 0x2B:
case 0x3B:
case 0x4B:
case 0x5B:
843 startLINE(time);
break;
845 case 0x0C:
case 0x1C:
case 0x2C:
case 0x3C:
case 0x4C:
case 0x5C:
846 startSRCH(time);
break;
848 case 0x0D: startPOINT<V9990P1 >(time);
break;
849 case 0x1D: startPOINT<V9990P2 >(time);
break;
850 case 0x2D: startPOINT<V9990Bpp2 >(time);
break;
851 case 0x3D: startPOINT<V9990Bpp4 >(time);
break;
852 case 0x4D: startPOINT<V9990Bpp8 >(time);
break;
853 case 0x5D: startPOINT<V9990Bpp16>(time);
break;
855 case 0x0E: startPSET<V9990P1 >(time);
break;
856 case 0x1E: startPSET<V9990P2 >(time);
break;
857 case 0x2E: startPSET<V9990Bpp2 >(time);
break;
858 case 0x3E: startPSET<V9990Bpp4 >(time);
break;
859 case 0x4E: startPSET<V9990Bpp8 >(time);
break;
860 case 0x5E: startPSET<V9990Bpp16>(time);
break;
862 case 0x0F:
case 0x1F:
case 0x2F:
case 0x3F:
case 0x4F:
case 0x5F:
863 startADVN(time);
break;
877 void V9990CmdEngine::setCommandMode()
880 if (dispMode ==
P1) {
882 }
else if (dispMode ==
P2) {
910 void V9990CmdEngine::reportV9990Command()
const
912 const char*
const COMMANDS[16] = {
913 "STOP",
"LMMC",
"LMMV",
"LMCM",
914 "LMMM",
"CMMC",
"CMMK",
"CMMM",
915 "BMXL",
"BMLX",
"BMLL",
"LINE",
916 "SRCH",
"POINT",
"PSET",
"ADVN"
918 std::cerr <<
"V9990Cmd " << COMMANDS[CMD >> 4]
919 <<
" SX=" << std::dec << SX
920 <<
" SY=" << std::dec << SY
921 <<
" DX=" << std::dec << DX
922 <<
" DY=" << std::dec << DY
923 <<
" NX=" << std::dec << NX
924 <<
" NY=" << std::dec << NY
925 <<
" ARG=" << std::hex << int(ARG)
926 <<
" LOG=" << std::hex << int(LOG)
927 <<
" WM=" << std::hex << WM
928 <<
" FC=" << std::hex << fgCol
929 <<
" BC=" << std::hex << bgCol
930 <<
" CMD=" << std::hex << int(CMD)
934 void V9990CmdEngine::update(
const Setting& setting) noexcept
936 brokenTiming =
static_cast<const EnumSetting<bool>&
>(setting).getEnum();
940 void V9990CmdEngine::startSTOP(EmuTime::param time)
945 void V9990CmdEngine::executeSTOP(EmuTime::param )
951 void V9990CmdEngine::startLMMC(EmuTime::param )
953 ANX = getWrappedNX();
954 ANY = getWrappedNY();
957 void V9990CmdEngine::startLMMC16(EmuTime::param time)
964 void V9990CmdEngine::executeLMMC<V9990CmdEngine::V9990Bpp16>(EmuTime::param limit)
966 if (!(status & TR)) {
973 word value = (data << 8) | partial;
974 unsigned pitch = V9990Bpp16::getPitch(vdp.getImageWidth());
975 const byte* lut = V9990Bpp16::getLogOpLUT(LOG);
976 V9990Bpp16::pset(vram, DX, DY, pitch, value, WM, lut, LOG);
977 int dx = (ARG &
DIX) ? -1 : 1;
980 int dy = (ARG &
DIY) ? -1 : 1;
986 ANX = getWrappedNX();
993 template<
typename Mode>
994 void V9990CmdEngine::executeLMMC(EmuTime::param limit)
996 if (!(status &
TR)) {
999 const byte* lut = Mode::getLogOpLUT(LOG);
1000 for (
int i = 0; (ANY > 0) && (i < Mode::PIXELS_PER_BYTE); ++i) {
1001 byte d = Mode::shift(data, i, DX);
1002 Mode::pset(vram, DX, DY, pitch, d, WM, lut, LOG);
1004 int dx = (ARG &
DIX) ? -1 : 1;
1007 int dy = (ARG &
DIY) ? -1 : 1;
1021 void V9990CmdEngine::startLMMV(EmuTime::param time)
1024 ANX = getWrappedNX();
1025 ANY = getWrappedNY();
1028 template<
typename Mode>
1029 void V9990CmdEngine::executeLMMV(EmuTime::param limit)
1035 int dx = (ARG &
DIX) ? -1 : 1;
1036 int dy = (ARG &
DIY) ? -1 : 1;
1037 const byte* lut = Mode::getLogOpLUT(LOG);
1038 while (engineTime < limit) {
1039 engineTime += delta;
1040 Mode::psetColor(vram, DX, DY, pitch, fgCol, WM, lut, LOG);
1047 cmdReady(engineTime);
1050 ANX = getWrappedNX();
1057 void V9990CmdEngine::startLMCM(EmuTime::param )
1059 ANX = getWrappedNX();
1060 ANY = getWrappedNY();
1062 endAfterRead =
false;
1064 void V9990CmdEngine::startLMCM16(EmuTime::param time)
1070 template<
typename Mode>
1071 void V9990CmdEngine::executeLMCM(EmuTime::param )
1073 if (!(status &
TR)) {
1075 if ((Mode::BITS_PER_PIXEL == 16) && bitsLeft) {
1081 typename Mode::Type d = 0;
1082 for (
int i = 0; (ANY > 0) && (i < Mode::PIXELS_PER_BYTE); ++i) {
1083 auto src = Mode::point(vram, SX, SY, pitch);
1084 d |= Mode::shift(src, SX, i) & Mode::shiftMask(i);
1086 int dx = (ARG &
DIX) ? -1 : 1;
1089 int dy = (ARG &
DIY) ? -1 : 1;
1093 endAfterRead =
true;
1095 ANX = getWrappedNX();
1099 if (Mode::BITS_PER_PIXEL == 16) {
1113 void V9990CmdEngine::startLMMM(EmuTime::param time)
1116 ANX = getWrappedNX();
1117 ANY = getWrappedNY();
1120 template<
typename Mode>
1121 void V9990CmdEngine::executeLMMM(EmuTime::param limit)
1127 int dx = (ARG &
DIX) ? -1 : 1;
1128 int dy = (ARG &
DIY) ? -1 : 1;
1129 const byte* lut = Mode::getLogOpLUT(LOG);
1130 while (engineTime < limit) {
1131 engineTime += delta;
1132 auto src = Mode::point(vram, SX, SY, pitch);
1133 src = Mode::shift(src, SX, DX);
1134 Mode::pset(vram, DX, DY, pitch, src, WM, lut, LOG);
1144 cmdReady(engineTime);
1147 ANX = getWrappedNX();
1154 void V9990CmdEngine::startCMMC(EmuTime::param )
1156 ANX = getWrappedNX();
1157 ANY = getWrappedNY();
1161 template<
typename Mode>
1162 void V9990CmdEngine::executeCMMC(EmuTime::param limit)
1164 if (!(status &
TR)) {
1168 int dx = (ARG &
DIX) ? -1 : 1;
1169 int dy = (ARG &
DIY) ? -1 : 1;
1170 const byte* lut = Mode::getLogOpLUT(LOG);
1171 for (
auto i :
xrange(8)) {
1173 bool bit = (data & 0x80) != 0;
1176 word src = bit ? fgCol : bgCol;
1177 Mode::psetColor(vram, DX, DY, pitch, src, WM, lut, LOG);
1187 ANX = getWrappedNX();
1195 void V9990CmdEngine::startCMMK(EmuTime::param time)
1197 std::cout <<
"V9990: CMMK not yet implemented\n";
1201 void V9990CmdEngine::executeCMMK(EmuTime::param )
1207 void V9990CmdEngine::startCMMM(EmuTime::param time)
1210 srcAddress = (SX & 0xFF) + ((SY & 0x7FF) << 8);
1211 ANX = getWrappedNX();
1212 ANY = getWrappedNY();
1216 template<
typename Mode>
1217 void V9990CmdEngine::executeCMMM(EmuTime::param limit)
1223 int dx = (ARG &
DIX) ? -1 : 1;
1224 int dy = (ARG &
DIY) ? -1 : 1;
1225 const byte* lut = Mode::getLogOpLUT(LOG);
1226 while (engineTime < limit) {
1227 engineTime += delta;
1229 data = vram.readVRAMBx(srcAddress++);
1233 bool bit = (data & 0x80) != 0;
1236 word color = bit ? fgCol : bgCol;
1237 Mode::psetColor(vram, DX, DY, pitch, color, WM, lut, LOG);
1244 cmdReady(engineTime);
1247 ANX = getWrappedNX();
1254 void V9990CmdEngine::startBMXL(EmuTime::param time)
1257 srcAddress = (SX & 0xFF) + ((SY & 0x7FF) << 8);
1258 ANX = getWrappedNX();
1259 ANY = getWrappedNY();
1263 void V9990CmdEngine::executeBMXL<V9990CmdEngine::V9990Bpp16>(EmuTime::param limit)
1267 unsigned pitch = V9990Bpp16::getPitch(vdp.getImageWidth());
1268 int dx = (ARG &
DIX) ? -1 : 1;
1269 int dy = (ARG &
DIY) ? -1 : 1;
1270 const byte* lut = V9990Bpp16::getLogOpLUT(LOG);
1272 while (engineTime < limit) {
1273 engineTime += delta;
1274 word src = vram.readVRAMBx(srcAddress + 0) +
1275 vram.readVRAMBx(srcAddress + 1) * 256;
1277 V9990Bpp16::pset(vram, DX, DY, pitch, src, WM, lut, LOG);
1283 cmdReady(engineTime);
1286 ANX = getWrappedNX();
1292 template<
typename Mode>
1293 void V9990CmdEngine::executeBMXL(EmuTime::param limit)
1297 int dx = (ARG &
DIX) ? -1 : 1;
1298 int dy = (ARG &
DIY) ? -1 : 1;
1299 const byte* lut = Mode::getLogOpLUT(LOG);
1301 while (engineTime < limit) {
1302 engineTime += delta;
1303 byte d = vram.readVRAMBx(srcAddress++);
1304 for (
int i = 0; (ANY > 0) && (i < Mode::PIXELS_PER_BYTE); ++i) {
1305 Mode::pset(vram, DX, DY, pitch, d, WM, lut, LOG);
1311 cmdReady(engineTime);
1314 ANX = getWrappedNX();
1322 void V9990CmdEngine::startBMLX(EmuTime::param time)
1325 dstAddress = (DX & 0xFF) + ((DY & 0x7FF) << 8);
1326 ANX = getWrappedNX();
1327 ANY = getWrappedNY();
1331 void V9990CmdEngine::executeBMLX<V9990CmdEngine::V9990Bpp16>(EmuTime::param limit)
1335 unsigned pitch = V9990Bpp16::getPitch(vdp.getImageWidth());
1336 int dx = (ARG &
DIX) ? -1 : 1;
1337 int dy = (ARG &
DIY) ? -1 : 1;
1339 while (engineTime < limit) {
1340 engineTime += delta;
1341 auto src = V9990Bpp16::point(vram, SX, SY, pitch);
1342 vram.writeVRAMBx(dstAddress++, src & 0xFF);
1343 vram.writeVRAMBx(dstAddress++, src >> 8);
1349 cmdReady(engineTime);
1352 ANX = getWrappedNX();
1357 template<
typename Mode>
1358 void V9990CmdEngine::executeBMLX(EmuTime::param limit)
1363 int dx = (ARG &
DIX) ? -1 : 1;
1364 int dy = (ARG &
DIY) ? -1 : 1;
1366 while (engineTime < limit) {
1367 engineTime += delta;
1369 for (
auto i :
xrange(Mode::PIXELS_PER_BYTE)) {
1370 auto src = Mode::point(vram, SX, SY, pitch);
1371 d |= Mode::shift(src, SX, i) & Mode::shiftMask(i);
1377 vram.writeVRAMBx(dstAddress++, d);
1378 cmdReady(engineTime);
1381 ANX = getWrappedNX();
1385 vram.writeVRAMBx(dstAddress++, d);
1390 void V9990CmdEngine::startBMLL(EmuTime::param time)
1393 srcAddress = (SX & 0xFF) + ((SY & 0x7FF) << 8);
1394 dstAddress = (DX & 0xFF) + ((DY & 0x7FF) << 8);
1395 nbBytes = (NX & 0xFF) + ((NY & 0x7FF) << 8);
1400 void V9990CmdEngine::startBMLL16(EmuTime::param time)
1411 void V9990CmdEngine::executeBMLL<V9990CmdEngine::V9990Bpp16>(EmuTime::param limit)
1416 const byte* lut = V9990Bpp16::getLogOpLUT(LOG);
1417 bool transp = (LOG & 0x10) != 0;
1418 while (engineTime < limit) {
1419 engineTime += delta;
1421 word srcColor = vram.readVRAMDirect(srcAddress + 0x00000) +
1422 vram.readVRAMDirect(srcAddress + 0x40000) * 256;
1423 word dstColor = vram.readVRAMDirect(dstAddress + 0x00000) +
1424 vram.readVRAMDirect(dstAddress + 0x40000) * 256;
1425 word newColor = V9990Bpp16::logOp(lut, srcColor, dstColor, transp);
1426 word result = (dstColor & ~WM) | (newColor & WM);
1427 vram.writeVRAMDirect(dstAddress + 0x00000, result & 0xFF);
1428 vram.writeVRAMDirect(dstAddress + 0x40000, result >> 8);
1429 srcAddress = (srcAddress + 1) & 0x3FFFF;
1430 dstAddress = (dstAddress + 1) & 0x3FFFF;
1432 cmdReady(engineTime);
1438 template<
typename Mode>
1439 void V9990CmdEngine::executeBMLL(EmuTime::param limit)
1443 const byte* lut = Mode::getLogOpLUT(LOG);
1444 while (engineTime < limit) {
1445 engineTime += delta;
1447 byte srcColor = vram.readVRAMBx(srcAddress);
1449 byte dstColor = vram.readVRAMDirect(addr);
1450 byte newColor = Mode::logOp(lut, srcColor, dstColor);
1451 byte mask = (addr & 0x40000) ? (WM >> 8) : (WM & 0xFF);
1452 byte result = (dstColor & ~
mask) | (newColor &
mask);
1453 vram.writeVRAMDirect(addr, result);
1454 srcAddress = (srcAddress + 1) & 0x7FFFF;
1455 dstAddress = (dstAddress + 1) & 0x7FFFF;
1457 cmdReady(engineTime);
1464 void V9990CmdEngine::startLINE(EmuTime::param time)
1472 template<
typename Mode>
1473 void V9990CmdEngine::executeLINE(EmuTime::param limit)
1477 unsigned pitch = Mode::getPitch(width);
1479 int TX = (ARG &
DIX) ? -1 : 1;
1480 int TY = (ARG &
DIY) ? -1 : 1;
1481 const byte* lut = Mode::getLogOpLUT(LOG);
1483 if ((ARG &
MAJ) == 0) {
1485 while (engineTime < limit) {
1486 engineTime += delta;
1487 Mode::psetColor(vram, ADX, DY, pitch, fgCol, WM, lut, LOG);
1496 if (ANX++ == NX || (ADX & width)) {
1497 cmdReady(engineTime);
1503 while (engineTime < limit) {
1504 engineTime += delta;
1505 Mode::psetColor(vram, ADX, DY, pitch, fgCol, WM, lut, LOG);
1513 if (ANX++ == NX || (ADX & width)) {
1514 cmdReady(engineTime);
1522 void V9990CmdEngine::startSRCH(EmuTime::param time)
1528 template<
typename Mode>
1529 void V9990CmdEngine::executeSRCH(EmuTime::param limit)
1533 unsigned pitch = Mode::getPitch(width);
1534 typename Mode::Type
mask = (1 << Mode::BITS_PER_PIXEL) -1;
1536 int TX = (ARG &
DIX) ? -1 : 1;
1537 bool AEQ = (ARG &
NEQ) != 0;
1539 while (engineTime < limit) {
1540 engineTime += delta;
1541 typename Mode::Type value;
1542 typename Mode::Type col;
1543 typename Mode::Type mask2;
1544 if (Mode::BITS_PER_PIXEL == 16) {
1545 value = Mode::point(vram, ASX, SY, pitch);
1546 col =
static_cast<typename Mode::Type
>(fgCol);
1547 mask2 =
static_cast<typename Mode::Type
>(~0);
1550 unsigned addr = Mode::addressOf(ASX, SY, pitch);
1551 value = vram.readVRAMDirect(addr);
1552 col = (addr & 0x40000) ? (fgCol >> 8) : (fgCol & 0xFF);
1553 mask2 = Mode::shift(
mask, 3, ASX);
1555 if (((value & mask2) == (col & mask2)) ^ AEQ) {
1557 cmdReady(engineTime);
1561 if ((ASX += TX) & width) {
1563 cmdReady(engineTime);
1571 template<
typename Mode>
1572 void V9990CmdEngine::startPOINT(EmuTime::param )
1575 auto d = Mode::point(vram, SX, SY, pitch);
1577 if (Mode::BITS_PER_PIXEL != 16) {
1579 endAfterRead =
true;
1586 endAfterRead =
false;
1591 template<
typename Mode>
1592 void V9990CmdEngine::executePOINT(EmuTime::param )
1594 if (status &
TR)
return;
1596 assert(Mode::BITS_PER_PIXEL == 16);
1599 endAfterRead =
true;
1603 template<
typename Mode>
1604 void V9990CmdEngine::startPSET(EmuTime::param time)
1607 const byte* lut = Mode::getLogOpLUT(LOG);
1608 Mode::psetColor(vram, DX, DY, pitch, fgCol, WM, lut, LOG);
1615 void V9990CmdEngine::executePSET(EmuTime::param )
1621 void V9990CmdEngine::startADVN(EmuTime::param time)
1623 std::cout <<
"V9990: ADVN not yet implemented\n";
1627 void V9990CmdEngine::executeADVN(EmuTime::param )
1637 switch (cmdMode | (CMD >> 4)) {
1638 case 0x00:
case 0x10:
case 0x20:
case 0x30:
case 0x40:
case 0x50:
1639 executeSTOP(time);
break;
1641 case 0x01: executeLMMC<V9990P1 >(time);
break;
1642 case 0x11: executeLMMC<V9990P2 >(time);
break;
1643 case 0x21: executeLMMC<V9990Bpp2 >(time);
break;
1644 case 0x31: executeLMMC<V9990Bpp4 >(time);
break;
1645 case 0x41: executeLMMC<V9990Bpp8 >(time);
break;
1646 case 0x51: executeLMMC<V9990Bpp16>(time);
break;
1648 case 0x02: executeLMMV<V9990P1 >(time);
break;
1649 case 0x12: executeLMMV<V9990P2 >(time);
break;
1650 case 0x22: executeLMMV<V9990Bpp2 >(time);
break;
1651 case 0x32: executeLMMV<V9990Bpp4 >(time);
break;
1652 case 0x42: executeLMMV<V9990Bpp8 >(time);
break;
1653 case 0x52: executeLMMV<V9990Bpp16>(time);
break;
1655 case 0x03: executeLMCM<V9990P1 >(time);
break;
1656 case 0x13: executeLMCM<V9990P2 >(time);
break;
1657 case 0x23: executeLMCM<V9990Bpp2 >(time);
break;
1658 case 0x33: executeLMCM<V9990Bpp4 >(time);
break;
1659 case 0x43: executeLMCM<V9990Bpp8 >(time);
break;
1660 case 0x53: executeLMCM<V9990Bpp16>(time);
break;
1662 case 0x04: executeLMMM<V9990P1 >(time);
break;
1663 case 0x14: executeLMMM<V9990P2 >(time);
break;
1664 case 0x24: executeLMMM<V9990Bpp2 >(time);
break;
1665 case 0x34: executeLMMM<V9990Bpp4 >(time);
break;
1666 case 0x44: executeLMMM<V9990Bpp8 >(time);
break;
1667 case 0x54: executeLMMM<V9990Bpp16>(time);
break;
1669 case 0x05: executeCMMC<V9990P1 >(time);
break;
1670 case 0x15: executeCMMC<V9990P2 >(time);
break;
1671 case 0x25: executeCMMC<V9990Bpp2 >(time);
break;
1672 case 0x35: executeCMMC<V9990Bpp4 >(time);
break;
1673 case 0x45: executeCMMC<V9990Bpp8 >(time);
break;
1674 case 0x55: executeCMMC<V9990Bpp16>(time);
break;
1676 case 0x06:
case 0x16:
case 0x26:
case 0x36:
case 0x46:
case 0x56:
1677 executeCMMK(time);
break;
1679 case 0x07: executeCMMM<V9990P1 >(time);
break;
1680 case 0x17: executeCMMM<V9990P2 >(time);
break;
1681 case 0x27: executeCMMM<V9990Bpp2 >(time);
break;
1682 case 0x37: executeCMMM<V9990Bpp4 >(time);
break;
1683 case 0x47: executeCMMM<V9990Bpp8 >(time);
break;
1684 case 0x57: executeCMMM<V9990Bpp16>(time);
break;
1686 case 0x08: executeBMXL<V9990P1 >(time);
break;
1687 case 0x18: executeBMXL<V9990P2 >(time);
break;
1688 case 0x28: executeBMXL<V9990Bpp2 >(time);
break;
1689 case 0x38: executeBMXL<V9990Bpp4 >(time);
break;
1690 case 0x48: executeBMXL<V9990Bpp8 >(time);
break;
1691 case 0x58: executeBMXL<V9990Bpp16>(time);
break;
1693 case 0x09: executeBMLX<V9990P1 >(time);
break;
1694 case 0x19: executeBMLX<V9990P2 >(time);
break;
1695 case 0x29: executeBMLX<V9990Bpp2 >(time);
break;
1696 case 0x39: executeBMLX<V9990Bpp4 >(time);
break;
1697 case 0x49: executeBMLX<V9990Bpp8 >(time);
break;
1698 case 0x59: executeBMLX<V9990Bpp16>(time);
break;
1700 case 0x0A: executeBMLL<V9990P1 >(time);
break;
1701 case 0x1A: executeBMLL<V9990P2 >(time);
break;
1702 case 0x2A: executeBMLL<V9990Bpp2 >(time);
break;
1703 case 0x3A: executeBMLL<V9990Bpp4 >(time);
break;
1704 case 0x4A: executeBMLL<V9990Bpp8 >(time);
break;
1705 case 0x5A: executeBMLL<V9990Bpp16>(time);
break;
1707 case 0x0B: executeLINE<V9990P1 >(time);
break;
1708 case 0x1B: executeLINE<V9990P2 >(time);
break;
1709 case 0x2B: executeLINE<V9990Bpp2 >(time);
break;
1710 case 0x3B: executeLINE<V9990Bpp4 >(time);
break;
1711 case 0x4B: executeLINE<V9990Bpp8 >(time);
break;
1712 case 0x5B: executeLINE<V9990Bpp16>(time);
break;
1714 case 0x0C: executeSRCH<V9990P1 >(time);
break;
1715 case 0x1C: executeSRCH<V9990P2 >(time);
break;
1716 case 0x2C: executeSRCH<V9990Bpp2 >(time);
break;
1717 case 0x3C: executeSRCH<V9990Bpp4 >(time);
break;
1718 case 0x4C: executeSRCH<V9990Bpp8 >(time);
break;
1719 case 0x5C: executeSRCH<V9990Bpp16>(time);
break;
1721 case 0x0D: executePOINT<V9990P1 >(time);
break;
1722 case 0x1D: executePOINT<V9990P2 >(time);
break;
1723 case 0x2D: executePOINT<V9990Bpp2 >(time);
break;
1724 case 0x3D: executePOINT<V9990Bpp4 >(time);
break;
1725 case 0x4D: executePOINT<V9990Bpp8 >(time);
break;
1726 case 0x5D: executePOINT<V9990Bpp16>(time);
break;
1728 case 0x0E:
case 0x1E:
case 0x2E:
case 0x3E:
case 0x4E:
case 0x5E:
1729 executePSET(time);
break;
1731 case 0x0F:
case 0x1F:
case 0x2F:
case 0x3F:
case 0x4F:
case 0x5F:
1732 executeADVN(time);
break;
1754 endAfterRead =
false;
1764 return (status &
TR) ? data : 0xFF;
1767 void V9990CmdEngine::cmdReady(EmuTime::param )
1770 status &= ~(
CE |
TR);
1796 delta = getTiming(*
this,
LMMV_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1799 delta = getTiming(*
this,
LMMM_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1802 delta = getTiming(*
this,
CMMM_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1805 delta = getTiming(*
this,
BMXL_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1808 delta = getTiming(*
this,
BMLX_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1821 delta = getTiming(*
this,
LINE_TIMING) * (NX - ANX);
1837 return engineTime + delta;
1842 template<
typename Archive>
1846 if (ar.versionAtLeast(version, 2)) {
1847 ar.serialize(
"time", engineTime);
1854 ar.serialize(
"srcAddress", srcAddress,
1855 "dstAddress", dstAddress,
1876 "bitsLeft", bitsLeft,
1878 "endAfterRead", endAfterRead);
1880 if (ar.isLoader()) {
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.
const T * data() const
Returns pointer to the start of the memory buffer.
void resize(size_t size)
Grow or shrink the memory block.
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)
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
byte peekCmdData(EmuTime::param time)
read the command data byte (without side-effects)
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
constexpr EDStorage CMMM_TIMING[4][3][4]
constexpr EDStorage LINE_TIMING[4][3][4]
constexpr EDStorage BMLX_TIMING[4][3][4]
constexpr unsigned maxLength
constexpr EDStorage LMMV_TIMING[4][3][4]
constexpr EDStorage SRCH_TIMING[4][3][4]
std::conditional_t<(MAX > detail::max32), EmuDuration, std::conditional_t<(MAX > detail::max16), EmuDuration32, std::conditional_t<(MAX > detail::max8), EmuDuration16, EmuDuration8 > >> EmuDurationStorageFor
EmuDurationStorageFor< d(maxLength).length()> EDStorage
constexpr EDStorage BMXL_TIMING[4][3][4]
uint16_t word
16 bit unsigned integer
constexpr KeyMatrixPosition x
Keyboard bindings.
constexpr EDStorage BMLL_TIMING[4][3][4]
constexpr nibble mask[4][13]
constexpr EDStorage LMMM_TIMING[4][3][4]
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)