62 const byte DIY = 0x08;
63 const byte DIX = 0x04;
65 const byte MAJ = 0x01;
69 template <
typename Mode>
70 static inline unsigned clipNX_1_pixel(
unsigned DX,
unsigned NX,
byte ARG)
72 if (
unlikely(DX >= Mode::PIXELS_PER_LINE)) {
75 NX = NX ? NX : Mode::PIXELS_PER_LINE;
78 : min(NX, Mode::PIXELS_PER_LINE - DX);
81 template <
typename Mode>
82 static inline unsigned clipNX_1_byte(
unsigned DX,
unsigned NX,
byte ARG)
84 static const unsigned BYTES_PER_LINE =
85 Mode::PIXELS_PER_LINE >> Mode::PIXELS_PER_BYTE_SHIFT;
87 DX >>= Mode::PIXELS_PER_BYTE_SHIFT;
88 if (
unlikely(BYTES_PER_LINE <= DX)) {
91 NX >>= Mode::PIXELS_PER_BYTE_SHIFT;
92 NX = NX ? NX : BYTES_PER_LINE;
95 : min(NX, BYTES_PER_LINE - DX);
98 template <
typename Mode>
99 static inline unsigned clipNX_2_pixel(
unsigned SX,
unsigned DX,
unsigned NX,
byte ARG)
101 if (
unlikely(SX >= Mode::PIXELS_PER_LINE) ||
102 unlikely(DX >= Mode::PIXELS_PER_LINE)) {
105 NX = NX ? NX : Mode::PIXELS_PER_LINE;
107 ? min(NX, min(SX, DX) + 1)
108 : min(NX, Mode::PIXELS_PER_LINE - max(SX, DX));
111 template <
typename Mode>
112 static inline unsigned clipNX_2_byte(
unsigned SX,
unsigned DX,
unsigned NX,
byte ARG)
114 static const unsigned BYTES_PER_LINE =
115 Mode::PIXELS_PER_LINE >> Mode::PIXELS_PER_BYTE_SHIFT;
117 SX >>= Mode::PIXELS_PER_BYTE_SHIFT;
118 DX >>= Mode::PIXELS_PER_BYTE_SHIFT;
119 if (
unlikely(BYTES_PER_LINE <= SX) ||
123 NX >>= Mode::PIXELS_PER_BYTE_SHIFT;
124 NX = NX ? NX : BYTES_PER_LINE;
126 ? min(NX, min(SX, DX) + 1)
127 : min(NX, BYTES_PER_LINE - max(SX, DX));
130 static inline unsigned clipNY_1(
unsigned DY,
unsigned NY,
byte ARG)
133 return (ARG & DIY) ? min(NY, DY + 1) : NY;
136 static inline unsigned clipNY_2(
unsigned SY,
unsigned DY,
unsigned NY,
byte ARG)
139 return (ARG & DIY) ? min(NY, min(SY, DY) + 1) : NY;
143 struct IncrByteAddr4;
144 struct IncrByteAddr5;
145 struct IncrByteAddr6;
146 struct IncrByteAddr7;
147 struct IncrPixelAddr4;
148 struct IncrPixelAddr5;
149 struct IncrPixelAddr6;
161 template <
typename LogOp>
static void psetFast(
166 op(time, vram, addr, src, color, mask);
181 static inline unsigned addressOf(
unsigned x,
unsigned y,
bool extVRAM);
182 static inline byte point(
VDPVRAM& vram,
unsigned x,
unsigned y,
bool extVRAM);
183 template <
typename LogOp>
185 unsigned x,
unsigned addr,
byte src,
byte color, LogOp op);
190 unsigned x,
unsigned y,
bool extVRAM)
193 ? (((y & 1023) << 7) | ((x & 255) >> 1))
194 : (((y & 511) << 7) | ((x & 255) >> 1) | 0x20000);
198 VDPVRAM& vram,
unsigned x,
unsigned y,
bool extVRAM)
201 >> (((~x) & 1) << 2) ) & 15;
204 template <
typename LogOp>
209 byte sh = ((~x) & 1) << 2;
210 op(time, vram, addr, src, color << sh, ~(15 << sh));
215 assert((color & 0xF0) == 0);
216 return color | (color << 4);
231 static inline unsigned addressOf(
unsigned x,
unsigned y,
bool extVRAM);
232 static inline byte point(
VDPVRAM& vram,
unsigned x,
unsigned y,
bool extVRAM);
233 template <
typename LogOp>
235 unsigned x,
unsigned addr,
byte src,
byte color, LogOp op);
240 unsigned x,
unsigned y,
bool extVRAM)
243 ? (((y & 1023) << 7) | ((x & 511) >> 2))
244 : (((y & 511) << 7) | ((x & 511) >> 2) | 0x20000);
248 VDPVRAM& vram,
unsigned x,
unsigned y,
bool extVRAM)
251 >> (((~x) & 3) << 1) ) & 3;
254 template <
typename LogOp>
259 byte sh = ((~x) & 3) << 1;
260 op(time, vram, addr, src, color << sh, ~(3 << sh));
265 assert((color & 0xFC) == 0);
283 static inline unsigned addressOf(
unsigned x,
unsigned y,
bool extVRAM);
284 static inline byte point(
VDPVRAM& vram,
unsigned x,
unsigned y,
bool extVRAM);
285 template <
typename LogOp>
287 unsigned x,
unsigned addr,
byte src,
byte color, LogOp op);
292 unsigned x,
unsigned y,
bool extVRAM)
295 ? (((x & 2) << 15) | ((y & 511) << 7) | ((x & 511) >> 2))
296 : (0x20000 | ((y & 511) << 7) | ((x & 511) >> 2));
300 VDPVRAM& vram,
unsigned x,
unsigned y,
bool extVRAM)
303 >> (((~x) & 1) << 2) ) & 15;
306 template <
typename LogOp>
311 byte sh = ((~x) & 1) << 2;
312 op(time, vram, addr, src, color << sh, ~(15 << sh));
317 assert((color & 0xF0) == 0);
318 return color | (color << 4);
333 static inline unsigned addressOf(
unsigned x,
unsigned y,
bool extVRAM);
334 static inline byte point(
VDPVRAM& vram,
unsigned x,
unsigned y,
bool extVRAM);
335 template <
typename LogOp>
337 unsigned x,
unsigned addr,
byte src,
byte color, LogOp op);
342 unsigned x,
unsigned y,
bool extVRAM)
345 ? (((x & 1) << 16) | ((y & 511) << 7) | ((x & 255) >> 1))
346 : (0x20000 | ((y & 511) << 7) | ((x & 255) >> 1));
350 VDPVRAM& vram,
unsigned x,
unsigned y,
bool extVRAM)
355 template <
typename LogOp>
360 op(time, vram, addr, src, color, 0);
411 : delta2((tx > 0) ? ( 0x10000 ^ (1 - 0x10000))
412 : (-0x10000 ^ (0x10000 - 1)))
415 delta = (tx > 0) ? 0x10000 : (0x10000 - 1);
416 if (x & 1) delta ^= delta2;
431 const unsigned delta2;
449 delta = (tx == 1) ? (x & 1) : ((x & 1) - 1);
469 c1 = -(signed(x) & 1);
492 : c3((tx == 1) ? unsigned(0x10000 ^ (1 - 0x10000))
493 : unsigned(-0x10000 ^ (0x10000 - 1)))
496 c1 = -(signed(x) & 1);
498 c2 = (x & 2) ? (1 - 0x10000) : 0x10000;
501 c2 = (x & 2) ? -0x10000 : (0x10000 - 1);
526 mask = 0x0F << ((x & 1) << 2);
543 : shift((tx > 0) ? 6 : 2)
545 mask = ~(0xC0 >> ((x & 3) << 1));
553 mask = (mask << shift) | (mask >> (8 - shift));
576 : shift(((dx - sx) & 1) * 4)
581 return (color >> shift) | (color << shift);
590 : shift(((dx - sx) & 3) * 2)
595 return (color >> shift) | (color << (8 - shift));
625 vram.
cmdWrite(addr, (src & mask) | color, time);
633 vram.
cmdWrite(addr, src & (color | mask), time);
641 vram.
cmdWrite(addr, src | color, time);
649 vram.
cmdWrite(addr, src ^ color, time);
657 vram.
cmdWrite(addr, (src & mask) | ~(color | mask), time);
661 template <
typename Op>
691 engine.commandDone(time);
714 engine.time = time; engine.nextAccessSlot(0);
718 template<
typename Mode>
721 if (
unlikely(engine.time >= limit))
return;
724 bool srcExt = (engine.ARG &
MXS) != 0;
725 bool doPoint = !srcExt || engine.hasExtendedVRAM;
726 engine.COL =
likely(doPoint)
727 ? Mode::point(vram, engine.SX, engine.SY, srcExt)
729 engine.commandDone(engine.time);
748 engine.time = time; engine.nextAccessSlot(0);
753 template<
typename Mode,
typename LogOp>
757 bool dstExt = (engine.ARG &
MXD) != 0;
758 bool doPset = !dstExt || engine.hasExtendedVRAM;
759 unsigned addr = Mode::addressOf(engine.DX, engine.DY, dstExt);
761 switch (engine.phase) {
763 if (
unlikely(engine.time >= limit)) { engine.phase = 0;
break; }
767 engine.nextAccessSlot(24);
770 if (
unlikely(engine.time >= limit)) { engine.phase = 1;
break; }
772 byte col = engine.COL & Mode::COLOR_MASK;
773 Mode::pset(engine.time, vram, engine.DX, addr,
774 engine.tmpDst, col, LogOp());
776 engine.commandDone(engine.time);
799 engine.ASX = engine.SX;
800 engine.time = time; engine.nextAccessSlot(0);
804 template <
typename Mode>
808 byte CL = engine.COL & Mode::COLOR_MASK;
809 int TX = (engine.ARG & DIX) ? -1 : 1;
810 bool AEQ = (engine.ARG &
EQ) != 0;
814 bool srcExt = (engine.ARG &
MXS) != 0;
815 bool doPoint = !srcExt || engine.hasExtendedVRAM;
816 auto calculator = engine.getSlotCalculator();
818 while (engine.time < limit) {
820 ? Mode::point(vram, engine.ASX, engine.SY, srcExt)
822 if ((p == CL) ^ AEQ) {
823 engine.status |= 0x10;
824 engine.commandDone(engine.time);
827 if ((engine.ASX += TX) & Mode::PIXELS_PER_LINE) {
828 engine.status &= 0xEF;
829 engine.commandDone(engine.time);
832 engine.nextAccessSlot(calculator, 88);
853 engine.ASX = ((engine.NX - 1) >> 1);
854 engine.ADX = engine.DX;
856 engine.time = time; engine.nextAccessSlot(0);
861 template <
typename Mode,
typename LogOp>
866 byte CL = engine.COL & Mode::COLOR_MASK;
867 int TX = (engine.ARG & DIX) ? -1 : 1;
868 int TY = (engine.ARG & DIY) ? -1 : 1;
869 bool dstExt = (engine.ARG &
MXD) != 0;
870 bool doPset = !dstExt || engine.hasExtendedVRAM;
871 unsigned addr = Mode::addressOf(engine.ADX, engine.DY, dstExt);
872 auto calculator = engine.getSlotCalculator();
874 switch (engine.phase) {
876 loop:
if (
unlikely(engine.time >= limit)) { engine.phase = 0;
break; }
880 engine.nextAccessSlot(calculator, 24);
883 if (
unlikely(engine.time >= limit)) { engine.phase = 1;
break; }
885 Mode::pset(engine.time, vram, engine.ADX, addr,
886 engine.tmpDst, CL, LogOp());
890 if ((engine.ARG & MAJ) == 0) {
897 if (engine.ANX++ == engine.NX || (engine.ADX & Mode::PIXELS_PER_LINE)) {
898 engine.commandDone(engine.time);
901 if (engine.ASX < engine.NY) {
902 engine.ASX += engine.NX;
906 engine.ASX -= engine.NY;
912 if (engine.ASX < engine.NY) {
913 engine.ASX += engine.NX;
917 engine.ASX -= engine.NY;
919 if (engine.ANX++ == engine.NX || (engine.ADX & Mode::PIXELS_PER_LINE)) {
920 engine.commandDone(engine.time);
924 addr = Mode::addressOf(engine.ADX, engine.DY, dstExt);
925 engine.nextAccessSlot(calculator, ticks);
939 unsigned NX,
unsigned NY,
unsigned ticksPerPixel);
943 unsigned NX,
unsigned NY,
unsigned ticksPerPixel)
945 if (!engine.currentCommand)
return;
951 t *= ((NX * (NY - 1)) + engine.ANX);
952 engine.statusChangeTime = engine.time + t;
966 template <
typename Mode>
973 unsigned NX = clipNX_1_pixel<Mode>(engine.DX, engine.NX, engine.ARG);
974 unsigned NY = clipNY_1(engine.DY, engine.NY, engine.ARG);
975 engine.ADX = engine.DX;
977 engine.time = time; engine.nextAccessSlot(0);
978 calcFinishTime(engine, NX, NY, 72 + 24);
982 template <
typename Mode,
typename LogOp>
987 unsigned NX = clipNX_1_pixel<Mode>(engine.DX, engine.NX, engine.ARG);
988 unsigned NY = clipNY_1(engine.DY, engine.NY, engine.ARG);
989 int TX = (engine.ARG & DIX) ? -1 : 1;
990 int TY = (engine.ARG & DIY) ? -1 : 1;
991 engine.ANX = clipNX_1_pixel<Mode>(engine.ADX, engine.ANX, engine.ARG);
992 byte CL = engine.COL & Mode::COLOR_MASK;
993 bool dstExt = (engine.ARG &
MXD) != 0;
994 bool doPset = !dstExt || engine.hasExtendedVRAM;
995 unsigned addr = Mode::addressOf(engine.ADX, engine.DY, dstExt);
996 auto calculator = engine.getSlotCalculator();
998 switch (engine.phase) {
1000 loop:
if (
unlikely(engine.time >= limit)) { engine.phase = 0;
break; }
1004 engine.nextAccessSlot(calculator, 24);
1007 if (
unlikely(engine.time >= limit)) { engine.phase = 1;
break; }
1009 Mode::pset(engine.time, vram, engine.ADX, addr,
1010 engine.tmpDst, CL, LogOp());
1014 if (--engine.ANX == 0) {
1016 engine.DY += TY; --(engine.NY);
1017 engine.ADX = engine.DX; engine.ANX = NX;
1019 engine.commandDone(engine.time);
1023 addr = Mode::addressOf(engine.ADX, engine.DY, dstExt);
1024 engine.nextAccessSlot(calculator, ticks);
1030 this->calcFinishTime(engine, NX, NY, 72 + 24);
1100 template <
typename Mode>
1107 unsigned NX = clipNX_2_pixel<Mode>(
1108 engine.SX, engine.DX, engine.NX, engine.ARG );
1109 unsigned NY = clipNY_2(engine.SY, engine.DY, engine.NY, engine.ARG);
1110 engine.ASX = engine.SX;
1111 engine.ADX = engine.DX;
1113 engine.time = time; engine.nextAccessSlot(0);
1114 calcFinishTime(engine, NX, NY, 64 + 32 + 24);
1118 template <
typename Mode,
typename LogOp>
1123 unsigned NX = clipNX_2_pixel<Mode>(
1124 engine.SX, engine.DX, engine.NX, engine.ARG );
1125 unsigned NY = clipNY_2(engine.SY, engine.DY, engine.NY, engine.ARG);
1126 int TX = (engine.ARG & DIX) ? -1 : 1;
1127 int TY = (engine.ARG & DIY) ? -1 : 1;
1128 engine.ANX = clipNX_2_pixel<Mode>(engine.ASX, engine.ADX, engine.ANX, engine.ARG);
1129 bool srcExt = (engine.ARG &
MXS) != 0;
1130 bool dstExt = (engine.ARG &
MXD) != 0;
1131 bool doPoint = !srcExt || engine.hasExtendedVRAM;
1132 bool doPset = !dstExt || engine.hasExtendedVRAM;
1133 unsigned dstAddr = Mode::addressOf(engine.ADX, engine.DY, dstExt);
1134 auto calculator = engine.getSlotCalculator();
1136 switch (engine.phase) {
1138 loop:
if (
unlikely(engine.time >= limit)) { engine.phase = 0;
break; }
1139 engine.tmpSrc =
likely(doPoint)
1140 ? Mode::point(vram, engine.ASX, engine.SY, srcExt)
1142 engine.nextAccessSlot(calculator, 32);
1145 if (
unlikely(engine.time >= limit)) { engine.phase = 1;
break; }
1149 engine.nextAccessSlot(calculator, 24);
1152 if (
unlikely(engine.time >= limit)) { engine.phase = 2;
break; }
1154 Mode::pset(engine.time, vram, engine.ADX, dstAddr,
1155 engine.tmpDst, engine.tmpSrc, LogOp());
1157 engine.ASX += TX; engine.ADX += TX;
1159 if (--engine.ANX == 0) {
1161 engine.SY += TY; engine.DY += TY; --(engine.NY);
1162 engine.ASX = engine.SX; engine.ADX = engine.DX; engine.ANX = NX;
1164 engine.commandDone(engine.time);
1168 dstAddr = Mode::addressOf(engine.ADX, engine.DY, dstExt);
1169 engine.nextAccessSlot(calculator, ticks);
1175 this->calcFinishTime(engine, NX, NY, 64 + 32 + 24);
1252 template <
typename Mode>
1259 unsigned NX = clipNX_1_pixel<Mode>(engine.SX, engine.NX, engine.ARG);
1260 engine.ASX = engine.SX;
1262 engine.transfer =
true;
1263 engine.status |= 0x80;
1264 engine.time = time; engine.nextAccessSlot(0);
1268 template <
typename Mode>
1271 if (!engine.transfer)
return;
1272 if (
unlikely(engine.time >= limit))
return;
1276 unsigned NX = clipNX_1_pixel<Mode>(engine.SX, engine.NX, engine.ARG);
1277 unsigned NY = clipNY_1(engine.SY, engine.NY, engine.ARG);
1278 int TX = (engine.ARG & DIX) ? -1 : 1;
1279 int TY = (engine.ARG & DIY) ? -1 : 1;
1280 engine.ANX = clipNX_1_pixel<Mode>(engine.ASX, engine.ANX, engine.ARG);
1281 bool srcExt = (engine.ARG &
MXS) != 0;
1282 bool doPoint = !srcExt || engine.hasExtendedVRAM;
1287 engine.COL =
likely(doPoint)
1288 ? Mode::point(vram, engine.ASX, engine.SY, srcExt)
1290 engine.transfer =
false;
1291 engine.ASX += TX; --engine.ANX;
1292 if (engine.ANX == 0) {
1293 engine.SY += TY; --(engine.NY);
1294 engine.ASX = engine.SX; engine.ANX = NX;
1296 engine.commandDone(engine.time);
1299 engine.time = limit; engine.nextAccessSlot(0);
1313 template <
typename Mode>
1320 unsigned NX = clipNX_1_pixel<Mode>(engine.DX, engine.NX, engine.ARG);
1321 engine.ADX = engine.DX;
1324 engine.transfer =
true;
1325 engine.status |= 0x80;
1326 engine.time = time; engine.nextAccessSlot(0);
1329 template <
typename Mode,
typename LogOp>
1334 unsigned NX = clipNX_1_pixel<Mode>(engine.DX, engine.NX, engine.ARG);
1335 unsigned NY = clipNY_1(engine.DY, engine.NY, engine.ARG);
1336 int TX = (engine.ARG & DIX) ? -1 : 1;
1337 int TY = (engine.ARG & DIY) ? -1 : 1;
1338 engine.ANX = clipNX_1_pixel<Mode>(engine.ADX, engine.ANX, engine.ARG);
1339 bool dstExt = (engine.ARG &
MXD) != 0;
1340 bool doPset = !dstExt || engine.hasExtendedVRAM;
1342 if (engine.transfer) {
1343 byte col = engine.COL & Mode::COLOR_MASK;
1350 unsigned addr = Mode::addressOf(engine.ADX, engine.DY, dstExt);
1352 Mode::pset(limit, vram, engine.ADX, addr,
1353 engine.tmpDst, col, LogOp());
1359 engine.transfer =
false;
1361 engine.ADX += TX; --engine.ANX;
1362 if (engine.ANX == 0) {
1363 engine.DY += TY; --(engine.NY);
1364 engine.ADX = engine.DX; engine.ANX = NX;
1366 engine.commandDone(limit);
1380 template <
typename Mode>
1387 unsigned NX = clipNX_1_byte<Mode>(engine.DX, engine.NX, engine.ARG);
1388 unsigned NY = clipNY_1(engine.DY, engine.NY, engine.ARG);
1389 engine.ADX = engine.DX;
1391 engine.time = time; engine.nextAccessSlot(0);
1392 calcFinishTime(engine, NX, NY, 48);
1395 template <
typename Mode>
1400 unsigned NX = clipNX_1_byte<Mode>(engine.DX, engine.NX, engine.ARG);
1401 unsigned NY = clipNY_1(engine.DY, engine.NY, engine.ARG);
1402 int TX = (engine.ARG & DIX)
1403 ? -Mode::PIXELS_PER_BYTE : Mode::PIXELS_PER_BYTE;
1404 int TY = (engine.ARG & DIY) ? -1 : 1;
1405 engine.ANX = clipNX_1_byte<Mode>(
1406 engine.ADX, engine.ANX << Mode::PIXELS_PER_BYTE_SHIFT, engine.ARG );
1407 bool dstExt = (engine.ARG &
MXD) != 0;
1408 bool doPset = !dstExt || engine.hasExtendedVRAM;
1409 auto calculator = engine.getSlotCalculator();
1411 while (engine.time < limit) {
1413 vram.
cmdWrite(Mode::addressOf(engine.ADX, engine.DY, dstExt),
1414 engine.COL, engine.time);
1418 if (--engine.ANX == 0) {
1420 engine.DY += TY; --(engine.NY);
1421 engine.ADX = engine.DX; engine.ANX = NX;
1423 engine.commandDone(engine.time);
1427 engine.nextAccessSlot(calculator, ticks);
1429 calcFinishTime(engine, NX, NY, 48);
1491 template <
typename Mode>
1498 unsigned NX = clipNX_2_byte<Mode>(
1499 engine.SX, engine.DX, engine.NX, engine.ARG );
1500 unsigned NY = clipNY_2(engine.SY, engine.DY, engine.NY, engine.ARG);
1501 engine.ASX = engine.SX;
1502 engine.ADX = engine.DX;
1504 engine.time = time; engine.nextAccessSlot(0);
1505 calcFinishTime(engine, NX, NY, 24 + 64);
1509 template <
typename Mode>
1514 unsigned NX = clipNX_2_byte<Mode>(
1515 engine.SX, engine.DX, engine.NX, engine.ARG);
1516 unsigned NY = clipNY_2(engine.SY, engine.DY, engine.NY, engine.ARG);
1517 int TX = (engine.ARG & DIX)
1518 ? -Mode::PIXELS_PER_BYTE : Mode::PIXELS_PER_BYTE;
1519 int TY = (engine.ARG & DIY) ? -1 : 1;
1520 engine.ANX = clipNX_2_byte<Mode>(
1521 engine.ASX, engine.ADX, engine.ANX << Mode::PIXELS_PER_BYTE_SHIFT, engine.ARG );
1522 bool srcExt = (engine.ARG &
MXS) != 0;
1523 bool dstExt = (engine.ARG &
MXD) != 0;
1524 bool doPoint = !srcExt || engine.hasExtendedVRAM;
1525 bool doPset = !dstExt || engine.hasExtendedVRAM;
1526 auto calculator = engine.getSlotCalculator();
1528 switch (engine.phase) {
1530 loop:
if (
unlikely(engine.time >= limit)) { engine.phase = 0;
break; }
1531 engine.tmpSrc =
likely(doPoint)
1533 Mode::addressOf(engine.ASX, engine.SY, srcExt))
1535 engine.nextAccessSlot(calculator, 24);
1538 if (
unlikely(engine.time >= limit)) { engine.phase = 1;
break; }
1540 vram.
cmdWrite(Mode::addressOf(engine.ADX, engine.DY, dstExt),
1541 engine.tmpSrc, engine.time);
1543 engine.ASX += TX; engine.ADX += TX;
1545 if (--engine.ANX == 0) {
1547 engine.SY += TY; engine.DY += TY; --(engine.NY);
1548 engine.ASX = engine.SX; engine.ADX = engine.DX; engine.ANX = NX;
1550 engine.commandDone(engine.time);
1554 engine.nextAccessSlot(calculator, ticks);
1561 calcFinishTime(engine, NX, NY, 24 + 64);
1633 template <
typename Mode>
1640 unsigned NX = clipNX_1_byte<Mode>(engine.DX, 512, engine.ARG);
1642 unsigned NY = clipNY_2(engine.SY, engine.DY, engine.NY, engine.ARG);
1643 engine.ADX = engine.DX;
1645 engine.time = time; engine.nextAccessSlot(0);
1646 calcFinishTime(engine, NX, NY, 24 + 40);
1650 template <
typename Mode>
1655 unsigned NX = clipNX_1_byte<Mode>(engine.DX, 512, engine.ARG);
1657 unsigned NY = clipNY_2(engine.SY, engine.DY, engine.NY, engine.ARG);
1658 int TX = (engine.ARG & DIX)
1659 ? -Mode::PIXELS_PER_BYTE : Mode::PIXELS_PER_BYTE;
1660 int TY = (engine.ARG & DIY) ? -1 : 1;
1661 engine.ANX = clipNX_1_byte<Mode>(engine.ADX, 512, engine.ARG);
1666 bool dstExt = (engine.ARG &
MXD) != 0;
1667 bool doPset = !dstExt || engine.hasExtendedVRAM;
1668 auto calculator = engine.getSlotCalculator();
1670 switch (engine.phase) {
1672 loop:
if (
unlikely(engine.time >= limit)) { engine.phase = 0;
break; }
1675 Mode::addressOf(engine.ADX, engine.SY, dstExt));
1677 engine.nextAccessSlot(calculator, 24);
1680 if (
unlikely(engine.time >= limit)) { engine.phase = 1;
break; }
1682 vram.
cmdWrite(Mode::addressOf(engine.ADX, engine.DY, dstExt),
1683 engine.tmpSrc, engine.time);
1686 if (--engine.ANX == 0) {
1688 engine.SY += TY; engine.DY += TY; --(engine.NY);
1689 engine.ADX = engine.DX; engine.ANX = NX;
1691 engine.commandDone(engine.time);
1695 engine.nextAccessSlot(calculator, 40);
1701 calcFinishTime(engine, NX, NY, 24 + 40);
1769 template <
typename Mode>
1776 unsigned NX = clipNX_1_byte<Mode>(engine.DX, engine.NX, engine.ARG);
1777 engine.ADX = engine.DX;
1780 engine.transfer =
true;
1781 engine.status |= 0x80;
1782 engine.time = time; engine.nextAccessSlot(0);
1785 template <
typename Mode>
1790 unsigned NX = clipNX_1_byte<Mode>(engine.DX, engine.NX, engine.ARG);
1791 unsigned NY = clipNY_1(engine.DY, engine.NY, engine.ARG);
1792 int TX = (engine.ARG & DIX)
1793 ? -Mode::PIXELS_PER_BYTE : Mode::PIXELS_PER_BYTE;
1794 int TY = (engine.ARG & DIY) ? -1 : 1;
1795 engine.ANX = clipNX_1_byte<Mode>(
1796 engine.ADX, engine.ANX << Mode::PIXELS_PER_BYTE_SHIFT, engine.ARG );
1797 bool dstExt = (engine.ARG &
MXD) != 0;
1798 bool doPset = !dstExt || engine.hasExtendedVRAM;
1800 if (engine.transfer) {
1805 vram.
cmdWrite(Mode::addressOf(engine.ADX, engine.DY, dstExt),
1808 engine.transfer =
false;
1810 engine.ADX += TX; --engine.ANX;
1811 if (engine.ANX == 0) {
1812 engine.DY += TY; --(engine.NY);
1813 engine.ADX = engine.DX; engine.ANX = NX;
1815 engine.commandDone(limit);
1824 template <
template <
typename Mode>
class Command>
1825 void VDPCmdEngine::createHEngines(
unsigned cmd)
1831 for (
int i = 1; i < 16; ++i) {
1832 for (
int j = 0; j < 4; ++j) {
1833 commands[cmd + i][j] = commands[cmd + 0][j];
1837 void VDPCmdEngine::deleteHEngines(
unsigned cmd)
1839 for (
int j = 0; j < 4; ++j) {
1840 delete commands[cmd + 0][j];
1844 template <
template <
typename Mode,
typename LopOp>
class Command>
1845 void VDPCmdEngine::createLEngines(
unsigned cmd, VDPCmd* dummy)
1847 commands[cmd + 0][0] =
new Command<Graphic4Mode, ImpOp >();
1848 commands[cmd + 0][1] =
new Command<Graphic5Mode, ImpOp >();
1849 commands[cmd + 0][2] =
new Command<Graphic6Mode, ImpOp >();
1850 commands[cmd + 0][3] =
new Command<Graphic7Mode, ImpOp >();
1852 commands[cmd + 1][0] =
new Command<Graphic4Mode, AndOp >();
1853 commands[cmd + 1][1] =
new Command<Graphic5Mode, AndOp >();
1854 commands[cmd + 1][2] =
new Command<Graphic6Mode, AndOp >();
1855 commands[cmd + 1][3] =
new Command<Graphic7Mode, AndOp >();
1857 commands[cmd + 2][0] =
new Command<Graphic4Mode, OrOp >();
1858 commands[cmd + 2][1] =
new Command<Graphic5Mode, OrOp >();
1859 commands[cmd + 2][2] =
new Command<Graphic6Mode, OrOp >();
1860 commands[cmd + 2][3] =
new Command<Graphic7Mode, OrOp >();
1862 commands[cmd + 3][0] =
new Command<Graphic4Mode, XorOp >();
1863 commands[cmd + 3][1] =
new Command<Graphic5Mode, XorOp >();
1864 commands[cmd + 3][2] =
new Command<Graphic6Mode, XorOp >();
1865 commands[cmd + 3][3] =
new Command<Graphic7Mode, XorOp >();
1867 commands[cmd + 4][0] =
new Command<Graphic4Mode, NotOp >();
1868 commands[cmd + 4][1] =
new Command<Graphic5Mode, NotOp >();
1869 commands[cmd + 4][2] =
new Command<Graphic6Mode, NotOp >();
1870 commands[cmd + 4][3] =
new Command<Graphic7Mode, NotOp >();
1872 commands[cmd + 5][0] = dummy;
1873 commands[cmd + 5][1] = dummy;
1874 commands[cmd + 5][2] = dummy;
1875 commands[cmd + 5][3] = dummy;
1877 commands[cmd + 6][0] = dummy;
1878 commands[cmd + 6][1] = dummy;
1879 commands[cmd + 6][2] = dummy;
1880 commands[cmd + 6][3] = dummy;
1882 commands[cmd + 7][0] = dummy;
1883 commands[cmd + 7][1] = dummy;
1884 commands[cmd + 7][2] = dummy;
1885 commands[cmd + 7][3] = dummy;
1887 commands[cmd + 8][0] =
new Command<Graphic4Mode, TImpOp >();
1888 commands[cmd + 8][1] =
new Command<Graphic5Mode, TImpOp >();
1889 commands[cmd + 8][2] =
new Command<Graphic6Mode, TImpOp >();
1890 commands[cmd + 8][3] =
new Command<Graphic7Mode, TImpOp >();
1892 commands[cmd + 9][0] =
new Command<Graphic4Mode, TAndOp >();
1893 commands[cmd + 9][1] =
new Command<Graphic5Mode, TAndOp >();
1894 commands[cmd + 9][2] =
new Command<Graphic6Mode, TAndOp >();
1895 commands[cmd + 9][3] =
new Command<Graphic7Mode, TAndOp >();
1897 commands[cmd + 10][0] =
new Command<Graphic4Mode, TOrOp >();
1898 commands[cmd + 10][1] =
new Command<Graphic5Mode, TOrOp >();
1899 commands[cmd + 10][2] =
new Command<Graphic6Mode, TOrOp >();
1900 commands[cmd + 10][3] =
new Command<Graphic7Mode, TOrOp >();
1902 commands[cmd + 11][0] =
new Command<Graphic4Mode, TXorOp >();
1903 commands[cmd + 11][1] =
new Command<Graphic5Mode, TXorOp >();
1904 commands[cmd + 11][2] =
new Command<Graphic6Mode, TXorOp >();
1905 commands[cmd + 11][3] =
new Command<Graphic7Mode, TXorOp >();
1907 commands[cmd + 12][0] =
new Command<Graphic4Mode, TNotOp >();
1908 commands[cmd + 12][1] =
new Command<Graphic5Mode, TNotOp >();
1909 commands[cmd + 12][2] =
new Command<Graphic6Mode, TNotOp >();
1910 commands[cmd + 12][3] =
new Command<Graphic7Mode, TNotOp >();
1912 commands[cmd + 13][0] = dummy;
1913 commands[cmd + 13][1] = dummy;
1914 commands[cmd + 13][2] = dummy;
1915 commands[cmd + 13][3] = dummy;
1917 commands[cmd + 14][0] = dummy;
1918 commands[cmd + 14][1] = dummy;
1919 commands[cmd + 14][2] = dummy;
1920 commands[cmd + 14][3] = dummy;
1922 commands[cmd + 15][0] = dummy;
1923 commands[cmd + 15][1] = dummy;
1924 commands[cmd + 15][2] = dummy;
1925 commands[cmd + 15][3] = dummy;
1928 void VDPCmdEngine::deleteLEngines(
unsigned cmd)
1930 for (
int i = 0; i < 5; ++i) {
1931 for (
int j = 0; j < 4; ++j) {
1932 delete commands[cmd + i + 0][j];
1933 delete commands[cmd + i + 8][j];
1941 : vdp(vdp_), vram(vdp.getVRAM())
1942 , renderSettings(renderSettings_)
1944 commandController, vdp_.
getName() ==
"VDP" ?
"vdpcmdtrace" :
1945 vdp_.
getName() +
" vdpcmdtrace",
"VDP command tracing on/off",
1948 commandController, vdp_.
getName() ==
"VDP" ?
1949 "vdpcmdinprogress_callback" : vdp_.
getName() +
1950 " vdpcmdinprogress_callback",
1951 "Tcl proc to call when a write to the VDP command engine is "
1952 "detected while the previous command is still in progress."))
1954 , statusChangeTime(
EmuTime::infinity)
1955 , hasExtendedVRAM(vram.getSize() == (192 * 1024))
1959 SX = SY = DX = DY = NX = NY = 0;
1960 ASX = ADX = ANX = 0;
1961 COL = ARG = CMD = 0;
1965 for (
unsigned cmd = 0x0; cmd < 0x40; ++cmd) {
1966 for (
unsigned mode = 0; mode < 4; ++mode) {
1967 commands[cmd][mode] = abort;
1970 createHEngines<PointCmd>(0x40);
1971 createLEngines<PsetCmd >(0x50, dummy);
1972 createHEngines<SrchCmd >(0x60);
1973 createLEngines<LineCmd >(0x70, dummy);
1974 createLEngines<LmmvCmd >(0x80, dummy);
1975 createLEngines<LmmmCmd >(0x90, dummy);
1976 createHEngines<LmcmCmd >(0xA0);
1977 createLEngines<LmmcCmd >(0xB0, dummy);
1978 createHEngines<HmmvCmd >(0xC0);
1979 createHEngines<HmmmCmd >(0xD0);
1980 createHEngines<YmmmCmd >(0xE0);
1981 createHEngines<HmmcCmd >(0xF0);
1982 currentCommand =
nullptr;
1993 delete commands[0x00][0];
1994 delete commands[0x55][0];
1995 deleteHEngines(0x40);
1996 deleteLEngines(0x50);
1997 deleteHEngines(0x60);
1998 deleteLEngines(0x70);
1999 deleteLEngines(0x80);
2000 deleteLEngines(0x90);
2001 deleteHEngines(0xA0);
2002 deleteLEngines(0xB0);
2003 deleteHEngines(0xC0);
2004 deleteHEngines(0xD0);
2005 deleteHEngines(0xE0);
2006 deleteHEngines(0xF0);
2013 for (
unsigned i = 0; i < 15; ++i) {
2020 void VDPCmdEngine::update(
const Setting& )
2028 if (currentCommand && (index != 12)) {
2029 cmdInProgressCallback->execute(index, value);
2033 SX = (SX & 0x100) | value;
2036 SX = (SX & 0x0FF) | ((value & 0x01) << 8);
2039 SY = (SY & 0x300) | value;
2042 SY = (SY & 0x0FF) | ((value & 0x03) << 8);
2046 DX = (DX & 0x100) | value;
2049 DX = (DX & 0x0FF) | ((value & 0x01) << 8);
2052 DY = (DY & 0x300) | value;
2055 DY = (DY & 0x0FF) | ((value & 0x03) << 8);
2061 NX = (NX & 0x300) | value;
2064 NX = (NX & 0x0FF) | ((value & 0x03) << 8);
2067 NY = (NY & 0x300) | value;
2070 NY = (NY & 0x0FF) | ((value & 0x03) << 8);
2078 if (!currentCommand) status &= 0x7F;
2086 executeCommand(time);
2096 case 0x00:
return SX & 0xFF;
2097 case 0x01:
return SX >> 8;
2098 case 0x02:
return SY & 0xFF;
2099 case 0x03:
return SY >> 8;
2101 case 0x04:
return DX & 0xFF;
2102 case 0x05:
return DX >> 8;
2103 case 0x06:
return DY & 0xFF;
2104 case 0x07:
return DY >> 8;
2106 case 0x08:
return NX & 0xFF;
2107 case 0x09:
return NX >> 8;
2108 case 0x0A:
return NY & 0xFF;
2109 case 0x0B:
return NY >> 8;
2111 case 0x0C:
return COL;
2112 case 0x0D:
return ARG;
2113 case 0x0E:
return CMD;
2144 if (newScrMode != scrMode) {
2146 if (currentCommand) {
2147 PRT_DEBUG(
"VDP mode switch while command in progress");
2148 if (newScrMode == -1) {
2155 currentCommand = commands[CMD][newScrMode];
2158 scrMode = newScrMode;
2171 if (cmdTraceSetting->getValue()) {
2177 currentCommand = commands[CMD][scrMode];
2178 currentCommand->
start(time, *
this);
2187 void VDPCmdEngine::reportVdpCommand()
2189 const char*
const COMMANDS[16] = {
2190 " ABRT",
" ????",
" ????",
" ????",
"POINT",
" PSET",
" SRCH",
" LINE",
2191 " LMMV",
" LMMM",
" LMCM",
" LMMC",
" HMMV",
" HMMM",
" YMMM",
" HMMC"
2193 const char*
const OPS[16] = {
2194 "IMP ",
"AND ",
"OR ",
"XOR ",
"NOT ",
"NOP ",
"NOP ",
"NOP ",
2195 "TIMP",
"TAND",
"TOR ",
"TXOR",
"TNOT",
"NOP ",
"NOP ",
"NOP "
2198 std::cerr <<
"VDPCmd " << COMMANDS[CMD >> 4] <<
'-' << OPS[CMD & 15]
2199 <<
'(' << int(SX) <<
',' << int(SY) <<
")->("
2200 << int(DX) <<
',' << int(DY) <<
")," << int(COL)
2201 <<
" [" << int((ARG & DIX) ? -
int(NX) :
int(NX))
2202 <<
',' << int((ARG & DIY) ? -
int(NY) :
int(NY)) <<
']' << std::endl;
2210 currentCommand =
nullptr;
2220 template<
typename Archive>
2227 if (!currentCommand) {
2228 assert((CMD & 0xF0) == 0);
2231 if (ar.versionAtLeast(version, 2)) {
2232 ar.serialize(
"time", time);
2235 assert(ar.isLoader());
2237 ar.serialize(
"clock", clock);
2238 time = clock.getTime();
2240 ar.serialize(
"statusChangeTime", statusChangeTime);
2241 ar.serialize(
"scrMode", scrMode);
2242 ar.serialize(
"status", status);
2243 ar.serialize(
"transfer", transfer);
2244 ar.serialize(
"SX", SX);
2245 ar.serialize(
"SY", SY);
2246 ar.serialize(
"DX", DX);
2247 ar.serialize(
"DY", DY);
2248 ar.serialize(
"NX", NX);
2249 ar.serialize(
"NY", NY);
2250 ar.serialize(
"ASX", ASX);
2251 ar.serialize(
"ADX", ADX);
2252 ar.serialize(
"ANX", ANX);
2253 ar.serialize(
"COL", COL);
2254 ar.serialize(
"ARG", ARG);
2255 ar.serialize(
"CMD", CMD);
2257 if (ar.versionAtLeast(version, 3)) {
2258 ar.serialize(
"phase", phase);
2259 ar.serialize(
"tmpSrc", tmpSrc);
2260 ar.serialize(
"tmpDst", tmpDst);
2262 assert(ar.isLoader());
2263 phase = tmpSrc = tmpDst = 0;
2266 if (ar.isLoader()) {
2268 assert(scrMode >= 0);
2269 currentCommand = commands[CMD][scrMode];
2271 currentCommand =
nullptr;