27static constexpr unsigned maxLength = 171;
28static constexpr EmuDuration d_(
unsigned x)
30 assert(x <= maxLength);
35using A = std::array<const EDStorage, 4>;
36using A2 = std::array<const A, 3>;
43static constexpr std::array LMMV_TIMING = {
44 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)}},
45 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)}},
46 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)}},
47 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)}}
49static constexpr std::array LMMM_TIMING = {
50 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)}},
51 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)}},
52 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)}},
53 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)}}
55static constexpr std::array BMXL_TIMING = {
56 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)}},
57 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)}},
58 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)}},
59 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)}}
61static constexpr std::array BMLX_TIMING = {
62 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)}},
63 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)}},
64 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)}},
65 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)}}
67static constexpr std::array BMLL_TIMING = {
68 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)}},
69 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)}},
70 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)}},
71 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)}}
73static constexpr std::array CMMM_TIMING = {
74 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)}},
75 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)}},
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)}}
79static constexpr std::array LINE_TIMING = {
80 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)}},
81 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)}},
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)}}
85static constexpr std::array SRCH_TIMING = {
86 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)}},
87 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)}},
88 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)}},
89 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)}}
92[[nodiscard]]
static EmuDuration getTiming(
const V9990CmdEngine& cmdEngine,
TimingTable table)
94 if (cmdEngine.getBrokenTiming()) [[unlikely]]
return {};
96 const auto& vdp = cmdEngine.getVDP();
97 auto mode = vdp.getDisplayMode();
100 (vdp.isOverScan()) ? 0 : 1;
101 unsigned idx2 = vdp.isDisplayEnabled() ? (vdp.spritesEnabled() ? 0 : 1)
103 unsigned idx3 = vdp.getColorDepth();
104 return EmuDuration(table[idx1][idx2][idx3]);
124static constexpr auto bitLUT = [] {
125 std::array<std::array<std::array<std::array<byte, 2>, 2>, 16>, 8> result = {};
126 for (
auto op :
xrange(16)) {
128 for (
auto src :
xrange(2)) {
129 for (
auto dst :
xrange(2)) {
130 unsigned b = tmp & 1;
131 for (
auto bit :
xrange(8)) {
132 result[bit][op][src][dst] = narrow<byte>(b << bit);
141[[nodiscard]]
static constexpr byte func01(
unsigned op,
unsigned src,
unsigned dst)
143 if ((src & 0x03) == 0)
return dst & 0x03;
145 res |= bitLUT[0][op][(src & 0x01) >> 0][(dst & 0x01) >> 0];
146 res |= bitLUT[1][op][(src & 0x02) >> 1][(dst & 0x02) >> 1];
149[[nodiscard]]
static constexpr byte func23(
unsigned op,
unsigned src,
unsigned dst)
151 if ((src & 0x0C) == 0)
return dst & 0x0C;
153 res |= bitLUT[2][op][(src & 0x04) >> 2][(dst & 0x04) >> 2];
154 res |= bitLUT[3][op][(src & 0x08) >> 3][(dst & 0x08) >> 3];
157[[nodiscard]]
static constexpr byte func45(
unsigned op,
unsigned src,
unsigned dst)
159 if ((src & 0x30) == 0)
return dst & 0x30;
161 res |= bitLUT[4][op][(src & 0x10) >> 4][(dst & 0x10) >> 4];
162 res |= bitLUT[5][op][(src & 0x20) >> 5][(dst & 0x20) >> 5];
165[[nodiscard]]
static constexpr byte func67(
unsigned op,
unsigned src,
unsigned dst)
167 if ((src & 0xC0) == 0)
return dst & 0xC0;
169 res |= bitLUT[6][op][(src & 0x40) >> 6][(dst & 0x40) >> 6];
170 res |= bitLUT[7][op][(src & 0x80) >> 7][(dst & 0x80) >> 7];
174[[nodiscard]]
static constexpr byte func03(
unsigned op,
unsigned src,
unsigned dst)
176 if ((src & 0x0F) == 0)
return dst & 0x0F;
178 res |= bitLUT[0][op][(src & 0x01) >> 0][(dst & 0x01) >> 0];
179 res |= bitLUT[1][op][(src & 0x02) >> 1][(dst & 0x02) >> 1];
180 res |= bitLUT[2][op][(src & 0x04) >> 2][(dst & 0x04) >> 2];
181 res |= bitLUT[3][op][(src & 0x08) >> 3][(dst & 0x08) >> 3];
184[[nodiscard]]
static constexpr byte func47(
unsigned op,
unsigned src,
unsigned dst)
186 if ((src & 0xF0) == 0)
return dst & 0xF0;
188 res |= bitLUT[4][op][(src & 0x10) >> 4][(dst & 0x10) >> 4];
189 res |= bitLUT[5][op][(src & 0x20) >> 5][(dst & 0x20) >> 5];
190 res |= bitLUT[6][op][(src & 0x40) >> 6][(dst & 0x40) >> 6];
191 res |= bitLUT[7][op][(src & 0x80) >> 7][(dst & 0x80) >> 7];
195[[nodiscard]]
static constexpr byte func07(
unsigned op,
unsigned src,
unsigned dst)
199 res |= bitLUT[0][op][(src & 0x01) >> 0][(dst & 0x01) >> 0];
200 res |= bitLUT[1][op][(src & 0x02) >> 1][(dst & 0x02) >> 1];
201 res |= bitLUT[2][op][(src & 0x04) >> 2][(dst & 0x04) >> 2];
202 res |= bitLUT[3][op][(src & 0x08) >> 3][(dst & 0x08) >> 3];
203 res |= bitLUT[4][op][(src & 0x10) >> 4][(dst & 0x10) >> 4];
204 res |= bitLUT[5][op][(src & 0x20) >> 5][(dst & 0x20) >> 5];
205 res |= bitLUT[6][op][(src & 0x40) >> 6][(dst & 0x40) >> 6];
206 res |= bitLUT[7][op][(src & 0x80) >> 7][(dst & 0x80) >> 7];
210static constexpr void fillTableNoT(
unsigned op, std::span<byte, 256 * 256> table)
212 for (
auto dst :
xrange(256)) {
213 for (
auto src :
xrange(256)) {
214 table[dst * 256 + src] = func07(op, src, dst);
219static constexpr void fillTable2(
unsigned op, std::span<byte, 256 * 256> table)
221 for (
auto dst :
xrange(256)) {
222 for (
auto src :
xrange(256)) {
224 res |= func01(op, src, dst);
225 res |= func23(op, src, dst);
226 res |= func45(op, src, dst);
227 res |= func67(op, src, dst);
228 table[dst * 256 + src] = res;
233static constexpr void fillTable4(
unsigned op, std::span<byte, 256 * 256> table)
235 for (
auto dst :
xrange(256)) {
236 for (
auto src :
xrange(256)) {
238 res |= func03(op, src, dst);
239 res |= func47(op, src, dst);
240 table[dst * 256 + src] = res;
245static constexpr void fillTable8(
unsigned op, std::span<byte, 256 * 256> table)
247 for (
auto dst :
xrange(256)) {
249 table[dst * 256 + 0 ] = narrow_cast<byte>(dst);
251 for (
auto src :
xrange(1, 256)) {
252 table[dst * 256 + src] = func07(op, src, dst);
257[[nodiscard]]
static std::span<const byte, 256 * 256> getLogOpImpl(
Log mode,
unsigned op)
260 auto& lut = logOpLUT[mode][op];
262 lut.resize(256 * 256);
263 std::span<byte, 256 * 256> s{lut};
282 return std::span<byte, 256 * 256>{lut};
286static constexpr byte DIY = 0x08;
287static constexpr byte DIX = 0x04;
288static constexpr byte NEQ = 0x02;
289static constexpr byte MAJ = 0x01;
292inline unsigned V9990CmdEngine::V9990P1::getPitch(
unsigned width)
297inline unsigned V9990CmdEngine::V9990P1::addressOf(
298 unsigned x,
unsigned y,
unsigned pitch)
303 return (addr & 0x3FFFF) | ((x & 0x200) << 9);
306inline byte V9990CmdEngine::V9990P1::point(
307 const V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
309 return vram.readVRAMDirect(addressOf(x, y, pitch));
312inline byte V9990CmdEngine::V9990P1::shift(
313 byte value,
unsigned fromX,
unsigned toX)
315 int shift = 4 * (narrow<int>(toX & 1) - narrow<int>(fromX & 1));
316 return (shift > 0) ?
byte(value >> shift) :
byte(value << -shift);
319inline byte V9990CmdEngine::V9990P1::shiftMask(
unsigned x)
321 return (x & 1) ? 0x0F : 0xF0;
324inline std::span<const byte, 256 * 256> V9990CmdEngine::V9990P1::getLogOpLUT(
byte op)
329inline byte V9990CmdEngine::V9990P1::logOp(
330 std::span<const byte, 256 * 256> lut,
byte src,
byte dst)
332 return lut[256 * dst + src];
335inline void V9990CmdEngine::V9990P1::pset(
336 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
337 byte srcColor,
word mask, std::span<const byte, 256 * 256> lut,
byte )
339 unsigned addr = addressOf(x, y, pitch);
340 byte dstColor = vram.readVRAMDirect(addr);
341 byte newColor = logOp(lut, srcColor, dstColor);
342 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
343 byte mask2 = mask1 & shiftMask(x);
344 byte result = (dstColor & ~mask2) | (newColor & mask2);
345 vram.writeVRAMDirect(addr, result);
347inline void V9990CmdEngine::V9990P1::psetColor(
348 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
349 word color,
word mask, std::span<const byte, 256 * 256> lut,
byte )
351 unsigned addr = addressOf(x, y, pitch);
352 byte srcColor = narrow_cast<byte>((addr & 0x40000) ? (color >> 8) : (color & 0xFF));
353 byte dstColor = vram.readVRAMDirect(addr);
354 byte newColor = logOp(lut, srcColor, dstColor);
355 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
356 byte mask2 = mask1 & (0xF0 >> (4 * (x & 1)));
357 byte result = (dstColor & ~mask2) | (newColor & mask2);
358 vram.writeVRAMDirect(addr, result);
362inline unsigned V9990CmdEngine::V9990P2::getPitch(
unsigned width)
367inline unsigned V9990CmdEngine::V9990P2::addressOf(
368 unsigned x,
unsigned y,
unsigned pitch)
374inline byte V9990CmdEngine::V9990P2::point(
375 const V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
377 return vram.readVRAMDirect(addressOf(x, y, pitch));
380inline byte V9990CmdEngine::V9990P2::shift(
381 byte value,
unsigned fromX,
unsigned toX)
383 int shift = 4 * (narrow<int>(toX & 1) - narrow<int>(fromX & 1));
384 return (shift > 0) ?
byte(value >> shift) :
byte(value << -shift);
387inline byte V9990CmdEngine::V9990P2::shiftMask(
unsigned x)
389 return (x & 1) ? 0x0F : 0xF0;
392inline std::span<const byte, 256 * 256> V9990CmdEngine::V9990P2::getLogOpLUT(
byte op)
397inline byte V9990CmdEngine::V9990P2::logOp(
398 std::span<const byte, 256 * 256> lut,
byte src,
byte dst)
400 return lut[256 * dst + src];
403inline void V9990CmdEngine::V9990P2::pset(
404 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
405 byte srcColor,
word mask, std::span<const byte, 256 * 256> lut,
byte )
407 unsigned addr = addressOf(x, y, pitch);
408 byte dstColor = vram.readVRAMDirect(addr);
409 byte newColor = logOp(lut, srcColor, dstColor);
410 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
411 byte mask2 = mask1 & shiftMask(x);
412 byte result = (dstColor & ~mask2) | (newColor & mask2);
413 vram.writeVRAMDirect(addr, result);
416inline void V9990CmdEngine::V9990P2::psetColor(
417 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
418 word color,
word mask, std::span<const byte, 256 * 256> lut,
byte )
420 unsigned addr = addressOf(x, y, pitch);
421 byte srcColor = narrow_cast<byte>((addr & 0x40000) ? (color >> 8) : (color & 0xFF));
422 byte dstColor = vram.readVRAMDirect(addr);
423 byte newColor = logOp(lut, srcColor, dstColor);
424 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
425 byte mask2 = mask1 & (0xF0 >> (4 * (x & 1)));
426 byte result = (dstColor & ~mask2) | (newColor & mask2);
427 vram.writeVRAMDirect(addr, result);
431inline unsigned V9990CmdEngine::V9990Bpp2::getPitch(
unsigned width)
436inline unsigned V9990CmdEngine::V9990Bpp2::addressOf(
437 unsigned x,
unsigned y,
unsigned pitch)
442inline byte V9990CmdEngine::V9990Bpp2::point(
443 const V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
445 return vram.readVRAMDirect(addressOf(x, y, pitch));
448inline byte V9990CmdEngine::V9990Bpp2::shift(
449 byte value,
unsigned fromX,
unsigned toX)
451 int shift = 2 * (narrow<int>(toX & 3) - narrow<int>(fromX & 3));
452 return (shift > 0) ?
byte(value >> shift) :
byte(value << -shift);
455inline byte V9990CmdEngine::V9990Bpp2::shiftMask(
unsigned x)
457 return 0xC0 >> (2 * (x & 3));
460inline std::span<const byte, 256 * 256> V9990CmdEngine::V9990Bpp2::getLogOpLUT(
byte op)
465inline byte V9990CmdEngine::V9990Bpp2::logOp(
466 std::span<const byte, 256 * 256> lut,
byte src,
byte dst)
468 return lut[256 * dst + src];
471inline void V9990CmdEngine::V9990Bpp2::pset(
472 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
473 byte srcColor,
word mask, std::span<const byte, 256 * 256> lut,
byte )
475 unsigned addr = addressOf(x, y, pitch);
476 byte dstColor = vram.readVRAMDirect(addr);
477 byte newColor = logOp(lut, srcColor, dstColor);
478 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
479 byte mask2 = mask1 & shiftMask(x);
480 byte result = (dstColor & ~mask2) | (newColor & mask2);
481 vram.writeVRAMDirect(addr, result);
484inline void V9990CmdEngine::V9990Bpp2::psetColor(
485 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
486 word color,
word mask, std::span<const byte, 256 * 256> lut,
byte )
488 unsigned addr = addressOf(x, y, pitch);
489 byte srcColor = narrow_cast<byte>((addr & 0x40000) ? (color >> 8) : (color & 0xFF));
490 byte dstColor = vram.readVRAMDirect(addr);
491 byte newColor = logOp(lut, srcColor, dstColor);
492 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
493 byte mask2 = mask1 & (0xC0 >> (2 * (x & 3)));
494 byte result = (dstColor & ~mask2) | (newColor & mask2);
495 vram.writeVRAMDirect(addr, result);
499inline unsigned V9990CmdEngine::V9990Bpp4::getPitch(
unsigned width)
504inline unsigned V9990CmdEngine::V9990Bpp4::addressOf(
505 unsigned x,
unsigned y,
unsigned pitch)
510inline byte V9990CmdEngine::V9990Bpp4::point(
511 const V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
513 return vram.readVRAMDirect(addressOf(x, y, pitch));
516inline byte V9990CmdEngine::V9990Bpp4::shift(
517 byte value,
unsigned fromX,
unsigned toX)
519 int shift = 4 * (narrow<int>(toX & 1) - narrow<int>(fromX & 1));
520 return (shift > 0) ?
byte(value >> shift) :
byte(value << -shift);
523inline byte V9990CmdEngine::V9990Bpp4::shiftMask(
unsigned x)
525 return (x & 1) ? 0x0F : 0xF0;
528inline std::span<const byte, 256 * 256> V9990CmdEngine::V9990Bpp4::getLogOpLUT(
byte op)
533inline byte V9990CmdEngine::V9990Bpp4::logOp(
534 std::span<const byte, 256 * 256> lut,
byte src,
byte dst)
536 return lut[256 * dst + src];
539inline void V9990CmdEngine::V9990Bpp4::pset(
540 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
541 byte srcColor,
word mask, std::span<const byte, 256 * 256> lut,
byte )
543 unsigned addr = addressOf(x, y, pitch);
544 byte dstColor = vram.readVRAMDirect(addr);
545 byte newColor = logOp(lut, srcColor, dstColor);
546 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
547 byte mask2 = mask1 & shiftMask(x);
548 byte result = (dstColor & ~mask2) | (newColor & mask2);
549 vram.writeVRAMDirect(addr, result);
552inline void V9990CmdEngine::V9990Bpp4::psetColor(
553 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
554 word color,
word mask, std::span<const byte, 256 * 256> lut,
byte )
556 unsigned addr = addressOf(x, y, pitch);
557 byte srcColor = narrow_cast<byte>((addr & 0x40000) ? (color >> 8) : (color & 0xFF));
558 byte dstColor = vram.readVRAMDirect(addr);
559 byte newColor = logOp(lut, srcColor, dstColor);
560 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
561 byte mask2 = mask1 & (0xF0 >> (4 * (x & 1)));
562 byte result = (dstColor & ~mask2) | (newColor & mask2);
563 vram.writeVRAMDirect(addr, result);
567inline unsigned V9990CmdEngine::V9990Bpp8::getPitch(
unsigned width)
572inline unsigned V9990CmdEngine::V9990Bpp8::addressOf(
573 unsigned x,
unsigned y,
unsigned pitch)
578inline byte V9990CmdEngine::V9990Bpp8::point(
579 const V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
581 return vram.readVRAMDirect(addressOf(x, y, pitch));
584inline byte V9990CmdEngine::V9990Bpp8::shift(
585 byte value,
unsigned ,
unsigned )
590inline byte V9990CmdEngine::V9990Bpp8::shiftMask(
unsigned )
595inline std::span<const byte, 256 * 256> V9990CmdEngine::V9990Bpp8::getLogOpLUT(
byte op)
600inline byte V9990CmdEngine::V9990Bpp8::logOp(
601 std::span<const byte, 256 * 256> lut,
byte src,
byte dst)
603 return lut[256 * dst + src];
606inline void V9990CmdEngine::V9990Bpp8::pset(
607 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
608 byte srcColor,
word mask, std::span<const byte, 256 * 256> lut,
byte )
610 unsigned addr = addressOf(x, y, pitch);
611 byte dstColor = vram.readVRAMDirect(addr);
612 byte newColor = logOp(lut, srcColor, dstColor);
613 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
614 byte result = (dstColor & ~mask1) | (newColor & mask1);
615 vram.writeVRAMDirect(addr, result);
618inline void V9990CmdEngine::V9990Bpp8::psetColor(
619 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
620 word color,
word mask, std::span<const byte, 256 * 256> lut,
byte )
622 unsigned addr = addressOf(x, y, pitch);
623 byte srcColor = narrow_cast<byte>((addr & 0x40000) ? (color >> 8) : (color & 0xFF));
624 byte dstColor = vram.readVRAMDirect(addr);
625 byte newColor = logOp(lut, srcColor, dstColor);
626 byte mask1 = narrow_cast<byte>((addr & 0x40000) ? (mask >> 8) : (mask & 0xFF));
627 byte result = (dstColor & ~mask1) | (newColor & mask1);
628 vram.writeVRAMDirect(addr, result);
632inline unsigned V9990CmdEngine::V9990Bpp16::getPitch(
unsigned width)
638inline unsigned V9990CmdEngine::V9990Bpp16::addressOf(
639 unsigned x,
unsigned y,
unsigned pitch)
642 return ((x & (pitch - 1)) + y * pitch) & 0x3FFFF;
645inline word V9990CmdEngine::V9990Bpp16::point(
646 const V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch)
648 unsigned addr = addressOf(x, y, pitch);
649 return word(vram.readVRAMDirect(addr + 0x00000) +
650 vram.readVRAMDirect(addr + 0x40000) * 256);
653inline word V9990CmdEngine::V9990Bpp16::shift(
654 word value,
unsigned ,
unsigned )
659inline word V9990CmdEngine::V9990Bpp16::shiftMask(
unsigned )
664inline std::span<const byte, 256 * 256> V9990CmdEngine::V9990Bpp16::getLogOpLUT(
byte op)
669inline word V9990CmdEngine::V9990Bpp16::logOp(
670 std::span<const byte, 256 * 256> lut,
word src,
word dst,
bool transp)
672 if (transp && (src == 0))
return dst;
673 return word((lut[((dst & 0x00FF) << 8) + ((src & 0x00FF) >> 0)] << 0) +
674 (lut[((dst & 0xFF00) << 0) + ((src & 0xFF00) >> 8)] << 8));
677inline void V9990CmdEngine::V9990Bpp16::pset(
678 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
679 word srcColor,
word mask, std::span<const byte, 256 * 256> lut,
byte op)
681 unsigned addr = addressOf(x, y, pitch);
682 auto dstColor =
word(vram.readVRAMDirect(addr + 0x00000) +
683 vram.readVRAMDirect(addr + 0x40000) * 256);
684 word newColor = logOp(lut, srcColor, dstColor, (op & 0x10) != 0);
685 word result = (dstColor & ~mask) | (newColor & mask);
686 vram.writeVRAMDirect(addr + 0x00000, narrow_cast<byte>(result & 0xFF));
687 vram.writeVRAMDirect(addr + 0x40000, narrow_cast<byte>(result >> 8));
690inline void V9990CmdEngine::V9990Bpp16::psetColor(
691 V9990VRAM& vram,
unsigned x,
unsigned y,
unsigned pitch,
692 word srcColor,
word mask, std::span<const byte, 256 * 256> lut,
byte op)
694 unsigned addr = addressOf(x, y, pitch);
695 auto dstColor =
word(vram.readVRAMDirect(addr + 0x00000) +
696 vram.readVRAMDirect(addr + 0x40000) * 256);
697 word newColor = logOp(lut, srcColor, dstColor, (op & 0x10) != 0);
698 word result = (dstColor & ~mask) | (newColor & mask);
699 vram.writeVRAMDirect(addr + 0x00000, narrow_cast<byte>(result & 0xFF));
700 vram.writeVRAMDirect(addr + 0x40000, narrow_cast<byte>(result >> 8));
708 : settings(settings_), vdp(vdp_), vram(vdp.getVRAM()), engineTime(time_)
713 "V9990 command tracing on/off",
false);
716 update(cmdTimingSetting);
717 cmdTimingSetting.
attach(*
this);
722 srcAddress = dstAddress = nbBytes = 0;
723 ASX = ADX = ANX = ANY = 0;
724 SX = SY = DX = DY = NX = NY = 0;
725 WM = fgCol = bgCol = 0;
727 data = bitsLeft = partial = 0;
740 endAfterRead =
false;
748 SX =
word((SX & 0x0700) | ((value & 0xFF) << 0));
751 SX =
word((SX & 0x00FF) | ((value & 0x07) << 8));
754 SY =
word((SY & 0x0F00) | ((value & 0xFF) << 0));
757 SY =
word((SY & 0x00FF) | ((value & 0x0F) << 8));
760 DX =
word((DX & 0x0700) | ((value & 0xFF) << 0));
763 DX =
word((DX & 0x00FF) | ((value & 0x07) << 8));
766 DY =
word((DY & 0x0F00) | ((value & 0xFF) << 0));
769 DY =
word((DY & 0x00FF) | ((value & 0x0F) << 8));
772 NX =
word((NX & 0x0F00) | ((value & 0xFF) << 0));
775 NX =
word((NX & 0x00FF) | ((value & 0x0F) << 8));
778 NY =
word((NY & 0x0F00) | ((value & 0xFF) << 0));
781 NY =
word((NY & 0x00FF) | ((value & 0x0F) << 8));
790 WM =
word((WM & 0xFF00) | (value << 0));
793 WM =
word((WM & 0x00FF) | (value << 8));
796 fgCol =
word((fgCol & 0xFF00) | (value << 0));
799 fgCol =
word((fgCol & 0x00FF) | (value << 8));
802 bgCol =
word((bgCol & 0xFF00) | (value << 0));
805 bgCol =
word((bgCol & 0x00FF) | (value << 8));
809 if (cmdTraceSetting->getBoolean()) {
810 reportV9990Command();
818 switch (cmdMode | (CMD >> 4)) {
819 case 0x00:
case 0x10:
case 0x20:
case 0x30:
case 0x40:
case 0x50:
820 startSTOP(time);
break;
822 case 0x01:
case 0x11:
case 0x21:
case 0x31:
case 0x41:
823 startLMMC (time);
break;
825 startLMMC16(time);
break;
827 case 0x02:
case 0x12:
case 0x22:
case 0x32:
case 0x42:
case 0x52:
828 startLMMV(time);
break;
830 case 0x03:
case 0x13:
case 0x23:
case 0x33:
case 0x43:
831 startLMCM (time);
break;
833 startLMCM16(time);
break;
835 case 0x04:
case 0x14:
case 0x24:
case 0x34:
case 0x44:
case 0x54:
836 startLMMM(time);
break;
838 case 0x05:
case 0x15:
case 0x25:
case 0x35:
case 0x45:
case 0x55:
839 startCMMC(time);
break;
841 case 0x06:
case 0x16:
case 0x26:
case 0x36:
case 0x46:
case 0x56:
842 startCMMK(time);
break;
844 case 0x07:
case 0x17:
case 0x27:
case 0x37:
case 0x47:
case 0x57:
845 startCMMM(time);
break;
847 case 0x08:
case 0x18:
case 0x28:
case 0x38:
case 0x48:
case 0x58:
848 startBMXL(time);
break;
850 case 0x09:
case 0x19:
case 0x29:
case 0x39:
case 0x49:
case 0x59:
851 startBMLX(time);
break;
853 case 0x0A:
case 0x1A:
case 0x2A:
case 0x3A:
case 0x4A:
854 startBMLL (time);
break;
856 startBMLL16(time);
break;
858 case 0x0B:
case 0x1B:
case 0x2B:
case 0x3B:
case 0x4B:
case 0x5B:
859 startLINE(time);
break;
861 case 0x0C:
case 0x1C:
case 0x2C:
case 0x3C:
case 0x4C:
case 0x5C:
862 startSRCH(time);
break;
864 case 0x0D: startPOINT<V9990P1 >(time);
break;
865 case 0x1D: startPOINT<V9990P2 >(time);
break;
866 case 0x2D: startPOINT<V9990Bpp2 >(time);
break;
867 case 0x3D: startPOINT<V9990Bpp4 >(time);
break;
868 case 0x4D: startPOINT<V9990Bpp8 >(time);
break;
869 case 0x5D: startPOINT<V9990Bpp16>(time);
break;
871 case 0x0E: startPSET<V9990P1 >(time);
break;
872 case 0x1E: startPSET<V9990P2 >(time);
break;
873 case 0x2E: startPSET<V9990Bpp2 >(time);
break;
874 case 0x3E: startPSET<V9990Bpp4 >(time);
break;
875 case 0x4E: startPSET<V9990Bpp8 >(time);
break;
876 case 0x5E: startPSET<V9990Bpp16>(time);
break;
878 case 0x0F:
case 0x1F:
case 0x2F:
case 0x3F:
case 0x4F:
case 0x5F:
879 startADVN(time);
break;
893void V9990CmdEngine::setCommandMode()
927void V9990CmdEngine::reportV9990Command()
const
929 static constexpr std::array<std::string_view, 16> COMMANDS = {
930 "STOP",
"LMMC",
"LMMV",
"LMCM",
931 "LMMM",
"CMMC",
"CMMK",
"CMMM",
932 "BMXL",
"BMLX",
"BMLL",
"LINE",
933 "SRCH",
"POINT",
"PSET",
"ADVN"
935 std::cerr <<
"V9990Cmd " << COMMANDS[CMD >> 4]
936 <<
" SX=" << std::dec << SX
937 <<
" SY=" << std::dec << SY
938 <<
" DX=" << std::dec << DX
939 <<
" DY=" << std::dec << DY
940 <<
" NX=" << std::dec << NX
941 <<
" NY=" << std::dec << NY
942 <<
" ARG=" << std::hex << int(ARG)
943 <<
" LOG=" << std::hex << int(LOG)
944 <<
" WM=" << std::hex << WM
945 <<
" FC=" << std::hex << fgCol
946 <<
" BC=" << std::hex << bgCol
947 <<
" CMD=" << std::hex << int(CMD)
951void V9990CmdEngine::update(
const Setting&
setting)
noexcept
953 brokenTiming = checked_cast<const EnumSetting<bool>&>(
setting).getEnum();
957void V9990CmdEngine::startSTOP(EmuTime::param time)
962void V9990CmdEngine::executeSTOP(EmuTime::param )
968void V9990CmdEngine::startLMMC(EmuTime::param )
970 ANX = getWrappedNX();
971 ANY = getWrappedNY();
974void V9990CmdEngine::startLMMC16(EmuTime::param time)
981void V9990CmdEngine::executeLMMC<V9990CmdEngine::V9990Bpp16>(EmuTime::param limit)
983 if (!(status & TR)) {
990 auto value =
word((data << 8) | partial);
991 unsigned pitch = V9990Bpp16::getPitch(vdp.getImageWidth());
992 auto lut = V9990Bpp16::getLogOpLUT(LOG);
993 V9990Bpp16::pset(vram, DX, DY, pitch, value, WM, lut, LOG);
994 word dx = (ARG & DIX) ?
word(-1) : 1;
997 word dy = (ARG & DIY) ?
word(-1) : 1;
1003 ANX = getWrappedNX();
1010template<
typename Mode>
1011void V9990CmdEngine::executeLMMC(EmuTime::param limit)
1013 if (!(status &
TR)) {
1016 auto lut = Mode::getLogOpLUT(LOG);
1017 for (
int i = 0; (ANY > 0) && (i < Mode::PIXELS_PER_BYTE); ++i) {
1018 byte d = Mode::shift(data, i, DX);
1019 Mode::pset(vram, DX, DY, pitch, d, WM, lut, LOG);
1021 word dx = (ARG & DIX) ?
word(-1) : 1;
1024 word dy = (ARG & DIY) ?
word(-1) : 1;
1025 DX -=
word(NX * dx);
1038void V9990CmdEngine::startLMMV(EmuTime::param time)
1041 ANX = getWrappedNX();
1042 ANY = getWrappedNY();
1045template<
typename Mode>
1046void V9990CmdEngine::executeLMMV(EmuTime::param limit)
1050 auto delta = getTiming(*
this, LMMV_TIMING);
1052 word dx = (ARG & DIX) ?
word(-1) : 1;
1053 word dy = (ARG & DIY) ?
word(-1) : 1;
1054 auto lut = Mode::getLogOpLUT(LOG);
1055 while (engineTime < limit) {
1056 engineTime += delta;
1057 Mode::psetColor(vram, DX, DY, pitch, fgCol, WM, lut, LOG);
1061 DX -=
word(NX * dx);
1064 cmdReady(engineTime);
1067 ANX = getWrappedNX();
1074void V9990CmdEngine::startLMCM(EmuTime::param )
1076 ANX = getWrappedNX();
1077 ANY = getWrappedNY();
1079 endAfterRead =
false;
1081void V9990CmdEngine::startLMCM16(EmuTime::param time)
1087template<
typename Mode>
1088void V9990CmdEngine::executeLMCM(EmuTime::param )
1090 if (!(status &
TR)) {
1092 if ((Mode::BITS_PER_PIXEL == 16) && bitsLeft) {
1098 using Type =
typename Mode::Type;
1100 for (
int i = 0; (ANY > 0) && (i < Mode::PIXELS_PER_BYTE); ++i) {
1101 auto src = Mode::point(vram, SX, SY, pitch);
1102 d |= Type(Mode::shift(src, SX, i) & Mode::shiftMask(i));
1104 word dx = (ARG & DIX) ?
word(-1) : 1;
1107 word dy = (ARG & DIY) ?
word(-1) : 1;
1108 SX -=
word(NX * dx);
1111 endAfterRead =
true;
1113 ANX = getWrappedNX();
1117 if constexpr (Mode::BITS_PER_PIXEL == 16) {
1121 data = narrow_cast<byte>(tmp & 0xff);
1122 partial = narrow_cast<byte>(tmp >> 8);
1131void V9990CmdEngine::startLMMM(EmuTime::param time)
1134 ANX = getWrappedNX();
1135 ANY = getWrappedNY();
1138template<
typename Mode>
1139void V9990CmdEngine::executeLMMM(EmuTime::param limit)
1143 auto delta = getTiming(*
this, LMMM_TIMING);
1145 word dx = (ARG & DIX) ?
word(-1) : 1;
1146 word dy = (ARG & DIY) ?
word(-1) : 1;
1147 auto lut = Mode::getLogOpLUT(LOG);
1148 while (engineTime < limit) {
1149 engineTime += delta;
1150 auto src = Mode::point(vram, SX, SY, pitch);
1151 src = Mode::shift(src, SX, DX);
1152 Mode::pset(vram, DX, DY, pitch, src, WM, lut, LOG);
1157 DX -=
word(NX * dx);
1158 SX -=
word(NX * dx);
1162 cmdReady(engineTime);
1165 ANX = getWrappedNX();
1172void V9990CmdEngine::startCMMC(EmuTime::param )
1174 ANX = getWrappedNX();
1175 ANY = getWrappedNY();
1179template<
typename Mode>
1180void V9990CmdEngine::executeCMMC(EmuTime::param limit)
1182 if (!(status &
TR)) {
1186 word dx = (ARG & DIX) ?
word(-1) : 1;
1187 word dy = (ARG & DIY) ?
word(-1) : 1;
1188 auto lut = Mode::getLogOpLUT(LOG);
1189 for (
auto i :
xrange(8)) {
1191 bool bit = (data & 0x80) != 0;
1194 word src = bit ? fgCol : bgCol;
1195 Mode::psetColor(vram, DX, DY, pitch, src, WM, lut, LOG);
1199 DX -=
word(NX * dx);
1205 ANX = getWrappedNX();
1213void V9990CmdEngine::startCMMK(EmuTime::param time)
1215 std::cout <<
"V9990: CMMK not yet implemented\n";
1219void V9990CmdEngine::executeCMMK(EmuTime::param )
1225void V9990CmdEngine::startCMMM(EmuTime::param time)
1228 srcAddress = (SX & 0xFF) + ((SY & 0x7FF) << 8);
1229 ANX = getWrappedNX();
1230 ANY = getWrappedNY();
1234template<
typename Mode>
1235void V9990CmdEngine::executeCMMM(EmuTime::param limit)
1239 auto delta = getTiming(*
this, CMMM_TIMING);
1241 word dx = (ARG & DIX) ?
word(-1) : 1;
1242 word dy = (ARG & DIY) ?
word(-1) : 1;
1243 auto lut = Mode::getLogOpLUT(LOG);
1244 while (engineTime < limit) {
1245 engineTime += delta;
1247 data = vram.readVRAMBx(srcAddress++);
1251 bool bit = (data & 0x80) != 0;
1254 word color = bit ? fgCol : bgCol;
1255 Mode::psetColor(vram, DX, DY, pitch, color, WM, lut, LOG);
1259 DX -=
word(NX * dx);
1262 cmdReady(engineTime);
1265 ANX = getWrappedNX();
1272void V9990CmdEngine::startBMXL(EmuTime::param time)
1275 srcAddress = (SX & 0xFF) + ((SY & 0x7FF) << 8);
1276 ANX = getWrappedNX();
1277 ANY = getWrappedNY();
1281void V9990CmdEngine::executeBMXL<V9990CmdEngine::V9990Bpp16>(EmuTime::param limit)
1284 auto delta = getTiming(*
this, BMXL_TIMING) * 2;
1285 unsigned pitch = V9990Bpp16::getPitch(vdp.getImageWidth());
1286 word dx = (ARG & DIX) ?
word(-1) : 1;
1287 word dy = (ARG & DIY) ?
word(-1) : 1;
1288 auto lut = V9990Bpp16::getLogOpLUT(LOG);
1290 while (engineTime < limit) {
1291 engineTime += delta;
1292 auto src =
word(vram.readVRAMBx(srcAddress + 0) +
1293 vram.readVRAMBx(srcAddress + 1) * 256);
1295 V9990Bpp16::pset(vram, DX, DY, pitch, src, WM, lut, LOG);
1298 DX -=
word(NX * dx);
1301 cmdReady(engineTime);
1304 ANX = getWrappedNX();
1310template<
typename Mode>
1311void V9990CmdEngine::executeBMXL(EmuTime::param limit)
1313 auto delta = getTiming(*
this, BMXL_TIMING);
1315 word dx = (ARG & DIX) ?
word(-1) : 1;
1316 word dy = (ARG & DIY) ?
word(-1) : 1;
1317 auto lut = Mode::getLogOpLUT(LOG);
1319 while (engineTime < limit) {
1320 engineTime += delta;
1321 byte d = vram.readVRAMBx(srcAddress++);
1322 for (
int i = 0; (ANY > 0) && (i < Mode::PIXELS_PER_BYTE); ++i) {
1323 auto d2 = Mode::shift(d, i, DX);
1324 Mode::pset(vram, DX, DY, pitch, d2, WM, lut, LOG);
1327 DX -=
word(NX * dx);
1330 cmdReady(engineTime);
1333 ANX = getWrappedNX();
1341void V9990CmdEngine::startBMLX(EmuTime::param time)
1344 dstAddress = (DX & 0xFF) + ((DY & 0x7FF) << 8);
1345 ANX = getWrappedNX();
1346 ANY = getWrappedNY();
1350void V9990CmdEngine::executeBMLX<V9990CmdEngine::V9990Bpp16>(EmuTime::param limit)
1353 auto delta = getTiming(*
this, BMLX_TIMING);
1354 unsigned pitch = V9990Bpp16::getPitch(vdp.getImageWidth());
1355 word dx = (ARG & DIX) ?
word(-1) : 1;
1356 word dy = (ARG & DIY) ?
word(-1) : 1;
1358 while (engineTime < limit) {
1359 engineTime += delta;
1360 auto src = V9990Bpp16::point(vram, SX, SY, pitch);
1361 vram.writeVRAMBx(dstAddress++, narrow_cast<byte>(src & 0xFF));
1362 vram.writeVRAMBx(dstAddress++, narrow_cast<byte>(src >> 8));
1365 SX -=
word(NX * dx);
1368 cmdReady(engineTime);
1371 ANX = getWrappedNX();
1376template<
typename Mode>
1377void V9990CmdEngine::executeBMLX(EmuTime::param limit)
1380 auto delta = getTiming(*
this, BMLX_TIMING);
1382 word dx = (ARG & DIX) ?
word(-1) : 1;
1383 word dy = (ARG & DIY) ?
word(-1) : 1;
1385 while (engineTime < limit) {
1386 engineTime += delta;
1388 for (
auto i :
xrange(Mode::PIXELS_PER_BYTE)) {
1389 auto src = Mode::point(vram, SX, SY, pitch);
1390 d |=
byte(Mode::shift(src, SX, i) & Mode::shiftMask(i));
1393 SX -=
word(NX * dx);
1396 vram.writeVRAMBx(dstAddress++, d);
1397 cmdReady(engineTime);
1400 ANX = getWrappedNX();
1404 vram.writeVRAMBx(dstAddress++, d);
1409void V9990CmdEngine::startBMLL(EmuTime::param time)
1412 srcAddress = (SX & 0xFF) + ((SY & 0x7FF) << 8);
1413 dstAddress = (DX & 0xFF) + ((DY & 0x7FF) << 8);
1414 nbBytes = (NX & 0xFF) + ((NY & 0x7FF) << 8);
1419void V9990CmdEngine::startBMLL16(EmuTime::param time)
1430void V9990CmdEngine::executeBMLL<V9990CmdEngine::V9990Bpp16>(EmuTime::param limit)
1434 auto delta = getTiming(*
this, BMLL_TIMING) * 2;
1435 auto lut = V9990Bpp16::getLogOpLUT(LOG);
1436 bool transp = (LOG & 0x10) != 0;
1437 while (engineTime < limit) {
1438 engineTime += delta;
1440 auto srcColor =
word(vram.readVRAMDirect(srcAddress + 0x00000) +
1441 vram.readVRAMDirect(srcAddress + 0x40000) * 256);
1442 auto dstColor =
word(vram.readVRAMDirect(dstAddress + 0x00000) +
1443 vram.readVRAMDirect(dstAddress + 0x40000) * 256);
1444 word newColor = V9990Bpp16::logOp(lut, srcColor, dstColor, transp);
1445 word result = (dstColor & ~WM) | (newColor & WM);
1446 vram.writeVRAMDirect(dstAddress + 0x00000, narrow_cast<byte>(result & 0xFF));
1447 vram.writeVRAMDirect(dstAddress + 0x40000, narrow_cast<byte>(result >> 8));
1448 srcAddress = (srcAddress + 1) & 0x3FFFF;
1449 dstAddress = (dstAddress + 1) & 0x3FFFF;
1451 cmdReady(engineTime);
1457template<
typename Mode>
1458void V9990CmdEngine::executeBMLL(EmuTime::param limit)
1461 auto delta = getTiming(*
this, BMLL_TIMING);
1462 auto lut = Mode::getLogOpLUT(LOG);
1463 while (engineTime < limit) {
1464 engineTime += delta;
1466 byte srcColor = vram.readVRAMBx(srcAddress);
1468 byte dstColor = vram.readVRAMDirect(addr);
1469 byte newColor = Mode::logOp(lut, srcColor, dstColor);
1470 byte mask = narrow_cast<byte>((addr & 0x40000) ? (WM >> 8) : (WM & 0xFF));
1471 byte result = (dstColor & ~mask) | (newColor & mask);
1472 vram.writeVRAMDirect(addr, result);
1473 srcAddress = (srcAddress + 1) & 0x7FFFF;
1474 dstAddress = (dstAddress + 1) & 0x7FFFF;
1476 cmdReady(engineTime);
1483void V9990CmdEngine::startLINE(EmuTime::param time)
1486 ASX =
word((NX - 1) / 2);
1491template<
typename Mode>
1492void V9990CmdEngine::executeLINE(EmuTime::param limit)
1494 auto delta = getTiming(*
this, LINE_TIMING);
1496 unsigned pitch = Mode::getPitch(width);
1498 word TX = (ARG & DIX) ?
word(-1) : 1;
1499 word TY = (ARG & DIY) ?
word(-1) : 1;
1500 auto lut = Mode::getLogOpLUT(LOG);
1502 if ((ARG & MAJ) == 0) {
1504 while (engineTime < limit) {
1505 engineTime += delta;
1506 Mode::psetColor(vram, ADX, DY, pitch, fgCol, WM, lut, LOG);
1515 if (ANX++ == NX || (ADX & width)) {
1516 cmdReady(engineTime);
1522 while (engineTime < limit) {
1523 engineTime += delta;
1524 Mode::psetColor(vram, ADX, DY, pitch, fgCol, WM, lut, LOG);
1532 if (ANX++ == NX || (ADX & width)) {
1533 cmdReady(engineTime);
1541void V9990CmdEngine::startSRCH(EmuTime::param time)
1547template<
typename Mode>
1548void V9990CmdEngine::executeSRCH(EmuTime::param limit)
1550 using Type =
typename Mode::Type;
1551 auto delta = getTiming(*
this, SRCH_TIMING);
1553 unsigned pitch = Mode::getPitch(width);
1554 Type mask = (1 << Mode::BITS_PER_PIXEL) -1;
1556 word TX = (ARG & DIX) ?
word(-1) : 1;
1557 bool AEQ = (ARG & NEQ) != 0;
1559 while (engineTime < limit) {
1560 engineTime += delta;
1564 if constexpr (Mode::BITS_PER_PIXEL == 16) {
1565 value = Mode::point(vram, ASX, SY, pitch);
1566 col =
static_cast<Type
>(fgCol);
1567 mask2 =
static_cast<Type
>(~0);
1570 unsigned addr = Mode::addressOf(ASX, SY, pitch);
1571 value = vram.readVRAMDirect(addr);
1572 col = narrow_cast<byte>((addr & 0x40000) ? (fgCol >> 8) : (fgCol & 0xFF));
1573 mask2 = Mode::shift(mask, 3, ASX);
1575 if (((value & mask2) == (col & mask2)) ^ AEQ) {
1577 cmdReady(engineTime);
1584 cmdReady(engineTime);
1592template<
typename Mode>
1593void V9990CmdEngine::startPOINT(EmuTime::param )
1596 auto d = Mode::point(vram, SX, SY, pitch);
1598 if constexpr (Mode::BITS_PER_PIXEL != 16) {
1600 endAfterRead =
true;
1605 data = narrow_cast<byte>(tmp & 0xff);
1606 partial = narrow_cast<byte>(tmp >> 8);
1607 endAfterRead =
false;
1612template<
typename Mode>
1613void V9990CmdEngine::executePOINT(EmuTime::param )
1615 if (status &
TR)
return;
1617 assert(Mode::BITS_PER_PIXEL == 16);
1620 endAfterRead =
true;
1624template<
typename Mode>
1625void V9990CmdEngine::startPSET(EmuTime::param time)
1628 auto lut = Mode::getLogOpLUT(LOG);
1629 Mode::psetColor(vram, DX, DY, pitch, fgCol, WM, lut, LOG);
1636void V9990CmdEngine::executePSET(EmuTime::param )
1642void V9990CmdEngine::startADVN(EmuTime::param time)
1644 std::cout <<
"V9990: ADVN not yet implemented\n";
1648void V9990CmdEngine::executeADVN(EmuTime::param )
1658 switch (cmdMode | (CMD >> 4)) {
1659 case 0x00:
case 0x10:
case 0x20:
case 0x30:
case 0x40:
case 0x50:
1660 executeSTOP(time);
break;
1662 case 0x01: executeLMMC<V9990P1 >(time);
break;
1663 case 0x11: executeLMMC<V9990P2 >(time);
break;
1664 case 0x21: executeLMMC<V9990Bpp2 >(time);
break;
1665 case 0x31: executeLMMC<V9990Bpp4 >(time);
break;
1666 case 0x41: executeLMMC<V9990Bpp8 >(time);
break;
1667 case 0x51: executeLMMC<V9990Bpp16>(time);
break;
1669 case 0x02: executeLMMV<V9990P1 >(time);
break;
1670 case 0x12: executeLMMV<V9990P2 >(time);
break;
1671 case 0x22: executeLMMV<V9990Bpp2 >(time);
break;
1672 case 0x32: executeLMMV<V9990Bpp4 >(time);
break;
1673 case 0x42: executeLMMV<V9990Bpp8 >(time);
break;
1674 case 0x52: executeLMMV<V9990Bpp16>(time);
break;
1676 case 0x03: executeLMCM<V9990P1 >(time);
break;
1677 case 0x13: executeLMCM<V9990P2 >(time);
break;
1678 case 0x23: executeLMCM<V9990Bpp2 >(time);
break;
1679 case 0x33: executeLMCM<V9990Bpp4 >(time);
break;
1680 case 0x43: executeLMCM<V9990Bpp8 >(time);
break;
1681 case 0x53: executeLMCM<V9990Bpp16>(time);
break;
1683 case 0x04: executeLMMM<V9990P1 >(time);
break;
1684 case 0x14: executeLMMM<V9990P2 >(time);
break;
1685 case 0x24: executeLMMM<V9990Bpp2 >(time);
break;
1686 case 0x34: executeLMMM<V9990Bpp4 >(time);
break;
1687 case 0x44: executeLMMM<V9990Bpp8 >(time);
break;
1688 case 0x54: executeLMMM<V9990Bpp16>(time);
break;
1690 case 0x05: executeCMMC<V9990P1 >(time);
break;
1691 case 0x15: executeCMMC<V9990P2 >(time);
break;
1692 case 0x25: executeCMMC<V9990Bpp2 >(time);
break;
1693 case 0x35: executeCMMC<V9990Bpp4 >(time);
break;
1694 case 0x45: executeCMMC<V9990Bpp8 >(time);
break;
1695 case 0x55: executeCMMC<V9990Bpp16>(time);
break;
1697 case 0x06:
case 0x16:
case 0x26:
case 0x36:
case 0x46:
case 0x56:
1698 executeCMMK(time);
break;
1700 case 0x07: executeCMMM<V9990P1 >(time);
break;
1701 case 0x17: executeCMMM<V9990P2 >(time);
break;
1702 case 0x27: executeCMMM<V9990Bpp2 >(time);
break;
1703 case 0x37: executeCMMM<V9990Bpp4 >(time);
break;
1704 case 0x47: executeCMMM<V9990Bpp8 >(time);
break;
1705 case 0x57: executeCMMM<V9990Bpp16>(time);
break;
1707 case 0x08: executeBMXL<V9990P1 >(time);
break;
1708 case 0x18: executeBMXL<V9990P2 >(time);
break;
1709 case 0x28: executeBMXL<V9990Bpp2 >(time);
break;
1710 case 0x38: executeBMXL<V9990Bpp4 >(time);
break;
1711 case 0x48: executeBMXL<V9990Bpp8 >(time);
break;
1712 case 0x58: executeBMXL<V9990Bpp16>(time);
break;
1714 case 0x09: executeBMLX<V9990P1 >(time);
break;
1715 case 0x19: executeBMLX<V9990P2 >(time);
break;
1716 case 0x29: executeBMLX<V9990Bpp2 >(time);
break;
1717 case 0x39: executeBMLX<V9990Bpp4 >(time);
break;
1718 case 0x49: executeBMLX<V9990Bpp8 >(time);
break;
1719 case 0x59: executeBMLX<V9990Bpp16>(time);
break;
1721 case 0x0A: executeBMLL<V9990P1 >(time);
break;
1722 case 0x1A: executeBMLL<V9990P2 >(time);
break;
1723 case 0x2A: executeBMLL<V9990Bpp2 >(time);
break;
1724 case 0x3A: executeBMLL<V9990Bpp4 >(time);
break;
1725 case 0x4A: executeBMLL<V9990Bpp8 >(time);
break;
1726 case 0x5A: executeBMLL<V9990Bpp16>(time);
break;
1728 case 0x0B: executeLINE<V9990P1 >(time);
break;
1729 case 0x1B: executeLINE<V9990P2 >(time);
break;
1730 case 0x2B: executeLINE<V9990Bpp2 >(time);
break;
1731 case 0x3B: executeLINE<V9990Bpp4 >(time);
break;
1732 case 0x4B: executeLINE<V9990Bpp8 >(time);
break;
1733 case 0x5B: executeLINE<V9990Bpp16>(time);
break;
1735 case 0x0C: executeSRCH<V9990P1 >(time);
break;
1736 case 0x1C: executeSRCH<V9990P2 >(time);
break;
1737 case 0x2C: executeSRCH<V9990Bpp2 >(time);
break;
1738 case 0x3C: executeSRCH<V9990Bpp4 >(time);
break;
1739 case 0x4C: executeSRCH<V9990Bpp8 >(time);
break;
1740 case 0x5C: executeSRCH<V9990Bpp16>(time);
break;
1742 case 0x0D: executePOINT<V9990P1 >(time);
break;
1743 case 0x1D: executePOINT<V9990P2 >(time);
break;
1744 case 0x2D: executePOINT<V9990Bpp2 >(time);
break;
1745 case 0x3D: executePOINT<V9990Bpp4 >(time);
break;
1746 case 0x4D: executePOINT<V9990Bpp8 >(time);
break;
1747 case 0x5D: executePOINT<V9990Bpp16>(time);
break;
1749 case 0x0E:
case 0x1E:
case 0x2E:
case 0x3E:
case 0x4E:
case 0x5E:
1750 executePSET(time);
break;
1752 case 0x0F:
case 0x1F:
case 0x2F:
case 0x3F:
case 0x4F:
case 0x5F:
1753 executeADVN(time);
break;
1775 endAfterRead =
false;
1785 return (status &
TR) ? data : 0xFF;
1788void V9990CmdEngine::cmdReady(EmuTime::param )
1791 status &= ~(
CE |
TR);
1817 delta = getTiming(*
this, LMMV_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1820 delta = getTiming(*
this, LMMM_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1823 delta = getTiming(*
this, CMMM_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1826 delta = getTiming(*
this, BMXL_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1829 delta = getTiming(*
this, BMLX_TIMING) * (ANX + (ANY - 1) * getWrappedNX());
1838 delta = getTiming(*
this, BMLL_TIMING) * nbBytes;
1842 delta = getTiming(*
this, LINE_TIMING) * (NX - ANX);
1847 delta = getTiming(*
this, SRCH_TIMING);
1858 return engineTime + delta;
1863template<
typename Archive>
1867 if (ar.versionAtLeast(version, 2)) {
1875 ar.serialize(
"srcAddress", srcAddress,
1876 "dstAddress", dstAddress,
1897 "bitsLeft", bitsLeft,
1899 "endAfterRead", endAfterRead);
1901 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.
void serialize(Archive &ar, unsigned)
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)