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 template<typename Archive>
736 void serialize(Archive& ar, unsigned version);
737
738private:
739 void initTables();
740
741 // VdpVersion bitmasks
742 static constexpr unsigned VM_MSX1 = 1; // set-> MSX1, unset-> MSX2 or MSX2+
743 static constexpr unsigned VM_PAL = 2; // set-> fixed PAL, unset-> fixed NTSC or switchable
744 static constexpr unsigned VM_NO_MIRRORING = 4; // set-> no (screen2) mirroring
745 static constexpr unsigned VM_PALCOL_MIRRORING = 8; // set-> pattern/color-table mirroring
746 static constexpr unsigned VM_VRAM_REMAPPING = 16; // set-> 4k,8/16k VRAM remapping
747 static constexpr unsigned VM_TOSHIBA_PALETTE = 32; // set-> has Toshiba palette
748 static constexpr unsigned VM_YJK = 64; // set-> has YJK (MSX2+)
749 static constexpr unsigned VM_YM2220_PALETTE = 128; // set-> has YM2220 palette
750
752 enum VdpVersion {
757 TMS99X8A = VM_MSX1 | VM_PALCOL_MIRRORING | VM_VRAM_REMAPPING,
758
760 TMS9929A = VM_MSX1 | VM_PALCOL_MIRRORING | VM_VRAM_REMAPPING | VM_PAL,
761
763 TMS9129 = VM_MSX1 | VM_PAL,
764
766 TMS91X8 = VM_MSX1,
767
769 T6950PAL = VM_MSX1 | VM_TOSHIBA_PALETTE | VM_NO_MIRRORING | VM_PAL,
770
772 T6950NTSC = VM_MSX1 | VM_TOSHIBA_PALETTE | VM_NO_MIRRORING,
773
775 T7937APAL = VM_MSX1 | VM_TOSHIBA_PALETTE | VM_PAL,
776
778 T7937ANTSC = VM_MSX1 | VM_TOSHIBA_PALETTE,
779
781 YM2220PAL = VM_MSX1 | VM_YM2220_PALETTE | VM_PALCOL_MIRRORING | VM_PAL,
782
784 YM2220NTSC = VM_MSX1 | VM_YM2220_PALETTE | VM_PALCOL_MIRRORING,
785
787 V9938 = 0,
788
790 V9958 = VM_YJK,
791 };
792
793 struct SyncBase : public Schedulable {
794 explicit SyncBase(const VDP& vdp_) : Schedulable(vdp_.getScheduler()) {}
798 protected:
799 ~SyncBase() = default;
800 };
801
802 struct SyncVSync final : public SyncBase {
803 using SyncBase::SyncBase;
804 void executeUntil(EmuTime::param time) override {
805 auto& vdp = OUTER(VDP, syncVSync);
806 vdp.execVSync(time);
807 }
808 } syncVSync;
809
810 struct SyncDisplayStart final : public SyncBase {
811 using SyncBase::SyncBase;
812 void executeUntil(EmuTime::param time) override {
813 auto& vdp = OUTER(VDP, syncDisplayStart);
814 vdp.execDisplayStart(time);
815 }
816 } syncDisplayStart;
817
818 struct SyncVScan final : public SyncBase {
819 using SyncBase::SyncBase;
820 void executeUntil(EmuTime::param time) override {
821 auto& vdp = OUTER(VDP, syncVScan);
822 vdp.execVScan(time);
823 }
824 } syncVScan;
825
826 struct SyncHScan final : public SyncBase {
827 using SyncBase::SyncBase;
828 void executeUntil(EmuTime::param /*time*/) override {
829 auto& vdp = OUTER(VDP, syncHScan);
830 vdp.execHScan();
831 }
832 } syncHScan;
833
834 struct SyncHorAdjust final : public SyncBase {
835 using SyncBase::SyncBase;
836 void executeUntil(EmuTime::param time) override {
837 auto& vdp = OUTER(VDP, syncHorAdjust);
838 vdp.execHorAdjust(time);
839 }
840 } syncHorAdjust;
841
842 struct SyncSetMode final : public SyncBase {
843 using SyncBase::SyncBase;
844 void executeUntil(EmuTime::param time) override {
845 auto& vdp = OUTER(VDP, syncSetMode);
846 vdp.execSetMode(time);
847 }
848 } syncSetMode;
849
850 struct SyncSetBlank final : public SyncBase {
851 using SyncBase::SyncBase;
852 void executeUntil(EmuTime::param time) override {
853 auto& vdp = OUTER(VDP, syncSetBlank);
854 vdp.execSetBlank(time);
855 }
856 } syncSetBlank;
857
858 struct SyncSetSprites final : public SyncBase {
859 using SyncBase::SyncBase;
860 void executeUntil(EmuTime::param time) override {
861 auto& vdp = OUTER(VDP, syncSetSprites);
862 vdp.execSetSprites(time);
863 }
864 } syncSetSprites;
865
866 struct SyncCpuVramAccess final : public SyncBase {
867 using SyncBase::SyncBase;
868 void executeUntil(EmuTime::param time) override {
869 auto& vdp = OUTER(VDP, syncCpuVramAccess);
870 vdp.execCpuVramAccess(time);
871 }
872 } syncCpuVramAccess;
873
874 struct SyncCmdDone final : public SyncBase {
875 using SyncBase::SyncBase;
876 void executeUntil(EmuTime::param time) override {
877 auto& vdp = OUTER(VDP, syncCmdDone);
878 vdp.execSyncCmdDone(time);
879 }
880 } syncCmdDone;
881
882 void execVSync(EmuTime::param time);
883 void execDisplayStart(EmuTime::param time);
884 void execVScan(EmuTime::param time);
885 void execHScan();
886 void execHorAdjust(EmuTime::param time);
887 void execSetMode(EmuTime::param time);
888 void execSetBlank(EmuTime::param time);
889 void execSetSprites(EmuTime::param time);
890 void execCpuVramAccess(EmuTime::param time);
891 void execSyncCmdDone(EmuTime::param time);
892
896 [[nodiscard]] int getVerticalAdjust() const {
897 return (controlRegs[18] >> 4) ^ 0x07;
898 }
899
909 [[nodiscard]] inline bool getHR(int ticksThisFrame) const {
910 // Note: These constants are located inside this function because
911 // GCC 4.0.x won't link if they are in the class scope.
915 static constexpr int HBLANK_LEN_TXT = 404;
919 static constexpr int HBLANK_LEN_GFX = 312;
920 return (ticksThisFrame + TICKS_PER_LINE - getRightBorder()) % TICKS_PER_LINE
921 < (displayMode.isTextMode() ? HBLANK_LEN_TXT : HBLANK_LEN_GFX);
922 }
923
924 // VideoSystemChangeListener interface:
925 void preVideoSystemChange() noexcept override;
926 void postVideoSystemChange() noexcept override;
927
932 void resetInit();
933
938 void resetMasks(EmuTime::param time);
939
943 void frameStart(EmuTime::param time);
944
952 void scheduleDisplayStart(EmuTime::param time);
953
959 void scheduleVScan(EmuTime::param time);
960
966 void scheduleHScan(EmuTime::param time);
967
970 void vramWrite(byte value, EmuTime::param time);
971
974 [[nodiscard]] byte vramRead(EmuTime::param time);
975
977 void scheduleCpuVramAccess(bool isRead, byte write, EmuTime::param time);
978 void executeCpuVramAccess(EmuTime::param time);
979
982 [[nodiscard]] byte readStatusReg(byte reg, EmuTime::param time);
983
986 void syncAtNextLine(SyncBase& type, EmuTime::param time) const;
987
990 void createRenderer();
991
995 void updateNameBase(EmuTime::param time);
996
1000 void updateColorBase(EmuTime::param time);
1001
1005 void updatePatternBase(EmuTime::param time);
1006
1010 void updateSpriteAttributeBase(EmuTime::param time);
1011
1015 void updateSpritePatternBase(EmuTime::param time);
1016
1020 void updateDisplayMode(DisplayMode newMode, bool cmdBit, EmuTime::param time);
1021
1022 // Observer<Setting>
1023 void update(const Setting& setting) noexcept override;
1024
1025private:
1026 Display& display;
1027 EnumSetting<bool>& cmdTiming;
1028 EnumSetting<bool>& tooFastAccess;
1029
1030 struct RegDebug final : SimpleDebuggable {
1031 explicit RegDebug(const VDP& vdp);
1032 [[nodiscard]] byte read(unsigned address) override;
1033 void write(unsigned address, byte value, EmuTime::param time) override;
1034 } vdpRegDebug;
1035
1036 struct StatusRegDebug final : SimpleDebuggable {
1037 explicit StatusRegDebug(const VDP& vdp);
1038 [[nodiscard]] byte read(unsigned address, EmuTime::param time) override;
1039 } vdpStatusRegDebug;
1040
1041 struct PaletteDebug final : SimpleDebuggable {
1042 explicit PaletteDebug(const VDP& vdp);
1043 [[nodiscard]] byte read(unsigned address) override;
1044 void write(unsigned address, byte value, EmuTime::param time) override;
1045 } vdpPaletteDebug;
1046
1047 struct VRAMPointerDebug final : SimpleDebuggable {
1048 explicit VRAMPointerDebug(const VDP& vdp);
1049 [[nodiscard]] byte read(unsigned address) override;
1050 void write(unsigned address, byte value, EmuTime::param time) override;
1051 } vramPointerDebug;
1052
1053 struct RegisterLatchStatusDebug final : SimpleDebuggable {
1054 explicit RegisterLatchStatusDebug(const VDP& vdp);
1055 [[nodiscard]] byte read(unsigned address) override;
1056 } registerLatchStatusDebug;
1057
1058 struct VramAccessStatusDebug final : SimpleDebuggable {
1059 explicit VramAccessStatusDebug(const VDP& vdp);
1060 [[nodiscard]] byte read(unsigned address) override;
1061 } vramAccessStatusDebug;
1062
1063 struct PaletteLatchStatusDebug final : SimpleDebuggable {
1064 explicit PaletteLatchStatusDebug(const VDP& vdp);
1065 [[nodiscard]] byte read(unsigned address) override;
1066 } paletteLatchStatusDebug;
1067
1068 struct DataLatchDebug final : SimpleDebuggable {
1069 explicit DataLatchDebug(const VDP& vdp);
1070 [[nodiscard]] byte read(unsigned address) override;
1071 } dataLatchDebug;
1072
1073 class Info : public InfoTopic {
1074 public:
1075 void execute(std::span<const TclObject> tokens,
1076 TclObject& result) const override;
1077 [[nodiscard]] std::string help(std::span<const TclObject> tokens) const override;
1078 [[nodiscard]] virtual int calc(const EmuTime& time) const = 0;
1079 protected:
1080 Info(VDP& vdp_, const std::string& name, std::string helpText_);
1081 ~Info() = default;
1082 VDP& vdp;
1083 const std::string helpText;
1084 };
1085
1086 struct FrameCountInfo final : Info {
1087 explicit FrameCountInfo(VDP& vdp);
1088 [[nodiscard]] int calc(const EmuTime& time) const override;
1089 } frameCountInfo;
1090
1091 struct CycleInFrameInfo final : Info {
1092 explicit CycleInFrameInfo(VDP& vdp);
1093 [[nodiscard]] int calc(const EmuTime& time) const override;
1094 } cycleInFrameInfo;
1095
1096 struct LineInFrameInfo final : Info {
1097 explicit LineInFrameInfo(VDP& vdp);
1098 [[nodiscard]] int calc(const EmuTime& time) const override;
1099 } lineInFrameInfo;
1100
1101 struct CycleInLineInfo final : Info {
1102 explicit CycleInLineInfo(VDP& vdp);
1103 [[nodiscard]] int calc(const EmuTime& time) const override;
1104 } cycleInLineInfo;
1105
1106 struct MsxYPosInfo final : Info {
1107 explicit MsxYPosInfo(VDP& vdp);
1108 [[nodiscard]] int calc(const EmuTime& time) const override;
1109 } msxYPosInfo;
1110
1111 struct MsxX256PosInfo final : Info {
1112 explicit MsxX256PosInfo(VDP& vdp);
1113 [[nodiscard]] int calc(const EmuTime& time) const override;
1114 } msxX256PosInfo;
1115
1116 struct MsxX512PosInfo final : Info {
1117 explicit MsxX512PosInfo(VDP& vdp);
1118 [[nodiscard]] int calc(const EmuTime& time) const override;
1119 } msxX512PosInfo;
1120
1123 std::unique_ptr<Renderer> renderer;
1124
1127 std::unique_ptr<VDPCmdEngine> cmdEngine;
1128
1131 std::unique_ptr<SpriteChecker> spriteChecker;
1132
1135 std::unique_ptr<VDPVRAM> vram;
1136
1140 const RawFrame* externalVideo;
1141
1147 const RawFrame* superimposing;
1148
1151 VDPClock frameStartTime;
1152
1155 OptionalIRQHelper irqVertical;
1156
1159 OptionalIRQHelper irqHorizontal;
1160
1163 EmuTime displayStartSyncTime;
1164
1167 EmuTime vScanSyncTime;
1168
1171 EmuTime hScanSyncTime;
1172
1173 TclCallback tooFastCallback;
1174 TclCallback dotClockDirectionCallback;
1175
1178 VdpVersion version;
1179
1184 int saturationPr;
1185
1190 int saturationPb;
1191
1197 int frameCount;
1198
1201 int displayStart;
1202
1206 int horizontalScanOffset;
1207
1211 int horizontalAdjust;
1212
1215 std::array<byte, 32> controlRegs;
1216
1221 byte controlRegMask;
1222
1229 std::array<byte, 32> controlValueMasks;
1230
1234 int blinkCount;
1235
1239 int vramPointer;
1240
1243 std::array<uint16_t, 16> palette;
1244
1247 bool isDisplayArea;
1248
1254 bool palTiming;
1255
1259 bool interlaced = false;
1260
1265 byte statusReg0;
1266
1272 byte statusReg1;
1273
1278 byte statusReg2;
1279
1282 bool blinkState;
1283
1286 byte dataLatch;
1287
1294 bool writeAccess;
1295
1298 bool registerDataStored;
1299
1302 bool paletteDataStored;
1303
1311 byte cpuVramData;
1312
1316 bool cpuVramReqIsRead;
1317 bool pendingCpuAccess; // always equal to pendingSyncPoint(CPU_VRAM_ACCESS)
1318
1322 bool cpuExtendedVram;
1323
1329 DisplayMode displayMode;
1330
1335 bool displayEnabled;
1336
1342 bool spriteEnabled;
1343
1347 bool warningPrinted = false;
1348
1350 bool brokenCmdTiming;
1351 bool allowTooFastAccess;
1352
1354 MSXCPU& cpu;
1355 const byte fixedVDPIOdelayCycles;
1356};
1358
1359} // namespace openmsx
1360
1361#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.
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
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:644
void changeRegister(byte reg, byte val, EmuTime::param time)
VDP control register has changed, work out the consequences.
Definition VDP.cc:1010
void scheduleCmdSync(EmuTime t)
Only used when there are commandExecuting-probe listeners.
Definition VDP.hh:700
byte peekRegister(unsigned address) const
Definition VDP.cc:750
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:1543
PostProcessor * getPostProcessor() const
Used by Video9000 to be able to couple the VDP and V9990 output.
Definition VDP.cc:246
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:745
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:895
void reset(EmuTime::param time) override
This method is called on reset.
Definition VDP.cc:324
void setPalette(unsigned index, word grb, EmuTime::param time)
Sets a palette entry.
Definition VDP.cc:761
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:1904
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:220
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:1004
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:889
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:984
std::string_view getVersionString() const
Definition VDP.cc:734
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:902
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition VDP.cc:318
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