openMSX
VDP.hh
Go to the documentation of this file.
1#ifndef VDP_HH
2#define VDP_HH
3
4#include "MSXDevice.hh"
5#include "Schedulable.hh"
7#include "SimpleDebuggable.hh"
8#include "TclCallback.hh"
9#include "InfoTopic.hh"
10#include "IRQHelper.hh"
11#include "Clock.hh"
12#include "DisplayMode.hh"
13#include "EnumSetting.hh"
14#include "Observer.hh"
15#include "narrow.hh"
16#include "openmsx.hh"
17#include "outer.hh"
18#include <memory>
19#include <array>
20
21namespace openmsx {
22
23class PostProcessor;
24class Renderer;
25class VDPCmdEngine;
26class VDPVRAM;
27class MSXCPU;
28class SpriteChecker;
29class Display;
30class RawFrame;
31class Setting;
32namespace VDPAccessSlots {
33 enum Delta : int;
34 class Calculator;
35}
36
62class VDP final : public MSXDevice, private VideoSystemChangeListener
63 , private Observer<Setting>
64{
65public:
68 static constexpr int TICKS_PER_SECOND = 3579545 * 6; // 21.5MHz;
70
73 static constexpr int TICKS_PER_LINE = 1368;
74
75 explicit VDP(const DeviceConfig& config);
76 ~VDP() override;
77
78 void powerUp(EmuTime::param time) override;
79 void reset(EmuTime::param time) override;
80 [[nodiscard]] byte readIO(word port, EmuTime::param time) override;
81 [[nodiscard]] byte peekIO(word port, EmuTime::param time) const override;
82 void writeIO(word port, byte value, EmuTime::param time) override;
83
84 void getExtraDeviceInfo(TclObject& result) const override;
85
90 [[nodiscard]] PostProcessor* getPostProcessor() const;
91
96 [[nodiscard]] inline bool isMSX1VDP() const {
97 return (version & VM_MSX1) != 0;
98 }
99
103 [[nodiscard]] inline bool isVDPwithPALonly() const {
104 return (version & VM_PAL) != 0;
105 }
106
110 [[nodiscard]] inline bool vdpLacksMirroring() const {
111 return (version & VM_NO_MIRRORING) != 0;
112 }
113
117 [[nodiscard]] inline bool vdpHasPatColMirroring() const {
118 return (version & VM_PALCOL_MIRRORING) != 0;
119 }
120
124 [[nodiscard]] inline bool isVDPwithVRAMremapping() const {
125 return (version & VM_VRAM_REMAPPING) != 0;
126 }
127
131 [[nodiscard]] inline bool hasYJK() const {
132 return (version & VM_YJK) != 0;
133 }
134
139 [[nodiscard]] std::array<std::array<uint8_t, 3>, 16> getMSX1Palette() const;
140
144 [[nodiscard]] inline DisplayMode getDisplayMode() const {
145 return displayMode;
146 }
147
150 [[nodiscard]] inline VDPVRAM& getVRAM() {
151 return *vram;
152 }
153
158 [[nodiscard]] inline const RawFrame* isSuperimposing() const {
159 // Note that bit 0 of r#0 has no effect on an V9938 or higher,
160 // but this bit is masked out. Also note that on an MSX1, if
161 // bit 0 of r#0 is enabled and there is no external video
162 // source, then we lose sync.
163 // Also note that because this property is fixed per frame we
164 // cannot (re)calculate it from register values.
165 return superimposing;
166 }
167
170 [[nodiscard]] inline SpriteChecker& getSpriteChecker() {
171 return *spriteChecker;
172 }
173
177 [[nodiscard]] inline bool getTransparency() const {
178 return (controlRegs[8] & 0x20) == 0;
179 }
180
183 [[nodiscard]] bool canSpriteColor0Collide() const {
184 // On MSX1 (so far only tested a TMS9129(?)) sprites with
185 // color=0 can always collide with other sprites. Though on
186 // V99x8 (only tested V9958) collisions only occur when color 0
187 // is not transparent. For more details see:
188 // https://github.com/openMSX/openMSX/issues/1198
189 return isMSX1VDP() || !getTransparency();
190 }
191
195 [[nodiscard]] inline int getForegroundColor() const {
196 return controlRegs[7] >> 4;
197 }
198
207 [[nodiscard]] inline byte getBackgroundColor() const {
208 byte reg7 = controlRegs[7];
209 if (displayMode.getByte() == DisplayMode::GRAPHIC7) {
210 return reg7;
211 } else {
212 return reg7 & 0x0F;
213 }
214 }
215
219 [[nodiscard]] inline int getBlinkForegroundColor() const {
220 return controlRegs[12] >> 4;
221 }
222
226 [[nodiscard]] inline int getBlinkBackgroundColor() const {
227 return controlRegs[12] & 0x0F;
228 }
229
233 [[nodiscard]] inline bool getBlinkState() const {
234 return blinkState;
235 }
236
242 [[nodiscard]] inline word getPalette(unsigned index) const {
243 return palette[index];
244 }
245
251 [[nodiscard]] inline bool isDisplayEnabled() const {
252 return isDisplayArea && displayEnabled;
253 }
254
259 [[nodiscard]] inline bool spritesEnabled() const {
260 return displayEnabled &&
261 (displayMode.getSpriteMode(isMSX1VDP()) != 0) &&
262 spriteEnabled;
263 }
264
268 [[nodiscard]] inline bool spritesEnabledFast() const {
269 assert(displayMode.getSpriteMode(isMSX1VDP()) != 0);
270 return displayEnabled && spriteEnabled;
271 }
272
276 [[nodiscard]] inline bool spritesEnabledRegister() const {
277 return spriteEnabled;
278 }
279
283 [[nodiscard]] inline byte getVerticalScroll() const {
284 return controlRegs[23];
285 }
286
292 [[nodiscard]] inline byte getHorizontalScrollLow() const {
293 return controlRegs[27];
294 }
295
301 [[nodiscard]] inline byte getHorizontalScrollHigh() const {
302 return controlRegs[26];
303 }
304
310 [[nodiscard]] inline bool isBorderMasked() const {
311 return (controlRegs[25] & 0x02) != 0;
312 }
313
320 [[nodiscard]] inline bool isMultiPageScrolling() const {
321 return (controlRegs[25] & 0x01) && (controlRegs[2] & 0x20);
322 }
323
328 [[nodiscard]] inline int getLineZero() const {
329 return displayStart / TICKS_PER_LINE;
330 }
331
336 [[nodiscard]] inline bool isPalTiming() const {
337 return palTiming;
338 }
339
347 [[nodiscard]] inline bool isInterlaced() const {
348 return interlaced;
349 }
350
361 [[nodiscard]] inline bool isFastBlinkEnabled() const {
362 return (controlRegs[1] & 4) != 0;
363 }
364
376 [[nodiscard]] inline bool isEvenOddEnabled() const {
377 if (isFastBlinkEnabled()) return false;
378 return (controlRegs[9] & 4) != 0;
379 }
380
384 [[nodiscard]] inline bool getEvenOdd() const {
385 return (statusReg2 & 2) != 0;
386 }
387
399 [[nodiscard]] inline unsigned getEvenOddMask() const {
400 // TODO: Verify which page is displayed on even fields.
401 assert(!isFastBlinkEnabled());
402 return (((~controlRegs[9] & 4) << 6) | ((statusReg2 & 2) << 7)) &
403 (!blinkState << 8);
404 }
405
412 [[nodiscard]] inline unsigned getEvenOddMask(int line) const {
413 if (isFastBlinkEnabled()) {
414 // EO and IL not considered in this mode
415 auto p = calculateLineBlinkState(line);
416 return (!p.state) << 8;
417 } else {
418 return getEvenOddMask();
419 }
420 }
421
427 bool state;
428 int count;
429 };
430 [[nodiscard]] BlinkStateCount calculateLineBlinkState(unsigned line) const {
431 assert(isFastBlinkEnabled());
432
433 if (blinkCount == 0) { // not changing
434 return {blinkState, blinkCount};
435 }
436
437 unsigned evenLen = ((controlRegs[13] >> 4) & 0x0F) * 10;
438 unsigned oddLen = ((controlRegs[13] >> 0) & 0x0F) * 10;
439 unsigned totalLen = evenLen + oddLen;
440 assert(totalLen != 0); // because this implies 'blinkCount == 0'
441 line %= totalLen; // reduce double flips
442
443 bool resultState = blinkState; // initial guess, adjusted later
444 if (blinkState) {
445 // We start in the 'even' period -> check first for
446 // even/odd transition, next for odd/even
447 } else {
448 // We start in the 'odd' period -> do the opposite
449 std::swap(evenLen, oddLen);
450 }
451 int newCount = blinkCount - narrow<int>(line);
452 if (newCount <= 0) {
453 // switch even->odd (or odd->even)
454 resultState = !resultState;
455 newCount += narrow<int>(oddLen);
456 if (newCount <= 0) {
457 // switch odd->even (or even->odd)
458 resultState = !resultState;
459 newCount += narrow<int>(evenLen);
460 assert(newCount > 0);
461 }
462 }
463 return {resultState, newCount};
464 }
465
469 [[nodiscard]] inline int getTicksThisFrame(EmuTime::param time) const {
470 return narrow<int>(frameStartTime.getTicksTill_fast(time));
471 }
472
473 [[nodiscard]] inline EmuTime::param getFrameStartTime() const {
474 return frameStartTime.getTime();
475 }
476
479 [[nodiscard]] inline int getSpriteSize() const {
480 return ((controlRegs[1] & 2) << 2) + 8;
481 }
482
485 [[nodiscard]] inline bool isSpriteMag() const {
486 return controlRegs[1] & 1;
487 }
488
492 [[nodiscard]] inline bool getCmdBit() const {
493 return (controlRegs[25] & 0x40) != 0;
494 }
495
498 [[nodiscard]] inline int getLinesPerFrame() const {
499 return palTiming ? 313 : 262;
500 }
501
504 [[nodiscard]] inline int getTicksPerFrame() const {
506 }
507
517 [[nodiscard]] inline bool isInsideFrame(EmuTime::param time) const {
518 return time >= frameStartTime.getTime() &&
520 }
521
525 [[nodiscard]] inline int getHorizontalAdjust() const {
526 return horizontalAdjust;
527 }
528
536 [[nodiscard]] inline int getLeftSprites() const {
537 return 100 + 102 + 56
538 + (horizontalAdjust - 7) * 4
539 + (displayMode.isTextMode() ? 36 : 0);
540 }
541
547 [[nodiscard]] inline int getLeftBorder() const {
548 return getLeftSprites() + (isBorderMasked() ? 8 * 4 : 0);
549 }
550
554 [[nodiscard]] inline int getRightBorder() const {
555 return getLeftSprites()
556 + (displayMode.isTextMode() ? 960 : 1024);
557 }
558
564 [[nodiscard]] inline int getLeftBackground() const {
565 return getLeftSprites() + getHorizontalScrollLow() * 4;
566 }
567
571 [[nodiscard]] byte getStatusReg0() const { return statusReg0; }
572
581 void setSpriteStatus(byte value)
582 {
583 statusReg0 = (statusReg0 & 0x80) | (value & 0x7F);
584 }
585
589 [[nodiscard]] bool getVRMode() const {
590 return (controlRegs[8] & 8) != 0;
591 }
592
595 void setExternalVideoSource(const RawFrame* externalSource) {
596 externalVideo = externalSource;
597 }
598
601 [[nodiscard]] bool getBrokenCmdTiming() const {
602 return brokenCmdTiming;
603 }
604
607 [[nodiscard]] EmuTime getAccessSlot(EmuTime::param time, VDPAccessSlots::Delta delta) const;
608
619 EmuTime::param time, EmuTime::param limit) const;
620
638 void scheduleCmdSync(EmuTime t) {
639 auto now = getCurrentTime();
640 if (t <= now) {
641 // The largest amount of VDP cycles between 'progress'
642 // in command emulation:
643 // - worst case the LMMM takes 120+64 cycles to fully process one pixel
644 // - the largest gap between access slots is 70 cycles
645 // - but if we're unlucky the CPU steals that slot
646 int LARGEST_STALL = 184 + 2 * 70;
647
648 t = now + VDPClock::duration(LARGEST_STALL);
649 }
650 syncCmdDone.setSyncPoint(t);
651 }
652
653 template<typename Archive>
654 void serialize(Archive& ar, unsigned version);
655
656private:
657 void initTables();
658
659 // VdpVersion bitmasks
660 static constexpr unsigned VM_MSX1 = 1; // set-> MSX1, unset-> MSX2 or MSX2+
661 static constexpr unsigned VM_PAL = 2; // set-> fixed PAL, unset-> fixed NTSC or switchable
662 static constexpr unsigned VM_NO_MIRRORING = 4; // set-> no (screen2) mirroring
663 static constexpr unsigned VM_PALCOL_MIRRORING = 8; // set-> pattern/color-table mirroring
664 static constexpr unsigned VM_VRAM_REMAPPING = 16; // set-> 4k,8/16k VRAM remapping
665 static constexpr unsigned VM_TOSHIBA_PALETTE = 32; // set-> has Toshiba palette
666 static constexpr unsigned VM_YJK = 64; // set-> has YJK (MSX2+)
667 static constexpr unsigned VM_YM2220_PALETTE = 128; // set-> has YM2220 palette
668
670 enum VdpVersion {
675 TMS99X8A = VM_MSX1 | VM_PALCOL_MIRRORING | VM_VRAM_REMAPPING,
676
678 TMS9929A = VM_MSX1 | VM_PALCOL_MIRRORING | VM_VRAM_REMAPPING | VM_PAL,
679
681 TMS9129 = VM_MSX1 | VM_PAL,
682
684 TMS91X8 = VM_MSX1,
685
687 T6950PAL = VM_MSX1 | VM_TOSHIBA_PALETTE | VM_NO_MIRRORING | VM_PAL,
688
690 T6950NTSC = VM_MSX1 | VM_TOSHIBA_PALETTE | VM_NO_MIRRORING,
691
693 T7937APAL = VM_MSX1 | VM_TOSHIBA_PALETTE | VM_PAL,
694
696 T7937ANTSC = VM_MSX1 | VM_TOSHIBA_PALETTE,
697
699 YM2220PAL = VM_MSX1 | VM_YM2220_PALETTE | VM_PALCOL_MIRRORING | VM_PAL,
700
702 YM2220NTSC = VM_MSX1 | VM_YM2220_PALETTE | VM_PALCOL_MIRRORING,
703
705 V9938 = 0,
706
708 V9958 = VM_YJK,
709 };
710
711 struct SyncBase : public Schedulable {
712 explicit SyncBase(VDP& vdp_) : Schedulable(vdp_.getScheduler()) {}
716 protected:
717 ~SyncBase() = default;
718 };
719
720 struct SyncVSync final : public SyncBase {
721 explicit SyncVSync(VDP& vdp) : SyncBase(vdp) {}
722 void executeUntil(EmuTime::param time) override {
723 auto& vdp = OUTER(VDP, syncVSync);
724 vdp.execVSync(time);
725 }
726 } syncVSync;
727
728 struct SyncDisplayStart final : public SyncBase {
729 explicit SyncDisplayStart(VDP& vdp) : SyncBase(vdp) {}
730 void executeUntil(EmuTime::param time) override {
731 auto& vdp = OUTER(VDP, syncDisplayStart);
732 vdp.execDisplayStart(time);
733 }
734 } syncDisplayStart;
735
736 struct SyncVScan final : public SyncBase {
737 explicit SyncVScan(VDP& vdp) : SyncBase(vdp) {}
738 void executeUntil(EmuTime::param time) override {
739 auto& vdp = OUTER(VDP, syncVScan);
740 vdp.execVScan(time);
741 }
742 } syncVScan;
743
744 struct SyncHScan final : public SyncBase {
745 explicit SyncHScan(VDP& vdp) : SyncBase(vdp) {}
746 void executeUntil(EmuTime::param /*time*/) override {
747 auto& vdp = OUTER(VDP, syncHScan);
748 vdp.execHScan();
749 }
750 } syncHScan;
751
752 struct SyncHorAdjust final : public SyncBase {
753 explicit SyncHorAdjust(VDP& vdp) : SyncBase(vdp) {}
754 void executeUntil(EmuTime::param time) override {
755 auto& vdp = OUTER(VDP, syncHorAdjust);
756 vdp.execHorAdjust(time);
757 }
758 } syncHorAdjust;
759
760 struct SyncSetMode final : public SyncBase {
761 explicit SyncSetMode(VDP& vdp) : SyncBase(vdp) {}
762 void executeUntil(EmuTime::param time) override {
763 auto& vdp = OUTER(VDP, syncSetMode);
764 vdp.execSetMode(time);
765 }
766 } syncSetMode;
767
768 struct SyncSetBlank final : public SyncBase {
769 explicit SyncSetBlank(VDP& vdp) : SyncBase(vdp) {}
770 void executeUntil(EmuTime::param time) override {
771 auto& vdp = OUTER(VDP, syncSetBlank);
772 vdp.execSetBlank(time);
773 }
774 } syncSetBlank;
775
776 struct SyncSetSprites final : public SyncBase {
777 explicit SyncSetSprites(VDP& vdp) : SyncBase(vdp) {}
778 void executeUntil(EmuTime::param time) override {
779 auto& vdp = OUTER(VDP, syncSetSprites);
780 vdp.execSetSprites(time);
781 }
782 } syncSetSprites;
783
784 struct SyncCpuVramAccess final : public SyncBase {
785 explicit SyncCpuVramAccess(VDP& vdp) : SyncBase(vdp) {}
786 void executeUntil(EmuTime::param time) override {
787 auto& vdp = OUTER(VDP, syncCpuVramAccess);
788 vdp.execCpuVramAccess(time);
789 }
790 } syncCpuVramAccess;
791
792 struct SyncCmdDone final : public SyncBase {
793 explicit SyncCmdDone(VDP& vdp) : SyncBase(vdp) {}
794 void executeUntil(EmuTime::param time) override {
795 auto& vdp = OUTER(VDP, syncCmdDone);
796 vdp.execSyncCmdDone(time);
797 }
798 } syncCmdDone;
799
800 void execVSync(EmuTime::param time);
801 void execDisplayStart(EmuTime::param time);
802 void execVScan(EmuTime::param time);
803 void execHScan();
804 void execHorAdjust(EmuTime::param time);
805 void execSetMode(EmuTime::param time);
806 void execSetBlank(EmuTime::param time);
807 void execSetSprites(EmuTime::param time);
808 void execCpuVramAccess(EmuTime::param time);
809 void execSyncCmdDone(EmuTime::param time);
810
814 [[nodiscard]] inline int getNumberOfLines() const {
815 return controlRegs[9] & 0x80 ? 212 : 192;
816 }
817
821 [[nodiscard]] int getVerticalAdjust() const {
822 return (controlRegs[18] >> 4) ^ 0x07;
823 }
824
834 [[nodiscard]] inline bool getHR(int ticksThisFrame) const {
835 // Note: These constants are located inside this function because
836 // GCC 4.0.x won't link if they are in the class scope.
840 static constexpr int HBLANK_LEN_TXT = 404;
844 static constexpr int HBLANK_LEN_GFX = 312;
845 return (ticksThisFrame + TICKS_PER_LINE - getRightBorder()) % TICKS_PER_LINE
846 < (displayMode.isTextMode() ? HBLANK_LEN_TXT : HBLANK_LEN_GFX);
847 }
848
849 // VideoSystemChangeListener interface:
850 void preVideoSystemChange() noexcept override;
851 void postVideoSystemChange() noexcept override;
852
857 void resetInit();
858
863 void resetMasks(EmuTime::param time);
864
868 void frameStart(EmuTime::param time);
869
877 void scheduleDisplayStart(EmuTime::param time);
878
884 void scheduleVScan(EmuTime::param time);
885
891 void scheduleHScan(EmuTime::param time);
892
895 void vramWrite(byte value, EmuTime::param time);
896
899 [[nodiscard]] byte vramRead(EmuTime::param time);
900
902 void scheduleCpuVramAccess(bool isRead, byte write, EmuTime::param time);
903 void executeCpuVramAccess(EmuTime::param time);
904
907 [[nodiscard]] byte peekStatusReg(byte reg, EmuTime::param time) const;
908 [[nodiscard]] byte readStatusReg(byte reg, EmuTime::param time);
909
912 void changeRegister(byte reg, byte val, EmuTime::param time);
913
916 void syncAtNextLine(SyncBase& type, EmuTime::param time);
917
920 void createRenderer();
921
925 void updateNameBase(EmuTime::param time);
926
930 void updateColorBase(EmuTime::param time);
931
935 void updatePatternBase(EmuTime::param time);
936
940 void updateSpriteAttributeBase(EmuTime::param time);
941
945 void updateSpritePatternBase(EmuTime::param time);
946
950 void updateDisplayMode(DisplayMode newMode, bool cmdBit, EmuTime::param time);
951
958 void setPalette(unsigned index, word grb, EmuTime::param time);
959
960 // Observer<Setting>
961 void update(const Setting& setting) noexcept override;
962
963private:
964 Display& display;
965 EnumSetting<bool>& cmdTiming;
966 EnumSetting<bool>& tooFastAccess;
967
968 struct RegDebug final : SimpleDebuggable {
969 explicit RegDebug(VDP& vdp);
970 [[nodiscard]] byte read(unsigned address) override;
971 void write(unsigned address, byte value, EmuTime::param time) override;
972 } vdpRegDebug;
973
974 struct StatusRegDebug final : SimpleDebuggable {
975 explicit StatusRegDebug(VDP& vdp);
976 [[nodiscard]] byte read(unsigned address, EmuTime::param time) override;
977 } vdpStatusRegDebug;
978
979 struct PaletteDebug final : SimpleDebuggable {
980 explicit PaletteDebug(VDP& vdp);
981 [[nodiscard]] byte read(unsigned address) override;
982 void write(unsigned address, byte value, EmuTime::param time) override;
983 } vdpPaletteDebug;
984
985 struct VRAMPointerDebug final : SimpleDebuggable {
986 explicit VRAMPointerDebug(VDP& vdp);
987 [[nodiscard]] byte read(unsigned address) override;
988 void write(unsigned address, byte value, EmuTime::param time) override;
989 } vramPointerDebug;
990
991 struct RegisterLatchStatusDebug final : SimpleDebuggable {
992 explicit RegisterLatchStatusDebug(VDP& vdp);
993 [[nodiscard]] byte read(unsigned address) override;
994 } registerLatchStatusDebug;
995
996 struct VramAccessStatusDebug final : SimpleDebuggable {
997 explicit VramAccessStatusDebug(VDP& vdp);
998 [[nodiscard]] byte read(unsigned address) override;
999 } vramAccessStatusDebug;
1000
1001 struct PaletteLatchStatusDebug final : SimpleDebuggable {
1002 explicit PaletteLatchStatusDebug(VDP& vdp);
1003 [[nodiscard]] byte read(unsigned address) override;
1004 } paletteLatchStatusDebug;
1005
1006 struct DataLatchDebug final : SimpleDebuggable {
1007 explicit DataLatchDebug(VDP& vdp);
1008 [[nodiscard]] byte read(unsigned address) override;
1009 } dataLatchDebug;
1010
1011 class Info : public InfoTopic {
1012 public:
1013 void execute(std::span<const TclObject> tokens,
1014 TclObject& result) const override;
1015 [[nodiscard]] std::string help(std::span<const TclObject> tokens) const override;
1016 [[nodiscard]] virtual int calc(const EmuTime& time) const = 0;
1017 protected:
1018 Info(VDP& vdp_, const std::string& name, std::string helpText_);
1019 ~Info() = default;
1020 VDP& vdp;
1021 const std::string helpText;
1022 };
1023
1024 struct FrameCountInfo final : Info {
1025 explicit FrameCountInfo(VDP& vdp);
1026 [[nodiscard]] int calc(const EmuTime& time) const override;
1027 } frameCountInfo;
1028
1029 struct CycleInFrameInfo final : Info {
1030 explicit CycleInFrameInfo(VDP& vdp);
1031 [[nodiscard]] int calc(const EmuTime& time) const override;
1032 } cycleInFrameInfo;
1033
1034 struct LineInFrameInfo final : Info {
1035 explicit LineInFrameInfo(VDP& vdp);
1036 [[nodiscard]] int calc(const EmuTime& time) const override;
1037 } lineInFrameInfo;
1038
1039 struct CycleInLineInfo final : Info {
1040 explicit CycleInLineInfo(VDP& vdp);
1041 [[nodiscard]] int calc(const EmuTime& time) const override;
1042 } cycleInLineInfo;
1043
1044 struct MsxYPosInfo final : Info {
1045 explicit MsxYPosInfo(VDP& vdp);
1046 [[nodiscard]] int calc(const EmuTime& time) const override;
1047 } msxYPosInfo;
1048
1049 struct MsxX256PosInfo final : Info {
1050 explicit MsxX256PosInfo(VDP& vdp);
1051 [[nodiscard]] int calc(const EmuTime& time) const override;
1052 } msxX256PosInfo;
1053
1054 struct MsxX512PosInfo final : Info {
1055 explicit MsxX512PosInfo(VDP& vdp);
1056 [[nodiscard]] int calc(const EmuTime& time) const override;
1057 } msxX512PosInfo;
1058
1061 std::unique_ptr<Renderer> renderer;
1062
1065 std::unique_ptr<VDPCmdEngine> cmdEngine;
1066
1069 std::unique_ptr<SpriteChecker> spriteChecker;
1070
1073 std::unique_ptr<VDPVRAM> vram;
1074
1078 const RawFrame* externalVideo;
1079
1085 const RawFrame* superimposing;
1086
1089 VDPClock frameStartTime;
1090
1093 OptionalIRQHelper irqVertical;
1094
1097 OptionalIRQHelper irqHorizontal;
1098
1101 EmuTime displayStartSyncTime;
1102
1105 EmuTime vScanSyncTime;
1106
1109 EmuTime hScanSyncTime;
1110
1111 TclCallback tooFastCallback;
1112
1115 VdpVersion version;
1116
1121 int saturationPr;
1122
1127 int saturationPb;
1128
1134 int frameCount;
1135
1138 int displayStart;
1139
1143 int horizontalScanOffset;
1144
1148 int horizontalAdjust;
1149
1152 std::array<byte, 32> controlRegs;
1153
1158 byte controlRegMask;
1159
1166 std::array<byte, 32> controlValueMasks;
1167
1171 int blinkCount;
1172
1176 int vramPointer;
1177
1180 std::array<uint16_t, 16> palette;
1181
1184 bool isDisplayArea;
1185
1191 bool palTiming;
1192
1196 bool interlaced = false;
1197
1202 byte statusReg0;
1203
1209 byte statusReg1;
1210
1215 byte statusReg2;
1216
1219 bool blinkState;
1220
1223 byte dataLatch;
1224
1231 bool writeAccess;
1232
1235 bool registerDataStored;
1236
1239 bool paletteDataStored;
1240
1248 byte cpuVramData;
1249
1253 bool cpuVramReqIsRead;
1254 bool pendingCpuAccess; // always equal to pendingSyncPoint(CPU_VRAM_ACCESS)
1255
1259 bool cpuExtendedVram;
1260
1266 DisplayMode displayMode;
1267
1272 bool displayEnabled;
1273
1279 bool spriteEnabled;
1280
1284 bool warningPrinted = false;
1285
1287 bool brokenCmdTiming;
1288 bool allowTooFastAccess;
1289
1291 MSXCPU& cpu;
1292 const byte fixedVDPIOdelayCycles;
1293};
1295
1296} // namespace openmsx
1297
1298#endif
BaseSetting * setting
Definition: Interpreter.cc:28
TclObject t
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 unsigned getTicksTill_fast(EmuTime::param e) const
Same as above, only faster, Though the time interval may not be too large.
Definition: Clock.hh:70
constexpr EmuTime::param getTime() const
Gets the time at which the last clock tick occurred.
Definition: Clock.hh:46
Represents a VDP display mode.
Definition: DisplayMode.hh:16
constexpr bool isTextMode() const
Is the current mode a text mode? Text1 and Text2 are text modes.
Definition: DisplayMode.hh:123
constexpr byte getByte() const
Get the display mode as a byte: YAE YJK M5..M1 combined.
Definition: DisplayMode.hh:94
constexpr int getSpriteMode(bool isMSX1) const
Get the sprite mode of this display mode.
Definition: DisplayMode.hh:159
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:36
Scheduler & getScheduler() const
Definition: MSXDevice.cc:137
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:125
Generic Gang-of-Four Observer class, templatized edition.
Definition: Observer.hh:10
Abstract base class for post processors.
A video frame as output by the VDP scanline conversion unit, before any postprocessing filters are ap...
Definition: RawFrame.hh:15
void setSyncPoint(EmuTime::param timestamp)
Definition: Schedulable.cc:23
bool pendingSyncPoint() const
Definition: Schedulable.cc:38
virtual byte read(unsigned address, EmuTime::param time)
byte read(unsigned address) override
void write(unsigned address, byte value) override
VDP-VRAM access slot calculator, meant to be used in the inner loops of the VDPCmdEngine commands.
Manages VRAM contents and synchronizes the various users of the VRAM.
Definition: VDPVRAM.hh:397
Unified implementation of MSX Video Display Processors (VDPs).
Definition: VDP.hh:64
int getHorizontalAdjust() const
This is a combination of the (horizontal) set adjust register and the YJK-mode bit.
Definition: VDP.hh:525
bool getEvenOdd() const
Is the even or odd field being displayed?
Definition: VDP.hh:384
int getLinesPerFrame() const
Gets the number of lines per frame.
Definition: VDP.hh:498
unsigned getEvenOddMask() const
Expresses the state of even/odd page interchange in a mask on the line number.
Definition: VDP.hh:399
bool spritesEnabled() const
Are sprites enabled?
Definition: VDP.hh:259
int getSpriteSize() const
Gets the sprite size in pixels (8/16).
Definition: VDP.hh:479
int getLeftBackground() const
Gets the number of VDP clock ticks between start of line and the time when the background pixel with ...
Definition: VDP.hh:564
SpriteChecker & getSpriteChecker()
Get the sprite checker for this VDP.
Definition: VDP.hh:170
bool getBrokenCmdTiming() const
Value of the cmdTiming setting, true means commands have infinite speed.
Definition: VDP.hh:601
bool isEvenOddEnabled() const
Get even/odd page alternation status.
Definition: VDP.hh:376
void writeIO(word port, byte value, EmuTime::param time) override
Write a byte to a given IO port at a certain time to this device.
Definition: VDP.cc:647
void scheduleCmdSync(EmuTime t)
Only used when there are commandExecuting-probe listeners.
Definition: VDP.hh:638
bool spritesEnabledRegister() const
Still faster variant (just looks at the sprite-enabled-bit).
Definition: VDP.hh:276
BlinkStateCount calculateLineBlinkState(unsigned line) const
Definition: VDP.hh:430
static constexpr int TICKS_PER_SECOND
Number of VDP clock ticks per second.
Definition: VDP.hh:68
VDPVRAM & getVRAM()
Get the VRAM object for this VDP.
Definition: VDP.hh:150
bool isFastBlinkEnabled() const
Get 'fast-blink' status.
Definition: VDP.hh:361
std::array< std::array< uint8_t, 3 >, 16 > getMSX1Palette() const
Get the (fixed) palette for this MSX1 VDP.
Definition: VDP.cc:1533
PostProcessor * getPostProcessor() const
Used by Video9000 to be able to couple the VDP and V9990 output.
Definition: VDP.cc:237
bool isVDPwithPALonly() const
Is this a VDP only capable of PAL?
Definition: VDP.hh:103
const RawFrame * isSuperimposing() const
Are we currently superimposing? In case of superimpose, returns a pointer to the to-be-superimposed f...
Definition: VDP.hh:158
void getExtraDeviceInfo(TclObject &result) const override
Definition: VDP.cc:737
bool getCmdBit() const
Are commands possible in non Graphic modes? (V9958 only)
Definition: VDP.hh:492
VDPAccessSlots::Calculator getAccessSlotCalculator(EmuTime::param time, EmuTime::param limit) const
Same as getAccessSlot(), but it can be much faster for repeated calls, e.g.
Definition: VDP.cc:882
void reset(EmuTime::param time) override
This method is called on reset.
Definition: VDP.cc:315
bool isBorderMasked() const
Gets the current border mask setting.
Definition: VDP.hh:310
byte getStatusReg0() const
Should only be used by SpriteChecker.
Definition: VDP.hh:571
bool spritesEnabledFast() const
Same as spritesEnabled(), but may only be called in sprite mode 1 or 2.
Definition: VDP.hh:268
int getForegroundColor() const
Gets the current foreground color.
Definition: VDP.hh:195
static constexpr int TICKS_PER_LINE
Number of VDP clock ticks per line.
Definition: VDP.hh:73
int getBlinkBackgroundColor() const
Gets the current blinking color for blinking text.
Definition: VDP.hh:226
word getPalette(unsigned index) const
Gets a palette entry.
Definition: VDP.hh:242
int getTicksPerFrame() const
Gets the number of VDP clock ticks (21MHz) per frame.
Definition: VDP.hh:504
bool isInsideFrame(EmuTime::param time) const
Is the given timestamp inside the current frame? Mainly useful for debugging, because relevant timest...
Definition: VDP.hh:517
void serialize(Archive &ar, unsigned version)
Definition: VDP.cc:1903
unsigned getEvenOddMask(int line) const
Similar to the above getEvenOddMask() method, but can also be called when 'isFastBlinkEnabled() == tr...
Definition: VDP.hh:412
void setSpriteStatus(byte value)
Should only be used by SpriteChecker.
Definition: VDP.hh:581
Clock< TICKS_PER_SECOND > VDPClock
Definition: VDP.hh:69
byte getHorizontalScrollHigh() const
Gets the current horizontal scroll higher bits.
Definition: VDP.hh:301
int getRightBorder() const
Gets the number of VDP clock ticks between start of line and the start of the right border.
Definition: VDP.hh:554
DisplayMode getDisplayMode() const
Get the display mode the VDP is in.
Definition: VDP.hh:144
~VDP() override
Definition: VDP.cc:211
bool getBlinkState() const
Gets the current blink state.
Definition: VDP.hh:233
int getLineZero() const
Get the absolute line number of display line zero.
Definition: VDP.hh:328
int getBlinkForegroundColor() const
Gets the current blinking color for blinking text.
Definition: VDP.hh:219
void setExternalVideoSource(const RawFrame *externalSource)
Enable superimposing.
Definition: VDP.hh:595
bool isMSX1VDP() const
Is this an MSX1 VDP?
Definition: VDP.hh:96
byte getBackgroundColor() const
Gets the current background color.
Definition: VDP.hh:207
byte getVerticalScroll() const
Gets the current vertical scroll (line displayed at Y=0).
Definition: VDP.hh:283
bool isVDPwithVRAMremapping() const
Does this VDP have VRAM remapping when switching from 4k to 8/16k mode?
Definition: VDP.hh:124
bool hasYJK() const
Does this VDP support YJK display?
Definition: VDP.hh:131
EmuTime::param getFrameStartTime() const
Definition: VDP.hh:473
bool canSpriteColor0Collide() const
Can a sprite which has color=0 collide with some other sprite?
Definition: VDP.hh:183
bool isMultiPageScrolling() const
Is multi page scrolling enabled? It is considered enabled if both the multi page scrolling flag is en...
Definition: VDP.hh:320
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
Definition: VDP.cc:991
int getLeftBorder() const
Gets the number of VDP clock ticks between start of line and the end of the left border.
Definition: VDP.hh:547
EmuTime getAccessSlot(EmuTime::param time, VDPAccessSlots::Delta delta) const
Get the earliest access slot that is at least 'delta' cycles in the future.
Definition: VDP.cc:876
bool isSpriteMag() const
Are sprites magnified?
Definition: VDP.hh:485
bool vdpHasPatColMirroring() const
Is this a VDP that has pattern/color table mirroring?
Definition: VDP.hh:117
bool isPalTiming() const
Is PAL timing active? This setting is fixed at start of frame.
Definition: VDP.hh:336
bool isInterlaced() const
Get interlace status.
Definition: VDP.hh:347
bool getTransparency() const
Gets the current transparency setting.
Definition: VDP.hh:177
bool getVRMode() const
Returns current VR mode.
Definition: VDP.hh:589
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
Definition: VDP.cc:971
bool isDisplayEnabled() const
Is the display enabled? Both the regular border and forced blanking by clearing the display enable bi...
Definition: VDP.hh:251
int getTicksThisFrame(EmuTime::param time) const
Gets the number of VDP clock ticks (21MHz) elapsed between a given time and the start of this frame.
Definition: VDP.hh:469
bool vdpLacksMirroring() const
Is this a VDP that lacks mirroring?
Definition: VDP.hh:110
byte getHorizontalScrollLow() const
Gets the current horizontal scroll lower bits.
Definition: VDP.hh:292
VDP(const DeviceConfig &config)
Definition: VDP.cc:62
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition: VDP.cc:309
int getLeftSprites() const
Gets the number of VDP clock ticks between start of line and the start of the sprite plane.
Definition: VDP.hh:536
This file implemented 3 utility functions:
Definition: Autofire.cc:9
IntHelper< OptionalIRQ > OptionalIRQHelper
Definition: IRQHelper.hh:123
AmdFlash::SectorInfo Info
Definition: RomManbow2.cc:18
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
SERIALIZE_CLASS_VERSION(CassettePlayer, 2)
void swap(openmsx::MemBuffer< T > &l, openmsx::MemBuffer< T > &r) noexcept
Definition: MemBuffer.hh:202
#define OUTER(type, member)
Definition: outer.hh:41
Calculates what 'blinkState' and 'blinkCount' would be at a specific line.
Definition: VDP.hh:426