OXYGENHUB
◆ main openmsx / src / video / DisplayMode.hh
5.9 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#ifndef DISPLAYMODE_HH
2
#define DISPLAYMODE_HH
3
4
#include "one_of.hh"
5
6
#include <cstdint>
7
8
namespace openmsx {
9
10
/** Represents a VDP display mode.
11
  * A display mode determines how bytes in the VRAM are converted to pixel
12
  * colors.
13
  * A display mode consists of a base mode with YJK filters on top.
14
  * Only the V9958 supports YJK filters.
15
  */
16
class DisplayMode
17
{
18
private:
19
	constexpr explicit DisplayMode(uint8_t mode_) : mode(mode_) {}
20
	/** Display mode flags: YAE YJK M5..M1.
21
	  * The YAE flag indicates whether YAE is active, not just the value of
22
	  * the corresponding mode bit; so if YJK is 0, YAE is 0 as well.
23
	  */
24
	uint8_t mode = 0;
25
26
public:
27
	static constexpr uint8_t GRAPHIC1   = 0x00; // Graphic 1
28
	static constexpr uint8_t TEXT1      = 0x01; // Text 1
29
	static constexpr uint8_t MULTICOLOR = 0x02; // Multicolor
30
	static constexpr uint8_t GRAPHIC2   = 0x04; // Graphic 2
31
	static constexpr uint8_t TEXT1Q     = 0x05; // !!
32
	static constexpr uint8_t MULTIQ     = 0x06; // !!
33
	static constexpr uint8_t GRAPHIC3   = 0x08; // Graphic 3
34
	static constexpr uint8_t TEXT2      = 0x09; // Text 2
35
	static constexpr uint8_t GRAPHIC4   = 0x0C; // Graphic 4
36
	static constexpr uint8_t GRAPHIC5   = 0x10; // Graphic 5
37
	static constexpr uint8_t GRAPHIC6   = 0x14; // Graphic 6
38
	static constexpr uint8_t GRAPHIC7   = 0x1C; // Graphic 7
39
40
	/** Bits of VDP register 0 that encode part of the display mode. */
41
	static constexpr uint8_t REG0_MASK = 0x0E;
42
43
	/** Bits of VDP register 1 that encode part of the display mode. */
44
	static constexpr uint8_t REG1_MASK = 0x18;
45
46
	/** Bits of VDP register 25 that encode part of the display mode. */
47
	static constexpr uint8_t REG25_MASK = 0x18;
48
49
	/** Encoding of YJK flag. */
50
	static constexpr uint8_t YJK = 0x20;
51
52
	/** Encoding of YAE flag. */
53
	static constexpr uint8_t YAE = 0x40;
54
55
	/** Create the initial display mode.
56
	  */
57
	constexpr DisplayMode() = default;
58
59
	/** Create a specific display mode.
60
	  * @param reg0 The contents of VDP register 0.
61
	  * @param reg1 The contents of VDP register 1.
62
	  * @param reg25 The contents of VDP register 25;
63
	  *     on non-V9958 chips, pass 0.
64
	  */
65
	constexpr DisplayMode(uint8_t reg0, uint8_t reg1, uint8_t reg25) {
66
		if ((reg25 & 0x08) == 0) reg25 = 0; // If YJK is off, ignore YAE.
67
		mode = uint8_t(
68
			((reg25 & 0x18) << 2) | // YAE YJK
69
			((reg0  & 0x0E) << 1) | // M5..M3
70
			((reg1  & 0x08) >> 2) | // M2
71
			((reg1  & 0x10) >> 4)); // M1
72
	}
73
74
	[[nodiscard]] constexpr DisplayMode updateReg25(uint8_t reg25) const {
75
		if ((reg25 & 0x08) == 0) reg25 = 0; // If YJK is off, ignore YAE.
76
		return DisplayMode(uint8_t(getBase() | ((reg25 & 0x18) << 2)));
77
	}
78
79
	/** Bring the display mode to its initial state.
80
	  */
81
	constexpr void reset() {
82
		*this = DisplayMode();
83
	}
84
85
	/** Equals operator.
86
	  */
87
	[[nodiscard]] constexpr bool operator==(const DisplayMode&) const = default;
88
89
	/** Get the display mode as a byte: YAE YJK M5..M1 combined.
90
	  * @return The byte representation of this display mode,
91
	  *     in the range [0..0x7F].
92
	  */
93
	[[nodiscard]] constexpr uint8_t getByte() const {
94
		return mode;
95
	}
96
97
	/** Used for de-serialization. */
98
	constexpr void setByte(uint8_t mode_) {
99
		mode = mode_;
100
	}
101
102
	/** Get the base display mode as an integer: M5..M1 combined.
103
	  * If YJK is active, the base mode is the underlying display mode.
104
	  * @return The integer representation of the base of this display mode,
105
	  *     in the range [0..0x1F].
106
	  */
107
	[[nodiscard]] constexpr uint8_t getBase() const {
108
		return mode & 0x1F;
109
	}
110
111
	/** Was this mode introduced by the V9938?
112
	  * @return True iff the base of this mode only is available on V9938/58.
113
	  */
114
	[[nodiscard]] constexpr bool isV9938Mode() const {
115
		return (mode & 0x18) != 0;
116
	}
117
118
	/** Is the current mode a text mode?
119
	  * Text1 and Text2 are text modes.
120
	  * @return True iff the current mode is a text mode.
121
	  */
122
	[[nodiscard]] constexpr bool isTextMode() const {
123
		return getBase() == one_of(TEXT1, TEXT2, TEXT1Q);
124
	}
125
126
	/** Is the current mode a bitmap mode?
127
	  * Graphic4 and higher are bitmap modes.
128
	  * @return True iff the current mode is a bitmap mode.
129
	  */
130
	[[nodiscard]] constexpr bool isBitmapMode() const {
131
		return getBase() >= 0x0C;
132
	}
133
134
	/** Is VRAM "planar" in the current display mode?
135
	  * Graphic 6 and 7 spread their bytes over two VRAM ICs,
136
	  * such that the even bytes go to the first half of the address
137
	  * space and the odd bytes to the second half.
138
	  * @return True iff the current display mode has planar VRAM.
139
	  */
140
	[[nodiscard]] constexpr bool isPlanar() const {
141
		// TODO: Is the display mode check OK? Profile undefined modes.
142
		return (mode & 0x14) == 0x14;
143
	}
144
145
	/** Are sprite pixels narrow?
146
	  */
147
	[[nodiscard]] constexpr bool isSpriteNarrow() const {
148
		// TODO: Check what happens to sprites in Graphic5 + YJK/YAE.
149
		return mode == GRAPHIC5;
150
	}
151
152
	/** Get the sprite mode of this display mode.
153
	  * @return The current sprite mode:
154
	  *     0 means no sprites,
155
	  *     1 means sprite mode 1 (MSX1 display modes),
156
	  *     2 means sprite mode 2 (MSX2 display modes).
157
	  */
158
	[[nodiscard]] constexpr int getSpriteMode(bool isMSX1) const {
159
		switch (getBase()) {
160
		case GRAPHIC1: case MULTICOLOR: case GRAPHIC2:
161
			return 1;
162
		case MULTIQ: // depends on VDP type
163
			return isMSX1 ? 1 : 0;
164
		case GRAPHIC3: case GRAPHIC4: case GRAPHIC5:
165
		case GRAPHIC6: case GRAPHIC7:
166
			return 2;
167
		case TEXT1: case TEXT1Q: case TEXT2:
168
		default: // and all other (bogus) modes
169
			// Verified on real V9958: none of the bogus modes
170
			// show sprites.
171
			// TODO check on TMSxxxx
172
			return 0;
173
		}
174
	}
175
176
	/** Get number of pixels on a display line in this mode.
177
	  * @return 512 for Text 2, Graphic 5 and 6, 256 for all other modes.
178
	  * TODO: Would it make more sense to treat Text 2 as 480 pixels?
179
	  */
180
	[[nodiscard]] constexpr unsigned getLineWidth() const {
181
		// Note: Testing "mode" instead of "base mode" ensures that YJK
182
		//       modes are treated as 256 pixels wide.
183
		return mode == one_of(TEXT2, GRAPHIC5, GRAPHIC6)
184
			? 512
185
			: 256;
186
	}
187
};
188
189
} // namespace openmsx
190
191
#endif