openMSX
VDPCmdEngine.cc
Go to the documentation of this file.
1/*
2TODO:
3- How is 64K VRAM handled?
4 VRAM size is never inspected by the command engine.
5 How does a real MSX handle it?
6 Mirroring of first 64K or empty memory space?
7- How is extended VRAM handled?
8 The current VDP implementation does not support it.
9 Since it is not accessed by the renderer, it is possible allocate
10 it here.
11 But maybe it makes more sense to have all RAM managed by the VDP?
12- Currently all VRAM access is done at the start time of a series of
13 updates: currentTime is not increased until the very end of the sync
14 method. It should of course be updated after every read and write.
15 An acceptable approximation would be an update after every pixel/byte
16 operation.
17*/
18
19/*
20 About NX, NY
21 - for block commands NX = 0 is equivalent to NX = 512 (TODO recheck this)
22 and NY = 0 is equivalent to NY = 1024
23 - when NX or NY is too large and the VDP command hits the border, the
24 following happens:
25 - when the left or right border is hit, the line terminates
26 - when the top border is hit (line 0) the command terminates
27 - when the bottom border (line 511 or 1023) the command continues
28 (wraps to the top)
29 - in 512 lines modes (e.g. screen 7) NY is NOT limited to 512, so when
30 NY > 512, part of the screen is overdrawn twice
31 - in 256 columns modes (e.g. screen 5) when "SX/DX >= 256", only 1 element
32 (pixel or byte) is processed per horizontal line. The real x-coordinate
33 is "SX/DX & 255".
34*/
35
36#include "VDPCmdEngine.hh"
37
38#include "VDPVRAM.hh"
39
40#include "EmuTime.hh"
41#include "serialize.hh"
42
43#include "unreachable.hh"
44
45#include <algorithm>
46#include <array>
47#include <cassert>
48#include <iostream>
49#include <string_view>
50
51namespace openmsx {
52
53using namespace VDPAccessSlots;
54
55// Constants:
56static constexpr byte MXD = 0x20;
57static constexpr byte MXS = 0x10;
58static constexpr byte DIY = 0x08;
59static constexpr byte DIX = 0x04;
60static constexpr byte EQ = 0x02;
61static constexpr byte MAJ = 0x01;
62
63
64template<typename Mode>
65static constexpr unsigned clipNX_1_pixel(unsigned DX, unsigned NX, byte ARG)
66{
67 if (DX >= Mode::PIXELS_PER_LINE) [[unlikely]] {
68 return 1;
69 }
70 NX = NX ? NX : Mode::PIXELS_PER_LINE;
71 return (ARG & DIX)
72 ? std::min(NX, DX + 1)
73 : std::min(NX, Mode::PIXELS_PER_LINE - DX);
74}
75
76template<typename Mode>
77static constexpr unsigned clipNX_1_byte(unsigned DX, unsigned NX, byte ARG)
78{
79 constexpr unsigned BYTES_PER_LINE =
80 Mode::PIXELS_PER_LINE >> Mode::PIXELS_PER_BYTE_SHIFT;
81
82 DX >>= Mode::PIXELS_PER_BYTE_SHIFT;
83 if (BYTES_PER_LINE <= DX) [[unlikely]] {
84 return 1;
85 }
86 NX >>= Mode::PIXELS_PER_BYTE_SHIFT;
87 NX = NX ? NX : BYTES_PER_LINE;
88 return (ARG & DIX)
89 ? std::min(NX, DX + 1)
90 : std::min(NX, BYTES_PER_LINE - DX);
91}
92
93template<typename Mode>
94static constexpr unsigned clipNX_2_pixel(unsigned SX, unsigned DX, unsigned NX, byte ARG)
95{
96 if ((SX >= Mode::PIXELS_PER_LINE) ||
97 (DX >= Mode::PIXELS_PER_LINE)) [[unlikely]] {
98 return 1;
99 }
100 NX = NX ? NX : Mode::PIXELS_PER_LINE;
101 return (ARG & DIX)
102 ? std::min(NX, std::min(SX, DX) + 1)
103 : std::min(NX, Mode::PIXELS_PER_LINE - std::max(SX, DX));
104}
105
106template<typename Mode>
107static constexpr unsigned clipNX_2_byte(unsigned SX, unsigned DX, unsigned NX, byte ARG)
108{
109 constexpr unsigned BYTES_PER_LINE =
110 Mode::PIXELS_PER_LINE >> Mode::PIXELS_PER_BYTE_SHIFT;
111
112 SX >>= Mode::PIXELS_PER_BYTE_SHIFT;
113 DX >>= Mode::PIXELS_PER_BYTE_SHIFT;
114 if ((BYTES_PER_LINE <= SX) ||
115 (BYTES_PER_LINE <= DX)) [[unlikely]] {
116 return 1;
117 }
118 NX >>= Mode::PIXELS_PER_BYTE_SHIFT;
119 NX = NX ? NX : BYTES_PER_LINE;
120 return (ARG & DIX)
121 ? std::min(NX, std::min(SX, DX) + 1)
122 : std::min(NX, BYTES_PER_LINE - std::max(SX, DX));
123}
124
125static constexpr unsigned clipNY_1(unsigned DY, unsigned NY, byte ARG)
126{
127 NY = NY ? NY : 1024;
128 return (ARG & DIY) ? std::min(NY, DY + 1) : NY;
129}
130
131static constexpr unsigned clipNY_2(unsigned SY, unsigned DY, unsigned NY, byte ARG)
132{
133 NY = NY ? NY : 1024;
134 return (ARG & DIY) ? std::min(NY, std::min(SY, DY) + 1) : NY;
135}
136
137
138//struct IncrByteAddr4;
139//struct IncrByteAddr5;
140//struct IncrByteAddr6;
141//struct IncrByteAddr7;
142//struct IncrPixelAddr4;
143//struct IncrPixelAddr5;
144//struct IncrPixelAddr6;
145//struct IncrMask4;
146//struct IncrMask5;
147//struct IncrMask7;
148//struct IncrShift4;
149//struct IncrShift5;
150//struct IncrShift7;
151//using IncrPixelAddr7 = IncrByteAddr7;
152//using IncrMask6 = IncrMask4;
153//using IncrShift6 = IncrShift4;
154
155
156template<typename LogOp> static void psetFast(
157 EmuTime::param time, VDPVRAM& vram, unsigned addr,
158 byte color, byte mask, LogOp op)
159{
160 byte src = vram.cmdWriteWindow.readNP(addr);
161 op(time, vram, addr, src, color, mask);
162}
163
167{
168 //using IncrByteAddr = IncrByteAddr4;
169 //using IncrPixelAddr = IncrPixelAddr4;
170 //using IncrMask = IncrMask4;
171 //using IncrShift = IncrShift4;
172 static constexpr byte COLOR_MASK = 0x0F;
173 static constexpr byte PIXELS_PER_BYTE = 2;
174 static constexpr byte PIXELS_PER_BYTE_SHIFT = 1;
175 static constexpr unsigned PIXELS_PER_LINE = 256;
176 static unsigned addressOf(unsigned x, unsigned y, bool extVRAM);
177 static byte point(const VDPVRAM& vram, unsigned x, unsigned y, bool extVRAM);
178 template<typename LogOp>
179 static void pset(EmuTime::param time, VDPVRAM& vram,
180 unsigned x, unsigned addr, byte src, byte color, LogOp op);
181 static byte duplicate(byte color);
182};
183
185 unsigned x, unsigned y, bool extVRAM)
186{
187 if (!extVRAM) [[likely]] {
188 return ((y & 1023) << 7) | ((x & 255) >> 1);
189 } else {
190 return ((y & 511) << 7) | ((x & 255) >> 1) | 0x20000;
191 }
192}
193
195 const VDPVRAM& vram, unsigned x, unsigned y, bool extVRAM)
196{
197 return (vram.cmdReadWindow.readNP(addressOf(x, y, extVRAM))
198 >> (((~x) & 1) << 2)) & 15;
199}
200
201template<typename LogOp>
203 EmuTime::param time, VDPVRAM& vram, unsigned x, unsigned addr,
204 byte src, byte color, LogOp op)
205{
206 auto sh = byte(((~x) & 1) << 2);
207 op(time, vram, addr, src, byte(color << sh), ~byte(15 << sh));
208}
209
210inline byte Graphic4Mode::duplicate(byte color)
211{
212 assert((color & 0xF0) == 0);
213 return byte(color | (color << 4));
214}
215
219{
220 //using IncrByteAddr = IncrByteAddr5;
221 //using IncrPixelAddr = IncrPixelAddr5;
222 //using IncrMask = IncrMask5;
223 //using IncrShift = IncrShift5;
224 static constexpr byte COLOR_MASK = 0x03;
225 static constexpr byte PIXELS_PER_BYTE = 4;
226 static constexpr byte PIXELS_PER_BYTE_SHIFT = 2;
227 static constexpr unsigned PIXELS_PER_LINE = 512;
228 static unsigned addressOf(unsigned x, unsigned y, bool extVRAM);
229 static byte point(const VDPVRAM& vram, unsigned x, unsigned y, bool extVRAM);
230 template<typename LogOp>
231 static void pset(EmuTime::param time, VDPVRAM& vram,
232 unsigned x, unsigned addr, byte src, byte color, LogOp op);
233 static byte duplicate(byte color);
234};
235
237 unsigned x, unsigned y, bool extVRAM)
238{
239 if (!extVRAM) [[likely]] {
240 return ((y & 1023) << 7) | ((x & 511) >> 2);
241 } else {
242 return ((y & 511) << 7) | ((x & 511) >> 2) | 0x20000;
243 }
244}
245
247 const VDPVRAM& vram, unsigned x, unsigned y, bool extVRAM)
248{
249 return (vram.cmdReadWindow.readNP(addressOf(x, y, extVRAM))
250 >> (((~x) & 3) << 1)) & 3;
251}
252
253template<typename LogOp>
255 EmuTime::param time, VDPVRAM& vram, unsigned x, unsigned addr,
256 byte src, byte color, LogOp op)
257{
258 auto sh = byte(((~x) & 3) << 1);
259 op(time, vram, addr, src, byte(color << sh), ~byte(3 << sh));
260}
261
262inline byte Graphic5Mode::duplicate(byte color)
263{
264 assert((color & 0xFC) == 0);
265 color |= color << 2;
266 color |= color << 4;
267 return color;
268}
269
273{
274 //using IncrByteAddr = IncrByteAddr6;
275 //using IncrPixelAddr = IncrPixelAddr6;
276 //using IncrMask = IncrMask6;
277 //using IncrShift = IncrShift6;
278 static constexpr byte COLOR_MASK = 0x0F;
279 static constexpr byte PIXELS_PER_BYTE = 2;
280 static constexpr byte PIXELS_PER_BYTE_SHIFT = 1;
281 static constexpr unsigned PIXELS_PER_LINE = 512;
282 static unsigned addressOf(unsigned x, unsigned y, bool extVRAM);
283 static byte point(const VDPVRAM& vram, unsigned x, unsigned y, bool extVRAM);
284 template<typename LogOp>
285 static void pset(EmuTime::param time, VDPVRAM& vram,
286 unsigned x, unsigned addr, byte src, byte color, LogOp op);
287 static byte duplicate(byte color);
288};
289
291 unsigned x, unsigned y, bool extVRAM)
292{
293 if (!extVRAM) [[likely]] {
294 return ((x & 2) << 15) | ((y & 511) << 7) | ((x & 511) >> 2);
295 } else {
296 return 0x20000 | ((y & 511) << 7) | ((x & 511) >> 2);
297 }
298}
299
301 const VDPVRAM& vram, unsigned x, unsigned y, bool extVRAM)
302{
303 return (vram.cmdReadWindow.readNP(addressOf(x, y, extVRAM))
304 >> (((~x) & 1) << 2)) & 15;
305}
306
307template<typename LogOp>
309 EmuTime::param time, VDPVRAM& vram, unsigned x, unsigned addr,
310 byte src, byte color, LogOp op)
311{
312 auto sh = byte(((~x) & 1) << 2);
313 op(time, vram, addr, src, byte(color << sh), ~byte(15 << sh));
314}
315
316inline byte Graphic6Mode::duplicate(byte color)
317{
318 assert((color & 0xF0) == 0);
319 return byte(color | (color << 4));
320}
321
325{
326 //using IncrByteAddr = IncrByteAddr7;
327 //using IncrPixelAddr = IncrPixelAddr7;
328 //using IncrMask = IncrMask7;
329 //using IncrShift = IncrShift7;
330 static constexpr byte COLOR_MASK = 0xFF;
331 static constexpr byte PIXELS_PER_BYTE = 1;
332 static constexpr byte PIXELS_PER_BYTE_SHIFT = 0;
333 static constexpr unsigned PIXELS_PER_LINE = 256;
334 static unsigned addressOf(unsigned x, unsigned y, bool extVRAM);
335 static byte point(const VDPVRAM& vram, unsigned x, unsigned y, bool extVRAM);
336 template<typename LogOp>
337 static void pset(EmuTime::param time, VDPVRAM& vram,
338 unsigned x, unsigned addr, byte src, byte color, LogOp op);
339 static byte duplicate(byte color);
340};
341
343 unsigned x, unsigned y, bool extVRAM)
344{
345 if (!extVRAM) [[likely]] {
346 return ((x & 1) << 16) | ((y & 511) << 7) | ((x & 255) >> 1);
347 } else {
348 return 0x20000 | ((y & 511) << 7) | ((x & 255) >> 1);
349 }
350}
351
353 const VDPVRAM& vram, unsigned x, unsigned y, bool extVRAM)
354{
355 return vram.cmdReadWindow.readNP(addressOf(x, y, extVRAM));
356}
357
358template<typename LogOp>
360 EmuTime::param time, VDPVRAM& vram, unsigned /*x*/, unsigned addr,
361 byte src, byte color, LogOp op)
362{
363 op(time, vram, addr, src, color, 0);
364}
365
366inline byte Graphic7Mode::duplicate(byte color)
367{
368 return color;
369}
370
375{
376 //using IncrByteAddr = IncrByteAddrNonBitMap;
377 //using IncrPixelAddr = IncrPixelAddrNonBitMap;
378 //using IncrMask = IncrMaskNonBitMap;
379 //using IncrShift = IncrShiftNonBitMap;
380 static constexpr byte COLOR_MASK = 0xFF;
381 static constexpr byte PIXELS_PER_BYTE = 1;
382 static constexpr byte PIXELS_PER_BYTE_SHIFT = 0;
383 static constexpr unsigned PIXELS_PER_LINE = 256;
384 static unsigned addressOf(unsigned x, unsigned y, bool extVRAM);
385 static byte point(const VDPVRAM& vram, unsigned x, unsigned y, bool extVRAM);
386 template<typename LogOp>
387 static void pset(EmuTime::param time, VDPVRAM& vram,
388 unsigned x, unsigned addr, byte src, byte color, LogOp op);
389 static byte duplicate(byte color);
390};
391
393 unsigned x, unsigned y, bool extVRAM)
394{
395 if (!extVRAM) [[likely]] {
396 return ((y & 511) << 8) | (x & 255);
397 } else {
398 return ((y & 255) << 8) | (x & 255) | 0x20000;
399 }
400}
401
403 const VDPVRAM& vram, unsigned x, unsigned y, bool extVRAM)
404{
405 return vram.cmdReadWindow.readNP(addressOf(x, y, extVRAM));
406}
407
408template<typename LogOp>
410 EmuTime::param time, VDPVRAM& vram, unsigned /*x*/, unsigned addr,
411 byte src, byte color, LogOp op)
412{
413 op(time, vram, addr, src, color, 0);
414}
415
416inline byte NonBitmapMode::duplicate(byte color)
417{
418 return color;
419}
420
424{
425 IncrByteAddr4(unsigned x, unsigned y, int /*tx*/)
426 : addr(Graphic4Mode::addressOf(x, y, false))
427 {
428 }
429 [[nodiscard]] unsigned getAddr() const
430 {
431 return addr;
432 }
433 void step(int tx)
434 {
435 addr += (tx >> 1);
436 }
437
438private:
439 unsigned addr;
440};
441
443{
444 IncrByteAddr5(unsigned x, unsigned y, int /*tx*/)
445 : addr(Graphic5Mode::addressOf(x, y, false))
446 {
447 }
448 [[nodiscard]] unsigned getAddr() const
449 {
450 return addr;
451 }
452 void step(int tx)
453 {
454 addr += (tx >> 2);
455 }
456
457private:
458 unsigned addr;
459};
460
462{
463 IncrByteAddr7(unsigned x, unsigned y, int tx)
464 : addr(Graphic7Mode::addressOf(x, y, false))
465 , delta((tx > 0) ? 0x10000 : (0x10000 - 1))
466 , delta2((tx > 0) ? ( 0x10000 ^ (1 - 0x10000))
467 : (-0x10000 ^ (0x10000 - 1)))
468 {
469 if (x & 1) delta ^= delta2;
470 }
471 [[nodiscard]] unsigned getAddr() const
472 {
473 return addr;
474 }
475 void step(int /*tx*/)
476 {
477 addr += delta;
478 delta ^= delta2;
479 }
480
481private:
482 unsigned addr;
483 unsigned delta;
484 const unsigned delta2;
485};
486
488{
489 IncrByteAddr6(unsigned x, unsigned y, int tx)
490 : IncrByteAddr7(x >> 1, y, tx)
491 {
492 }
493};
494
498{
499 IncrPixelAddr4(unsigned x, unsigned y, int tx)
500 : addr(Graphic4Mode::addressOf(x, y, false))
501 , delta((tx == 1) ? (x & 1) : ((x & 1) - 1))
502 {
503 }
504 [[nodiscard]] unsigned getAddr() const { return addr; }
505 void step(int tx)
506 {
507 addr += delta;
508 delta ^= tx;
509 }
510private:
511 unsigned addr;
512 unsigned delta;
513};
514
516{
517 IncrPixelAddr5(unsigned x, unsigned y, int tx)
518 : addr(Graphic5Mode::addressOf(x, y, false))
519 // x | 0 | 1 | 2 | 3
520 //-----------------------
521 , c1(-(signed(x) & 1)) // | 0 | -1 | 0 | -1
522 , c2((x & 2) >> 1) // | 0 | 0 | 1 | 1
523 {
524 if (tx < 0) {
525 c1 = ~c1; // | -1 | 0 | -1 | 0
526 c2 -= 1; // | -1 | -1 | 0 | 0
527 }
528 }
529 [[nodiscard]] unsigned getAddr() const { return addr; }
530 void step(int tx)
531 {
532 addr += (c1 & c2);
533 c2 ^= (c1 & tx);
534 c1 = ~c1;
535 }
536private:
537 unsigned addr;
538 unsigned c1;
539 unsigned c2;
540};
541
543{
544 IncrPixelAddr6(unsigned x, unsigned y, int tx)
545 : addr(Graphic6Mode::addressOf(x, y, false))
546 , c1(-(signed(x) & 1))
547 , c3((tx == 1) ? unsigned(0x10000 ^ (1 - 0x10000)) // == -0x1FFFF
548 : unsigned(-0x10000 ^ (0x10000 - 1))) // == -1
549 {
550 if (tx == 1) {
551 c2 = (x & 2) ? (1 - 0x10000) : 0x10000;
552 } else {
553 c1 = ~c1;
554 c2 = (x & 2) ? -0x10000 : (0x10000 - 1);
555 }
556 }
557 [[nodiscard]] unsigned getAddr() const { return addr; }
558 void step(int /*tx*/)
559 {
560 addr += (c1 & c2);
561 c2 ^= (c1 & c3);
562 c1 = ~c1;
563 }
564private:
565 unsigned addr;
566 unsigned c1;
567 unsigned c2;
568 const unsigned c3;
569};
570
571
576{
577 IncrMask4(unsigned x, int /*tx*/)
578 : mask(byte(0x0F << ((x & 1) << 2)))
579 {
580 }
581 [[nodiscard]] byte getMask() const
582 {
583 return mask;
584 }
585 void step()
586 {
587 mask = ~mask;
588 }
589private:
590 byte mask;
591};
592
594{
595 IncrMask5(unsigned x, int tx)
596 : mask(~byte(0xC0 >> ((x & 3) << 1)))
597 , shift((tx > 0) ? 6 : 2)
598 {
599 }
600 [[nodiscard]] byte getMask() const
601 {
602 return mask;
603 }
604 void step()
605 {
606 mask = byte((mask << shift) | (mask >> (8 - shift)));
607 }
608private:
609 byte mask;
610 const byte shift;
611};
612
614{
615 IncrMask7(unsigned /*x*/, int /*tx*/) {}
616 [[nodiscard]] byte getMask() const
617 {
618 return 0;
619 }
620 void step() const {}
621};
622
623
624/* Shift between source and destination pixel for LMMM command.
625 */
627{
628 IncrShift4(unsigned sx, unsigned dx)
629 : shift(((dx - sx) & 1) * 4)
630 {
631 }
632 [[nodiscard]] byte doShift(byte color) const
633 {
634 return byte((color >> shift) | (color << shift));
635 }
636private:
637 const byte shift;
638};
639
641{
642 IncrShift5(unsigned sx, unsigned dx)
643 : shift(((dx - sx) & 3) * 2)
644 {
645 }
646 [[nodiscard]] byte doShift(byte color) const
647 {
648 return byte((color >> shift) | (color << (8 - shift)));
649 }
650private:
651 const byte shift;
652};
653
655{
656 IncrShift7(unsigned /*sx*/, unsigned /*dx*/) {}
657 [[nodiscard]] byte doShift(byte color) const
658 {
659 return color;
660 }
661};
662
663
664// Logical operations:
665
666struct DummyOp {
667 void operator()(EmuTime::param /*time*/, VDPVRAM& /*vram*/, unsigned /*addr*/,
668 byte /*src*/, byte /*color*/, byte /*mask*/) const
669 {
670 // Undefined logical operations do nothing.
671 }
672};
673
674struct ImpOp {
675 void operator()(EmuTime::param time, VDPVRAM& vram, unsigned addr,
676 byte src, byte color, byte mask) const
677 {
678 vram.cmdWrite(addr, (src & mask) | color, time);
679 }
680};
681
682struct AndOp {
683 void operator()(EmuTime::param time, VDPVRAM& vram, unsigned addr,
684 byte src, byte color, byte mask) const
685 {
686 vram.cmdWrite(addr, src & (color | mask), time);
687 }
688};
689
690struct OrOp {
691 void operator()(EmuTime::param time, VDPVRAM& vram, unsigned addr,
692 byte src, byte color, byte /*mask*/) const
693 {
694 vram.cmdWrite(addr, src | color, time);
695 }
696};
697
698struct XorOp {
699 void operator()(EmuTime::param time, VDPVRAM& vram, unsigned addr,
700 byte src, byte color, byte /*mask*/) const
701 {
702 vram.cmdWrite(addr, src ^ color, time);
703 }
704};
705
706struct NotOp {
707 void operator()(EmuTime::param time, VDPVRAM& vram, unsigned addr,
708 byte src, byte color, byte mask) const
709 {
710 vram.cmdWrite(addr, (src & mask) | ~(color | mask), time);
711 }
712};
713
714template<typename Op>
715struct TransparentOp : Op {
716 void operator()(EmuTime::param time, VDPVRAM& vram, unsigned addr,
717 byte src, byte color, byte mask) const
718 {
719 // TODO does this skip the write or re-write the original value
720 // might make a difference in case the CPU has written
721 // the same address between the command read and write
722 if (color) Op::operator()(time, vram, addr, src, color, mask);
723 }
724};
730
731
732// Commands
733
734void VDPCmdEngine::setStatusChangeTime(EmuTime::param t)
735{
736 statusChangeTime = t;
737 if ((t != EmuTime::infinity()) && executingProbe.anyObservers()) {
738 vdp.scheduleCmdSync(t);
739 }
740}
741
742void VDPCmdEngine::calcFinishTime(unsigned nx, unsigned ny, unsigned ticksPerPixel)
743{
744 if (!CMD) return;
745 if (vdp.getBrokenCmdTiming()) {
746 setStatusChangeTime(EmuTime::zero()); // will finish soon
747 return;
748 }
749
750 // Underestimation for when the command will be finished. This assumes
751 // we never have to wait for access slots and that there's no overhead
752 // per line.
753 auto t = VDP::VDPClock::duration(ticksPerPixel);
754 t *= ((nx * (ny - 1)) + (ANX - 1));
755 setStatusChangeTime(engineTime + t);
756}
757
760void VDPCmdEngine::startAbrt(EmuTime::param time)
761{
762 commandDone(time);
763}
764
767void VDPCmdEngine::startPoint(EmuTime::param time)
768{
769 vram.cmdReadWindow.setMask(0x3FFFF, ~0u << 18, time);
770 vram.cmdWriteWindow.disable(time);
771 nextAccessSlot(time);
772 setStatusChangeTime(EmuTime::zero()); // will finish soon
773}
774
775template<typename Mode>
776void VDPCmdEngine::executePoint(EmuTime::param limit)
777{
778 if (engineTime >= limit) [[unlikely]] return;
779
780 bool srcExt = (ARG & MXS) != 0;
781 if (bool doPoint = !srcExt || hasExtendedVRAM; doPoint) [[likely]] {
782 COL = Mode::point(vram, SX, SY, srcExt);
783 } else {
784 COL = 0xFF;
785 }
786 commandDone(engineTime);
787}
788
791void VDPCmdEngine::startPset(EmuTime::param time)
792{
793 vram.cmdReadWindow.disable(time);
794 vram.cmdWriteWindow.setMask(0x3FFFF, ~0u << 18, time);
795 nextAccessSlot(time);
796 setStatusChangeTime(EmuTime::zero()); // will finish soon
797 phase = 0;
798}
799
800template<typename Mode, typename LogOp>
801void VDPCmdEngine::executePset(EmuTime::param limit)
802{
803 bool dstExt = (ARG & MXD) != 0;
804 bool doPset = !dstExt || hasExtendedVRAM;
805 unsigned addr = Mode::addressOf(DX, DY, dstExt);
806
807 switch (phase) {
808 case 0:
809 if (engineTime >= limit) [[unlikely]] { phase = 0; break; }
810 if (doPset) [[likely]] {
811 tmpDst = vram.cmdWriteWindow.readNP(addr);
812 }
813 nextAccessSlot(Delta::D24); // TODO
814 [[fallthrough]];
815 case 1:
816 if (engineTime >= limit) [[unlikely]] { phase = 1; break; }
817 if (doPset) [[likely]] {
818 byte col = COL & Mode::COLOR_MASK;
819 Mode::pset(engineTime, vram, DX, addr, tmpDst, col, LogOp());
820 }
821 commandDone(engineTime);
822 break;
823 default:
825 }
826}
827
830void VDPCmdEngine::startSrch(EmuTime::param time)
831{
832 vram.cmdReadWindow.setMask(0x3FFFF, ~0u << 18, time);
833 vram.cmdWriteWindow.disable(time);
834 ASX = SX;
835 nextAccessSlot(time);
836 setStatusChangeTime(EmuTime::zero()); // we can find it any moment
837}
838
839template<typename Mode>
840void VDPCmdEngine::executeSrch(EmuTime::param limit)
841{
842 byte CL = COL & Mode::COLOR_MASK;
843 int TX = (ARG & DIX) ? -1 : 1;
844 bool AEQ = (ARG & EQ) != 0; // TODO: Do we look for "==" or "!="?
845
846 // TODO use MXS or MXD here?
847 // datasheet says MXD but MXS seems more logical
848 bool srcExt = (ARG & MXS) != 0;
849 bool doPoint = !srcExt || hasExtendedVRAM;
850 auto calculator = getSlotCalculator(limit);
851
852 while (!calculator.limitReached()) {
853 auto p = [&] () -> byte {
854 if (doPoint) [[likely]] {
855 return Mode::point(vram, ASX, SY, srcExt);
856 } else {
857 return 0xFF;
858 }
859 }();
860 if ((p == CL) ^ AEQ) {
861 status |= 0x10; // border detected
862 commandDone(calculator.getTime());
863 break;
864 }
865 ASX += TX;
866 if (ASX & Mode::PIXELS_PER_LINE) {
867 status &= 0xEF; // border not detected
868 commandDone(calculator.getTime());
869 break;
870 }
871 calculator.next(Delta::D88); // TODO
872 }
873 engineTime = calculator.getTime();
874}
875
878void VDPCmdEngine::startLine(EmuTime::param time)
879{
880 vram.cmdReadWindow.disable(time);
881 vram.cmdWriteWindow.setMask(0x3FFFF, ~0u << 18, time);
882 NY &= 1023;
883 ASX = ((NX - 1) >> 1);
884 ADX = DX;
885 ANX = 0;
886 nextAccessSlot(time);
887 setStatusChangeTime(EmuTime::zero()); // TODO can still be optimized
888 phase = 0;
889}
890
891template<typename Mode, typename LogOp>
892void VDPCmdEngine::executeLine(EmuTime::param limit)
893{
894 // See doc/line-speed.txt for some background info on the timing.
895 byte CL = COL & Mode::COLOR_MASK;
896 int TX = (ARG & DIX) ? -1 : 1;
897 int TY = (ARG & DIY) ? -1 : 1;
898 bool dstExt = (ARG & MXD) != 0;
899 bool doPset = !dstExt || hasExtendedVRAM;
900 unsigned addr = Mode::addressOf(ADX, DY, dstExt);
901 auto calculator = getSlotCalculator(limit);
902
903 switch (phase) {
904 case 0:
905loop: if (calculator.limitReached()) [[unlikely]] { phase = 0; break; }
906 if (doPset) [[likely]] {
907 tmpDst = vram.cmdWriteWindow.readNP(addr);
908 }
909 calculator.next(Delta::D24);
910 [[fallthrough]];
911 case 1: {
912 if (calculator.limitReached()) [[unlikely]] { phase = 1; break; }
913 if (doPset) [[likely]] {
914 Mode::pset(calculator.getTime(), vram, ADX, addr,
915 tmpDst, CL, LogOp());
916 }
917
918 Delta delta = Delta::D88;
919 if ((ARG & MAJ) == 0) {
920 // X-Axis is major direction.
921 ADX += TX;
922 // confirmed on real HW:
923 // - end-test happens before DY += TY
924 // - (ADX & PPL) test only happens after first pixel
925 // is drawn. And it does test with 'AND' (not with ==)
926 if (ANX++ == NX || (ADX & Mode::PIXELS_PER_LINE)) {
927 commandDone(calculator.getTime());
928 break;
929 }
930 if (ASX < NY) {
931 ASX += NX;
932 DY += TY;
933 delta = Delta::D120; // 88 + 32
934 }
935 ASX -= NY;
936 ASX &= 1023; // mask to 10 bits range
937 } else {
938 // Y-Axis is major direction.
939 // confirmed on real HW: DY += TY happens before end-test
940 DY += TY;
941 if (ASX < NY) {
942 ASX += NX;
943 ADX += TX;
944 delta = Delta::D120; // 88 + 32
945 }
946 ASX -= NY;
947 ASX &= 1023; // mask to 10 bits range
948 if (ANX++ == NX || (ADX & Mode::PIXELS_PER_LINE)) {
949 commandDone(calculator.getTime());
950 break;
951 }
952 }
953 addr = Mode::addressOf(ADX, DY, dstExt);
954 calculator.next(delta);
955 goto loop;
956 }
957 default:
959 }
960 engineTime = calculator.getTime();
961}
962
963
966template<typename Mode>
967void VDPCmdEngine::startLmmv(EmuTime::param time)
968{
969 vram.cmdReadWindow.disable(time);
970 vram.cmdWriteWindow.setMask(0x3FFFF, ~0u << 18, time);
971 NY &= 1023;
972 unsigned tmpNX = clipNX_1_pixel<Mode>(DX, NX, ARG);
973 unsigned tmpNY = clipNY_1(DY, NY, ARG);
974 ADX = DX;
975 ANX = tmpNX;
976 nextAccessSlot(time);
977 calcFinishTime(tmpNX, tmpNY, 72 + 24);
978 phase = 0;
979}
980
981template<typename Mode, typename LogOp>
982void VDPCmdEngine::executeLmmv(EmuTime::param limit)
983{
984 NY &= 1023;
985 unsigned tmpNX = clipNX_1_pixel<Mode>(DX, NX, ARG);
986 unsigned tmpNY = clipNY_1(DY, NY, ARG);
987 int TX = (ARG & DIX) ? -1 : 1;
988 int TY = (ARG & DIY) ? -1 : 1;
989 ANX = clipNX_1_pixel<Mode>(ADX, ANX, ARG);
990 byte CL = COL & Mode::COLOR_MASK;
991 bool dstExt = (ARG & MXD) != 0;
992 bool doPset = !dstExt || hasExtendedVRAM;
993 unsigned addr = Mode::addressOf(ADX, DY, dstExt);
994 auto calculator = getSlotCalculator(limit);
995
996 switch (phase) {
997 case 0:
998loop: if (calculator.limitReached()) [[unlikely]] { phase = 0; break; }
999 if (doPset) [[likely]] {
1000 tmpDst = vram.cmdWriteWindow.readNP(addr);
1001 }
1002 calculator.next(Delta::D24);
1003 [[fallthrough]];
1004 case 1: {
1005 if (calculator.limitReached()) [[unlikely]] { phase = 1; break; }
1006 if (doPset) [[likely]] {
1007 Mode::pset(calculator.getTime(), vram, ADX, addr,
1008 tmpDst, CL, LogOp());
1009 }
1010 ADX += TX;
1011 Delta delta = Delta::D72;
1012 if (--ANX == 0) {
1013 delta = Delta::D136; // 72 + 64;
1014 DY += TY; --NY;
1015 ADX = DX; ANX = tmpNX;
1016 if (--tmpNY == 0) {
1017 commandDone(calculator.getTime());
1018 break;
1019 }
1020 }
1021 addr = Mode::addressOf(ADX, DY, dstExt);
1022 calculator.next(delta);
1023 goto loop;
1024 }
1025 default:
1027 }
1028 engineTime = calculator.getTime();
1029 this->calcFinishTime(tmpNX, tmpNY, 72 + 24);
1030
1031 /*
1032 if (dstExt) [[unlikely]] {
1033 bool doPset = !dstExt || hasExtendedVRAM;
1034 while (engineTime < limit) {
1035 if (doPset) [[likely]] {
1036 Mode::pset(engineTime, vram, ADX, DY,
1037 dstExt, CL, LogOp());
1038 }
1039 engineTime += delta;
1040 ADX += TX;
1041 if (--ANX == 0) {
1042 DY += TY; --NY;
1043 ADX = DX; ANX = tmpNX;
1044 if (--tmpNY == 0) {
1045 commandDone(engineTime);
1046 break;
1047 }
1048 }
1049 }
1050 } else {
1051 // fast-path, no extended VRAM
1052 CL = Mode::duplicate(CL);
1053 while (engineTime < limit) {
1054 typename Mode::IncrPixelAddr dstAddr(ADX, DY, TX);
1055 typename Mode::IncrMask dstMask(ADX, TX);
1056 EmuDuration dur = limit - engineTime;
1057 unsigned num = (delta != EmuDuration::zero())
1058 ? std::min(dur.divUp(delta), ANX)
1059 : ANX;
1060 for (auto i : xrange(num)) {
1061 byte mask = dstMask.getMask();
1062 psetFast(engineTime, vram, dstAddr.getAddr(),
1063 CL & ~mask, mask, LogOp());
1064 engineTime += delta;
1065 dstAddr.step(TX);
1066 dstMask.step();
1067 }
1068 ANX -= num;
1069 if (ANX == 0) {
1070 DY += TY;
1071 NY -= 1;
1072 ADX = DX;
1073 ANX = tmpNX;
1074 if (--tmpNY == 0) {
1075 commandDone(engineTime);
1076 break;
1077 }
1078 } else {
1079 ADX += num * TX;
1080 assert(engineTime >= limit);
1081 break;
1082 }
1083 }
1084 }
1085 */
1086}
1087
1090template<typename Mode>
1091void VDPCmdEngine::startLmmm(EmuTime::param time)
1092{
1093 vram.cmdReadWindow .setMask(0x3FFFF, ~0u << 18, time);
1094 vram.cmdWriteWindow.setMask(0x3FFFF, ~0u << 18, time);
1095 NY &= 1023;
1096 unsigned tmpNX = clipNX_2_pixel<Mode>(SX, DX, NX, ARG);
1097 unsigned tmpNY = clipNY_2(SY, DY, NY, ARG);
1098 ASX = SX;
1099 ADX = DX;
1100 ANX = tmpNX;
1101 nextAccessSlot(time);
1102 calcFinishTime(tmpNX, tmpNY, 64 + 32 + 24);
1103 phase = 0;
1104}
1105
1106template<typename Mode, typename LogOp>
1107void VDPCmdEngine::executeLmmm(EmuTime::param limit)
1108{
1109 NY &= 1023;
1110 unsigned tmpNX = clipNX_2_pixel<Mode>(SX, DX, NX, ARG);
1111 unsigned tmpNY = clipNY_2(SY, DY, NY, ARG);
1112 int TX = (ARG & DIX) ? -1 : 1;
1113 int TY = (ARG & DIY) ? -1 : 1;
1114 ANX = clipNX_2_pixel<Mode>(ASX, ADX, ANX, ARG);
1115 bool srcExt = (ARG & MXS) != 0;
1116 bool dstExt = (ARG & MXD) != 0;
1117 bool doPoint = !srcExt || hasExtendedVRAM;
1118 bool doPset = !dstExt || hasExtendedVRAM;
1119 unsigned dstAddr = Mode::addressOf(ADX, DY, dstExt);
1120 auto calculator = getSlotCalculator(limit);
1121
1122 switch (phase) {
1123 case 0:
1124loop: if (calculator.limitReached()) [[unlikely]] { phase = 0; break; }
1125 if (doPoint) [[likely]] {
1126 tmpSrc = Mode::point(vram, ASX, SY, srcExt);
1127 } else {
1128 tmpSrc = 0xFF;
1129 }
1130 calculator.next(Delta::D32);
1131 [[fallthrough]];
1132 case 1:
1133 if (calculator.limitReached()) [[unlikely]] { phase = 1; break; }
1134 if (doPset) [[likely]] {
1135 tmpDst = vram.cmdWriteWindow.readNP(dstAddr);
1136 }
1137 calculator.next(Delta::D24);
1138 [[fallthrough]];
1139 case 2: {
1140 if (calculator.limitReached()) [[unlikely]] { phase = 2; break; }
1141 if (doPset) [[likely]] {
1142 Mode::pset(calculator.getTime(), vram, ADX, dstAddr,
1143 tmpDst, tmpSrc, LogOp());
1144 }
1145 ASX += TX; ADX += TX;
1146 Delta delta = Delta::D64;
1147 if (--ANX == 0) {
1148 delta = Delta::D128; // 64 + 64
1149 SY += TY; DY += TY; --NY;
1150 ASX = SX; ADX = DX; ANX = tmpNX;
1151 if (--tmpNY == 0) {
1152 commandDone(calculator.getTime());
1153 break;
1154 }
1155 }
1156 dstAddr = Mode::addressOf(ADX, DY, dstExt);
1157 calculator.next(delta);
1158 goto loop;
1159 }
1160 default:
1162 }
1163 engineTime = calculator.getTime();
1164 this->calcFinishTime(tmpNX, tmpNY, 64 + 32 + 24);
1165
1166 /*if (srcExt || dstExt) [[unlikely]] {
1167 bool doPoint = !srcExt || hasExtendedVRAM;
1168 bool doPset = !dstExt || hasExtendedVRAM;
1169 while (engineTime < limit) {
1170 if (doPset) [[likely]] {
1171 auto p = [&] () -> byte {
1172 if (doPoint) [[likely]] {
1173 return Mode::point(vram, ASX, SY, srcExt);
1174 } else {
1175 return 0xFF;
1176 }
1177 }();
1178 Mode::pset(engineTime, vram, ADX, DY,
1179 dstExt, p, LogOp());
1180 }
1181 engineTime += delta;
1182 ASX += TX; ADX += TX;
1183 if (--ANX == 0) {
1184 SY += TY; DY += TY; --NY;
1185 ASX = SX; ADX = DX; ANX = tmpNX;
1186 if (--tmpNY == 0) {
1187 commandDone(engineTime);
1188 break;
1189 }
1190 }
1191 }
1192 } else {
1193 // fast-path, no extended VRAM
1194 while (engineTime < limit) {
1195 typename Mode::IncrPixelAddr srcAddr(ASX, SY, TX);
1196 typename Mode::IncrPixelAddr dstAddr(ADX, DY, TX);
1197 typename Mode::IncrMask dstMask(ADX, TX);
1198 typename Mode::IncrShift shift (ASX, ADX);
1199 EmuDuration dur = limit - engineTime;
1200 unsigned num = (delta != EmuDuration::zero())
1201 ? std::min(dur.divUp(delta), ANX)
1202 : ANX;
1203 for (auto i : xrange(num)) {
1204 byte p = vram.cmdReadWindow.readNP(srcAddr.getAddr());
1205 p = shift.doShift(p);
1206 byte mask = dstMask.getMask();
1207 psetFast(engineTime, vram, dstAddr.getAddr(),
1208 p & ~mask, mask, LogOp());
1209 engineTime += delta;
1210 srcAddr.step(TX);
1211 dstAddr.step(TX);
1212 dstMask.step();
1213 }
1214 ANX -= num;
1215 if (ANX == 0) {
1216 SY += TY;
1217 DY += TY;
1218 NY -= 1;
1219 ASX = SX;
1220 ADX = DX;
1221 ANX = tmpNX;
1222 if (--tmpNY == 0) {
1223 commandDone(engineTime);
1224 break;
1225 }
1226 } else {
1227 ASX += num * TX;
1228 ADX += num * TX;
1229 assert(engineTime >= limit);
1230 break;
1231 }
1232 }
1233 }
1234 */
1235}
1236
1239template<typename Mode>
1240void VDPCmdEngine::startLmcm(EmuTime::param time)
1241{
1242 vram.cmdReadWindow.setMask(0x3FFFF, ~0u << 18, time);
1243 vram.cmdWriteWindow.disable(time);
1244 NY &= 1023;
1245 unsigned tmpNX = clipNX_1_pixel<Mode>(SX, NX, ARG);
1246 ASX = SX;
1247 ANX = tmpNX;
1248 transfer = true;
1249 status |= 0x80;
1250 nextAccessSlot(time);
1251 setStatusChangeTime(EmuTime::zero());
1252}
1253
1254template<typename Mode>
1255void VDPCmdEngine::executeLmcm(EmuTime::param limit)
1256{
1257 if (!transfer) return;
1258 if (engineTime >= limit) [[unlikely]] return;
1259
1260 NY &= 1023;
1261 unsigned tmpNX = clipNX_1_pixel<Mode>(SX, NX, ARG);
1262 unsigned tmpNY = clipNY_1(SY, NY, ARG);
1263 int TX = (ARG & DIX) ? -1 : 1;
1264 int TY = (ARG & DIY) ? -1 : 1;
1265 ANX = clipNX_1_pixel<Mode>(ASX, ANX, ARG);
1266 bool srcExt = (ARG & MXS) != 0;
1267
1268 // TODO we should (most likely) perform the actual read earlier and
1269 // buffer it, and on a CPU-IO-read start the next read (just like how
1270 // regular reading from VRAM works).
1271 if (bool doPoint = !srcExt || hasExtendedVRAM; doPoint) [[likely]] {
1272 COL = Mode::point(vram, ASX, SY, srcExt);
1273 } else {
1274 COL = 0xFF;
1275 }
1276 transfer = false;
1277 ASX += TX; --ANX;
1278 if (ANX == 0) {
1279 SY += TY; --NY;
1280 ASX = SX; ANX = tmpNX;
1281 if (--tmpNY == 0) {
1282 commandDone(engineTime);
1283 }
1284 }
1285 nextAccessSlot(limit); // TODO
1286}
1287
1290template<typename Mode>
1291void VDPCmdEngine::startLmmc(EmuTime::param time)
1292{
1293 vram.cmdReadWindow.disable(time);
1294 vram.cmdWriteWindow.setMask(0x3FFFF, ~0u << 18, time);
1295 NY &= 1023;
1296 unsigned tmpNX = clipNX_1_pixel<Mode>(DX, NX, ARG);
1297 ADX = DX;
1298 ANX = tmpNX;
1299 setStatusChangeTime(EmuTime::zero());
1300 // do not set 'transfer = true', this fixes bug#1014
1301 // Baltak Rampage: characters in greetings part are one pixel offset
1302 status |= 0x80;
1303 nextAccessSlot(time);
1304}
1305
1306template<typename Mode, typename LogOp>
1307void VDPCmdEngine::executeLmmc(EmuTime::param limit)
1308{
1309 NY &= 1023;
1310 unsigned tmpNX = clipNX_1_pixel<Mode>(DX, NX, ARG);
1311 unsigned tmpNY = clipNY_1(DY, NY, ARG);
1312 int TX = (ARG & DIX) ? -1 : 1;
1313 int TY = (ARG & DIY) ? -1 : 1;
1314 ANX = clipNX_1_pixel<Mode>(ADX, ANX, ARG);
1315 bool dstExt = (ARG & MXD) != 0;
1316 bool doPset = !dstExt || hasExtendedVRAM;
1317
1318 if (transfer) {
1319 byte col = COL & Mode::COLOR_MASK;
1320 // TODO: timing is inaccurate, this executes the read and write
1321 // in the same access slot. Instead we should
1322 // - wait for a byte
1323 // - in next access slot read
1324 // - in next access slot write
1325 if (doPset) [[likely]] {
1326 unsigned addr = Mode::addressOf(ADX, DY, dstExt);
1327 tmpDst = vram.cmdWriteWindow.readNP(addr);
1328 Mode::pset(limit, vram, ADX, addr,
1329 tmpDst, col, LogOp());
1330 }
1331 // Execution is emulated as instantaneous, so don't bother
1332 // with the timing.
1333 // Note: Correct timing would require currentTime to be set
1334 // to the moment transfer becomes true.
1335 transfer = false;
1336
1337 ADX += TX; --ANX;
1338 if (ANX == 0) {
1339 DY += TY; --NY;
1340 ADX = DX; ANX = tmpNX;
1341 if (--tmpNY == 0) {
1342 commandDone(limit);
1343 }
1344 }
1345 }
1346 nextAccessSlot(limit); // inaccurate, but avoid assert
1347}
1348
1351template<typename Mode>
1352void VDPCmdEngine::startHmmv(EmuTime::param time)
1353{
1354 vram.cmdReadWindow.disable(time);
1355 vram.cmdWriteWindow.setMask(0x3FFFF, ~0u << 18, time);
1356 NY &= 1023;
1357 unsigned tmpNX = clipNX_1_byte<Mode>(DX, NX, ARG);
1358 unsigned tmpNY = clipNY_1(DY, NY, ARG);
1359 ADX = DX;
1360 ANX = tmpNX;
1361 nextAccessSlot(time);
1362 calcFinishTime(tmpNX, tmpNY, 48);
1363}
1364
1365template<typename Mode>
1366void VDPCmdEngine::executeHmmv(EmuTime::param limit)
1367{
1368 NY &= 1023;
1369 unsigned tmpNX = clipNX_1_byte<Mode>(DX, NX, ARG);
1370 unsigned tmpNY = clipNY_1(DY, NY, ARG);
1371 int TX = (ARG & DIX)
1372 ? -Mode::PIXELS_PER_BYTE : Mode::PIXELS_PER_BYTE;
1373 int TY = (ARG & DIY) ? -1 : 1;
1374 ANX = clipNX_1_byte<Mode>(
1375 ADX, ANX << Mode::PIXELS_PER_BYTE_SHIFT, ARG);
1376 bool dstExt = (ARG & MXD) != 0;
1377 bool doPset = !dstExt || hasExtendedVRAM;
1378 auto calculator = getSlotCalculator(limit);
1379
1380 while (!calculator.limitReached()) {
1381 if (doPset) [[likely]] {
1382 vram.cmdWrite(Mode::addressOf(ADX, DY, dstExt),
1383 COL, calculator.getTime());
1384 }
1385 ADX += TX;
1386 Delta delta = Delta::D48;
1387 if (--ANX == 0) {
1388 delta = Delta::D104; // 48 + 56;
1389 DY += TY; --NY;
1390 ADX = DX; ANX = tmpNX;
1391 if (--tmpNY == 0) {
1392 commandDone(calculator.getTime());
1393 break;
1394 }
1395 }
1396 calculator.next(delta);
1397 }
1398 engineTime = calculator.getTime();
1399 calcFinishTime(tmpNX, tmpNY, 48);
1400
1401 /*if (dstExt) [[unlikely]] {
1402 bool doPset = !dstExt || hasExtendedVRAM;
1403 while (engineTime < limit) {
1404 if (doPset) [[likely]] {
1405 vram.cmdWrite(Mode::addressOf(ADX, DY, dstExt),
1406 COL, engineTime);
1407 }
1408 engineTime += delta;
1409 ADX += TX;
1410 if (--ANX == 0) {
1411 DY += TY; --NY;
1412 ADX = DX; ANX = tmpNX;
1413 if (--tmpNY == 0) {
1414 commandDone(engineTime);
1415 break;
1416 }
1417 }
1418 }
1419 } else {
1420 // fast-path, no extended VRAM
1421 while (engineTime < limit) {
1422 typename Mode::IncrByteAddr dstAddr(ADX, DY, TX);
1423 EmuDuration dur = limit - engineTime;
1424 unsigned num = (delta != EmuDuration::zero())
1425 ? std::min(dur.divUp(delta), ANX)
1426 : ANX;
1427 for (auto i : xrange(num)) {
1428 vram.cmdWrite(dstAddr.getAddr(), COL,
1429 engineTime);
1430 engineTime += delta;
1431 dstAddr.step(TX);
1432 }
1433 ANX -= num;
1434 if (ANX == 0) {
1435 DY += TY;
1436 NY -= 1;
1437 ADX = DX;
1438 ANX = tmpNX;
1439 if (--tmpNY == 0) {
1440 commandDone(engineTime);
1441 break;
1442 }
1443 } else {
1444 ADX += num * TX;
1445 assert(engineTime >= limit);
1446 break;
1447 }
1448 }
1449 }
1450 */
1451}
1452
1455template<typename Mode>
1456void VDPCmdEngine::startHmmm(EmuTime::param time)
1457{
1458 vram.cmdReadWindow .setMask(0x3FFFF, ~0u << 18, time);
1459 vram.cmdWriteWindow.setMask(0x3FFFF, ~0u << 18, time);
1460 NY &= 1023;
1461 unsigned tmpNX = clipNX_2_byte<Mode>(SX, DX, NX, ARG);
1462 unsigned tmpNY = clipNY_2(SY, DY, NY, ARG);
1463 ASX = SX;
1464 ADX = DX;
1465 ANX = tmpNX;
1466 nextAccessSlot(time);
1467 calcFinishTime(tmpNX, tmpNY, 24 + 64);
1468 phase = 0;
1469}
1470
1471template<typename Mode>
1472void VDPCmdEngine::executeHmmm(EmuTime::param limit)
1473{
1474 NY &= 1023;
1475 unsigned tmpNX = clipNX_2_byte<Mode>(SX, DX, NX, ARG);
1476 unsigned tmpNY = clipNY_2(SY, DY, NY, ARG);
1477 int TX = (ARG & DIX)
1478 ? -Mode::PIXELS_PER_BYTE : Mode::PIXELS_PER_BYTE;
1479 int TY = (ARG & DIY) ? -1 : 1;
1480 ANX = clipNX_2_byte<Mode>(
1481 ASX, ADX, ANX << Mode::PIXELS_PER_BYTE_SHIFT, ARG);
1482 bool srcExt = (ARG & MXS) != 0;
1483 bool dstExt = (ARG & MXD) != 0;
1484 bool doPoint = !srcExt || hasExtendedVRAM;
1485 bool doPset = !dstExt || hasExtendedVRAM;
1486 auto calculator = getSlotCalculator(limit);
1487
1488 switch (phase) {
1489 case 0:
1490loop: if (calculator.limitReached()) [[unlikely]] { phase = 0; break; }
1491 if (doPoint) [[likely]] {
1492 tmpSrc = vram.cmdReadWindow.readNP(Mode::addressOf(ASX, SY, srcExt));
1493 } else {
1494 tmpSrc = 0xFF;
1495 }
1496 calculator.next(Delta::D24);
1497 [[fallthrough]];
1498 case 1: {
1499 if (calculator.limitReached()) [[unlikely]] { phase = 1; break; }
1500 if (doPset) [[likely]] {
1501 vram.cmdWrite(Mode::addressOf(ADX, DY, dstExt),
1502 tmpSrc, calculator.getTime());
1503 }
1504 ASX += TX; ADX += TX;
1505 Delta delta = Delta::D64;
1506 if (--ANX == 0) {
1507 delta = Delta::D128; // 64 + 64
1508 SY += TY; DY += TY; --NY;
1509 ASX = SX; ADX = DX; ANX = tmpNX;
1510 if (--tmpNY == 0) {
1511 commandDone(calculator.getTime());
1512 break;
1513 }
1514 }
1515 calculator.next(delta);
1516 goto loop;
1517 }
1518 default:
1520 }
1521 engineTime = calculator.getTime();
1522 calcFinishTime(tmpNX, tmpNY, 24 + 64);
1523
1524 /*if (srcExt || dstExt) [[unlikely]] {
1525 bool doPoint = !srcExt || hasExtendedVRAM;
1526 bool doPset = !dstExt || hasExtendedVRAM;
1527 while (engineTime < limit) {
1528 if (doPset) [[likely]] {
1529 auto p = [&] () -> byte {
1530 if (doPoint) [[likely]] {
1531 return vram.cmdReadWindow.readNP(Mode::addressOf(ASX, SY, srcExt));
1532 } else {
1533 return 0xFF;
1534 }
1535 }();
1536 vram.cmdWrite(Mode::addressOf(ADX, DY, dstExt),
1537 p, engineTime);
1538 }
1539 engineTime += delta;
1540 ASX += TX; ADX += TX;
1541 if (--ANX == 0) {
1542 SY += TY; DY += TY; --NY;
1543 ASX = SX; ADX = DX; ANX = tmpNX;
1544 if (--tmpNY == 0) {
1545 commandDone(engineTime);
1546 break;
1547 }
1548 }
1549 }
1550 } else {
1551 // fast-path, no extended VRAM
1552 while (engineTime < limit) {
1553 typename Mode::IncrByteAddr srcAddr(ASX, SY, TX);
1554 typename Mode::IncrByteAddr dstAddr(ADX, DY, TX);
1555 EmuDuration dur = limit - engineTime;
1556 unsigned num = (delta != EmuDuration::zero())
1557 ? std::min(dur.divUp(delta), ANX)
1558 : ANX;
1559 for (auto i : xrange(num)) {
1560 byte p = vram.cmdReadWindow.readNP(srcAddr.getAddr());
1561 vram.cmdWrite(dstAddr.getAddr(), p, engineTime);
1562 engineTime += delta;
1563 srcAddr.step(TX);
1564 dstAddr.step(TX);
1565 }
1566 ANX -= num;
1567 if (ANX == 0) {
1568 SY += TY;
1569 DY += TY;
1570 NY -= 1;
1571 ASX = SX;
1572 ADX = DX;
1573 ANX = tmpNX;
1574 if (--tmpNY == 0) {
1575 commandDone(engineTime);
1576 break;
1577 }
1578 } else {
1579 ASX += num * TX;
1580 ADX += num * TX;
1581 assert(engineTime >= limit);
1582 break;
1583 }
1584 }
1585 }
1586 */
1587}
1588
1591template<typename Mode>
1592void VDPCmdEngine::startYmmm(EmuTime::param time)
1593{
1594 vram.cmdReadWindow .setMask(0x3FFFF, ~0u << 18, time);
1595 vram.cmdWriteWindow.setMask(0x3FFFF, ~0u << 18, time);
1596 NY &= 1023;
1597 unsigned tmpNX = clipNX_1_byte<Mode>(DX, 512, ARG);
1598 // large enough so that it gets clipped
1599 unsigned tmpNY = clipNY_2(SY, DY, NY, ARG);
1600 ADX = DX;
1601 ANX = tmpNX;
1602 nextAccessSlot(time);
1603 calcFinishTime(tmpNX, tmpNY, 24 + 40);
1604 phase = 0;
1605}
1606
1607template<typename Mode>
1608void VDPCmdEngine::executeYmmm(EmuTime::param limit)
1609{
1610 NY &= 1023;
1611 unsigned tmpNX = clipNX_1_byte<Mode>(DX, 512, ARG);
1612 // large enough so that it gets clipped
1613 unsigned tmpNY = clipNY_2(SY, DY, NY, ARG);
1614 int TX = (ARG & DIX)
1615 ? -Mode::PIXELS_PER_BYTE : Mode::PIXELS_PER_BYTE;
1616 int TY = (ARG & DIY) ? -1 : 1;
1617 ANX = clipNX_1_byte<Mode>(ADX, 512, ARG);
1618
1619 // TODO does this use MXD for both read and write?
1620 // it says so in the datasheet, but it seems illogical
1621 // OTOH YMMM also uses DX for both read and write
1622 bool dstExt = (ARG & MXD) != 0;
1623 bool doPset = !dstExt || hasExtendedVRAM;
1624 auto calculator = getSlotCalculator(limit);
1625
1626 switch (phase) {
1627 case 0:
1628loop: if (calculator.limitReached()) [[unlikely]] { phase = 0; break; }
1629 if (doPset) [[likely]] {
1630 tmpSrc = vram.cmdReadWindow.readNP(
1631 Mode::addressOf(ADX, SY, dstExt));
1632 }
1633 calculator.next(Delta::D24);
1634 [[fallthrough]];
1635 case 1:
1636 if (calculator.limitReached()) [[unlikely]] { phase = 1; break; }
1637 if (doPset) [[likely]] {
1638 vram.cmdWrite(Mode::addressOf(ADX, DY, dstExt),
1639 tmpSrc, calculator.getTime());
1640 }
1641 ADX += TX;
1642 if (--ANX == 0) {
1643 // note: going to the next line does not take extra time
1644 SY += TY; DY += TY; --NY;
1645 ADX = DX; ANX = tmpNX;
1646 if (--tmpNY == 0) {
1647 commandDone(calculator.getTime());
1648 break;
1649 }
1650 }
1651 calculator.next(Delta::D40);
1652 goto loop;
1653 default:
1655 }
1656 engineTime = calculator.getTime();
1657 calcFinishTime(tmpNX, tmpNY, 24 + 40);
1658
1659 /*
1660 if (dstExt) [[unlikely]] {
1661 bool doPset = !dstExt || hasExtendedVRAM;
1662 while (engineTime < limit) {
1663 if (doPset) [[likely]] {
1664 byte p = vram.cmdReadWindow.readNP(
1665 Mode::addressOf(ADX, SY, dstExt));
1666 vram.cmdWrite(Mode::addressOf(ADX, DY, dstExt),
1667 p, engineTime);
1668 }
1669 engineTime += delta;
1670 ADX += TX;
1671 if (--ANX == 0) {
1672 SY += TY; DY += TY; --NY;
1673 ADX = DX; ANX = tmpNX;
1674 if (--tmpNY == 0) {
1675 commandDone(engineTime);
1676 break;
1677 }
1678 }
1679 }
1680 } else {
1681 // fast-path, no extended VRAM
1682 while (engineTime < limit) {
1683 typename Mode::IncrByteAddr srcAddr(ADX, SY, TX);
1684 typename Mode::IncrByteAddr dstAddr(ADX, DY, TX);
1685 EmuDuration dur = limit - engineTime;
1686 unsigned num = (delta != EmuDuration::zero())
1687 ? std::min(dur.divUp(delta), ANX)
1688 : ANX;
1689 for (auto i : xrange(num)) {
1690 byte p = vram.cmdReadWindow.readNP(srcAddr.getAddr());
1691 vram.cmdWrite(dstAddr.getAddr(), p, engineTime);
1692 engineTime += delta;
1693 srcAddr.step(TX);
1694 dstAddr.step(TX);
1695 }
1696 ANX -= num;
1697 if (ANX == 0) {
1698 SY += TY;
1699 DY += TY;
1700 NY -= 1;
1701 ADX = DX;
1702 ANX = tmpNX;
1703 if (--tmpNY == 0) {
1704 commandDone(engineTime);
1705 break;
1706 }
1707 } else {
1708 ADX += num * TX;
1709 assert(engineTime >= limit);
1710 break;
1711 }
1712 }
1713 }
1714 */
1715}
1716
1719template<typename Mode>
1720void VDPCmdEngine::startHmmc(EmuTime::param time)
1721{
1722 vram.cmdReadWindow.disable(time);
1723 vram.cmdWriteWindow.setMask(0x3FFFF, ~0u << 18, time);
1724 NY &= 1023;
1725 unsigned tmpNX = clipNX_1_byte<Mode>(DX, NX, ARG);
1726 ADX = DX;
1727 ANX = tmpNX;
1728 setStatusChangeTime(EmuTime::zero());
1729 // do not set 'transfer = true', see startLmmc()
1730 status |= 0x80;
1731 nextAccessSlot(time);
1732}
1733
1734template<typename Mode>
1735void VDPCmdEngine::executeHmmc(EmuTime::param limit)
1736{
1737 NY &= 1023;
1738 unsigned tmpNX = clipNX_1_byte<Mode>(DX, NX, ARG);
1739 unsigned tmpNY = clipNY_1(DY, NY, ARG);
1740 int TX = (ARG & DIX)
1741 ? -Mode::PIXELS_PER_BYTE : Mode::PIXELS_PER_BYTE;
1742 int TY = (ARG & DIY) ? -1 : 1;
1743 ANX = clipNX_1_byte<Mode>(
1744 ADX, ANX << Mode::PIXELS_PER_BYTE_SHIFT, ARG);
1745 bool dstExt = (ARG & MXD) != 0;
1746 bool doPset = !dstExt || hasExtendedVRAM;
1747
1748 if (transfer) {
1749 // TODO: timing is inaccurate. We should
1750 // - wait for a byte
1751 // - on the next access slot write that byte
1752 if (doPset) [[likely]] {
1753 vram.cmdWrite(Mode::addressOf(ADX, DY, dstExt),
1754 COL, limit);
1755 }
1756 transfer = false;
1757
1758 ADX += TX; --ANX;
1759 if (ANX == 0) {
1760 DY += TY; --NY;
1761 ADX = DX; ANX = tmpNX;
1762 if (--tmpNY == 0) {
1763 commandDone(limit);
1764 }
1765 }
1766 }
1767 nextAccessSlot(limit); // inaccurate, but avoid assert
1768}
1769
1770
1772 : vdp(vdp_), vram(vdp.getVRAM())
1773 , cmdTraceSetting(
1774 commandController, vdp_.getName() == "VDP" ? "vdpcmdtrace" :
1775 vdp_.getName() + " vdpcmdtrace", "VDP command tracing on/off",
1776 false)
1777 , cmdInProgressCallback(
1778 commandController, vdp_.getName() == "VDP" ?
1779 "vdpcmdinprogress_callback" : vdp_.getName() +
1780 " vdpcmdinprogress_callback",
1781 "Tcl proc to call when a write to the VDP command engine is "
1782 "detected while the previous command is still in progress.",
1783 "",
1784 Setting::Save::YES)
1785 , executingProbe(
1786 vdp_.getMotherBoard().getDebugger(),
1787 strCat(vdp.getName(), '.', "commandExecuting"),
1788 "Is the V99x8 VDP is currently executing a command",
1789 false)
1790 , hasExtendedVRAM(vram.getSize() == (192 * 1024))
1791{
1792}
1793
1794void VDPCmdEngine::reset(EmuTime::param time)
1795{
1796 for (int i = 14; i >= 0; --i) { // start with ABORT
1797 setCmdReg(byte(i), 0, time);
1798 }
1799 status = 0;
1800 scrMode = -1;
1801
1802 updateDisplayMode(vdp.getDisplayMode(), vdp.getCmdBit(), time);
1803}
1804
1805void VDPCmdEngine::setCmdReg(byte index, byte value, EmuTime::param time)
1806{
1807 sync(time);
1808 if (CMD && (index != 12)) {
1809 cmdInProgressCallback.execute(index, value);
1810 }
1811 switch (index) {
1812 case 0x00: // source X low
1813 SX = (SX & 0x100) | value;
1814 break;
1815 case 0x01: // source X high
1816 SX = (SX & 0x0FF) | ((value & 0x01) << 8);
1817 break;
1818 case 0x02: // source Y low
1819 SY = (SY & 0x300) | value;
1820 break;
1821 case 0x03: // source Y high
1822 SY = (SY & 0x0FF) | ((value & 0x03) << 8);
1823 break;
1824
1825 case 0x04: // destination X low
1826 DX = (DX & 0x100) | value;
1827 break;
1828 case 0x05: // destination X high
1829 DX = (DX & 0x0FF) | ((value & 0x01) << 8);
1830 break;
1831 case 0x06: // destination Y low
1832 DY = (DY & 0x300) | value;
1833 break;
1834 case 0x07: // destination Y high
1835 DY = (DY & 0x0FF) | ((value & 0x03) << 8);
1836 break;
1837
1838 // TODO is DX 9 or 10 bits, at least current implementation needs
1839 // 10 bits (otherwise texts in UR are screwed)
1840 case 0x08: // number X low
1841 NX = (NX & 0x300) | value;
1842 break;
1843 case 0x09: // number X high
1844 NX = (NX & 0x0FF) | ((value & 0x03) << 8);
1845 break;
1846 case 0x0A: // number Y low
1847 NY = (NY & 0x300) | value;
1848 break;
1849 case 0x0B: // number Y high
1850 NY = (NY & 0x0FF) | ((value & 0x03) << 8);
1851 break;
1852
1853 case 0x0C: // color
1854 COL = value;
1855 // Note: Real VDP always resets TR, but for such a short time
1856 // that the MSX won't notice it.
1857 // TODO: What happens on non-transfer commands?
1858 if (!CMD) status &= 0x7F;
1859 transfer = true;
1860 break;
1861 case 0x0D: // argument
1862 ARG = value;
1863 break;
1864 case 0x0E: // command
1865 CMD = value;
1866 executeCommand(time);
1867 break;
1868 default:
1870 }
1871}
1872
1873byte VDPCmdEngine::peekCmdReg(byte index) const
1874{
1875 switch (index) {
1876 case 0x00: return narrow_cast<byte>(SX & 0xFF);
1877 case 0x01: return narrow_cast<byte>(SX >> 8);
1878 case 0x02: return narrow_cast<byte>(SY & 0xFF);
1879 case 0x03: return narrow_cast<byte>(SY >> 8);
1880
1881 case 0x04: return narrow_cast<byte>(DX & 0xFF);
1882 case 0x05: return narrow_cast<byte>(DX >> 8);
1883 case 0x06: return narrow_cast<byte>(DY & 0xFF);
1884 case 0x07: return narrow_cast<byte>(DY >> 8);
1885
1886 case 0x08: return narrow_cast<byte>(NX & 0xFF);
1887 case 0x09: return narrow_cast<byte>(NX >> 8);
1888 case 0x0A: return narrow_cast<byte>(NY & 0xFF);
1889 case 0x0B: return narrow_cast<byte>(NY >> 8);
1890
1891 case 0x0C: return COL;
1892 case 0x0D: return ARG;
1893 case 0x0E: return CMD;
1894 default: UNREACHABLE;
1895 }
1896}
1897
1898void VDPCmdEngine::updateDisplayMode(DisplayMode mode, bool cmdBit, EmuTime::param time)
1899{
1900 int newScrMode = [&] {
1901 switch (mode.getBase()) {
1903 return 0;
1905 return 1;
1907 return 2;
1909 return 3;
1910 default:
1911 if (cmdBit) {
1912 return 4; // like GRAPHIC7, but non-planar
1913 // TODO timing might be different
1914 } else {
1915 return -1; // no commands
1916 }
1917 }
1918 }();
1919
1920 if (newScrMode != scrMode) {
1921 sync(time);
1922 if (CMD) {
1923 // VDP mode switch while command in progress
1924 if (newScrMode == -1) {
1925 // TODO: For now abort cmd in progress,
1926 // later find out what really happens.
1927 // At least CE remains high for a while,
1928 // but it is not yet clear what happens in VRAM.
1929 commandDone(time);
1930 }
1931 }
1932 scrMode = newScrMode;
1933 }
1934}
1935
1936void VDPCmdEngine::executeCommand(EmuTime::param time)
1937{
1938 // V9938 ops only work in SCREEN 5-8.
1939 // V9958 ops work in non SCREEN 5-8 when CMD bit is set
1940 if (scrMode < 0) {
1941 commandDone(time);
1942 return;
1943 }
1944
1945 if (cmdTraceSetting.getBoolean()) {
1946 reportVdpCommand();
1947 }
1948
1949 // Start command.
1950 status |= 0x01;
1951 executingProbe = true;
1952
1953 switch ((scrMode << 4) | (CMD >> 4)) {
1954 case 0x00: case 0x10: case 0x20: case 0x30: case 0x40:
1955 case 0x01: case 0x11: case 0x21: case 0x31: case 0x41:
1956 case 0x02: case 0x12: case 0x22: case 0x32: case 0x42:
1957 case 0x03: case 0x13: case 0x23: case 0x33: case 0x43:
1958 startAbrt(time); break;
1959
1960 case 0x04: case 0x14: case 0x24: case 0x34: case 0x44:
1961 startPoint(time); break;
1962 case 0x05: case 0x15: case 0x25: case 0x35: case 0x45:
1963 startPset(time); break;
1964 case 0x06: case 0x16: case 0x26: case 0x36: case 0x46:
1965 startSrch(time); break;
1966 case 0x07: case 0x17: case 0x27: case 0x37: case 0x47:
1967 startLine(time); break;
1968
1969 case 0x08: startLmmv<Graphic4Mode >(time); break;
1970 case 0x18: startLmmv<Graphic5Mode >(time); break;
1971 case 0x28: startLmmv<Graphic6Mode >(time); break;
1972 case 0x38: startLmmv<Graphic7Mode >(time); break;
1973 case 0x48: startLmmv<NonBitmapMode>(time); break;
1974
1975 case 0x09: startLmmm<Graphic4Mode >(time); break;
1976 case 0x19: startLmmm<Graphic5Mode >(time); break;
1977 case 0x29: startLmmm<Graphic6Mode >(time); break;
1978 case 0x39: startLmmm<Graphic7Mode >(time); break;
1979 case 0x49: startLmmm<NonBitmapMode>(time); break;
1980
1981 case 0x0A: startLmcm<Graphic4Mode >(time); break;
1982 case 0x1A: startLmcm<Graphic5Mode >(time); break;
1983 case 0x2A: startLmcm<Graphic6Mode >(time); break;
1984 case 0x3A: startLmcm<Graphic7Mode >(time); break;
1985 case 0x4A: startLmcm<NonBitmapMode>(time); break;
1986
1987 case 0x0B: startLmmc<Graphic4Mode >(time); break;
1988 case 0x1B: startLmmc<Graphic5Mode >(time); break;
1989 case 0x2B: startLmmc<Graphic6Mode >(time); break;
1990 case 0x3B: startLmmc<Graphic7Mode >(time); break;
1991 case 0x4B: startLmmc<NonBitmapMode>(time); break;
1992
1993 case 0x0C: startHmmv<Graphic4Mode >(time); break;
1994 case 0x1C: startHmmv<Graphic5Mode >(time); break;
1995 case 0x2C: startHmmv<Graphic6Mode >(time); break;
1996 case 0x3C: startHmmv<Graphic7Mode >(time); break;
1997 case 0x4C: startHmmv<NonBitmapMode>(time); break;
1998
1999 case 0x0D: startHmmm<Graphic4Mode >(time); break;
2000 case 0x1D: startHmmm<Graphic5Mode >(time); break;
2001 case 0x2D: startHmmm<Graphic6Mode >(time); break;
2002 case 0x3D: startHmmm<Graphic7Mode >(time); break;
2003 case 0x4D: startHmmm<NonBitmapMode>(time); break;
2004
2005 case 0x0E: startYmmm<Graphic4Mode >(time); break;
2006 case 0x1E: startYmmm<Graphic5Mode >(time); break;
2007 case 0x2E: startYmmm<Graphic6Mode >(time); break;
2008 case 0x3E: startYmmm<Graphic7Mode >(time); break;
2009 case 0x4E: startYmmm<NonBitmapMode>(time); break;
2010
2011 case 0x0F: startHmmc<Graphic4Mode >(time); break;
2012 case 0x1F: startHmmc<Graphic5Mode >(time); break;
2013 case 0x2F: startHmmc<Graphic6Mode >(time); break;
2014 case 0x3F: startHmmc<Graphic7Mode >(time); break;
2015 case 0x4F: startHmmc<NonBitmapMode>(time); break;
2016
2017 default: UNREACHABLE;
2018 }
2019}
2020
2021void VDPCmdEngine::sync2(EmuTime::param time)
2022{
2023 switch ((scrMode << 8) | CMD) {
2024 case 0x000: case 0x100: case 0x200: case 0x300: case 0x400:
2025 case 0x001: case 0x101: case 0x201: case 0x301: case 0x401:
2026 case 0x002: case 0x102: case 0x202: case 0x302: case 0x402:
2027 case 0x003: case 0x103: case 0x203: case 0x303: case 0x403:
2028 case 0x004: case 0x104: case 0x204: case 0x304: case 0x404:
2029 case 0x005: case 0x105: case 0x205: case 0x305: case 0x405:
2030 case 0x006: case 0x106: case 0x206: case 0x306: case 0x406:
2031 case 0x007: case 0x107: case 0x207: case 0x307: case 0x407:
2032 case 0x008: case 0x108: case 0x208: case 0x308: case 0x408:
2033 case 0x009: case 0x109: case 0x209: case 0x309: case 0x409:
2034 case 0x00A: case 0x10A: case 0x20A: case 0x30A: case 0x40A:
2035 case 0x00B: case 0x10B: case 0x20B: case 0x30B: case 0x40B:
2036 case 0x00C: case 0x10C: case 0x20C: case 0x30C: case 0x40C:
2037 case 0x00D: case 0x10D: case 0x20D: case 0x30D: case 0x40D:
2038 case 0x00E: case 0x10E: case 0x20E: case 0x30E: case 0x40E:
2039 case 0x00F: case 0x10F: case 0x20F: case 0x30F: case 0x40F:
2040 case 0x010: case 0x110: case 0x210: case 0x310: case 0x410:
2041 case 0x011: case 0x111: case 0x211: case 0x311: case 0x411:
2042 case 0x012: case 0x112: case 0x212: case 0x312: case 0x412:
2043 case 0x013: case 0x113: case 0x213: case 0x313: case 0x413:
2044 case 0x014: case 0x114: case 0x214: case 0x314: case 0x414:
2045 case 0x015: case 0x115: case 0x215: case 0x315: case 0x415:
2046 case 0x016: case 0x116: case 0x216: case 0x316: case 0x416:
2047 case 0x017: case 0x117: case 0x217: case 0x317: case 0x417:
2048 case 0x018: case 0x118: case 0x218: case 0x318: case 0x418:
2049 case 0x019: case 0x119: case 0x219: case 0x319: case 0x419:
2050 case 0x01A: case 0x11A: case 0x21A: case 0x31A: case 0x41A:
2051 case 0x01B: case 0x11B: case 0x21B: case 0x31B: case 0x41B:
2052 case 0x01C: case 0x11C: case 0x21C: case 0x31C: case 0x41C:
2053 case 0x01D: case 0x11D: case 0x21D: case 0x31D: case 0x41D:
2054 case 0x01E: case 0x11E: case 0x21E: case 0x31E: case 0x41E:
2055 case 0x01F: case 0x11F: case 0x21F: case 0x31F: case 0x41F:
2056 case 0x020: case 0x120: case 0x220: case 0x320: case 0x420:
2057 case 0x021: case 0x121: case 0x221: case 0x321: case 0x421:
2058 case 0x022: case 0x122: case 0x222: case 0x322: case 0x422:
2059 case 0x023: case 0x123: case 0x223: case 0x323: case 0x423:
2060 case 0x024: case 0x124: case 0x224: case 0x324: case 0x424:
2061 case 0x025: case 0x125: case 0x225: case 0x325: case 0x425:
2062 case 0x026: case 0x126: case 0x226: case 0x326: case 0x426:
2063 case 0x027: case 0x127: case 0x227: case 0x327: case 0x427:
2064 case 0x028: case 0x128: case 0x228: case 0x328: case 0x428:
2065 case 0x029: case 0x129: case 0x229: case 0x329: case 0x429:
2066 case 0x02A: case 0x12A: case 0x22A: case 0x32A: case 0x42A:
2067 case 0x02B: case 0x12B: case 0x22B: case 0x32B: case 0x42B:
2068 case 0x02C: case 0x12C: case 0x22C: case 0x32C: case 0x42C:
2069 case 0x02D: case 0x12D: case 0x22D: case 0x32D: case 0x42D:
2070 case 0x02E: case 0x12E: case 0x22E: case 0x32E: case 0x42E:
2071 case 0x02F: case 0x12F: case 0x22F: case 0x32F: case 0x42F:
2072 case 0x030: case 0x130: case 0x230: case 0x330: case 0x430:
2073 case 0x031: case 0x131: case 0x231: case 0x331: case 0x431:
2074 case 0x032: case 0x132: case 0x232: case 0x332: case 0x432:
2075 case 0x033: case 0x133: case 0x233: case 0x333: case 0x433:
2076 case 0x034: case 0x134: case 0x234: case 0x334: case 0x434:
2077 case 0x035: case 0x135: case 0x235: case 0x335: case 0x435:
2078 case 0x036: case 0x136: case 0x236: case 0x336: case 0x436:
2079 case 0x037: case 0x137: case 0x237: case 0x337: case 0x437:
2080 case 0x038: case 0x138: case 0x238: case 0x338: case 0x438:
2081 case 0x039: case 0x139: case 0x239: case 0x339: case 0x439:
2082 case 0x03A: case 0x13A: case 0x23A: case 0x33A: case 0x43A:
2083 case 0x03B: case 0x13B: case 0x23B: case 0x33B: case 0x43B:
2084 case 0x03C: case 0x13C: case 0x23C: case 0x33C: case 0x43C:
2085 case 0x03D: case 0x13D: case 0x23D: case 0x33D: case 0x43D:
2086 case 0x03E: case 0x13E: case 0x23E: case 0x33E: case 0x43E:
2087 case 0x03F: case 0x13F: case 0x23F: case 0x33F: case 0x43F:
2089
2090 case 0x040: case 0x041: case 0x042: case 0x043:
2091 case 0x044: case 0x045: case 0x046: case 0x047:
2092 case 0x048: case 0x049: case 0x04A: case 0x04B:
2093 case 0x04C: case 0x04D: case 0x04E: case 0x04F:
2094 executePoint<Graphic4Mode>(time); break;
2095 case 0x140: case 0x141: case 0x142: case 0x143:
2096 case 0x144: case 0x145: case 0x146: case 0x147:
2097 case 0x148: case 0x149: case 0x14A: case 0x14B:
2098 case 0x14C: case 0x14D: case 0x14E: case 0x14F:
2099 executePoint<Graphic5Mode>(time); break;
2100 case 0x240: case 0x241: case 0x242: case 0x243:
2101 case 0x244: case 0x245: case 0x246: case 0x247:
2102 case 0x248: case 0x249: case 0x24A: case 0x24B:
2103 case 0x24C: case 0x24D: case 0x24E: case 0x24F:
2104 executePoint<Graphic6Mode>(time); break;
2105 case 0x340: case 0x341: case 0x342: case 0x343:
2106 case 0x344: case 0x345: case 0x346: case 0x347:
2107 case 0x348: case 0x349: case 0x34A: case 0x34B:
2108 case 0x34C: case 0x34D: case 0x34E: case 0x34F:
2109 executePoint<Graphic7Mode>(time); break;
2110 case 0x440: case 0x441: case 0x442: case 0x443:
2111 case 0x444: case 0x445: case 0x446: case 0x447:
2112 case 0x448: case 0x449: case 0x44A: case 0x44B:
2113 case 0x44C: case 0x44D: case 0x44E: case 0x44F:
2114 executePoint<NonBitmapMode>(time); break;
2115
2116 case 0x050: executePset<Graphic4Mode, ImpOp>(time); break;
2117 case 0x051: executePset<Graphic4Mode, AndOp>(time); break;
2118 case 0x052: executePset<Graphic4Mode, OrOp >(time); break;
2119 case 0x053: executePset<Graphic4Mode, XorOp>(time); break;
2120 case 0x054: executePset<Graphic4Mode, NotOp>(time); break;
2121 case 0x058: executePset<Graphic4Mode, TImpOp>(time); break;
2122 case 0x059: executePset<Graphic4Mode, TAndOp>(time); break;
2123 case 0x05A: executePset<Graphic4Mode, TOrOp >(time); break;
2124 case 0x05B: executePset<Graphic4Mode, TXorOp>(time); break;
2125 case 0x05C: executePset<Graphic4Mode, TNotOp>(time); break;
2126 case 0x055: case 0x056: case 0x057: case 0x05D: case 0x05E: case 0x05F:
2127 executePset<Graphic4Mode, DummyOp>(time); break;
2128 case 0x150: executePset<Graphic5Mode, ImpOp>(time); break;
2129 case 0x151: executePset<Graphic5Mode, AndOp>(time); break;
2130 case 0x152: executePset<Graphic5Mode, OrOp >(time); break;
2131 case 0x153: executePset<Graphic5Mode, XorOp>(time); break;
2132 case 0x154: executePset<Graphic5Mode, NotOp>(time); break;
2133 case 0x158: executePset<Graphic5Mode, TImpOp>(time); break;
2134 case 0x159: executePset<Graphic5Mode, TAndOp>(time); break;
2135 case 0x15A: executePset<Graphic5Mode, TOrOp >(time); break;
2136 case 0x15B: executePset<Graphic5Mode, TXorOp>(time); break;
2137 case 0x15C: executePset<Graphic5Mode, TNotOp>(time); break;
2138 case 0x155: case 0x156: case 0x157: case 0x15D: case 0x15E: case 0x15F:
2139 executePset<Graphic5Mode, DummyOp>(time); break;
2140 case 0x250: executePset<Graphic6Mode, ImpOp>(time); break;
2141 case 0x251: executePset<Graphic6Mode, AndOp>(time); break;
2142 case 0x252: executePset<Graphic6Mode, OrOp >(time); break;
2143 case 0x253: executePset<Graphic6Mode, XorOp>(time); break;
2144 case 0x254: executePset<Graphic6Mode, NotOp>(time); break;
2145 case 0x258: executePset<Graphic6Mode, TImpOp>(time); break;
2146 case 0x259: executePset<Graphic6Mode, TAndOp>(time); break;
2147 case 0x25A: executePset<Graphic6Mode, TOrOp >(time); break;
2148 case 0x25B: executePset<Graphic6Mode, TXorOp>(time); break;
2149 case 0x25C: executePset<Graphic6Mode, TNotOp>(time); break;
2150 case 0x255: case 0x256: case 0x257: case 0x25D: case 0x25E: case 0x25F:
2151 executePset<Graphic6Mode, DummyOp>(time); break;
2152 case 0x350: executePset<Graphic7Mode, ImpOp>(time); break;
2153 case 0x351: executePset<Graphic7Mode, AndOp>(time); break;
2154 case 0x352: executePset<Graphic7Mode, OrOp >(time); break;
2155 case 0x353: executePset<Graphic7Mode, XorOp>(time); break;
2156 case 0x354: executePset<Graphic7Mode, NotOp>(time); break;
2157 case 0x358: executePset<Graphic7Mode, TImpOp>(time); break;
2158 case 0x359: executePset<Graphic7Mode, TAndOp>(time); break;
2159 case 0x35A: executePset<Graphic7Mode, TOrOp >(time); break;
2160 case 0x35B: executePset<Graphic7Mode, TXorOp>(time); break;
2161 case 0x35C: executePset<Graphic7Mode, TNotOp>(time); break;
2162 case 0x355: case 0x356: case 0x357: case 0x35D: case 0x35E: case 0x35F:
2163 executePset<Graphic7Mode, DummyOp>(time); break;
2164 case 0x450: executePset<NonBitmapMode, ImpOp>(time); break;
2165 case 0x451: executePset<NonBitmapMode, AndOp>(time); break;
2166 case 0x452: executePset<NonBitmapMode, OrOp >(time); break;
2167 case 0x453: executePset<NonBitmapMode, XorOp>(time); break;
2168 case 0x454: executePset<NonBitmapMode, NotOp>(time); break;
2169 case 0x458: executePset<NonBitmapMode, TImpOp>(time); break;
2170 case 0x459: executePset<NonBitmapMode, TAndOp>(time); break;
2171 case 0x45A: executePset<NonBitmapMode, TOrOp >(time); break;
2172 case 0x45B: executePset<NonBitmapMode, TXorOp>(time); break;
2173 case 0x45C: executePset<NonBitmapMode, TNotOp>(time); break;
2174 case 0x455: case 0x456: case 0x457: case 0x45D: case 0x45E: case 0x45F:
2175 executePset<NonBitmapMode, DummyOp>(time); break;
2176
2177 case 0x060: case 0x061: case 0x062: case 0x063:
2178 case 0x064: case 0x065: case 0x066: case 0x067:
2179 case 0x068: case 0x069: case 0x06A: case 0x06B:
2180 case 0x06C: case 0x06D: case 0x06E: case 0x06F:
2181 executeSrch<Graphic4Mode>(time); break;
2182 case 0x160: case 0x161: case 0x162: case 0x163:
2183 case 0x164: case 0x165: case 0x166: case 0x167:
2184 case 0x168: case 0x169: case 0x16A: case 0x16B:
2185 case 0x16C: case 0x16D: case 0x16E: case 0x16F:
2186 executeSrch<Graphic5Mode>(time); break;
2187 case 0x260: case 0x261: case 0x262: case 0x263:
2188 case 0x264: case 0x265: case 0x266: case 0x267:
2189 case 0x268: case 0x269: case 0x26A: case 0x26B:
2190 case 0x26C: case 0x26D: case 0x26E: case 0x26F:
2191 executeSrch<Graphic6Mode>(time); break;
2192 case 0x360: case 0x361: case 0x362: case 0x363:
2193 case 0x364: case 0x365: case 0x366: case 0x367:
2194 case 0x368: case 0x369: case 0x36A: case 0x36B:
2195 case 0x36C: case 0x36D: case 0x36E: case 0x36F:
2196 executeSrch<Graphic7Mode>(time); break;
2197 case 0x460: case 0x461: case 0x462: case 0x463:
2198 case 0x464: case 0x465: case 0x466: case 0x467:
2199 case 0x468: case 0x469: case 0x46A: case 0x46B:
2200 case 0x46C: case 0x46D: case 0x46E: case 0x46F:
2201 executeSrch<NonBitmapMode>(time); break;
2202
2203 case 0x070: executeLine<Graphic4Mode, ImpOp>(time); break;
2204 case 0x071: executeLine<Graphic4Mode, AndOp>(time); break;
2205 case 0x072: executeLine<Graphic4Mode, OrOp >(time); break;
2206 case 0x073: executeLine<Graphic4Mode, XorOp>(time); break;
2207 case 0x074: executeLine<Graphic4Mode, NotOp>(time); break;
2208 case 0x078: executeLine<Graphic4Mode, TImpOp>(time); break;
2209 case 0x079: executeLine<Graphic4Mode, TAndOp>(time); break;
2210 case 0x07A: executeLine<Graphic4Mode, TOrOp >(time); break;
2211 case 0x07B: executeLine<Graphic4Mode, TXorOp>(time); break;
2212 case 0x07C: executeLine<Graphic4Mode, TNotOp>(time); break;
2213 case 0x075: case 0x076: case 0x077: case 0x07D: case 0x07E: case 0x07F:
2214 executeLine<Graphic4Mode, DummyOp>(time); break;
2215 case 0x170: executeLine<Graphic5Mode, ImpOp>(time); break;
2216 case 0x171: executeLine<Graphic5Mode, AndOp>(time); break;
2217 case 0x172: executeLine<Graphic5Mode, OrOp >(time); break;
2218 case 0x173: executeLine<Graphic5Mode, XorOp>(time); break;
2219 case 0x174: executeLine<Graphic5Mode, NotOp>(time); break;
2220 case 0x178: executeLine<Graphic5Mode, TImpOp>(time); break;
2221 case 0x179: executeLine<Graphic5Mode, TAndOp>(time); break;
2222 case 0x17A: executeLine<Graphic5Mode, TOrOp >(time); break;
2223 case 0x17B: executeLine<Graphic5Mode, TXorOp>(time); break;
2224 case 0x17C: executeLine<Graphic5Mode, TNotOp>(time); break;
2225 case 0x175: case 0x176: case 0x177: case 0x17D: case 0x17E: case 0x17F:
2226 executeLine<Graphic5Mode, DummyOp>(time); break;
2227 case 0x270: executeLine<Graphic6Mode, ImpOp>(time); break;
2228 case 0x271: executeLine<Graphic6Mode, AndOp>(time); break;
2229 case 0x272: executeLine<Graphic6Mode, OrOp >(time); break;
2230 case 0x273: executeLine<Graphic6Mode, XorOp>(time); break;
2231 case 0x274: executeLine<Graphic6Mode, NotOp>(time); break;
2232 case 0x278: executeLine<Graphic6Mode, TImpOp>(time); break;
2233 case 0x279: executeLine<Graphic6Mode, TAndOp>(time); break;
2234 case 0x27A: executeLine<Graphic6Mode, TOrOp >(time); break;
2235 case 0x27B: executeLine<Graphic6Mode, TXorOp>(time); break;
2236 case 0x27C: executeLine<Graphic6Mode, TNotOp>(time); break;
2237 case 0x275: case 0x276: case 0x277: case 0x27D: case 0x27E: case 0x27F:
2238 executeLine<Graphic6Mode, DummyOp>(time); break;
2239 case 0x370: executeLine<Graphic7Mode, ImpOp>(time); break;
2240 case 0x371: executeLine<Graphic7Mode, AndOp>(time); break;
2241 case 0x372: executeLine<Graphic7Mode, OrOp >(time); break;
2242 case 0x373: executeLine<Graphic7Mode, XorOp>(time); break;
2243 case 0x374: executeLine<Graphic7Mode, NotOp>(time); break;
2244 case 0x378: executeLine<Graphic7Mode, TImpOp>(time); break;
2245 case 0x379: executeLine<Graphic7Mode, TAndOp>(time); break;
2246 case 0x37A: executeLine<Graphic7Mode, TOrOp >(time); break;
2247 case 0x37B: executeLine<Graphic7Mode, TXorOp>(time); break;
2248 case 0x37C: executeLine<Graphic7Mode, TNotOp>(time); break;
2249 case 0x375: case 0x376: case 0x377: case 0x37D: case 0x37E: case 0x37F:
2250 executeLine<Graphic7Mode, DummyOp>(time); break;
2251 case 0x470: executeLine<NonBitmapMode, ImpOp>(time); break;
2252 case 0x471: executeLine<NonBitmapMode, AndOp>(time); break;
2253 case 0x472: executeLine<NonBitmapMode, OrOp >(time); break;
2254 case 0x473: executeLine<NonBitmapMode, XorOp>(time); break;
2255 case 0x474: executeLine<NonBitmapMode, NotOp>(time); break;
2256 case 0x478: executeLine<NonBitmapMode, TImpOp>(time); break;
2257 case 0x479: executeLine<NonBitmapMode, TAndOp>(time); break;
2258 case 0x47A: executeLine<NonBitmapMode, TOrOp >(time); break;
2259 case 0x47B: executeLine<NonBitmapMode, TXorOp>(time); break;
2260 case 0x47C: executeLine<NonBitmapMode, TNotOp>(time); break;
2261 case 0x475: case 0x476: case 0x477: case 0x47D: case 0x47E: case 0x47F:
2262 executeLine<NonBitmapMode, DummyOp>(time); break;
2263
2264 case 0x080: executeLmmv<Graphic4Mode, ImpOp>(time); break;
2265 case 0x081: executeLmmv<Graphic4Mode, AndOp>(time); break;
2266 case 0x082: executeLmmv<Graphic4Mode, OrOp >(time); break;
2267 case 0x083: executeLmmv<Graphic4Mode, XorOp>(time); break;
2268 case 0x084: executeLmmv<Graphic4Mode, NotOp>(time); break;
2269 case 0x088: executeLmmv<Graphic4Mode, TImpOp>(time); break;
2270 case 0x089: executeLmmv<Graphic4Mode, TAndOp>(time); break;
2271 case 0x08A: executeLmmv<Graphic4Mode, TOrOp >(time); break;
2272 case 0x08B: executeLmmv<Graphic4Mode, TXorOp>(time); break;
2273 case 0x08C: executeLmmv<Graphic4Mode, TNotOp>(time); break;
2274 case 0x085: case 0x086: case 0x087: case 0x08D: case 0x08E: case 0x08F:
2275 executeLmmv<Graphic4Mode, DummyOp>(time); break;
2276 case 0x180: executeLmmv<Graphic5Mode, ImpOp>(time); break;
2277 case 0x181: executeLmmv<Graphic5Mode, AndOp>(time); break;
2278 case 0x182: executeLmmv<Graphic5Mode, OrOp >(time); break;
2279 case 0x183: executeLmmv<Graphic5Mode, XorOp>(time); break;
2280 case 0x184: executeLmmv<Graphic5Mode, NotOp>(time); break;
2281 case 0x188: executeLmmv<Graphic5Mode, TImpOp>(time); break;
2282 case 0x189: executeLmmv<Graphic5Mode, TAndOp>(time); break;
2283 case 0x18A: executeLmmv<Graphic5Mode, TOrOp >(time); break;
2284 case 0x18B: executeLmmv<Graphic5Mode, TXorOp>(time); break;
2285 case 0x18C: executeLmmv<Graphic5Mode, TNotOp>(time); break;
2286 case 0x185: case 0x186: case 0x187: case 0x18D: case 0x18E: case 0x18F:
2287 executeLmmv<Graphic5Mode, DummyOp>(time); break;
2288 case 0x280: executeLmmv<Graphic6Mode, ImpOp>(time); break;
2289 case 0x281: executeLmmv<Graphic6Mode, AndOp>(time); break;
2290 case 0x282: executeLmmv<Graphic6Mode, OrOp >(time); break;
2291 case 0x283: executeLmmv<Graphic6Mode, XorOp>(time); break;
2292 case 0x284: executeLmmv<Graphic6Mode, NotOp>(time); break;
2293 case 0x288: executeLmmv<Graphic6Mode, TImpOp>(time); break;
2294 case 0x289: executeLmmv<Graphic6Mode, TAndOp>(time); break;
2295 case 0x28A: executeLmmv<Graphic6Mode, TOrOp >(time); break;
2296 case 0x28B: executeLmmv<Graphic6Mode, TXorOp>(time); break;
2297 case 0x28C: executeLmmv<Graphic6Mode, TNotOp>(time); break;
2298 case 0x285: case 0x286: case 0x287: case 0x28D: case 0x28E: case 0x28F:
2299 executeLmmv<Graphic6Mode, DummyOp>(time); break;
2300 case 0x380: executeLmmv<Graphic7Mode, ImpOp>(time); break;
2301 case 0x381: executeLmmv<Graphic7Mode, AndOp>(time); break;
2302 case 0x382: executeLmmv<Graphic7Mode, OrOp >(time); break;
2303 case 0x383: executeLmmv<Graphic7Mode, XorOp>(time); break;
2304 case 0x384: executeLmmv<Graphic7Mode, NotOp>(time); break;
2305 case 0x388: executeLmmv<Graphic7Mode, TImpOp>(time); break;
2306 case 0x389: executeLmmv<Graphic7Mode, TAndOp>(time); break;
2307 case 0x38A: executeLmmv<Graphic7Mode, TOrOp >(time); break;
2308 case 0x38B: executeLmmv<Graphic7Mode, TXorOp>(time); break;
2309 case 0x38C: executeLmmv<Graphic7Mode, TNotOp>(time); break;
2310 case 0x385: case 0x386: case 0x387: case 0x38D: case 0x38E: case 0x38F:
2311 executeLmmv<Graphic7Mode, DummyOp>(time); break;
2312 case 0x480: executeLmmv<NonBitmapMode, ImpOp>(time); break;
2313 case 0x481: executeLmmv<NonBitmapMode, AndOp>(time); break;
2314 case 0x482: executeLmmv<NonBitmapMode, OrOp >(time); break;
2315 case 0x483: executeLmmv<NonBitmapMode, XorOp>(time); break;
2316 case 0x484: executeLmmv<NonBitmapMode, NotOp>(time); break;
2317 case 0x488: executeLmmv<NonBitmapMode, TImpOp>(time); break;
2318 case 0x489: executeLmmv<NonBitmapMode, TAndOp>(time); break;
2319 case 0x48A: executeLmmv<NonBitmapMode, TOrOp >(time); break;
2320 case 0x48B: executeLmmv<NonBitmapMode, TXorOp>(time); break;
2321 case 0x48C: executeLmmv<NonBitmapMode, TNotOp>(time); break;
2322 case 0x485: case 0x486: case 0x487: case 0x48D: case 0x48E: case 0x48F:
2323 executeLmmv<NonBitmapMode, DummyOp>(time); break;
2324
2325 case 0x090: executeLmmm<Graphic4Mode, ImpOp>(time); break;
2326 case 0x091: executeLmmm<Graphic4Mode, AndOp>(time); break;
2327 case 0x092: executeLmmm<Graphic4Mode, OrOp >(time); break;
2328 case 0x093: executeLmmm<Graphic4Mode, XorOp>(time); break;
2329 case 0x094: executeLmmm<Graphic4Mode, NotOp>(time); break;
2330 case 0x098: executeLmmm<Graphic4Mode, TImpOp>(time); break;
2331 case 0x099: executeLmmm<Graphic4Mode, TAndOp>(time); break;
2332 case 0x09A: executeLmmm<Graphic4Mode, TOrOp >(time); break;
2333 case 0x09B: executeLmmm<Graphic4Mode, TXorOp>(time); break;
2334 case 0x09C: executeLmmm<Graphic4Mode, TNotOp>(time); break;
2335 case 0x095: case 0x096: case 0x097: case 0x09D: case 0x09E: case 0x09F:
2336 executeLmmm<Graphic4Mode, DummyOp>(time); break;
2337 case 0x190: executeLmmm<Graphic5Mode, ImpOp>(time); break;
2338 case 0x191: executeLmmm<Graphic5Mode, AndOp>(time); break;
2339 case 0x192: executeLmmm<Graphic5Mode, OrOp >(time); break;
2340 case 0x193: executeLmmm<Graphic5Mode, XorOp>(time); break;
2341 case 0x194: executeLmmm<Graphic5Mode, NotOp>(time); break;
2342 case 0x198: executeLmmm<Graphic5Mode, TImpOp>(time); break;
2343 case 0x199: executeLmmm<Graphic5Mode, TAndOp>(time); break;
2344 case 0x19A: executeLmmm<Graphic5Mode, TOrOp >(time); break;
2345 case 0x19B: executeLmmm<Graphic5Mode, TXorOp>(time); break;
2346 case 0x19C: executeLmmm<Graphic5Mode, TNotOp>(time); break;
2347 case 0x195: case 0x196: case 0x197: case 0x19D: case 0x19E: case 0x19F:
2348 executeLmmm<Graphic5Mode, DummyOp>(time); break;
2349 case 0x290: executeLmmm<Graphic6Mode, ImpOp>(time); break;
2350 case 0x291: executeLmmm<Graphic6Mode, AndOp>(time); break;
2351 case 0x292: executeLmmm<Graphic6Mode, OrOp >(time); break;
2352 case 0x293: executeLmmm<Graphic6Mode, XorOp>(time); break;
2353 case 0x294: executeLmmm<Graphic6Mode, NotOp>(time); break;
2354 case 0x298: executeLmmm<Graphic6Mode, TImpOp>(time); break;
2355 case 0x299: executeLmmm<Graphic6Mode, TAndOp>(time); break;
2356 case 0x29A: executeLmmm<Graphic6Mode, TOrOp >(time); break;
2357 case 0x29B: executeLmmm<Graphic6Mode, TXorOp>(time); break;
2358 case 0x29C: executeLmmm<Graphic6Mode, TNotOp>(time); break;
2359 case 0x295: case 0x296: case 0x297: case 0x29D: case 0x29E: case 0x29F:
2360 executeLmmm<Graphic6Mode, DummyOp>(time); break;
2361 case 0x390: executeLmmm<Graphic7Mode, ImpOp>(time); break;
2362 case 0x391: executeLmmm<Graphic7Mode, AndOp>(time); break;
2363 case 0x392: executeLmmm<Graphic7Mode, OrOp >(time); break;
2364 case 0x393: executeLmmm<Graphic7Mode, XorOp>(time); break;
2365 case 0x394: executeLmmm<Graphic7Mode, NotOp>(time); break;
2366 case 0x398: executeLmmm<Graphic7Mode, TImpOp>(time); break;
2367 case 0x399: executeLmmm<Graphic7Mode, TAndOp>(time); break;
2368 case 0x39A: executeLmmm<Graphic7Mode, TOrOp >(time); break;
2369 case 0x39B: executeLmmm<Graphic7Mode, TXorOp>(time); break;
2370 case 0x39C: executeLmmm<Graphic7Mode, TNotOp>(time); break;
2371 case 0x395: case 0x396: case 0x397: case 0x39D: case 0x39E: case 0x39F:
2372 executeLmmm<Graphic7Mode, DummyOp>(time); break;
2373 case 0x490: executeLmmm<NonBitmapMode, ImpOp>(time); break;
2374 case 0x491: executeLmmm<NonBitmapMode, AndOp>(time); break;
2375 case 0x492: executeLmmm<NonBitmapMode, OrOp >(time); break;
2376 case 0x493: executeLmmm<NonBitmapMode, XorOp>(time); break;
2377 case 0x494: executeLmmm<NonBitmapMode, NotOp>(time); break;
2378 case 0x498: executeLmmm<NonBitmapMode, TImpOp>(time); break;
2379 case 0x499: executeLmmm<NonBitmapMode, TAndOp>(time); break;
2380 case 0x49A: executeLmmm<NonBitmapMode, TOrOp >(time); break;
2381 case 0x49B: executeLmmm<NonBitmapMode, TXorOp>(time); break;
2382 case 0x49C: executeLmmm<NonBitmapMode, TNotOp>(time); break;
2383 case 0x495: case 0x496: case 0x497: case 0x49D: case 0x49E: case 0x49F:
2384 executeLmmm<NonBitmapMode, DummyOp>(time); break;
2385
2386 case 0x0A0: case 0x0A1: case 0x0A2: case 0x0A3:
2387 case 0x0A4: case 0x0A5: case 0x0A6: case 0x0A7:
2388 case 0x0A8: case 0x0A9: case 0x0AA: case 0x0AB:
2389 case 0x0AC: case 0x0AD: case 0x0AE: case 0x0AF:
2390 executeLmcm<Graphic4Mode>(time); break;
2391 case 0x1A0: case 0x1A1: case 0x1A2: case 0x1A3:
2392 case 0x1A4: case 0x1A5: case 0x1A6: case 0x1A7:
2393 case 0x1A8: case 0x1A9: case 0x1AA: case 0x1AB:
2394 case 0x1AC: case 0x1AD: case 0x1AE: case 0x1AF:
2395 executeLmcm<Graphic5Mode>(time); break;
2396 case 0x2A0: case 0x2A1: case 0x2A2: case 0x2A3:
2397 case 0x2A4: case 0x2A5: case 0x2A6: case 0x2A7:
2398 case 0x2A8: case 0x2A9: case 0x2AA: case 0x2AB:
2399 case 0x2AC: case 0x2AD: case 0x2AE: case 0x2AF:
2400 executeLmcm<Graphic6Mode>(time); break;
2401 case 0x3A0: case 0x3A1: case 0x3A2: case 0x3A3:
2402 case 0x3A4: case 0x3A5: case 0x3A6: case 0x3A7:
2403 case 0x3A8: case 0x3A9: case 0x3AA: case 0x3AB:
2404 case 0x3AC: case 0x3AD: case 0x3AE: case 0x3AF:
2405 executeLmcm<Graphic7Mode>(time); break;
2406 case 0x4A0: case 0x4A1: case 0x4A2: case 0x4A3:
2407 case 0x4A4: case 0x4A5: case 0x4A6: case 0x4A7:
2408 case 0x4A8: case 0x4A9: case 0x4AA: case 0x4AB:
2409 case 0x4AC: case 0x4AD: case 0x4AE: case 0x4AF:
2410 executeLmcm<NonBitmapMode>(time); break;
2411
2412 case 0x0B0: executeLmmc<Graphic4Mode, ImpOp>(time); break;
2413 case 0x0B1: executeLmmc<Graphic4Mode, AndOp>(time); break;
2414 case 0x0B2: executeLmmc<Graphic4Mode, OrOp >(time); break;
2415 case 0x0B3: executeLmmc<Graphic4Mode, XorOp>(time); break;
2416 case 0x0B4: executeLmmc<Graphic4Mode, NotOp>(time); break;
2417 case 0x0B8: executeLmmc<Graphic4Mode, TImpOp>(time); break;
2418 case 0x0B9: executeLmmc<Graphic4Mode, TAndOp>(time); break;
2419 case 0x0BA: executeLmmc<Graphic4Mode, TOrOp >(time); break;
2420 case 0x0BB: executeLmmc<Graphic4Mode, TXorOp>(time); break;
2421 case 0x0BC: executeLmmc<Graphic4Mode, TNotOp>(time); break;
2422 case 0x0B5: case 0x0B6: case 0x0B7: case 0x0BD: case 0x0BE: case 0x0BF:
2423 executeLmmc<Graphic4Mode, DummyOp>(time); break;
2424 case 0x1B0: executeLmmc<Graphic5Mode, ImpOp>(time); break;
2425 case 0x1B1: executeLmmc<Graphic5Mode, AndOp>(time); break;
2426 case 0x1B2: executeLmmc<Graphic5Mode, OrOp >(time); break;
2427 case 0x1B3: executeLmmc<Graphic5Mode, XorOp>(time); break;
2428 case 0x1B4: executeLmmc<Graphic5Mode, NotOp>(time); break;
2429 case 0x1B8: executeLmmc<Graphic5Mode, TImpOp>(time); break;
2430 case 0x1B9: executeLmmc<Graphic5Mode, TAndOp>(time); break;
2431 case 0x1BA: executeLmmc<Graphic5Mode, TOrOp >(time); break;
2432 case 0x1BB: executeLmmc<Graphic5Mode, TXorOp>(time); break;
2433 case 0x1BC: executeLmmc<Graphic5Mode, TNotOp>(time); break;
2434 case 0x1B5: case 0x1B6: case 0x1B7: case 0x1BD: case 0x1BE: case 0x1BF:
2435 executeLmmc<Graphic5Mode, DummyOp>(time); break;
2436 case 0x2B0: executeLmmc<Graphic6Mode, ImpOp>(time); break;
2437 case 0x2B1: executeLmmc<Graphic6Mode, AndOp>(time); break;
2438 case 0x2B2: executeLmmc<Graphic6Mode, OrOp >(time); break;
2439 case 0x2B3: executeLmmc<Graphic6Mode, XorOp>(time); break;
2440 case 0x2B4: executeLmmc<Graphic6Mode, NotOp>(time); break;
2441 case 0x2B8: executeLmmc<Graphic6Mode, TImpOp>(time); break;
2442 case 0x2B9: executeLmmc<Graphic6Mode, TAndOp>(time); break;
2443 case 0x2BA: executeLmmc<Graphic6Mode, TOrOp >(time); break;
2444 case 0x2BB: executeLmmc<Graphic6Mode, TXorOp>(time); break;
2445 case 0x2BC: executeLmmc<Graphic6Mode, TNotOp>(time); break;
2446 case 0x2B5: case 0x2B6: case 0x2B7: case 0x2BD: case 0x2BE: case 0x2BF:
2447 executeLmmc<Graphic6Mode, DummyOp>(time); break;
2448 case 0x3B0: executeLmmc<Graphic7Mode, ImpOp>(time); break;
2449 case 0x3B1: executeLmmc<Graphic7Mode, AndOp>(time); break;
2450 case 0x3B2: executeLmmc<Graphic7Mode, OrOp >(time); break;
2451 case 0x3B3: executeLmmc<Graphic7Mode, XorOp>(time); break;
2452 case 0x3B4: executeLmmc<Graphic7Mode, NotOp>(time); break;
2453 case 0x3B8: executeLmmc<Graphic7Mode, TImpOp>(time); break;
2454 case 0x3B9: executeLmmc<Graphic7Mode, TAndOp>(time); break;
2455 case 0x3BA: executeLmmc<Graphic7Mode, TOrOp >(time); break;
2456 case 0x3BB: executeLmmc<Graphic7Mode, TXorOp>(time); break;
2457 case 0x3BC: executeLmmc<Graphic7Mode, TNotOp>(time); break;
2458 case 0x3B5: case 0x3B6: case 0x3B7: case 0x3BD: case 0x3BE: case 0x3BF:
2459 executeLmmc<Graphic7Mode, DummyOp>(time); break;
2460 case 0x4B0: executeLmmc<NonBitmapMode, ImpOp>(time); break;
2461 case 0x4B1: executeLmmc<NonBitmapMode, AndOp>(time); break;
2462 case 0x4B2: executeLmmc<NonBitmapMode, OrOp >(time); break;
2463 case 0x4B3: executeLmmc<NonBitmapMode, XorOp>(time); break;
2464 case 0x4B4: executeLmmc<NonBitmapMode, NotOp>(time); break;
2465 case 0x4B8: executeLmmc<NonBitmapMode, TImpOp>(time); break;
2466 case 0x4B9: executeLmmc<NonBitmapMode, TAndOp>(time); break;
2467 case 0x4BA: executeLmmc<NonBitmapMode, TOrOp >(time); break;
2468 case 0x4BB: executeLmmc<NonBitmapMode, TXorOp>(time); break;
2469 case 0x4BC: executeLmmc<NonBitmapMode, TNotOp>(time); break;
2470 case 0x4B5: case 0x4B6: case 0x4B7: case 0x4BD: case 0x4BE: case 0x4BF:
2471 executeLmmc<NonBitmapMode, DummyOp>(time); break;
2472
2473 case 0x0C0: case 0x0C1: case 0x0C2: case 0x0C3:
2474 case 0x0C4: case 0x0C5: case 0x0C6: case 0x0C7:
2475 case 0x0C8: case 0x0C9: case 0x0CA: case 0x0CB:
2476 case 0x0CC: case 0x0CD: case 0x0CE: case 0x0CF:
2477 executeHmmv<Graphic4Mode>(time); break;
2478 case 0x1C0: case 0x1C1: case 0x1C2: case 0x1C3:
2479 case 0x1C4: case 0x1C5: case 0x1C6: case 0x1C7:
2480 case 0x1C8: case 0x1C9: case 0x1CA: case 0x1CB:
2481 case 0x1CC: case 0x1CD: case 0x1CE: case 0x1CF:
2482 executeHmmv<Graphic5Mode>(time); break;
2483 case 0x2C0: case 0x2C1: case 0x2C2: case 0x2C3:
2484 case 0x2C4: case 0x2C5: case 0x2C6: case 0x2C7:
2485 case 0x2C8: case 0x2C9: case 0x2CA: case 0x2CB:
2486 case 0x2CC: case 0x2CD: case 0x2CE: case 0x2CF:
2487 executeHmmv<Graphic6Mode>(time); break;
2488 case 0x3C0: case 0x3C1: case 0x3C2: case 0x3C3:
2489 case 0x3C4: case 0x3C5: case 0x3C6: case 0x3C7:
2490 case 0x3C8: case 0x3C9: case 0x3CA: case 0x3CB:
2491 case 0x3CC: case 0x3CD: case 0x3CE: case 0x3CF:
2492 executeHmmv<Graphic7Mode>(time); break;
2493 case 0x4C0: case 0x4C1: case 0x4C2: case 0x4C3:
2494 case 0x4C4: case 0x4C5: case 0x4C6: case 0x4C7:
2495 case 0x4C8: case 0x4C9: case 0x4CA: case 0x4CB:
2496 case 0x4CC: case 0x4CD: case 0x4CE: case 0x4CF:
2497 executeHmmv<NonBitmapMode>(time); break;
2498
2499 case 0x0D0: case 0x0D1: case 0x0D2: case 0x0D3:
2500 case 0x0D4: case 0x0D5: case 0x0D6: case 0x0D7:
2501 case 0x0D8: case 0x0D9: case 0x0DA: case 0x0DB:
2502 case 0x0DC: case 0x0DD: case 0x0DE: case 0x0DF:
2503 executeHmmm<Graphic4Mode>(time); break;
2504 case 0x1D0: case 0x1D1: case 0x1D2: case 0x1D3:
2505 case 0x1D4: case 0x1D5: case 0x1D6: case 0x1D7:
2506 case 0x1D8: case 0x1D9: case 0x1DA: case 0x1DB:
2507 case 0x1DC: case 0x1DD: case 0x1DE: case 0x1DF:
2508 executeHmmm<Graphic5Mode>(time); break;
2509 case 0x2D0: case 0x2D1: case 0x2D2: case 0x2D3:
2510 case 0x2D4: case 0x2D5: case 0x2D6: case 0x2D7:
2511 case 0x2D8: case 0x2D9: case 0x2DA: case 0x2DB:
2512 case 0x2DC: case 0x2DD: case 0x2DE: case 0x2DF:
2513 executeHmmm<Graphic6Mode>(time); break;
2514 case 0x3D0: case 0x3D1: case 0x3D2: case 0x3D3:
2515 case 0x3D4: case 0x3D5: case 0x3D6: case 0x3D7:
2516 case 0x3D8: case 0x3D9: case 0x3DA: case 0x3DB:
2517 case 0x3DC: case 0x3DD: case 0x3DE: case 0x3DF:
2518 executeHmmm<Graphic7Mode>(time); break;
2519 case 0x4D0: case 0x4D1: case 0x4D2: case 0x4D3:
2520 case 0x4D4: case 0x4D5: case 0x4D6: case 0x4D7:
2521 case 0x4D8: case 0x4D9: case 0x4DA: case 0x4DB:
2522 case 0x4DC: case 0x4DD: case 0x4DE: case 0x4DF:
2523 executeHmmm<NonBitmapMode>(time); break;
2524
2525 case 0x0E0: case 0x0E1: case 0x0E2: case 0x0E3:
2526 case 0x0E4: case 0x0E5: case 0x0E6: case 0x0E7:
2527 case 0x0E8: case 0x0E9: case 0x0EA: case 0x0EB:
2528 case 0x0EC: case 0x0ED: case 0x0EE: case 0x0EF:
2529 executeYmmm<Graphic4Mode>(time); break;
2530 case 0x1E0: case 0x1E1: case 0x1E2: case 0x1E3:
2531 case 0x1E4: case 0x1E5: case 0x1E6: case 0x1E7:
2532 case 0x1E8: case 0x1E9: case 0x1EA: case 0x1EB:
2533 case 0x1EC: case 0x1ED: case 0x1EE: case 0x1EF:
2534 executeYmmm<Graphic5Mode>(time); break;
2535 case 0x2E0: case 0x2E1: case 0x2E2: case 0x2E3:
2536 case 0x2E4: case 0x2E5: case 0x2E6: case 0x2E7:
2537 case 0x2E8: case 0x2E9: case 0x2EA: case 0x2EB:
2538 case 0x2EC: case 0x2ED: case 0x2EE: case 0x2EF:
2539 executeYmmm<Graphic6Mode>(time); break;
2540 case 0x3E0: case 0x3E1: case 0x3E2: case 0x3E3:
2541 case 0x3E4: case 0x3E5: case 0x3E6: case 0x3E7:
2542 case 0x3E8: case 0x3E9: case 0x3EA: case 0x3EB:
2543 case 0x3EC: case 0x3ED: case 0x3EE: case 0x3EF:
2544 executeYmmm<Graphic7Mode>(time); break;
2545 case 0x4E0: case 0x4E1: case 0x4E2: case 0x4E3:
2546 case 0x4E4: case 0x4E5: case 0x4E6: case 0x4E7:
2547 case 0x4E8: case 0x4E9: case 0x4EA: case 0x4EB:
2548 case 0x4EC: case 0x4ED: case 0x4EE: case 0x4EF:
2549 executeYmmm<NonBitmapMode>(time); break;
2550
2551 case 0x0F0: case 0x0F1: case 0x0F2: case 0x0F3:
2552 case 0x0F4: case 0x0F5: case 0x0F6: case 0x0F7:
2553 case 0x0F8: case 0x0F9: case 0x0FA: case 0x0FB:
2554 case 0x0FC: case 0x0FD: case 0x0FE: case 0x0FF:
2555 executeHmmc<Graphic4Mode>(time); break;
2556 case 0x1F0: case 0x1F1: case 0x1F2: case 0x1F3:
2557 case 0x1F4: case 0x1F5: case 0x1F6: case 0x1F7:
2558 case 0x1F8: case 0x1F9: case 0x1FA: case 0x1FB:
2559 case 0x1FC: case 0x1FD: case 0x1FE: case 0x1FF:
2560 executeHmmc<Graphic5Mode>(time); break;
2561 case 0x2F0: case 0x2F1: case 0x2F2: case 0x2F3:
2562 case 0x2F4: case 0x2F5: case 0x2F6: case 0x2F7:
2563 case 0x2F8: case 0x2F9: case 0x2FA: case 0x2FB:
2564 case 0x2FC: case 0x2FD: case 0x2FE: case 0x2FF:
2565 executeHmmc<Graphic6Mode>(time); break;
2566 case 0x3F0: case 0x3F1: case 0x3F2: case 0x3F3:
2567 case 0x3F4: case 0x3F5: case 0x3F6: case 0x3F7:
2568 case 0x3F8: case 0x3F9: case 0x3FA: case 0x3FB:
2569 case 0x3FC: case 0x3FD: case 0x3FE: case 0x3FF:
2570 executeHmmc<Graphic7Mode>(time); break;
2571 case 0x4F0: case 0x4F1: case 0x4F2: case 0x4F3:
2572 case 0x4F4: case 0x4F5: case 0x4F6: case 0x4F7:
2573 case 0x4F8: case 0x4F9: case 0x4FA: case 0x4FB:
2574 case 0x4FC: case 0x4FD: case 0x4FE: case 0x4FF:
2575 executeHmmc<NonBitmapMode>(time); break;
2576
2577 default:
2579 }
2580}
2581
2582void VDPCmdEngine::reportVdpCommand() const
2583{
2584 static constexpr std::array<std::string_view, 16> COMMANDS = {
2585 " ABRT"," ????"," ????"," ????","POINT"," PSET"," SRCH"," LINE",
2586 " LMMV"," LMMM"," LMCM"," LMMC"," HMMV"," HMMM"," YMMM"," HMMC"
2587 };
2588 static constexpr std::array<std::string_view, 16> OPS = {
2589 "IMP ","AND ","OR ","XOR ","NOT ","NOP ","NOP ","NOP ",
2590 "TIMP","TAND","TOR ","TXOR","TNOT","NOP ","NOP ","NOP "
2591 };
2592
2593 std::cerr << "VDPCmd " << COMMANDS[CMD >> 4] << '-' << OPS[CMD & 15]
2594 << '(' << int(SX) << ',' << int(SY) << ")->("
2595 << int(DX) << ',' << int(DY) << ")," << int(COL)
2596 << " [" << int((ARG & DIX) ? -int(NX) : int(NX))
2597 << ',' << int((ARG & DIY) ? -int(NY) : int(NY)) << "]\n";
2598}
2599
2600void VDPCmdEngine::commandDone(EmuTime::param time)
2601{
2602 // Note: TR is not reset yet; it is reset when S#2 is read next.
2603 status &= 0xFE; // reset CE
2604 executingProbe = false;
2605 CMD = 0;
2606 setStatusChangeTime(EmuTime::infinity());
2607 vram.cmdReadWindow.disable(time);
2608 vram.cmdWriteWindow.disable(time);
2609}
2610
2611
2612// version 1: initial version
2613// version 2: replaced member 'Clock<> clock' with 'EmuTime time'
2614// version 3: added 'phase', 'tmpSrc', 'tmpDst'
2615template<typename Archive>
2616void VDPCmdEngine::serialize(Archive& ar, unsigned version)
2617{
2618 // In older (development) versions CMD was split in a CMD and a LOG
2619 // member, though it was combined for the savestate. Only the CMD part
2620 // was guaranteed to be zero when no command was executing. So when
2621 // loading an older savestate this can still be the case.
2622
2623 if (ar.versionAtLeast(version, 2)) {
2624 ar.serialize("time", engineTime);
2625 } else {
2626 // in version 1, the 'engineTime' member had type 'Clock<>'
2627 assert(Archive::IS_LOADER);
2628 VDP::VDPClock clock(EmuTime::dummy());
2629 ar.serialize("clock", clock);
2630 engineTime = clock.getTime();
2631 }
2632 ar.serialize("statusChangeTime", statusChangeTime,
2633 "scrMode", scrMode,
2634 "status", status,
2635 "transfer", transfer,
2636 "SX", SX,
2637 "SY", SY,
2638 "DX", DX,
2639 "DY", DY,
2640 "NX", NX,
2641 "NY", NY,
2642 "ASX", ASX,
2643 "ADX", ADX,
2644 "ANX", ANX,
2645 "COL", COL,
2646 "ARG", ARG,
2647 "CMD", CMD);
2648
2649 if (ar.versionAtLeast(version, 3)) {
2650 ar.serialize("phase", phase,
2651 "tmpSrc", tmpSrc,
2652 "tmpDst", tmpDst);
2653 } else {
2654 assert(Archive::IS_LOADER);
2655 phase = tmpSrc = tmpDst = 0;
2656 }
2657
2658 if constexpr (Archive::IS_LOADER) {
2659 if (CMD & 0xF0) {
2660 assert(scrMode >= 0);
2661 } else {
2662 CMD = 0; // see note above
2663 }
2664 }
2665}
2667
2668} // namespace openmsx
TclObject t
bool getBoolean() const noexcept
static constexpr EmuDuration duration(unsigned ticks)
Calculates the duration of the given number of ticks at this clock's frequency.
Definition Clock.hh:35
constexpr EmuTime::param getTime() const
Gets the time at which the last clock tick occurred.
Definition Clock.hh:46
Represents a VDP display mode.
constexpr byte getBase() const
Get the base display mode as an integer: M5..M1 combined.
static constexpr uint8_t GRAPHIC4
static constexpr uint8_t GRAPHIC5
static constexpr uint8_t GRAPHIC7
static constexpr uint8_t GRAPHIC6
bool anyObservers() const
Definition Subject.hh:27
TclObject execute() const
VDP command engine by Alex Wulms.
void updateDisplayMode(DisplayMode mode, bool cmdBit, EmuTime::param time)
Informs the command engine of a VDP display mode change.
void serialize(Archive &ar, unsigned version)
Interface for logical operations.
void reset(EmuTime::param time)
Reinitialize Renderer state.
VDPCmdEngine(VDP &vdp, CommandController &commandController)
void sync2(EmuTime::param time)
byte peekCmdReg(byte index) const
Read the content of a command register.
void sync(EmuTime::param time)
Synchronizes the command engine with the VDP.
void setCmdReg(byte index, byte value, EmuTime::param time)
Writes to a command register.
Manages VRAM contents and synchronizes the various users of the VRAM.
Definition VDPVRAM.hh:399
void cmdWrite(unsigned address, byte value, EmuTime::param time)
Write a byte from the command engine.
Definition VDPVRAM.hh:427
VRAMWindow cmdReadWindow
Definition VDPVRAM.hh:687
Unified implementation of MSX Video Display Processors (VDPs).
Definition VDP.hh:66
bool getBrokenCmdTiming() const
Value of the cmdTiming setting, true means commands have infinite speed.
Definition VDP.hh:662
void scheduleCmdSync(EmuTime t)
Only used when there are commandExecuting-probe listeners.
Definition VDP.hh:699
bool getCmdBit() const
Are commands possible in non Graphic modes? (V9958 only)
Definition VDP.hh:546
DisplayMode getDisplayMode() const
Get the display mode the VDP is in.
Definition VDP.hh:155
byte readNP(unsigned index) const
Reads a byte from VRAM in its current state.
Definition VDPVRAM.hh:265
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition gl_vec.hh:302
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition gl_vec.hh:320
This file implemented 3 utility functions:
Definition Autofire.cc:11
uint8_t byte
8 bit unsigned integer
Definition openmsx.hh:26
STL namespace.
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
std::string strCat()
Definition strCat.hh:703
void operator()(EmuTime::param time, VDPVRAM &vram, unsigned addr, byte src, byte color, byte mask) const
void operator()(EmuTime::param, VDPVRAM &, unsigned, byte, byte, byte) const
Represents V9938 Graphic 4 mode (SCREEN5).
static void pset(EmuTime::param time, VDPVRAM &vram, unsigned x, unsigned addr, byte src, byte color, LogOp op)
static byte point(const VDPVRAM &vram, unsigned x, unsigned y, bool extVRAM)
static constexpr byte PIXELS_PER_BYTE
static constexpr byte COLOR_MASK
static constexpr byte PIXELS_PER_BYTE_SHIFT
static unsigned addressOf(unsigned x, unsigned y, bool extVRAM)
static constexpr unsigned PIXELS_PER_LINE
static byte duplicate(byte color)
Represents V9938 Graphic 5 mode (SCREEN6).
static void pset(EmuTime::param time, VDPVRAM &vram, unsigned x, unsigned addr, byte src, byte color, LogOp op)
static constexpr unsigned PIXELS_PER_LINE
static byte duplicate(byte color)
static constexpr byte PIXELS_PER_BYTE_SHIFT
static constexpr byte COLOR_MASK
static byte point(const VDPVRAM &vram, unsigned x, unsigned y, bool extVRAM)
static unsigned addressOf(unsigned x, unsigned y, bool extVRAM)
static constexpr byte PIXELS_PER_BYTE
Represents V9938 Graphic 6 mode (SCREEN7).
static constexpr byte PIXELS_PER_BYTE
static byte duplicate(byte color)
static byte point(const VDPVRAM &vram, unsigned x, unsigned y, bool extVRAM)
static void pset(EmuTime::param time, VDPVRAM &vram, unsigned x, unsigned addr, byte src, byte color, LogOp op)
static unsigned addressOf(unsigned x, unsigned y, bool extVRAM)
static constexpr byte PIXELS_PER_BYTE_SHIFT
static constexpr byte COLOR_MASK
static constexpr unsigned PIXELS_PER_LINE
Represents V9938 Graphic 7 mode (SCREEN8).
static constexpr byte PIXELS_PER_BYTE
static constexpr byte PIXELS_PER_BYTE_SHIFT
static byte duplicate(byte color)
static byte point(const VDPVRAM &vram, unsigned x, unsigned y, bool extVRAM)
static void pset(EmuTime::param time, VDPVRAM &vram, unsigned x, unsigned addr, byte src, byte color, LogOp op)
static unsigned addressOf(unsigned x, unsigned y, bool extVRAM)
static constexpr byte COLOR_MASK
static constexpr unsigned PIXELS_PER_LINE
void operator()(EmuTime::param time, VDPVRAM &vram, unsigned addr, byte src, byte color, byte mask) const
Incremental address calculation (byte based, no extended VRAM)
unsigned getAddr() const
IncrByteAddr4(unsigned x, unsigned y, int)
unsigned getAddr() const
IncrByteAddr5(unsigned x, unsigned y, int)
IncrByteAddr6(unsigned x, unsigned y, int tx)
IncrByteAddr7(unsigned x, unsigned y, int tx)
unsigned getAddr() const
Incremental mask calculation.
byte getMask() const
IncrMask4(unsigned x, int)
byte getMask() const
IncrMask5(unsigned x, int tx)
byte getMask() const
IncrMask7(unsigned, int)
Incremental address calculation (pixel-based)
unsigned getAddr() const
IncrPixelAddr4(unsigned x, unsigned y, int tx)
unsigned getAddr() const
IncrPixelAddr5(unsigned x, unsigned y, int tx)
unsigned getAddr() const
IncrPixelAddr6(unsigned x, unsigned y, int tx)
byte doShift(byte color) const
IncrShift4(unsigned sx, unsigned dx)
byte doShift(byte color) const
IncrShift5(unsigned sx, unsigned dx)
IncrShift7(unsigned, unsigned)
byte doShift(byte color) const
Represents V9958 non-bitmap command mode.
static unsigned addressOf(unsigned x, unsigned y, bool extVRAM)
static constexpr byte COLOR_MASK
static byte point(const VDPVRAM &vram, unsigned x, unsigned y, bool extVRAM)
static constexpr byte PIXELS_PER_BYTE_SHIFT
static byte duplicate(byte color)
static void pset(EmuTime::param time, VDPVRAM &vram, unsigned x, unsigned addr, byte src, byte color, LogOp op)
static constexpr byte PIXELS_PER_BYTE
static constexpr unsigned PIXELS_PER_LINE
void operator()(EmuTime::param time, VDPVRAM &vram, unsigned addr, byte src, byte color, byte mask) const
void operator()(EmuTime::param time, VDPVRAM &vram, unsigned addr, byte src, byte color, byte) const
void operator()(EmuTime::param time, VDPVRAM &vram, unsigned addr, byte src, byte color, byte mask) const
void operator()(EmuTime::param time, VDPVRAM &vram, unsigned addr, byte src, byte color, byte) const
#define UNREACHABLE