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 "openmsx.hh"
15
16#include "Observer.hh"
17#include "gl_vec.hh"
18#include "narrow.hh"
19#include "outer.hh"
20
21#include <memory>
22#include <array>
23
24namespace openmsx {
25
26class PostProcessor;
27class Renderer;
28class VDPCmdEngine;
29class VDPVRAM;
30class MSXCPU;
31class SpriteChecker;
32class Display;
33class RawFrame;
34class Setting;
35namespace VDPAccessSlots {
36 enum class Delta : int;
37 class Calculator;
38}
39
65class VDP final : public MSXDevice, private VideoSystemChangeListener
66 , private Observer<Setting>
67{
68public:
71 static constexpr int TICKS_PER_SECOND = 3579545 * 6; // 21.5MHz;
73
76 static constexpr int TICKS_PER_LINE = 1368;
77
78 explicit VDP(const DeviceConfig& config);
79 ~VDP() override;
80
81 void powerUp(EmuTime::param time) override;
82 void reset(EmuTime::param time) override;
83 [[nodiscard]] byte readIO(word port, EmuTime::param time) override;
84 [[nodiscard]] byte peekIO(word port, EmuTime::param time) const override;
85 void writeIO(word port, byte value, EmuTime::param time) override;
86
87 void getExtraDeviceInfo(TclObject& result) const override;
88 [[nodiscard]] std::string_view getVersionString() const;
89
90 [[nodiscard]] byte peekRegister(unsigned address) const;
91 [[nodiscard]] byte peekStatusReg(byte reg, EmuTime::param time) const;
92
95 void changeRegister(byte reg, byte val, EmuTime::param time);
96
97
102 [[nodiscard]] PostProcessor* getPostProcessor() const;
103
108 [[nodiscard]] inline bool isMSX1VDP() const {
109 return (version & VM_MSX1) != 0;
110 }
111
115 [[nodiscard]] inline bool isVDPwithPALonly() const {
116 return (version & VM_PAL) != 0;
117 }
118
122 [[nodiscard]] inline bool vdpLacksMirroring() const {
123 return (version & VM_NO_MIRRORING) != 0;
124 }
125
129 [[nodiscard]] inline bool vdpHasPatColMirroring() const {
130 return (version & VM_PALCOL_MIRRORING) != 0;
131 }
132
136 [[nodiscard]] inline bool isVDPwithVRAMremapping() const {
137 return (version & VM_VRAM_REMAPPING) != 0;
138 }
139
143 [[nodiscard]] inline bool hasYJK() const {
144 return (version & VM_YJK) != 0;
145 }
146
151 [[nodiscard]] std::array<std::array<uint8_t, 3>, 16> getMSX1Palette() const;
152
156 [[nodiscard]] inline DisplayMode getDisplayMode() const {
157 return displayMode;
158 }
159
162 [[nodiscard]] inline VDPVRAM& getVRAM() {
163 return *vram;
164 }
165
170 [[nodiscard]] inline const RawFrame* isSuperimposing() const {
171 // Note that bit 0 of r#0 has no effect on an V9938 or higher,
172 // but this bit is masked out. Also note that on an MSX1, if
173 // bit 0 of r#0 is enabled and there is no external video
174 // source, then we lose sync.
175 // Also note that because this property is fixed per frame we
176 // cannot (re)calculate it from register values.
177 return superimposing;
178 }
179
182 [[nodiscard]] inline SpriteChecker& getSpriteChecker() {
183 return *spriteChecker;
184 }
185
189 [[nodiscard]] inline bool getTransparency() const {
190 return (controlRegs[8] & 0x20) == 0;
191 }
192
195 [[nodiscard]] bool canSpriteColor0Collide() const {
196 // On MSX1 (so far only tested a TMS9129(?)) sprites with
197 // color=0 can always collide with other sprites. Though on
198 // V99x8 (only tested V9958) collisions only occur when color 0
199 // is not transparent. For more details see:
200 // https://github.com/openMSX/openMSX/issues/1198
201 return isMSX1VDP() || !getTransparency();
202 }
203
207 [[nodiscard]] inline int getForegroundColor() const {
208 return controlRegs[7] >> 4;
209 }
210
219 [[nodiscard]] inline byte getBackgroundColor() const {
220 byte reg7 = controlRegs[7];
221 if (displayMode.getByte() == DisplayMode::GRAPHIC7) {
222 return reg7;
223 } else {
224 return reg7 & 0x0F;
225 }
226 }
227
231 [[nodiscard]] inline int getBlinkForegroundColor() const {
232 return controlRegs[12] >> 4;
233 }
234
238 [[nodiscard]] inline int getBlinkBackgroundColor() const {
239 return controlRegs[12] & 0x0F;
240 }
241
245 [[nodiscard]] inline bool getBlinkState() const {
246 return blinkState;
247 }
248
250 [[nodiscard]] int getPatternTableBase() const {
251 return controlRegs[4] << 11;
252 }
254 [[nodiscard]] int getColorTableBase() const {
255 return (controlRegs[10] << 14) | (controlRegs[3] << 6);
256 }
258 [[nodiscard]] int getNameTableBase() const {
259 return controlRegs[2] << 10;
260 }
262 [[nodiscard]] int getSpritePatternTableBase() const {
263 return controlRegs[6] << 11;
264 }
266 [[nodiscard]] int getSpriteAttributeTableBase() const {
267 return (controlRegs[11] << 15) | (controlRegs[5] << 7);
268 }
270 [[nodiscard]] int getVramPointer() const {
271 return vramPointer;
272 }
273
279 [[nodiscard]] inline uint16_t getPalette(unsigned index) const {
280 return palette[index];
281 }
282 [[nodiscard]] inline std::span<const uint16_t, 16> getPalette() const {
283 return palette;
284 }
285
292 void setPalette(unsigned index, word grb, EmuTime::param time);
293
299 [[nodiscard]] inline bool isDisplayEnabled() const {
300 return isDisplayArea && displayEnabled;
301 }
302
307 [[nodiscard]] inline bool spritesEnabled() const {
308 return displayEnabled &&
309 (displayMode.getSpriteMode(isMSX1VDP()) != 0) &&
310 spriteEnabled;
311 }
312
316 [[nodiscard]] inline bool spritesEnabledFast() const {
317 assert(displayMode.getSpriteMode(isMSX1VDP()) != 0);
318 return displayEnabled && spriteEnabled;
319 }
320
324 [[nodiscard]] inline bool spritesEnabledRegister() const {
325 return spriteEnabled;
326 }
327
331 [[nodiscard]] inline byte getVerticalScroll() const {
332 return controlRegs[23];
333 }
334
340 [[nodiscard]] inline byte getHorizontalScrollLow() const {
341 return controlRegs[27];
342 }
343
349 [[nodiscard]] inline byte getHorizontalScrollHigh() const {
350 return controlRegs[26];
351 }
352
358 [[nodiscard]] inline bool isBorderMasked() const {
359 return (controlRegs[25] & 0x02) != 0;
360 }
361
368 [[nodiscard]] inline bool isMultiPageScrolling() const {
369 return (controlRegs[25] & 0x01) && (controlRegs[2] & 0x20);
370 }
371
375 [[nodiscard]] int getDisplayPage() const {
376 return (controlRegs[2] >> 5) & 3;
377 }
378
383 [[nodiscard]] inline int getLineZero() const {
384 return displayStart / TICKS_PER_LINE;
385 }
386
391 [[nodiscard]] inline bool isPalTiming() const {
392 return palTiming;
393 }
394
402 [[nodiscard]] inline bool isInterlaced() const {
403 return interlaced;
404 }
405
416 [[nodiscard]] inline bool isFastBlinkEnabled() const {
417 return (controlRegs[1] & 4) != 0;
418 }
419
431 [[nodiscard]] inline bool isEvenOddEnabled() const {
432 if (isFastBlinkEnabled()) return false;
433 return (controlRegs[9] & 4) != 0;
434 }
435
439 [[nodiscard]] inline bool getEvenOdd() const {
440 return (statusReg2 & 2) != 0;
441 }
442
454 [[nodiscard]] inline unsigned getEvenOddMask() const {
455 // TODO: Verify which page is displayed on even fields.
456 assert(!isFastBlinkEnabled());
457 return (((~controlRegs[9] & 4) << 6) | ((statusReg2 & 2) << 7)) &
458 (!blinkState << 8);
459 }
460
467 [[nodiscard]] inline unsigned getEvenOddMask(int line) const {
468 if (isFastBlinkEnabled()) {
469 // EO and IL not considered in this mode
470 auto p = calculateLineBlinkState(line);
471 return (!p.state) << 8;
472 } else {
473 return getEvenOddMask();
474 }
475 }
476
482 bool state;
483 int count;
484 };
485 [[nodiscard]] BlinkStateCount calculateLineBlinkState(unsigned line) const {
486 assert(isFastBlinkEnabled());
487
488 if (blinkCount == 0) { // not changing
489 return {blinkState, blinkCount};
490 }
491
492 unsigned evenLen = ((controlRegs[13] >> 4) & 0x0F) * 10;
493 unsigned oddLen = ((controlRegs[13] >> 0) & 0x0F) * 10;
494 unsigned totalLen = evenLen + oddLen;
495 assert(totalLen != 0); // because this implies 'blinkCount == 0'
496 line %= totalLen; // reduce double flips
497
498 bool resultState = blinkState; // initial guess, adjusted later
499 if (blinkState) {
500 // We start in the 'even' period -> check first for
501 // even/odd transition, next for odd/even
502 } else {
503 // We start in the 'odd' period -> do the opposite
504 std::swap(evenLen, oddLen);
505 }
506 int newCount = blinkCount - narrow<int>(line);
507 if (newCount <= 0) {
508 // switch even->odd (or odd->even)
509 resultState = !resultState;
510 newCount += narrow<int>(oddLen);
511 if (newCount <= 0) {
512 // switch odd->even (or even->odd)
513 resultState = !resultState;
514 newCount += narrow<int>(evenLen);
515 assert(newCount > 0);
516 }
517 }
518 return {resultState, newCount};
519 }
520
524 [[nodiscard]] inline int getTicksThisFrame(EmuTime::param time) const {
525 return narrow<int>(frameStartTime.getTicksTill_fast(time));
526 }
527
528 [[nodiscard]] inline EmuTime::param getFrameStartTime() const {
529 return frameStartTime.getTime();
530 }
531
534 [[nodiscard]] inline int getSpriteSize() const {
535 return ((controlRegs[1] & 2) << 2) + 8;
536 }
537
540 [[nodiscard]] inline bool isSpriteMag() const {
541 return controlRegs[1] & 1;
542 }
543
547 [[nodiscard]] inline bool getCmdBit() const {
548 return (controlRegs[25] & 0x40) != 0;
549 }
550
553 [[nodiscard]] inline int getLinesPerFrame() const {
554 return palTiming ? 313 : 262;
555 }
556
560 [[nodiscard]] inline int getNumberOfLines() const {
561 return controlRegs[9] & 0x80 ? 212 : 192;
562 }
563
566 [[nodiscard]] inline int getTicksPerFrame() const {
568 }
569
579 [[nodiscard]] inline bool isInsideFrame(EmuTime::param time) const {
580 return time >= frameStartTime.getTime() &&
582 }
583
587 [[nodiscard]] inline int getHorizontalAdjust() const {
588 return horizontalAdjust;
589 }
590
598 [[nodiscard]] inline int getLeftSprites() const {
599 return 100 + 102 + 56
600 + (horizontalAdjust - 7) * 4
601 + (displayMode.isTextMode() ? 36 : 0);
602 }
603
609 [[nodiscard]] inline int getLeftBorder() const {
610 return getLeftSprites() + (isBorderMasked() ? 8 * 4 : 0);
611 }
612
616 [[nodiscard]] inline int getRightBorder() const {
617 return getLeftSprites()
618 + (displayMode.isTextMode() ? 960 : 1024);
619 }
620
626 [[nodiscard]] inline int getLeftBackground() const {
627 return getLeftSprites() + getHorizontalScrollLow() * 4;
628 }
629
633 [[nodiscard]] byte getStatusReg0() const { return statusReg0; }
634
643 void setSpriteStatus(byte value)
644 {
645 statusReg0 = (statusReg0 & 0x80) | (value & 0x7F);
646 }
647
651 [[nodiscard]] bool getVRMode() const {
652 return (controlRegs[8] & 8) != 0;
653 }
654
657 void setExternalVideoSource(const RawFrame* externalSource) {
658 externalVideo = externalSource;
659 }
660
663 [[nodiscard]] bool getBrokenCmdTiming() const {
664 return brokenCmdTiming;
665 }
666
669 [[nodiscard]] EmuTime getAccessSlot(EmuTime::param time, VDPAccessSlots::Delta delta) const;
670
681 EmuTime::param time, EmuTime::param limit) const;
682
700 void scheduleCmdSync(EmuTime t) {
701 if (auto now = getCurrentTime(); t <= now) {
702 // The largest amount of VDP cycles between 'progress'
703 // in command emulation:
704 // - worst case the LMMM takes 120+64 cycles to fully process one pixel
705 // - the largest gap between access slots is 70 cycles
706 // - but if we're unlucky the CPU steals that slot
707 int LARGEST_STALL = 184 + 2 * 70;
708
709 t = now + VDPClock::duration(LARGEST_STALL);
710 }
711 syncCmdDone.setSyncPoint(t);
712 }
713
729 [[nodiscard]] gl::ivec2 getMSXPos(EmuTime::param time) const {
730 auto ticks = getTicksThisFrame(time);
731 return {((ticks % VDP::TICKS_PER_LINE) - getLeftSprites()) / 2,
732 (ticks / VDP::TICKS_PER_LINE) - getLineZero()};
733 }
734
735 // for debugging only
736 VDPCmdEngine& getCmdEngine() { return *cmdEngine; }
737
738 template<typename Archive>
739 void serialize(Archive& ar, unsigned version);
740
741private:
742 void initTables();
743
744 // VdpVersion bitmasks
745 static constexpr unsigned VM_MSX1 = 1; // set-> MSX1, unset-> MSX2 or MSX2+
746 static constexpr unsigned VM_PAL = 2; // set-> fixed PAL, unset-> fixed NTSC or switchable
747 static constexpr unsigned VM_NO_MIRRORING = 4; // set-> no (screen2) mirroring
748 static constexpr unsigned VM_PALCOL_MIRRORING = 8; // set-> pattern/color-table mirroring
749 static constexpr unsigned VM_VRAM_REMAPPING = 16; // set-> 4k,8/16k VRAM remapping
750 static constexpr unsigned VM_TOSHIBA_PALETTE = 32; // set-> has Toshiba palette
751 static constexpr unsigned VM_YJK = 64; // set-> has YJK (MSX2+)
752 static constexpr unsigned VM_YM2220_PALETTE = 128; // set-> has YM2220 palette
753
755 enum VdpVersion {
760 TMS99X8A = VM_MSX1 | VM_PALCOL_MIRRORING | VM_VRAM_REMAPPING,
761
763 TMS9929A = VM_MSX1 | VM_PALCOL_MIRRORING | VM_VRAM_REMAPPING | VM_PAL,
764
766 TMS9129 = VM_MSX1 | VM_PAL,
767
769 TMS91X8 = VM_MSX1,
770
772 T6950PAL = VM_MSX1 | VM_TOSHIBA_PALETTE | VM_NO_MIRRORING | VM_PAL,
773
775 T6950NTSC = VM_MSX1 | VM_TOSHIBA_PALETTE | VM_NO_MIRRORING,
776
778 T7937APAL = VM_MSX1 | VM_TOSHIBA_PALETTE | VM_PAL,
779
781 T7937ANTSC = VM_MSX1 | VM_TOSHIBA_PALETTE,
782
784 YM2220PAL = VM_MSX1 | VM_YM2220_PALETTE | VM_PALCOL_MIRRORING | VM_PAL,
785
787 YM2220NTSC = VM_MSX1 | VM_YM2220_PALETTE | VM_PALCOL_MIRRORING,
788
790 V9938 = 0,
791
793 V9958 = VM_YJK,
794 };
795
796 struct SyncBase : public Schedulable {
797 explicit SyncBase(const VDP& vdp_) : Schedulable(vdp_.getScheduler()) {}
801 protected:
802 ~SyncBase() = default;
803 };
804
805 struct SyncVSync final : public SyncBase {
806 using SyncBase::SyncBase;
807 void executeUntil(EmuTime::param time) override {
808 auto& vdp = OUTER(VDP, syncVSync);
809 vdp.execVSync(time);
810 }
811 } syncVSync;
812
813 struct SyncDisplayStart final : public SyncBase {
814 using SyncBase::SyncBase;
815 void executeUntil(EmuTime::param time) override {
816 auto& vdp = OUTER(VDP, syncDisplayStart);
817 vdp.execDisplayStart(time);
818 }
819 } syncDisplayStart;
820
821 struct SyncVScan final : public SyncBase {
822 using SyncBase::SyncBase;
823 void executeUntil(EmuTime::param time) override {
824 auto& vdp = OUTER(VDP, syncVScan);
825 vdp.execVScan(time);
826 }
827 } syncVScan;
828
829 struct SyncHScan final : public SyncBase {
830 using SyncBase::SyncBase;
831 void executeUntil(EmuTime::param /*time*/) override {
832 auto& vdp = OUTER(VDP, syncHScan);
833 vdp.execHScan();
834 }
835 } syncHScan;
836
837 struct SyncHorAdjust final : public SyncBase {
838 using SyncBase::SyncBase;
839 void executeUntil(EmuTime::param time) override {
840 auto& vdp = OUTER(VDP, syncHorAdjust);
841 vdp.execHorAdjust(time);
842 }
843 } syncHorAdjust;
844
845 struct SyncSetMode final : public SyncBase {
846 using SyncBase::SyncBase;
847 void executeUntil(EmuTime::param time) override {
848 auto& vdp = OUTER(VDP, syncSetMode);
849 vdp.execSetMode(time);
850 }
851 } syncSetMode;
852
853 struct SyncSetBlank final : public SyncBase {
854 using SyncBase::SyncBase;
855 void executeUntil(EmuTime::param time) override {
856 auto& vdp = OUTER(VDP, syncSetBlank);
857 vdp.execSetBlank(time);
858 }
859 } syncSetBlank;
860
861 struct SyncSetSprites final : public SyncBase {
862 using SyncBase::SyncBase;
863 void executeUntil(EmuTime::param time) override {
864 auto& vdp = OUTER(VDP, syncSetSprites);
865 vdp.execSetSprites(time);
866 }
867 } syncSetSprites;
868
869 struct SyncCpuVramAccess final : public SyncBase {
870 using SyncBase::SyncBase;
871 void executeUntil(EmuTime::param time) override {
872 auto& vdp = OUTER(VDP, syncCpuVramAccess);
873 vdp.execCpuVramAccess(time);
874 }
875 } syncCpuVramAccess;
876
877 struct SyncCmdDone final : public SyncBase {
878 using SyncBase::SyncBase;
879 void executeUntil(EmuTime::param time) override {
880 auto& vdp = OUTER(VDP, syncCmdDone);
881 vdp.execSyncCmdDone(time);
882 }
883 } syncCmdDone;
884
885 void execVSync(EmuTime::param time);
886 void execDisplayStart(EmuTime::param time);
887 void execVScan(EmuTime::param time);
888 void execHScan();
889 void execHorAdjust(EmuTime::param time);
890 void execSetMode(EmuTime::param time);
891 void execSetBlank(EmuTime::param time);
892 void execSetSprites(EmuTime::param time);
893 void execCpuVramAccess(EmuTime::param time);
894 void execSyncCmdDone(EmuTime::param time);
895
899 [[nodiscard]] int getVerticalAdjust() const {
900 return (controlRegs[18] >> 4) ^ 0x07;
901 }
902
912 [[nodiscard]] inline bool getHR(int ticksThisFrame) const {
913 // Note: These constants are located inside this function because
914 // GCC 4.0.x won't link if they are in the class scope.
918 static constexpr int HBLANK_LEN_TXT = 404;
922 static constexpr int HBLANK_LEN_GFX = 312;
923 return (ticksThisFrame + TICKS_PER_LINE - getRightBorder()) % TICKS_PER_LINE
924 < (displayMode.isTextMode() ? HBLANK_LEN_TXT : HBLANK_LEN_GFX);
925 }
926
927 // VideoSystemChangeListener interface:
928 void preVideoSystemChange() noexcept override;
929 void postVideoSystemChange() noexcept override;
930
935 void resetInit();
936
941 void resetMasks(EmuTime::param time);
942
946 void frameStart(EmuTime::param time);
947
955 void scheduleDisplayStart(EmuTime::param time);
956
962 void scheduleVScan(EmuTime::param time);
963
969 void scheduleHScan(EmuTime::param time);
970
973 void vramWrite(byte value, EmuTime::param time);
974
977 [[nodiscard]] byte vramRead(EmuTime::param time);
978
980 void scheduleCpuVramAccess(bool isRead, byte write, EmuTime::param time);
981 void executeCpuVramAccess(EmuTime::param time);
982
985 [[nodiscard]] byte readStatusReg(byte reg, EmuTime::param time);
986
989 void syncAtNextLine(SyncBase& type, EmuTime::param time) const;
990
993 void createRenderer();
994
998 void updateNameBase(EmuTime::param time);
999
1003 void updateColorBase(EmuTime::param time);
1004
1008 void updatePatternBase(EmuTime::param time);
1009
1013 void updateSpriteAttributeBase(EmuTime::param time);
1014
1018 void updateSpritePatternBase(EmuTime::param time);
1019
1023 void updateDisplayMode(DisplayMode newMode, bool cmdBit, EmuTime::param time);
1024
1025 // Observer<Setting>
1026 void update(const Setting& setting) noexcept override;
1027
1028private:
1029 Display& display;
1030 EnumSetting<bool>& cmdTiming;
1031 EnumSetting<bool>& tooFastAccess;
1032
1033 struct RegDebug final : SimpleDebuggable {
1034 explicit RegDebug(const VDP& vdp);
1035 [[nodiscard]] byte read(unsigned address) override;
1036 void write(unsigned address, byte value, EmuTime::param time) override;
1037 } vdpRegDebug;
1038
1039 struct StatusRegDebug final : SimpleDebuggable {
1040 explicit StatusRegDebug(const VDP& vdp);
1041 [[nodiscard]] byte read(unsigned address, EmuTime::param time) override;
1042 } vdpStatusRegDebug;
1043
1044 struct PaletteDebug final : SimpleDebuggable {
1045 explicit PaletteDebug(const VDP& vdp);
1046 [[nodiscard]] byte read(unsigned address) override;
1047 void write(unsigned address, byte value, EmuTime::param time) override;
1048 } vdpPaletteDebug;
1049
1050 struct VRAMPointerDebug final : SimpleDebuggable {
1051 explicit VRAMPointerDebug(const VDP& vdp);
1052 [[nodiscard]] byte read(unsigned address) override;
1053 void write(unsigned address, byte value, EmuTime::param time) override;
1054 } vramPointerDebug;
1055
1056 struct RegisterLatchStatusDebug final : SimpleDebuggable {
1057 explicit RegisterLatchStatusDebug(const VDP& vdp);
1058 [[nodiscard]] byte read(unsigned address) override;
1059 } registerLatchStatusDebug;
1060
1061 struct VramAccessStatusDebug final : SimpleDebuggable {
1062 explicit VramAccessStatusDebug(const VDP& vdp);
1063 [[nodiscard]] byte read(unsigned address) override;
1064 } vramAccessStatusDebug;
1065
1066 struct PaletteLatchStatusDebug final : SimpleDebuggable {
1067 explicit PaletteLatchStatusDebug(const VDP& vdp);
1068 [[nodiscard]] byte read(unsigned address) override;
1069 } paletteLatchStatusDebug;
1070
1071 struct DataLatchDebug final : SimpleDebuggable {
1072 explicit DataLatchDebug(const VDP& vdp);
1073 [[nodiscard]] byte read(unsigned address) override;
1074 } dataLatchDebug;
1075
1076 class Info : public InfoTopic {
1077 public:
1078 void execute(std::span<const TclObject> tokens,
1079 TclObject& result) const override;
1080 [[nodiscard]] std::string help(std::span<const TclObject> tokens) const override;
1081 [[nodiscard]] virtual int calc(const EmuTime& time) const = 0;
1082 protected:
1083 Info(VDP& vdp_, const std::string& name, std::string helpText_);
1084 ~Info() = default;
1085 VDP& vdp;
1086 const std::string helpText;
1087 };
1088
1089 struct FrameCountInfo final : Info {
1090 explicit FrameCountInfo(VDP& vdp);
1091 [[nodiscard]] int calc(const EmuTime& time) const override;
1092 } frameCountInfo;
1093
1094 struct CycleInFrameInfo final : Info {
1095 explicit CycleInFrameInfo(VDP& vdp);
1096 [[nodiscard]] int calc(const EmuTime& time) const override;
1097 } cycleInFrameInfo;
1098
1099 struct LineInFrameInfo final : Info {
1100 explicit LineInFrameInfo(VDP& vdp);
1101 [[nodiscard]] int calc(const EmuTime& time) const override;
1102 } lineInFrameInfo;
1103
1104 struct CycleInLineInfo final : Info {
1105 explicit CycleInLineInfo(VDP& vdp);
1106 [[nodiscard]] int calc(const EmuTime& time) const override;
1107 } cycleInLineInfo;
1108
1109 struct MsxYPosInfo final : Info {
1110 explicit MsxYPosInfo(VDP& vdp);
1111 [[nodiscard]] int calc(const EmuTime& time) const override;
1112 } msxYPosInfo;
1113
1114 struct MsxX256PosInfo final : Info {
1115 explicit MsxX256PosInfo(VDP& vdp);
1116 [[nodiscard]] int calc(const EmuTime& time) const override;
1117 } msxX256PosInfo;
1118
1119 struct MsxX512PosInfo final : Info {
1120 explicit MsxX512PosInfo(VDP& vdp);
1121 [[nodiscard]] int calc(const EmuTime& time) const override;
1122 } msxX512PosInfo;
1123
1126 std::unique_ptr<Renderer> renderer;
1127
1130 std::unique_ptr<VDPCmdEngine> cmdEngine;
1131
1134 std::unique_ptr<SpriteChecker> spriteChecker;
1135
1138 std::unique_ptr<VDPVRAM> vram;
1139
1143 const RawFrame* externalVideo;
1144
1150 const RawFrame* superimposing;
1151
1154 VDPClock frameStartTime;
1155
1158 OptionalIRQHelper irqVertical;
1159
1162 OptionalIRQHelper irqHorizontal;
1163
1166 EmuTime displayStartSyncTime;
1167
1170 EmuTime vScanSyncTime;
1171
1174 EmuTime hScanSyncTime;
1175
1176 TclCallback tooFastCallback;
1177 TclCallback dotClockDirectionCallback;
1178
1181 VdpVersion version;
1182
1187 int saturationPr;
1188
1193 int saturationPb;
1194
1200 int frameCount;
1201
1204 int displayStart;
1205
1209 int horizontalScanOffset;
1210
1214 int horizontalAdjust;
1215
1218 std::array<byte, 32> controlRegs;
1219
1224 byte controlRegMask;
1225
1232 std::array<byte, 32> controlValueMasks;
1233
1237 int blinkCount;
1238
1242 int vramPointer;
1243
1246 std::array<uint16_t, 16> palette;
1247
1250 bool isDisplayArea;
1251
1257 bool palTiming;
1258
1262 bool interlaced = false;
1263
1268 byte statusReg0;
1269
1275 byte statusReg1;
1276
1281 byte statusReg2;
1282
1285 bool blinkState;
1286
1289 byte dataLatch;
1290
1297 bool writeAccess;
1298
1301 bool registerDataStored;
1302
1305 bool paletteDataStored;
1306
1314 byte cpuVramData;
1315
1319 bool cpuVramReqIsRead;
1320 bool pendingCpuAccess; // always equal to pendingSyncPoint(CPU_VRAM_ACCESS)
1321
1325 bool cpuExtendedVram;
1326
1332 DisplayMode displayMode;
1333
1338 bool displayEnabled;
1339
1345 bool spriteEnabled;
1346
1350 bool warningPrinted = false;
1351
1353 bool brokenCmdTiming;
1354 bool allowTooFastAccess;
1355
1357 MSXCPU& cpu;
1358 const byte fixedVDPIOdelayCycles;
1359};
1361
1362} // namespace openmsx
1363
1364#endif
BaseSetting * setting
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.
static constexpr uint8_t GRAPHIC7
constexpr bool isTextMode() const
Is the current mode a text mode? Text1 and Text2 are text modes.
constexpr byte getByte() const
Get the display mode as a byte: YAE YJK M5..M1 combined.
constexpr int getSpriteMode(bool isMSX1) const
Get the sprite mode of this display mode.
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition MSXDevice.hh:36
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:16
void setSyncPoint(EmuTime::param timestamp)
bool pendingSyncPoint() const
Scheduler & getScheduler() const
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.
VDP command engine by Alex Wulms.
Manages VRAM contents and synchronizes the various users of the VRAM.
Definition VDPVRAM.hh:399
Unified implementation of MSX Video Display Processors (VDPs).
Definition VDP.hh:67
int getHorizontalAdjust() const
This is a combination of the (horizontal) set adjust register and the YJK-mode bit.
Definition VDP.hh:587
bool getEvenOdd() const
Is the even or odd field being displayed?
Definition VDP.hh:439
int getLinesPerFrame() const
Gets the number of lines per frame.
Definition VDP.hh:553
int getNumberOfLines() const
Gets the number of display lines per screen.
Definition VDP.hh:560
unsigned getEvenOddMask() const
Expresses the state of even/odd page interchange in a mask on the line number.
Definition VDP.hh:454
bool spritesEnabled() const
Are sprites enabled?
Definition VDP.hh:307
int getSpriteSize() const
Gets the sprite size in pixels (8/16).
Definition VDP.hh:534
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:626
SpriteChecker & getSpriteChecker()
Get the sprite checker for this VDP.
Definition VDP.hh:182
bool getBrokenCmdTiming() const
Value of the cmdTiming setting, true means commands have infinite speed.
Definition VDP.hh:663
VDPCmdEngine & getCmdEngine()
Definition VDP.hh:736
int getNameTableBase() const
Get address of name table (only for debugger)
Definition VDP.hh:258
bool isEvenOddEnabled() const
Get even/odd page alternation status.
Definition VDP.hh:431
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:645
void changeRegister(byte reg, byte val, EmuTime::param time)
VDP control register has changed, work out the consequences.
Definition VDP.cc:1011
void scheduleCmdSync(EmuTime t)
Only used when there are commandExecuting-probe listeners.
Definition VDP.hh:700
byte peekRegister(unsigned address) const
Definition VDP.cc:751
bool spritesEnabledRegister() const
Still faster variant (just looks at the sprite-enabled-bit).
Definition VDP.hh:324
BlinkStateCount calculateLineBlinkState(unsigned line) const
Definition VDP.hh:485
static constexpr int TICKS_PER_SECOND
Number of VDP clock ticks per second.
Definition VDP.hh:71
VDPVRAM & getVRAM()
Get the VRAM object for this VDP.
Definition VDP.hh:162
bool isFastBlinkEnabled() const
Get 'fast-blink' status.
Definition VDP.hh:416
std::array< std::array< uint8_t, 3 >, 16 > getMSX1Palette() const
Get the (fixed) palette for this MSX1 VDP.
Definition VDP.cc:1544
PostProcessor * getPostProcessor() const
Used by Video9000 to be able to couple the VDP and V9990 output.
Definition VDP.cc:247
int getSpritePatternTableBase() const
Get address of pattern table (only for debugger)
Definition VDP.hh:262
bool isVDPwithPALonly() const
Is this a VDP only capable of PAL?
Definition VDP.hh:115
const RawFrame * isSuperimposing() const
Are we currently superimposing? In case of superimpose, returns a pointer to the to-be-superimposed f...
Definition VDP.hh:170
int getVramPointer() const
Get vram pointer (14-bit) (only for debugger)
Definition VDP.hh:270
void getExtraDeviceInfo(TclObject &result) const override
Definition VDP.cc:746
bool getCmdBit() const
Are commands possible in non Graphic modes? (V9958 only)
Definition VDP.hh:547
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:896
void reset(EmuTime::param time) override
This method is called on reset.
Definition VDP.cc:325
void setPalette(unsigned index, word grb, EmuTime::param time)
Sets a palette entry.
Definition VDP.cc:762
bool isBorderMasked() const
Gets the current border mask setting.
Definition VDP.hh:358
byte getStatusReg0() const
Should only be used by SpriteChecker.
Definition VDP.hh:633
bool spritesEnabledFast() const
Same as spritesEnabled(), but may only be called in sprite mode 1 or 2.
Definition VDP.hh:316
int getForegroundColor() const
Gets the current foreground color.
Definition VDP.hh:207
static constexpr int TICKS_PER_LINE
Number of VDP clock ticks per line.
Definition VDP.hh:76
int getBlinkBackgroundColor() const
Gets the current blinking color for blinking text.
Definition VDP.hh:238
int getTicksPerFrame() const
Gets the number of VDP clock ticks (21MHz) per frame.
Definition VDP.hh:566
bool isInsideFrame(EmuTime::param time) const
Is the given timestamp inside the current frame? Mainly useful for debugging, because relevant timest...
Definition VDP.hh:579
void serialize(Archive &ar, unsigned version)
Definition VDP.cc:1905
unsigned getEvenOddMask(int line) const
Similar to the above getEvenOddMask() method, but can also be called when 'isFastBlinkEnabled() == tr...
Definition VDP.hh:467
void setSpriteStatus(byte value)
Should only be used by SpriteChecker.
Definition VDP.hh:643
Clock< TICKS_PER_SECOND > VDPClock
Definition VDP.hh:72
gl::ivec2 getMSXPos(EmuTime::param time) const
Returns the position of the raster beam expressed in 'narrow' MSX screen coordinates (like 'screen 7'...
Definition VDP.hh:729
uint16_t getPalette(unsigned index) const
Gets a palette entry.
Definition VDP.hh:279
byte getHorizontalScrollHigh() const
Gets the current horizontal scroll higher bits.
Definition VDP.hh:349
int getRightBorder() const
Gets the number of VDP clock ticks between start of line and the start of the right border.
Definition VDP.hh:616
DisplayMode getDisplayMode() const
Get the display mode the VDP is in.
Definition VDP.hh:156
int getPatternTableBase() const
Get address of pattern table (only for debugger)
Definition VDP.hh:250
int getDisplayPage() const
Only used by debugger.
Definition VDP.hh:375
~VDP() override
Definition VDP.cc:221
bool getBlinkState() const
Gets the current blink state.
Definition VDP.hh:245
int getColorTableBase() const
Get address of color table (only for debugger)
Definition VDP.hh:254
int getLineZero() const
Get the absolute line number of display line zero.
Definition VDP.hh:383
int getBlinkForegroundColor() const
Gets the current blinking color for blinking text.
Definition VDP.hh:231
void setExternalVideoSource(const RawFrame *externalSource)
Enable superimposing.
Definition VDP.hh:657
bool isMSX1VDP() const
Is this an MSX1 VDP?
Definition VDP.hh:108
byte getBackgroundColor() const
Gets the current background color.
Definition VDP.hh:219
byte getVerticalScroll() const
Gets the current vertical scroll (line displayed at Y=0).
Definition VDP.hh:331
bool isVDPwithVRAMremapping() const
Does this VDP have VRAM remapping when switching from 4k to 8/16k mode?
Definition VDP.hh:136
bool hasYJK() const
Does this VDP support YJK display?
Definition VDP.hh:143
EmuTime::param getFrameStartTime() const
Definition VDP.hh:528
bool canSpriteColor0Collide() const
Can a sprite which has color=0 collide with some other sprite?
Definition VDP.hh:195
bool isMultiPageScrolling() const
Is multi page scrolling enabled? It is considered enabled if both the multi page scrolling flag is en...
Definition VDP.hh:368
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
Definition VDP.cc:1005
int getLeftBorder() const
Gets the number of VDP clock ticks between start of line and the end of the left border.
Definition VDP.hh:609
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:890
bool isSpriteMag() const
Are sprites magnified?
Definition VDP.hh:540
bool vdpHasPatColMirroring() const
Is this a VDP that has pattern/color table mirroring?
Definition VDP.hh:129
bool isPalTiming() const
Is PAL timing active? This setting is fixed at start of frame.
Definition VDP.hh:391
bool isInterlaced() const
Get interlace status.
Definition VDP.hh:402
bool getTransparency() const
Gets the current transparency setting.
Definition VDP.hh:189
int getSpriteAttributeTableBase() const
Get address of color table (only for debugger)
Definition VDP.hh:266
bool getVRMode() const
Returns current VR mode.
Definition VDP.hh:651
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:985
std::string_view getVersionString() const
Definition VDP.cc:735
bool isDisplayEnabled() const
Is the display enabled? Both the regular border and forced blanking by clearing the display enable bi...
Definition VDP.hh:299
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:524
bool vdpLacksMirroring() const
Is this a VDP that lacks mirroring?
Definition VDP.hh:122
byte getHorizontalScrollLow() const
Gets the current horizontal scroll lower bits.
Definition VDP.hh:340
byte peekStatusReg(byte reg, EmuTime::param time) const
Definition VDP.cc:903
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition VDP.cc:319
int getLeftSprites() const
Gets the number of VDP clock ticks between start of line and the start of the sprite plane.
Definition VDP.hh:598
std::span< const uint16_t, 16 > getPalette() const
Definition VDP.hh:282
This file implemented 3 utility functions:
Definition Autofire.cc:11
IntHelper< OptionalIRQ > OptionalIRQHelper
Definition IRQHelper.hh:125
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
#define OUTER(type, member)
Definition outer.hh:42
#define SERIALIZE_CLASS_VERSION(CLASS, VERSION)
Calculates what 'blinkState' and 'blinkCount' would be at a specific line.
Definition VDP.hh:481