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 [[nodiscard]] std::string_view getVersionString() const;
86
87 [[nodiscard]] byte peekRegister(unsigned address) const;
88 [[nodiscard]] byte peekStatusReg(byte reg, EmuTime::param time) const;
89
92 void changeRegister(byte reg, byte val, EmuTime::param time);
93
94
99 [[nodiscard]] PostProcessor* getPostProcessor() const;
100
105 [[nodiscard]] inline bool isMSX1VDP() const {
106 return (version & VM_MSX1) != 0;
107 }
108
112 [[nodiscard]] inline bool isVDPwithPALonly() const {
113 return (version & VM_PAL) != 0;
114 }
115
119 [[nodiscard]] inline bool vdpLacksMirroring() const {
120 return (version & VM_NO_MIRRORING) != 0;
121 }
122
126 [[nodiscard]] inline bool vdpHasPatColMirroring() const {
127 return (version & VM_PALCOL_MIRRORING) != 0;
128 }
129
133 [[nodiscard]] inline bool isVDPwithVRAMremapping() const {
134 return (version & VM_VRAM_REMAPPING) != 0;
135 }
136
140 [[nodiscard]] inline bool hasYJK() const {
141 return (version & VM_YJK) != 0;
142 }
143
148 [[nodiscard]] std::array<std::array<uint8_t, 3>, 16> getMSX1Palette() const;
149
153 [[nodiscard]] inline DisplayMode getDisplayMode() const {
154 return displayMode;
155 }
156
159 [[nodiscard]] inline VDPVRAM& getVRAM() {
160 return *vram;
161 }
162
167 [[nodiscard]] inline const RawFrame* isSuperimposing() const {
168 // Note that bit 0 of r#0 has no effect on an V9938 or higher,
169 // but this bit is masked out. Also note that on an MSX1, if
170 // bit 0 of r#0 is enabled and there is no external video
171 // source, then we lose sync.
172 // Also note that because this property is fixed per frame we
173 // cannot (re)calculate it from register values.
174 return superimposing;
175 }
176
179 [[nodiscard]] inline SpriteChecker& getSpriteChecker() {
180 return *spriteChecker;
181 }
182
186 [[nodiscard]] inline bool getTransparency() const {
187 return (controlRegs[8] & 0x20) == 0;
188 }
189
192 [[nodiscard]] bool canSpriteColor0Collide() const {
193 // On MSX1 (so far only tested a TMS9129(?)) sprites with
194 // color=0 can always collide with other sprites. Though on
195 // V99x8 (only tested V9958) collisions only occur when color 0
196 // is not transparent. For more details see:
197 // https://github.com/openMSX/openMSX/issues/1198
198 return isMSX1VDP() || !getTransparency();
199 }
200
204 [[nodiscard]] inline int getForegroundColor() const {
205 return controlRegs[7] >> 4;
206 }
207
216 [[nodiscard]] inline byte getBackgroundColor() const {
217 byte reg7 = controlRegs[7];
218 if (displayMode.getByte() == DisplayMode::GRAPHIC7) {
219 return reg7;
220 } else {
221 return reg7 & 0x0F;
222 }
223 }
224
228 [[nodiscard]] inline int getBlinkForegroundColor() const {
229 return controlRegs[12] >> 4;
230 }
231
235 [[nodiscard]] inline int getBlinkBackgroundColor() const {
236 return controlRegs[12] & 0x0F;
237 }
238
242 [[nodiscard]] inline bool getBlinkState() const {
243 return blinkState;
244 }
245
247 [[nodiscard]] int getPatternTableBase() const {
248 return controlRegs[4] << 11;
249 }
251 [[nodiscard]] int getColorTableBase() const {
252 return (controlRegs[10] << 14) | (controlRegs[3] << 6);
253 }
255 [[nodiscard]] int getNameTableBase() const {
256 return controlRegs[2] << 10;
257 }
259 [[nodiscard]] int getSpritePatternTableBase() const {
260 return controlRegs[6] << 11;
261 }
263 [[nodiscard]] int getSpriteAttributeTableBase() const {
264 return (controlRegs[11] << 15) | (controlRegs[5] << 7);
265 }
266
272 [[nodiscard]] inline uint16_t getPalette(unsigned index) const {
273 return palette[index];
274 }
275 [[nodiscard]] inline std::span<const uint16_t, 16> getPalette() const {
276 return palette;
277 }
278
285 void setPalette(unsigned index, word grb, EmuTime::param time);
286
292 [[nodiscard]] inline bool isDisplayEnabled() const {
293 return isDisplayArea && displayEnabled;
294 }
295
300 [[nodiscard]] inline bool spritesEnabled() const {
301 return displayEnabled &&
302 (displayMode.getSpriteMode(isMSX1VDP()) != 0) &&
303 spriteEnabled;
304 }
305
309 [[nodiscard]] inline bool spritesEnabledFast() const {
310 assert(displayMode.getSpriteMode(isMSX1VDP()) != 0);
311 return displayEnabled && spriteEnabled;
312 }
313
317 [[nodiscard]] inline bool spritesEnabledRegister() const {
318 return spriteEnabled;
319 }
320
324 [[nodiscard]] inline byte getVerticalScroll() const {
325 return controlRegs[23];
326 }
327
333 [[nodiscard]] inline byte getHorizontalScrollLow() const {
334 return controlRegs[27];
335 }
336
342 [[nodiscard]] inline byte getHorizontalScrollHigh() const {
343 return controlRegs[26];
344 }
345
351 [[nodiscard]] inline bool isBorderMasked() const {
352 return (controlRegs[25] & 0x02) != 0;
353 }
354
361 [[nodiscard]] inline bool isMultiPageScrolling() const {
362 return (controlRegs[25] & 0x01) && (controlRegs[2] & 0x20);
363 }
364
368 [[nodiscard]] int getDisplayPage() const {
369 return (controlRegs[2] >> 5) & 3;
370 }
371
376 [[nodiscard]] inline int getLineZero() const {
377 return displayStart / TICKS_PER_LINE;
378 }
379
384 [[nodiscard]] inline bool isPalTiming() const {
385 return palTiming;
386 }
387
395 [[nodiscard]] inline bool isInterlaced() const {
396 return interlaced;
397 }
398
409 [[nodiscard]] inline bool isFastBlinkEnabled() const {
410 return (controlRegs[1] & 4) != 0;
411 }
412
424 [[nodiscard]] inline bool isEvenOddEnabled() const {
425 if (isFastBlinkEnabled()) return false;
426 return (controlRegs[9] & 4) != 0;
427 }
428
432 [[nodiscard]] inline bool getEvenOdd() const {
433 return (statusReg2 & 2) != 0;
434 }
435
447 [[nodiscard]] inline unsigned getEvenOddMask() const {
448 // TODO: Verify which page is displayed on even fields.
449 assert(!isFastBlinkEnabled());
450 return (((~controlRegs[9] & 4) << 6) | ((statusReg2 & 2) << 7)) &
451 (!blinkState << 8);
452 }
453
460 [[nodiscard]] inline unsigned getEvenOddMask(int line) const {
461 if (isFastBlinkEnabled()) {
462 // EO and IL not considered in this mode
463 auto p = calculateLineBlinkState(line);
464 return (!p.state) << 8;
465 } else {
466 return getEvenOddMask();
467 }
468 }
469
475 bool state;
476 int count;
477 };
478 [[nodiscard]] BlinkStateCount calculateLineBlinkState(unsigned line) const {
479 assert(isFastBlinkEnabled());
480
481 if (blinkCount == 0) { // not changing
482 return {blinkState, blinkCount};
483 }
484
485 unsigned evenLen = ((controlRegs[13] >> 4) & 0x0F) * 10;
486 unsigned oddLen = ((controlRegs[13] >> 0) & 0x0F) * 10;
487 unsigned totalLen = evenLen + oddLen;
488 assert(totalLen != 0); // because this implies 'blinkCount == 0'
489 line %= totalLen; // reduce double flips
490
491 bool resultState = blinkState; // initial guess, adjusted later
492 if (blinkState) {
493 // We start in the 'even' period -> check first for
494 // even/odd transition, next for odd/even
495 } else {
496 // We start in the 'odd' period -> do the opposite
497 std::swap(evenLen, oddLen);
498 }
499 int newCount = blinkCount - narrow<int>(line);
500 if (newCount <= 0) {
501 // switch even->odd (or odd->even)
502 resultState = !resultState;
503 newCount += narrow<int>(oddLen);
504 if (newCount <= 0) {
505 // switch odd->even (or even->odd)
506 resultState = !resultState;
507 newCount += narrow<int>(evenLen);
508 assert(newCount > 0);
509 }
510 }
511 return {resultState, newCount};
512 }
513
517 [[nodiscard]] inline int getTicksThisFrame(EmuTime::param time) const {
518 return narrow<int>(frameStartTime.getTicksTill_fast(time));
519 }
520
521 [[nodiscard]] inline EmuTime::param getFrameStartTime() const {
522 return frameStartTime.getTime();
523 }
524
527 [[nodiscard]] inline int getSpriteSize() const {
528 return ((controlRegs[1] & 2) << 2) + 8;
529 }
530
533 [[nodiscard]] inline bool isSpriteMag() const {
534 return controlRegs[1] & 1;
535 }
536
540 [[nodiscard]] inline bool getCmdBit() const {
541 return (controlRegs[25] & 0x40) != 0;
542 }
543
546 [[nodiscard]] inline int getLinesPerFrame() const {
547 return palTiming ? 313 : 262;
548 }
549
553 [[nodiscard]] inline int getNumberOfLines() const {
554 return controlRegs[9] & 0x80 ? 212 : 192;
555 }
556
559 [[nodiscard]] inline int getTicksPerFrame() const {
561 }
562
572 [[nodiscard]] inline bool isInsideFrame(EmuTime::param time) const {
573 return time >= frameStartTime.getTime() &&
575 }
576
580 [[nodiscard]] inline int getHorizontalAdjust() const {
581 return horizontalAdjust;
582 }
583
591 [[nodiscard]] inline int getLeftSprites() const {
592 return 100 + 102 + 56
593 + (horizontalAdjust - 7) * 4
594 + (displayMode.isTextMode() ? 36 : 0);
595 }
596
602 [[nodiscard]] inline int getLeftBorder() const {
603 return getLeftSprites() + (isBorderMasked() ? 8 * 4 : 0);
604 }
605
609 [[nodiscard]] inline int getRightBorder() const {
610 return getLeftSprites()
611 + (displayMode.isTextMode() ? 960 : 1024);
612 }
613
619 [[nodiscard]] inline int getLeftBackground() const {
620 return getLeftSprites() + getHorizontalScrollLow() * 4;
621 }
622
626 [[nodiscard]] byte getStatusReg0() const { return statusReg0; }
627
636 void setSpriteStatus(byte value)
637 {
638 statusReg0 = (statusReg0 & 0x80) | (value & 0x7F);
639 }
640
644 [[nodiscard]] bool getVRMode() const {
645 return (controlRegs[8] & 8) != 0;
646 }
647
650 void setExternalVideoSource(const RawFrame* externalSource) {
651 externalVideo = externalSource;
652 }
653
656 [[nodiscard]] bool getBrokenCmdTiming() const {
657 return brokenCmdTiming;
658 }
659
662 [[nodiscard]] EmuTime getAccessSlot(EmuTime::param time, VDPAccessSlots::Delta delta) const;
663
674 EmuTime::param time, EmuTime::param limit) const;
675
693 void scheduleCmdSync(EmuTime t) {
694 auto now = getCurrentTime();
695 if (t <= now) {
696 // The largest amount of VDP cycles between 'progress'
697 // in command emulation:
698 // - worst case the LMMM takes 120+64 cycles to fully process one pixel
699 // - the largest gap between access slots is 70 cycles
700 // - but if we're unlucky the CPU steals that slot
701 int LARGEST_STALL = 184 + 2 * 70;
702
703 t = now + VDPClock::duration(LARGEST_STALL);
704 }
705 syncCmdDone.setSyncPoint(t);
706 }
707
708 template<typename Archive>
709 void serialize(Archive& ar, unsigned version);
710
711private:
712 void initTables();
713
714 // VdpVersion bitmasks
715 static constexpr unsigned VM_MSX1 = 1; // set-> MSX1, unset-> MSX2 or MSX2+
716 static constexpr unsigned VM_PAL = 2; // set-> fixed PAL, unset-> fixed NTSC or switchable
717 static constexpr unsigned VM_NO_MIRRORING = 4; // set-> no (screen2) mirroring
718 static constexpr unsigned VM_PALCOL_MIRRORING = 8; // set-> pattern/color-table mirroring
719 static constexpr unsigned VM_VRAM_REMAPPING = 16; // set-> 4k,8/16k VRAM remapping
720 static constexpr unsigned VM_TOSHIBA_PALETTE = 32; // set-> has Toshiba palette
721 static constexpr unsigned VM_YJK = 64; // set-> has YJK (MSX2+)
722 static constexpr unsigned VM_YM2220_PALETTE = 128; // set-> has YM2220 palette
723
725 enum VdpVersion {
730 TMS99X8A = VM_MSX1 | VM_PALCOL_MIRRORING | VM_VRAM_REMAPPING,
731
733 TMS9929A = VM_MSX1 | VM_PALCOL_MIRRORING | VM_VRAM_REMAPPING | VM_PAL,
734
736 TMS9129 = VM_MSX1 | VM_PAL,
737
739 TMS91X8 = VM_MSX1,
740
742 T6950PAL = VM_MSX1 | VM_TOSHIBA_PALETTE | VM_NO_MIRRORING | VM_PAL,
743
745 T6950NTSC = VM_MSX1 | VM_TOSHIBA_PALETTE | VM_NO_MIRRORING,
746
748 T7937APAL = VM_MSX1 | VM_TOSHIBA_PALETTE | VM_PAL,
749
751 T7937ANTSC = VM_MSX1 | VM_TOSHIBA_PALETTE,
752
754 YM2220PAL = VM_MSX1 | VM_YM2220_PALETTE | VM_PALCOL_MIRRORING | VM_PAL,
755
757 YM2220NTSC = VM_MSX1 | VM_YM2220_PALETTE | VM_PALCOL_MIRRORING,
758
760 V9938 = 0,
761
763 V9958 = VM_YJK,
764 };
765
766 struct SyncBase : public Schedulable {
767 explicit SyncBase(VDP& vdp_) : Schedulable(vdp_.getScheduler()) {}
771 protected:
772 ~SyncBase() = default;
773 };
774
775 struct SyncVSync final : public SyncBase {
776 explicit SyncVSync(VDP& vdp) : SyncBase(vdp) {}
777 void executeUntil(EmuTime::param time) override {
778 auto& vdp = OUTER(VDP, syncVSync);
779 vdp.execVSync(time);
780 }
781 } syncVSync;
782
783 struct SyncDisplayStart final : public SyncBase {
784 explicit SyncDisplayStart(VDP& vdp) : SyncBase(vdp) {}
785 void executeUntil(EmuTime::param time) override {
786 auto& vdp = OUTER(VDP, syncDisplayStart);
787 vdp.execDisplayStart(time);
788 }
789 } syncDisplayStart;
790
791 struct SyncVScan final : public SyncBase {
792 explicit SyncVScan(VDP& vdp) : SyncBase(vdp) {}
793 void executeUntil(EmuTime::param time) override {
794 auto& vdp = OUTER(VDP, syncVScan);
795 vdp.execVScan(time);
796 }
797 } syncVScan;
798
799 struct SyncHScan final : public SyncBase {
800 explicit SyncHScan(VDP& vdp) : SyncBase(vdp) {}
801 void executeUntil(EmuTime::param /*time*/) override {
802 auto& vdp = OUTER(VDP, syncHScan);
803 vdp.execHScan();
804 }
805 } syncHScan;
806
807 struct SyncHorAdjust final : public SyncBase {
808 explicit SyncHorAdjust(VDP& vdp) : SyncBase(vdp) {}
809 void executeUntil(EmuTime::param time) override {
810 auto& vdp = OUTER(VDP, syncHorAdjust);
811 vdp.execHorAdjust(time);
812 }
813 } syncHorAdjust;
814
815 struct SyncSetMode final : public SyncBase {
816 explicit SyncSetMode(VDP& vdp) : SyncBase(vdp) {}
817 void executeUntil(EmuTime::param time) override {
818 auto& vdp = OUTER(VDP, syncSetMode);
819 vdp.execSetMode(time);
820 }
821 } syncSetMode;
822
823 struct SyncSetBlank final : public SyncBase {
824 explicit SyncSetBlank(VDP& vdp) : SyncBase(vdp) {}
825 void executeUntil(EmuTime::param time) override {
826 auto& vdp = OUTER(VDP, syncSetBlank);
827 vdp.execSetBlank(time);
828 }
829 } syncSetBlank;
830
831 struct SyncSetSprites final : public SyncBase {
832 explicit SyncSetSprites(VDP& vdp) : SyncBase(vdp) {}
833 void executeUntil(EmuTime::param time) override {
834 auto& vdp = OUTER(VDP, syncSetSprites);
835 vdp.execSetSprites(time);
836 }
837 } syncSetSprites;
838
839 struct SyncCpuVramAccess final : public SyncBase {
840 explicit SyncCpuVramAccess(VDP& vdp) : SyncBase(vdp) {}
841 void executeUntil(EmuTime::param time) override {
842 auto& vdp = OUTER(VDP, syncCpuVramAccess);
843 vdp.execCpuVramAccess(time);
844 }
845 } syncCpuVramAccess;
846
847 struct SyncCmdDone final : public SyncBase {
848 explicit SyncCmdDone(VDP& vdp) : SyncBase(vdp) {}
849 void executeUntil(EmuTime::param time) override {
850 auto& vdp = OUTER(VDP, syncCmdDone);
851 vdp.execSyncCmdDone(time);
852 }
853 } syncCmdDone;
854
855 void execVSync(EmuTime::param time);
856 void execDisplayStart(EmuTime::param time);
857 void execVScan(EmuTime::param time);
858 void execHScan();
859 void execHorAdjust(EmuTime::param time);
860 void execSetMode(EmuTime::param time);
861 void execSetBlank(EmuTime::param time);
862 void execSetSprites(EmuTime::param time);
863 void execCpuVramAccess(EmuTime::param time);
864 void execSyncCmdDone(EmuTime::param time);
865
869 [[nodiscard]] int getVerticalAdjust() const {
870 return (controlRegs[18] >> 4) ^ 0x07;
871 }
872
882 [[nodiscard]] inline bool getHR(int ticksThisFrame) const {
883 // Note: These constants are located inside this function because
884 // GCC 4.0.x won't link if they are in the class scope.
888 static constexpr int HBLANK_LEN_TXT = 404;
892 static constexpr int HBLANK_LEN_GFX = 312;
893 return (ticksThisFrame + TICKS_PER_LINE - getRightBorder()) % TICKS_PER_LINE
894 < (displayMode.isTextMode() ? HBLANK_LEN_TXT : HBLANK_LEN_GFX);
895 }
896
897 // VideoSystemChangeListener interface:
898 void preVideoSystemChange() noexcept override;
899 void postVideoSystemChange() noexcept override;
900
905 void resetInit();
906
911 void resetMasks(EmuTime::param time);
912
916 void frameStart(EmuTime::param time);
917
925 void scheduleDisplayStart(EmuTime::param time);
926
932 void scheduleVScan(EmuTime::param time);
933
939 void scheduleHScan(EmuTime::param time);
940
943 void vramWrite(byte value, EmuTime::param time);
944
947 [[nodiscard]] byte vramRead(EmuTime::param time);
948
950 void scheduleCpuVramAccess(bool isRead, byte write, EmuTime::param time);
951 void executeCpuVramAccess(EmuTime::param time);
952
955 [[nodiscard]] byte readStatusReg(byte reg, EmuTime::param time);
956
959 void syncAtNextLine(SyncBase& type, EmuTime::param time);
960
963 void createRenderer();
964
968 void updateNameBase(EmuTime::param time);
969
973 void updateColorBase(EmuTime::param time);
974
978 void updatePatternBase(EmuTime::param time);
979
983 void updateSpriteAttributeBase(EmuTime::param time);
984
988 void updateSpritePatternBase(EmuTime::param time);
989
993 void updateDisplayMode(DisplayMode newMode, bool cmdBit, EmuTime::param time);
994
995 // Observer<Setting>
996 void update(const Setting& setting) noexcept override;
997
998private:
999 Display& display;
1000 EnumSetting<bool>& cmdTiming;
1001 EnumSetting<bool>& tooFastAccess;
1002
1003 struct RegDebug final : SimpleDebuggable {
1004 explicit RegDebug(VDP& vdp);
1005 [[nodiscard]] byte read(unsigned address) override;
1006 void write(unsigned address, byte value, EmuTime::param time) override;
1007 } vdpRegDebug;
1008
1009 struct StatusRegDebug final : SimpleDebuggable {
1010 explicit StatusRegDebug(VDP& vdp);
1011 [[nodiscard]] byte read(unsigned address, EmuTime::param time) override;
1012 } vdpStatusRegDebug;
1013
1014 struct PaletteDebug final : SimpleDebuggable {
1015 explicit PaletteDebug(VDP& vdp);
1016 [[nodiscard]] byte read(unsigned address) override;
1017 void write(unsigned address, byte value, EmuTime::param time) override;
1018 } vdpPaletteDebug;
1019
1020 struct VRAMPointerDebug final : SimpleDebuggable {
1021 explicit VRAMPointerDebug(VDP& vdp);
1022 [[nodiscard]] byte read(unsigned address) override;
1023 void write(unsigned address, byte value, EmuTime::param time) override;
1024 } vramPointerDebug;
1025
1026 struct RegisterLatchStatusDebug final : SimpleDebuggable {
1027 explicit RegisterLatchStatusDebug(VDP& vdp);
1028 [[nodiscard]] byte read(unsigned address) override;
1029 } registerLatchStatusDebug;
1030
1031 struct VramAccessStatusDebug final : SimpleDebuggable {
1032 explicit VramAccessStatusDebug(VDP& vdp);
1033 [[nodiscard]] byte read(unsigned address) override;
1034 } vramAccessStatusDebug;
1035
1036 struct PaletteLatchStatusDebug final : SimpleDebuggable {
1037 explicit PaletteLatchStatusDebug(VDP& vdp);
1038 [[nodiscard]] byte read(unsigned address) override;
1039 } paletteLatchStatusDebug;
1040
1041 struct DataLatchDebug final : SimpleDebuggable {
1042 explicit DataLatchDebug(VDP& vdp);
1043 [[nodiscard]] byte read(unsigned address) override;
1044 } dataLatchDebug;
1045
1046 class Info : public InfoTopic {
1047 public:
1048 void execute(std::span<const TclObject> tokens,
1049 TclObject& result) const override;
1050 [[nodiscard]] std::string help(std::span<const TclObject> tokens) const override;
1051 [[nodiscard]] virtual int calc(const EmuTime& time) const = 0;
1052 protected:
1053 Info(VDP& vdp_, const std::string& name, std::string helpText_);
1054 ~Info() = default;
1055 VDP& vdp;
1056 const std::string helpText;
1057 };
1058
1059 struct FrameCountInfo final : Info {
1060 explicit FrameCountInfo(VDP& vdp);
1061 [[nodiscard]] int calc(const EmuTime& time) const override;
1062 } frameCountInfo;
1063
1064 struct CycleInFrameInfo final : Info {
1065 explicit CycleInFrameInfo(VDP& vdp);
1066 [[nodiscard]] int calc(const EmuTime& time) const override;
1067 } cycleInFrameInfo;
1068
1069 struct LineInFrameInfo final : Info {
1070 explicit LineInFrameInfo(VDP& vdp);
1071 [[nodiscard]] int calc(const EmuTime& time) const override;
1072 } lineInFrameInfo;
1073
1074 struct CycleInLineInfo final : Info {
1075 explicit CycleInLineInfo(VDP& vdp);
1076 [[nodiscard]] int calc(const EmuTime& time) const override;
1077 } cycleInLineInfo;
1078
1079 struct MsxYPosInfo final : Info {
1080 explicit MsxYPosInfo(VDP& vdp);
1081 [[nodiscard]] int calc(const EmuTime& time) const override;
1082 } msxYPosInfo;
1083
1084 struct MsxX256PosInfo final : Info {
1085 explicit MsxX256PosInfo(VDP& vdp);
1086 [[nodiscard]] int calc(const EmuTime& time) const override;
1087 } msxX256PosInfo;
1088
1089 struct MsxX512PosInfo final : Info {
1090 explicit MsxX512PosInfo(VDP& vdp);
1091 [[nodiscard]] int calc(const EmuTime& time) const override;
1092 } msxX512PosInfo;
1093
1096 std::unique_ptr<Renderer> renderer;
1097
1100 std::unique_ptr<VDPCmdEngine> cmdEngine;
1101
1104 std::unique_ptr<SpriteChecker> spriteChecker;
1105
1108 std::unique_ptr<VDPVRAM> vram;
1109
1113 const RawFrame* externalVideo;
1114
1120 const RawFrame* superimposing;
1121
1124 VDPClock frameStartTime;
1125
1128 OptionalIRQHelper irqVertical;
1129
1132 OptionalIRQHelper irqHorizontal;
1133
1136 EmuTime displayStartSyncTime;
1137
1140 EmuTime vScanSyncTime;
1141
1144 EmuTime hScanSyncTime;
1145
1146 TclCallback tooFastCallback;
1147
1150 VdpVersion version;
1151
1156 int saturationPr;
1157
1162 int saturationPb;
1163
1169 int frameCount;
1170
1173 int displayStart;
1174
1178 int horizontalScanOffset;
1179
1183 int horizontalAdjust;
1184
1187 std::array<byte, 32> controlRegs;
1188
1193 byte controlRegMask;
1194
1201 std::array<byte, 32> controlValueMasks;
1202
1206 int blinkCount;
1207
1211 int vramPointer;
1212
1215 std::array<uint16_t, 16> palette;
1216
1219 bool isDisplayArea;
1220
1226 bool palTiming;
1227
1231 bool interlaced = false;
1232
1237 byte statusReg0;
1238
1244 byte statusReg1;
1245
1250 byte statusReg2;
1251
1254 bool blinkState;
1255
1258 byte dataLatch;
1259
1266 bool writeAccess;
1267
1270 bool registerDataStored;
1271
1274 bool paletteDataStored;
1275
1283 byte cpuVramData;
1284
1288 bool cpuVramReqIsRead;
1289 bool pendingCpuAccess; // always equal to pendingSyncPoint(CPU_VRAM_ACCESS)
1290
1294 bool cpuExtendedVram;
1295
1301 DisplayMode displayMode;
1302
1307 bool displayEnabled;
1308
1314 bool spriteEnabled;
1315
1319 bool warningPrinted = false;
1320
1322 bool brokenCmdTiming;
1323 bool allowTooFastAccess;
1324
1326 MSXCPU& cpu;
1327 const byte fixedVDPIOdelayCycles;
1328};
1330
1331} // namespace openmsx
1332
1333#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
A post processor builds the frame that is displayed from the MSX frame, while applying effects such a...
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:580
bool getEvenOdd() const
Is the even or odd field being displayed?
Definition: VDP.hh:432
int getLinesPerFrame() const
Gets the number of lines per frame.
Definition: VDP.hh:546
int getNumberOfLines() const
Gets the number of display lines per screen.
Definition: VDP.hh:553
unsigned getEvenOddMask() const
Expresses the state of even/odd page interchange in a mask on the line number.
Definition: VDP.hh:447
bool spritesEnabled() const
Are sprites enabled?
Definition: VDP.hh:300
int getSpriteSize() const
Gets the sprite size in pixels (8/16).
Definition: VDP.hh:527
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:619
SpriteChecker & getSpriteChecker()
Get the sprite checker for this VDP.
Definition: VDP.hh:179
bool getBrokenCmdTiming() const
Value of the cmdTiming setting, true means commands have infinite speed.
Definition: VDP.hh:656
int getNameTableBase() const
Get address of name table (only for debugger)
Definition: VDP.hh:255
bool isEvenOddEnabled() const
Get even/odd page alternation status.
Definition: VDP.hh:424
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 changeRegister(byte reg, byte val, EmuTime::param time)
VDP control register has changed, work out the consequences.
Definition: VDP.cc:1013
void scheduleCmdSync(EmuTime t)
Only used when there are commandExecuting-probe listeners.
Definition: VDP.hh:693
byte peekRegister(unsigned address) const
Definition: VDP.cc:753
bool spritesEnabledRegister() const
Still faster variant (just looks at the sprite-enabled-bit).
Definition: VDP.hh:317
BlinkStateCount calculateLineBlinkState(unsigned line) const
Definition: VDP.hh:478
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:159
bool isFastBlinkEnabled() const
Get 'fast-blink' status.
Definition: VDP.hh:409
std::array< std::array< uint8_t, 3 >, 16 > getMSX1Palette() const
Get the (fixed) palette for this MSX1 VDP.
Definition: VDP.cc:1549
PostProcessor * getPostProcessor() const
Used by Video9000 to be able to couple the VDP and V9990 output.
Definition: VDP.cc:237
int getSpritePatternTableBase() const
Get address of pattern table (only for debugger)
Definition: VDP.hh:259
bool isVDPwithPALonly() const
Is this a VDP only capable of PAL?
Definition: VDP.hh:112
const RawFrame * isSuperimposing() const
Are we currently superimposing? In case of superimpose, returns a pointer to the to-be-superimposed f...
Definition: VDP.hh:167
void getExtraDeviceInfo(TclObject &result) const override
Definition: VDP.cc:748
bool getCmdBit() const
Are commands possible in non Graphic modes? (V9958 only)
Definition: VDP.hh:540
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:898
void reset(EmuTime::param time) override
This method is called on reset.
Definition: VDP.cc:315
void setPalette(unsigned index, word grb, EmuTime::param time)
Sets a palette entry.
Definition: VDP.cc:764
bool isBorderMasked() const
Gets the current border mask setting.
Definition: VDP.hh:351
byte getStatusReg0() const
Should only be used by SpriteChecker.
Definition: VDP.hh:626
bool spritesEnabledFast() const
Same as spritesEnabled(), but may only be called in sprite mode 1 or 2.
Definition: VDP.hh:309
int getForegroundColor() const
Gets the current foreground color.
Definition: VDP.hh:204
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:235
int getTicksPerFrame() const
Gets the number of VDP clock ticks (21MHz) per frame.
Definition: VDP.hh:559
bool isInsideFrame(EmuTime::param time) const
Is the given timestamp inside the current frame? Mainly useful for debugging, because relevant timest...
Definition: VDP.hh:572
void serialize(Archive &ar, unsigned version)
Definition: VDP.cc:1913
unsigned getEvenOddMask(int line) const
Similar to the above getEvenOddMask() method, but can also be called when 'isFastBlinkEnabled() == tr...
Definition: VDP.hh:460
void setSpriteStatus(byte value)
Should only be used by SpriteChecker.
Definition: VDP.hh:636
Clock< TICKS_PER_SECOND > VDPClock
Definition: VDP.hh:69
uint16_t getPalette(unsigned index) const
Gets a palette entry.
Definition: VDP.hh:272
byte getHorizontalScrollHigh() const
Gets the current horizontal scroll higher bits.
Definition: VDP.hh:342
int getRightBorder() const
Gets the number of VDP clock ticks between start of line and the start of the right border.
Definition: VDP.hh:609
DisplayMode getDisplayMode() const
Get the display mode the VDP is in.
Definition: VDP.hh:153
int getPatternTableBase() const
Get address of pattern table (only for debugger)
Definition: VDP.hh:247
int getDisplayPage() const
Only used by debugger.
Definition: VDP.hh:368
~VDP() override
Definition: VDP.cc:211
bool getBlinkState() const
Gets the current blink state.
Definition: VDP.hh:242
int getColorTableBase() const
Get address of color table (only for debugger)
Definition: VDP.hh:251
int getLineZero() const
Get the absolute line number of display line zero.
Definition: VDP.hh:376
int getBlinkForegroundColor() const
Gets the current blinking color for blinking text.
Definition: VDP.hh:228
void setExternalVideoSource(const RawFrame *externalSource)
Enable superimposing.
Definition: VDP.hh:650
bool isMSX1VDP() const
Is this an MSX1 VDP?
Definition: VDP.hh:105
byte getBackgroundColor() const
Gets the current background color.
Definition: VDP.hh:216
byte getVerticalScroll() const
Gets the current vertical scroll (line displayed at Y=0).
Definition: VDP.hh:324
bool isVDPwithVRAMremapping() const
Does this VDP have VRAM remapping when switching from 4k to 8/16k mode?
Definition: VDP.hh:133
bool hasYJK() const
Does this VDP support YJK display?
Definition: VDP.hh:140
EmuTime::param getFrameStartTime() const
Definition: VDP.hh:521
bool canSpriteColor0Collide() const
Can a sprite which has color=0 collide with some other sprite?
Definition: VDP.hh:192
bool isMultiPageScrolling() const
Is multi page scrolling enabled? It is considered enabled if both the multi page scrolling flag is en...
Definition: VDP.hh:361
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
Definition: VDP.cc:1007
int getLeftBorder() const
Gets the number of VDP clock ticks between start of line and the end of the left border.
Definition: VDP.hh:602
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:892
bool isSpriteMag() const
Are sprites magnified?
Definition: VDP.hh:533
bool vdpHasPatColMirroring() const
Is this a VDP that has pattern/color table mirroring?
Definition: VDP.hh:126
bool isPalTiming() const
Is PAL timing active? This setting is fixed at start of frame.
Definition: VDP.hh:384
bool isInterlaced() const
Get interlace status.
Definition: VDP.hh:395
bool getTransparency() const
Gets the current transparency setting.
Definition: VDP.hh:186
int getSpriteAttributeTableBase() const
Get address of color table (only for debugger)
Definition: VDP.hh:263
bool getVRMode() const
Returns current VR mode.
Definition: VDP.hh:644
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:987
std::string_view getVersionString() const
Definition: VDP.cc:737
bool isDisplayEnabled() const
Is the display enabled? Both the regular border and forced blanking by clearing the display enable bi...
Definition: VDP.hh:292
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:517
bool vdpLacksMirroring() const
Is this a VDP that lacks mirroring?
Definition: VDP.hh:119
byte getHorizontalScrollLow() const
Gets the current horizontal scroll lower bits.
Definition: VDP.hh:333
VDP(const DeviceConfig &config)
Definition: VDP.cc:62
byte peekStatusReg(byte reg, EmuTime::param time) const
Definition: VDP.cc:905
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:591
std::span< const uint16_t, 16 > getPalette() const
Definition: VDP.hh:275
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:474