OXYGENHUB
◆ main openmsx / src / video / v9990 / V9990CmdEngine.hh
11.6 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#ifndef V9990CMDENGINE_HH
2
#define V9990CMDENGINE_HH
3
4
#include "EmuTime.hh"
5
#include "serialize_meta.hh"
6
7
#include "Observer.hh"
8
9
#include <cstdint>
10
11
namespace openmsx {
12
13
class V9990;
14
class V9990VRAM;
15
class Setting;
16
class RenderSettings;
17
class BooleanSetting;
18
19
/** Command engine.
20
  */
21
class V9990CmdEngine final : private Observer<Setting>
22
{
23
public:
24
	// status bits
25
	static constexpr uint8_t TR = 0x80;
26
	static constexpr uint8_t BD = 0x10;
27
	static constexpr uint8_t CE = 0x01;
28
29
	V9990CmdEngine(V9990& vdp, EmuTime time,
30
	               RenderSettings& settings);
31
	~V9990CmdEngine();
32
33
	/** Re-initialise the command engine's state
34
	  * @param time   Moment in emulated time the reset occurs
35
	  */
36
	void reset(EmuTime time);
37
38
	/** Synchronizes the command engine with the V9990
39
	  * @param time The moment in emulated time to sync to.
40
	  */
41
	void sync(EmuTime time) {
42
		if (CMD >> 4) sync2(time);
43
	}
44
	void sync2(EmuTime time);
45
46
	/** Set a value to one of the command registers
47
	  */
48
	void setCmdReg(uint8_t reg, uint8_t val, EmuTime time);
49
50
	/** set the data byte
51
	  */
52
	void setCmdData(uint8_t value, EmuTime time);
53
54
	/** read the command data byte
55
	  */
56
	[[nodiscard]] uint8_t getCmdData(EmuTime time);
57
58
	/** read the command data byte (without side-effects)
59
	  */
60
	[[nodiscard]] uint8_t peekCmdData(EmuTime time) const;
61
62
	/** Get command engine related status bits
63
	  *  - TR command data transfer ready (bit 7)
64
	  *  - BD border color detect         (bit 4)
65
	  *  - CE command being executed      (bit 0)
66
	  */
67
	[[nodiscard]] uint8_t getStatus(EmuTime time) const {
68
		// note: used for both normal and debug read
69
		const_cast<V9990CmdEngine*>(this)->sync(time);
70
		return status;
71
	}
72
73
	[[nodiscard]] uint16_t getBorderX(EmuTime time) const {
74
		// note: used for both normal and debug read
75
		const_cast<V9990CmdEngine*>(this)->sync(time);
76
		return borderX;
77
	}
78
79
	/** Calculate an (under-)estimation for when the command will finish.
80
	  * The main purpose of this function is to insert extra sync points
81
	  * so that the Command-End (CE) interrupt properly synchronizes with
82
	  * CPU emulation.
83
	  * This estimation:
84
	  * - Is the current time (engineTime) when no command is executing
85
	  *   or the command doesn't require extra syncs.
86
	  * - Is allowed to be an underestimation, on the condition that (when
87
	  *   that point in time is reached) the new estimation is more
88
	  *   accurate and converges to the actual end time.
89
	  */
90
	[[nodiscard]] EmuTime estimateCmdEnd() const;
91
92
	[[nodiscard]] const V9990& getVDP() const { return vdp; }
93
	[[nodiscard]] bool getBrokenTiming() const { return brokenTiming; }
94
95
	template<typename Archive>
96
	void serialize(Archive& ar, unsigned version);
97
98
private:
99
	class V9990P1 {
100
	public:
101
		using Type = uint8_t;
102
		static constexpr uint16_t BITS_PER_PIXEL  = 4;
103
		static constexpr uint16_t PIXELS_PER_BYTE = 2;
104
		static unsigned getPitch(unsigned width);
105
		static unsigned addressOf(unsigned x, unsigned y, unsigned pitch);
106
		static uint8_t point(const V9990VRAM& vram,
107
		                  unsigned x, unsigned y, unsigned pitch);
108
		static uint8_t shift(uint8_t value, unsigned fromX, unsigned toX);
109
		static uint8_t shiftMask(unsigned x);
110
		static std::span<const uint8_t, 256 * 256> getLogOpLUT(uint8_t op);
111
		static uint8_t logOp(std::span<const uint8_t, 256 * 256> lut, uint8_t src, uint8_t dst);
112
		static void pset(
113
			V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch,
114
			uint8_t srcColor, uint16_t mask, std::span<const uint8_t, 256 * 256> lut, uint8_t op);
115
		static void psetColor(
116
			V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch,
117
			uint16_t color, uint16_t mask, std::span<const uint8_t, 256 * 256> lut, uint8_t op);
118
	};
119
120
	class V9990P2 {
121
	public:
122
		using Type = uint8_t;
123
		static constexpr uint16_t BITS_PER_PIXEL  = 4;
124
		static constexpr uint16_t PIXELS_PER_BYTE = 2;
125
		static unsigned getPitch(unsigned width);
126
		static unsigned addressOf(unsigned x, unsigned y, unsigned pitch);
127
		static uint8_t point(const V9990VRAM& vram,
128
		                  unsigned x, unsigned y, unsigned pitch);
129
		static uint8_t shift(uint8_t value, unsigned fromX, unsigned toX);
130
		static uint8_t shiftMask(unsigned x);
131
		static std::span<const uint8_t, 256 * 256> getLogOpLUT(uint8_t op);
132
		static uint8_t logOp(std::span<const uint8_t, 256 * 256> lut, uint8_t src, uint8_t dst);
133
		static void pset(
134
			V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch,
135
			uint8_t srcColor, uint16_t mask, std::span<const uint8_t, 256 * 256> lut, uint8_t op);
136
		static void psetColor(
137
			V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch,
138
			uint16_t color, uint16_t mask, std::span<const uint8_t, 256 * 256> lut, uint8_t op);
139
	};
140
141
	class V9990Bpp2 {
142
	public:
143
		using Type = uint8_t;
144
		static constexpr uint16_t BITS_PER_PIXEL  = 2;
145
		static constexpr uint16_t PIXELS_PER_BYTE = 4;
146
		static unsigned getPitch(unsigned width);
147
		static unsigned addressOf(unsigned x, unsigned y, unsigned pitch);
148
		static uint8_t point(const V9990VRAM& vram,
149
		                  unsigned x, unsigned y, unsigned pitch);
150
		static uint8_t shift(uint8_t value, unsigned fromX, unsigned toX);
151
		static uint8_t shiftMask(unsigned x);
152
		static std::span<const uint8_t, 256 * 256> getLogOpLUT(uint8_t op);
153
		static uint8_t logOp(std::span<const uint8_t, 256 * 256> lut, uint8_t src, uint8_t dst);
154
		static void pset(
155
			V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch,
156
			uint8_t srcColor, uint16_t mask, std::span<const uint8_t, 256 * 256> lut, uint8_t op);
157
		static void psetColor(
158
			V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch,
159
			uint16_t color, uint16_t mask, std::span<const uint8_t, 256 * 256> lut, uint8_t op);
160
	};
161
162
	class V9990Bpp4 {
163
	public:
164
		using Type = uint8_t;
165
		static constexpr uint16_t BITS_PER_PIXEL  = 4;
166
		static constexpr uint16_t PIXELS_PER_BYTE = 2;
167
		static unsigned getPitch(unsigned width);
168
		static unsigned addressOf(unsigned x, unsigned y, unsigned pitch);
169
		static uint8_t point(const V9990VRAM& vram,
170
		                  unsigned x, unsigned y, unsigned pitch);
171
		static uint8_t shift(uint8_t value, unsigned fromX, unsigned toX);
172
		static uint8_t shiftMask(unsigned x);
173
		static std::span<const uint8_t, 256 * 256> getLogOpLUT(uint8_t op);
174
		static uint8_t logOp(std::span<const uint8_t, 256 * 256> lut, uint8_t src, uint8_t dst);
175
		static void pset(
176
			V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch,
177
			uint8_t srcColor, uint16_t mask, std::span<const uint8_t, 256 * 256> lut, uint8_t op);
178
		static void psetColor(
179
			V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch,
180
			uint16_t color, uint16_t mask, std::span<const uint8_t, 256 * 256> lut, uint8_t op);
181
	};
182
183
	class V9990Bpp8 {
184
	public:
185
		using Type = uint8_t;
186
		static constexpr uint16_t BITS_PER_PIXEL  = 8;
187
		static constexpr uint16_t PIXELS_PER_BYTE = 1;
188
		static unsigned getPitch(unsigned width);
189
		static unsigned addressOf(unsigned x, unsigned y, unsigned pitch);
190
		static uint8_t point(const V9990VRAM& vram,
191
		                  unsigned x, unsigned y, unsigned pitch);
192
		static uint8_t shift(uint8_t value, unsigned fromX, unsigned toX);
193
		static uint8_t shiftMask(unsigned x);
194
		static std::span<const uint8_t, 256 * 256> getLogOpLUT(uint8_t op);
195
		static uint8_t logOp(std::span<const uint8_t, 256 * 256> lut, uint8_t src, uint8_t dst);
196
		static void pset(
197
			V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch,
198
			uint8_t srcColor, uint16_t mask, std::span<const uint8_t, 256 * 256> lut, uint8_t op);
199
		static void psetColor(
200
			V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch,
201
			uint16_t color, uint16_t mask, std::span<const uint8_t, 256 * 256> lut, uint8_t op);
202
	};
203
204
	class V9990Bpp16 {
205
	public:
206
		using Type = uint16_t;
207
		static constexpr uint16_t BITS_PER_PIXEL  = 16;
208
		static constexpr uint16_t PIXELS_PER_BYTE = 0;
209
		static unsigned getPitch(unsigned width);
210
		static unsigned addressOf(unsigned x, unsigned y, unsigned pitch);
211
		static uint16_t point(const V9990VRAM& vram,
212
		                  unsigned x, unsigned y, unsigned pitch);
213
		static uint16_t shift(uint16_t value, unsigned fromX, unsigned toX);
214
		static uint16_t shiftMask(unsigned x);
215
		static std::span<const uint8_t, 256 * 256> getLogOpLUT(uint8_t op);
216
		static uint16_t logOp(std::span<const uint8_t, 256 * 256> lut, uint16_t src, uint16_t dst, bool transp);
217
		static void pset(
218
			V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch,
219
			uint16_t srcColor, uint16_t mask, std::span<const uint8_t, 256 * 256> lut, uint8_t op);
220
		static void psetColor(
221
			V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch,
222
			uint16_t color, uint16_t mask, std::span<const uint8_t, 256 * 256> lut, uint8_t op);
223
	};
224
225
	void startSTOP  (EmuTime time);
226
	void startLMMC  (EmuTime time);
227
	void startLMMC16(EmuTime time);
228
	void startLMMV  (EmuTime time);
229
	void startLMCM  (EmuTime time);
230
	void startLMCM16(EmuTime time);
231
	void startLMMM  (EmuTime time);
232
	void startCMMC  (EmuTime time);
233
	void startCMMK  (EmuTime time);
234
	void startCMMM  (EmuTime time);
235
	void startBMXL  (EmuTime time);
236
	void startBMLX  (EmuTime time);
237
	void startBMLL  (EmuTime time);
238
	void startBMLL16(EmuTime time);
239
	void startLINE  (EmuTime time);
240
	void startSRCH  (EmuTime time);
241
	template<typename Mode> void startPOINT(EmuTime time);
242
	template<typename Mode> void startPSET (EmuTime time);
243
	void startADVN  (EmuTime time);
244
245
	                        void executeSTOP (EmuTime limit);
246
	template<typename Mode> void executeLMMC (EmuTime limit);
247
	template<typename Mode> void executeLMMV (EmuTime limit);
248
	template<typename Mode> void executeLMCM (EmuTime limit);
249
	template<typename Mode> void executeLMMM (EmuTime limit);
250
	template<typename Mode> void executeCMMC (EmuTime limit);
251
	                        void executeCMMK (EmuTime limit);
252
	template<typename Mode> void executeCMMM (EmuTime limit);
253
	template<typename Mode> void executeBMXL (EmuTime limit);
254
	template<typename Mode> void executeBMLX (EmuTime limit);
255
	template<typename Mode> void executeBMLL (EmuTime limit);
256
	template<typename Mode> void executeLINE (EmuTime limit);
257
	template<typename Mode> void executeSRCH (EmuTime limit);
258
	template<typename Mode> void executePOINT(EmuTime limit);
259
	                        void executePSET (EmuTime limit);
260
	                        void executeADVN (EmuTime limit);
261
262
	RenderSettings& settings;
263
264
	/** Only call reportV9990Command() when this setting is turned on
265
	  */
266
	std::shared_ptr<BooleanSetting> cmdTraceSetting;
267
268
	/** V9990 VDP this engine belongs to
269
	  */
270
	V9990& vdp;
271
	V9990VRAM& vram;
272
273
	EmuTime engineTime;
274
275
	/** VRAM read/write address for various commands
276
	  */
277
	unsigned srcAddress;
278
	unsigned dstAddress;
279
	unsigned nbBytes;
280
281
	/** The X coord of a border detected by SRCH
282
	 */
283
	uint16_t borderX;
284
285
	/** counters
286
	  */
287
	uint16_t ASX, ADX, ANX, ANY;
288
289
	/** Command parameters
290
	  */
291
	uint16_t SX, SY, DX, DY, NX, NY;
292
	uint16_t WM, fgCol, bgCol;
293
	uint8_t ARG, LOG, CMD;
294
295
	unsigned cmdMode; // TODO keep this up-to-date (now it's calculated at the start of a command)
296
297
	/** Status bits
298
	 */
299
	uint8_t status;
300
301
	/** Data byte to transfer between V9990 and CPU
302
	  */
303
	uint8_t data;
304
305
	/** Bit counter for CMMx commands
306
	  */
307
	uint8_t bitsLeft;
308
309
	/** Partial data for LMMC command
310
	  */
311
	uint8_t partial;
312
313
	/** Should command end after next getCmdData().
314
	 */
315
	bool endAfterRead;
316
317
	/** Real command timing or instantaneous (broken) timing
318
	 */
319
	bool brokenTiming;
320
321
	/** The running command is complete. Perform necessary clean-up actions.
322
	  */
323
	void cmdReady(EmuTime time);
324
325
	/** For debugging: Print the info about the current command.
326
	  */
327
	void reportV9990Command() const;
328
329
	// Observer<Setting>
330
	void update(const Setting& setting) noexcept override;
331
332
	void setCommandMode();
333
334
	[[nodiscard]] uint16_t getWrappedNX() const {
335
		return NX ? NX : 2048;
336
	}
337
	[[nodiscard]] uint16_t getWrappedNY() const {
338
		return NY ? NY : 4096;
339
	}
340
};
341
SERIALIZE_CLASS_VERSION(V9990CmdEngine, 2);
342
343
} // namespace openmsx
344
345
#endif