OXYGENHUB
◆ main openmsx / src / cpu / CPUCore.hh
13.8 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#ifndef CPUCORE_HH
2
#define CPUCORE_HH
3
4
#include "CPURegs.hh"
5
#include "CacheLine.hh"
6
7
#include "BooleanSetting.hh"
8
#include "EmuTime.hh"
9
#include "IntegerSetting.hh"
10
#include "Probe.hh"
11
#include "serialize_meta.hh"
12
13
#include <array>
14
#include <atomic>
15
#include <cstdint>
16
#include <span>
17
#include <string>
18
19
namespace openmsx {
20
21
class MSXCPUInterface;
22
class Scheduler;
23
class MSXMotherBoard;
24
class TclCallback;
25
enum Reg8  : uint8_t;
26
enum Reg16 : uint8_t;
27
28
class CPUBase {}; // only for bw-compat savestates
29
30
struct II { // InstructionInfo
31
	// Number of instruction byte fetches since the last M1 cycle.
32
	// In other words, at the end of an instruction the PC register should
33
	// be incremented by this amount.
34
	uint16_t length;
35
36
	// Total duration of the instruction. At the end of the instruction
37
	// this value is added to the total cycle counter. For efficiency
38
	// reasons we only want to adjust this total once per instruction
39
	// instead of small incremental updates after each micro-code.
40
	int cycles;
41
};
42
43
enum class ExecIRQ : uint8_t {
44
	NMI,  // about to execute NMI routine
45
	IRQ,  // about to execute normal IRQ routine
46
	NONE, // about to execute regular instruction
47
};
48
49
struct CacheLines {
50
	std::span<const uint8_t*, CacheLine::NUM> read;
51
	std::span<      uint8_t*, CacheLine::NUM> write;
52
};
53
54
template<typename CPU_POLICY>
55
class CPUCore final : public CPUBase, public CPURegs, public CPU_POLICY
56
{
57
public:
58
	CPUCore(MSXMotherBoard& motherboard, const std::string& name,
59
	        TclCallback& diHaltCallback, EmuTime time);
60
61
	void setInterface(MSXCPUInterface* interface_) { interface = interface_; }
62
63
	/**
64
	 * Reset the CPU.
65
	 */
66
	void doReset(EmuTime time);
67
68
	void execute(bool fastForward);
69
70
	/** Request to exit the main CPU emulation loop.
71
	  * This method may only be called from the main thread. The CPU loop
72
	  * will immediately be exited (current instruction will be finished,
73
	  * but no new instruction will be executed).
74
	  */
75
	void exitCPULoopSync();
76
77
	/** Similar to exitCPULoopSync(), but this method may be called from
78
	  * any thread. Although now the loop will only be exited 'soon'.
79
	  */
80
	void exitCPULoopAsync();
81
82
	void warp(EmuTime time);
83
	[[nodiscard]] EmuTime getCurrentTime() const;
84
	void wait(EmuTime time);
85
	EmuTime waitCycles(EmuTime time, unsigned cycles);
86
	void setNextSyncPoint(EmuTime time);
87
	[[nodiscard]] CacheLines getCacheLines() {
88
		return {.read = readCacheLine, .write = writeCacheLine};
89
	}
90
	[[nodiscard]] bool isM1Cycle(unsigned address) const;
91
92
	/**
93
	 * Raises the maskable interrupt count.
94
	 * Devices should call MSXCPU::raiseIRQ instead, or use the IRQHelper class.
95
	 */
96
	void raiseIRQ();
97
98
	/**
99
	 * Lowers the maskable interrupt count.
100
	 * Devices should call MSXCPU::lowerIRQ instead, or use the IRQHelper class.
101
	 */
102
	void lowerIRQ();
103
104
	/**
105
	 * Raises the non-maskable interrupt count.
106
	 * Devices should call MSXCPU::raiseNMI instead, or use the IRQHelper class.
107
	 */
108
	void raiseNMI();
109
110
	/**
111
	 * Lowers the non-maskable interrupt count.
112
	 * Devices should call MSXCPU::lowerNMI instead, or use the IRQHelper class.
113
	 */
114
	void lowerNMI();
115
116
	/**
117
	 * Change the clock freq.
118
	 */
119
	void setFreq(unsigned freq);
120
121
	[[nodiscard]] BooleanSetting& getFreqLockedSetting() { return freqLocked; }
122
	[[nodiscard]] IntegerSetting& getFreqValueSetting()  { return freqValue; }
123
124
	template<typename Archive>
125
	void serialize(Archive& ar, unsigned version);
126
127
private:
128
	void execute2(bool fastForward);
129
	[[nodiscard]] bool needExitCPULoop();
130
	void setSlowInstructions();
131
	void doSetFreq();
132
133
	// Observer<Setting>  !! non-virtual !!
134
	void update(const Setting& setting) noexcept;
135
136
private:
137
	// memory cache
138
	std::array<const uint8_t*, CacheLine::NUM> readCacheLine;
139
	std::array<      uint8_t*, CacheLine::NUM> writeCacheLine;
140
141
	MSXMotherBoard& motherboard;
142
	Scheduler& scheduler;
143
	MSXCPUInterface* interface = nullptr;
144
145
	TclCallback& diHaltCallback;
146
147
	Probe<int> IRQStatus;
148
	Probe<void> IRQAccept;
149
150
	// dynamic freq
151
	BooleanSetting freqLocked;
152
	IntegerSetting freqValue;
153
	unsigned freq;
154
155
	// state machine variables
156
	int slowInstructions;
157
	int NMIStatus = 0;
158
159
	/**
160
	 * Set to true when there was a rising edge on the NMI line
161
	 * (rising = non-active -> active).
162
	 * Set to false when the CPU jumps to the NMI handler address.
163
	 */
164
	bool nmiEdge = false;
165
166
	std::atomic<bool> exitLoop = false;
167
168
	/** An NMOS Z80 and a CMOS Z80 behave slightly differently */
169
	const bool isCMOS;
170
171
private:
172
	inline uint8_t READ_PORT(uint16_t port, unsigned cc);
173
	inline void WRITE_PORT(uint16_t port, uint8_t value, unsigned cc);
174
175
	template<bool PRE_PB, bool POST_PB>
176
	uint8_t RDMEMslow(unsigned address, unsigned cc);
177
	template<bool PRE_PB, bool POST_PB>
178
	inline uint8_t RDMEM_impl2(unsigned address, unsigned cc);
179
	template<bool PRE_PB, bool POST_PB>
180
	inline uint8_t RDMEM_impl (unsigned address, unsigned cc);
181
	template<unsigned PC_OFFSET>
182
	inline uint8_t RDMEM_OPCODE(unsigned cc);
183
	inline uint8_t RDMEM(unsigned address, unsigned cc);
184
185
	template<bool PRE_PB, bool POST_PB>
186
	uint16_t RD_WORD_slow(unsigned address, unsigned cc);
187
	template<bool PRE_PB, bool POST_PB>
188
	inline uint16_t RD_WORD_impl2(unsigned address, unsigned cc);
189
	template<bool PRE_PB, bool POST_PB>
190
	inline uint16_t RD_WORD_impl (unsigned address, unsigned cc);
191
	template<unsigned PC_OFFSET>
192
	inline uint16_t RD_WORD_PC(unsigned cc);
193
	inline uint16_t RD_WORD(unsigned address, unsigned cc);
194
195
	template<bool PRE_PB, bool POST_PB>
196
	void WRMEMslow(unsigned address, uint8_t value, unsigned cc);
197
	template<bool PRE_PB, bool POST_PB>
198
	inline void WRMEM_impl2(unsigned address, uint8_t value, unsigned cc);
199
	template<bool PRE_PB, bool POST_PB>
200
	inline void WRMEM_impl (unsigned address, uint8_t value, unsigned cc);
201
	inline void WRMEM(unsigned address, uint8_t value, unsigned cc);
202
203
	void WR_WORD_slow(unsigned address, uint16_t value, unsigned cc);
204
	inline void WR_WORD(unsigned address, uint16_t value, unsigned cc);
205
206
	template<bool PRE_PB, bool POST_PB>
207
	void WR_WORD_rev_slow(unsigned address, uint16_t value, unsigned cc);
208
	template<bool PRE_PB, bool POST_PB>
209
	inline void WR_WORD_rev2(unsigned address, uint16_t value, unsigned cc);
210
	template<bool PRE_PB, bool POST_PB>
211
	inline void WR_WORD_rev (unsigned address, uint16_t value, unsigned cc);
212
213
	void executeInstructions();
214
	inline void nmi();
215
	inline void irq0();
216
	inline void irq1();
217
	inline void irq2();
218
	[[nodiscard]] ExecIRQ getExecIRQ() const;
219
	void executeSlow(ExecIRQ execIRQ);
220
221
	template<Reg8>  [[nodiscard]] inline uint8_t get8()  const;
222
	template<Reg16> [[nodiscard]] inline uint16_t get16() const;
223
	template<Reg8>  inline void set8 (uint8_t x);
224
	template<Reg16> inline void set16(uint16_t x);
225
226
	template<Reg8 DST, Reg8 SRC, int EE> inline II ld_R_R();
227
	template<Reg16 REG, int EE> inline II ld_sp_SS();
228
	template<Reg16 REG> inline II ld_SS_a();
229
	template<Reg8 SRC> inline II ld_xhl_R();
230
	template<Reg16 IXY, Reg8 SRC> inline II ld_xix_R();
231
232
	inline II ld_xhl_byte();
233
	template<Reg16 IXY> inline II ld_xix_byte();
234
235
	template<int EE> inline II WR_NN_Y(uint16_t reg);
236
	template<Reg16 REG, int EE> inline II ld_xword_SS();
237
	template<Reg16 REG> inline II ld_xword_SS_ED();
238
	template<Reg16 REG> inline II ld_a_SS();
239
240
	inline II ld_xbyte_a();
241
	inline II ld_a_xbyte();
242
243
	template<Reg8 DST, int EE> inline II ld_R_byte();
244
	template<Reg8 DST> inline II ld_R_xhl();
245
	template<Reg8 DST, Reg16 IXY> inline II ld_R_xix();
246
247
	template<int EE> inline uint16_t RD_P_XX();
248
	template<Reg16 REG, int EE> inline II ld_SS_xword();
249
	template<Reg16 REG> inline II ld_SS_xword_ED();
250
251
	template<Reg16 REG, int EE> inline II ld_SS_word();
252
253
	inline void ADC(uint8_t reg);
254
	inline II adc_a_a();
255
	template<Reg8 SRC, int EE> inline II adc_a_R();
256
	inline II adc_a_byte();
257
	inline II adc_a_xhl();
258
	template<Reg16 IXY> inline II adc_a_xix();
259
260
	inline void ADD(uint8_t reg);
261
	inline II add_a_a();
262
	template<Reg8 SRC, int EE> inline II add_a_R();
263
	inline II add_a_byte();
264
	inline II add_a_xhl();
265
	template<Reg16 IXY> inline II add_a_xix();
266
267
	inline void AND(uint8_t reg);
268
	inline II and_a();
269
	template<Reg8 SRC, int EE> inline II and_R();
270
	inline II and_byte();
271
	inline II and_xhl();
272
	template<Reg16 IXY> inline II and_xix();
273
274
	inline void CP(uint8_t reg);
275
	inline II cp_a();
276
	template<Reg8 SRC, int EE> inline II cp_R();
277
	inline II cp_byte();
278
	inline II cp_xhl();
279
	template<Reg16 IXY> inline II cp_xix();
280
281
	inline void OR(uint8_t reg);
282
	inline II or_a();
283
	template<Reg8 SRC, int EE> inline II or_R();
284
	inline II or_byte();
285
	inline II or_xhl();
286
	template<Reg16 IXY> inline II or_xix();
287
288
	inline void SBC(uint8_t reg);
289
	inline II sbc_a_a();
290
	template<Reg8 SRC, int EE> inline II sbc_a_R();
291
	inline II sbc_a_byte();
292
	inline II sbc_a_xhl();
293
	template<Reg16 IXY> inline II sbc_a_xix();
294
295
	inline void SUB(uint8_t reg);
296
	inline II sub_a();
297
	template<Reg8 SRC, int EE> inline II sub_R();
298
	inline II sub_byte();
299
	inline II sub_xhl();
300
	template<Reg16 IXY> inline II sub_xix();
301
302
	inline void XOR(uint8_t reg);
303
	inline II xor_a();
304
	template<Reg8 SRC, int EE> inline II xor_R();
305
	inline II xor_byte();
306
	inline II xor_xhl();
307
	template<Reg16 IXY> inline II xor_xix();
308
309
	inline uint8_t DEC(uint8_t reg);
310
	template<Reg8 REG, int EE> inline II dec_R();
311
	template<int EE> inline void DEC_X(unsigned x);
312
	inline II dec_xhl();
313
	template<Reg16 IXY> inline II dec_xix();
314
315
	inline uint8_t INC(uint8_t reg);
316
	template<Reg8 REG, int EE> inline II inc_R();
317
	template<int EE> inline void INC_X(unsigned x);
318
	inline II inc_xhl();
319
	template<Reg16 IXY> inline II inc_xix();
320
321
	template<Reg16 REG> inline II adc_hl_SS();
322
	inline II adc_hl_hl();
323
	template<Reg16 REG1, Reg16 REG2, int EE> inline II add_SS_TT();
324
	template<Reg16 REG, int EE> inline II add_SS_SS();
325
	template<Reg16 REG> inline II sbc_hl_SS();
326
	inline II sbc_hl_hl();
327
328
	template<Reg16 REG, int EE> inline II dec_SS();
329
	template<Reg16 REG, int EE> inline II inc_SS();
330
331
	template<unsigned N, Reg8 REG> inline II bit_N_R();
332
	template<unsigned N> inline II bit_N_xhl();
333
	template<unsigned N> inline II bit_N_xix(unsigned a);
334
335
	template<unsigned N, Reg8 REG> inline II res_N_R();
336
	template<int EE> inline uint8_t RES_X(unsigned bit, unsigned addr);
337
	template<unsigned N> inline II res_N_xhl();
338
	template<unsigned N, Reg8 REG> inline II res_N_xix_R(unsigned a);
339
340
	template<unsigned N, Reg8 REG> inline II set_N_R();
341
	template<int EE> inline uint8_t SET_X(unsigned bit, unsigned addr);
342
	template<unsigned N> inline II set_N_xhl();
343
	template<unsigned N, Reg8 REG> inline II set_N_xix_R(unsigned a);
344
345
	inline uint8_t RL(uint8_t reg);
346
	template<int EE> inline uint8_t RL_X(unsigned x);
347
	template<Reg8 REG> inline II rl_R();
348
	inline II rl_xhl();
349
	template<Reg8 REG> inline II rl_xix_R(unsigned a);
350
351
	inline uint8_t RLC(uint8_t reg);
352
	template<int EE> inline uint8_t RLC_X(unsigned x);
353
	template<Reg8 REG> inline II rlc_R();
354
	inline II rlc_xhl();
355
	template<Reg8 REG> inline II rlc_xix_R(unsigned a);
356
357
	inline uint8_t RR(uint8_t reg);
358
	template<int EE> inline uint8_t RR_X(unsigned x);
359
	template<Reg8 REG> inline II rr_R();
360
	inline II rr_xhl();
361
	template<Reg8 REG> inline II rr_xix_R(unsigned a);
362
363
	inline uint8_t RRC(uint8_t reg);
364
	template<int EE> inline uint8_t RRC_X(unsigned x);
365
	template<Reg8 REG> inline II rrc_R();
366
	inline II rrc_xhl();
367
	template<Reg8 REG> inline II rrc_xix_R(unsigned a);
368
369
	inline uint8_t SLA(uint8_t reg);
370
	template<int EE> inline uint8_t SLA_X(unsigned x);
371
	template<Reg8 REG> inline II sla_R();
372
	inline II sla_xhl();
373
	template<Reg8 REG> inline II sla_xix_R(unsigned a);
374
375
	inline uint8_t SLL(uint8_t reg);
376
	template<int EE> inline uint8_t SLL_X(unsigned x);
377
	template<Reg8 REG> inline II sll_R();
378
	inline II sll_xhl();
379
	template<Reg8 REG> inline II sll_xix_R(unsigned a);
380
	inline II sll2();
381
382
	inline uint8_t SRA(uint8_t reg);
383
	template<int EE> inline uint8_t SRA_X(unsigned x);
384
	template<Reg8 REG> inline II sra_R();
385
	inline II sra_xhl();
386
	template<Reg8 REG> inline II sra_xix_R(unsigned a);
387
388
	inline uint8_t SRL(uint8_t reg);
389
	template<int EE> inline uint8_t SRL_X(unsigned x);
390
	template<Reg8 REG> inline II srl_R();
391
	inline II srl_xhl();
392
	template<Reg8 REG> inline II srl_xix_R(unsigned a);
393
394
	inline II rla();
395
	inline II rlca();
396
	inline II rra();
397
	inline II rrca();
398
399
	inline II rld();
400
	inline II rrd();
401
402
	template<int EE> inline void PUSH(uint16_t reg);
403
	template<Reg16 REG, int EE> inline II push_SS();
404
	template<int EE> inline uint16_t POP();
405
	template<Reg16 REG, int EE> inline II pop_SS();
406
407
	template<typename COND> inline II call(COND cond);
408
	template<unsigned ADDR> inline II rst();
409
410
	template<int EE, typename COND> inline II RET(COND cond);
411
	template<typename COND> inline II ret(COND cond);
412
	inline II ret();
413
	inline II retn();
414
415
	template<Reg16 REG, int EE> inline II jp_SS();
416
	template<typename COND> inline II jp(COND cond);
417
	template<typename COND> inline II jr(COND cond);
418
	inline II djnz();
419
420
	template<Reg16 REG, int EE> inline II ex_xsp_SS();
421
422
	template<Reg8 REG> inline II in_R_c();
423
	inline II in_a_byte();
424
	template<Reg8 REG> inline II out_c_R();
425
	inline II out_c_0();
426
	inline II out_byte_a();
427
428
	inline II BLOCK_CP(int increase, bool repeat);
429
	inline II cpd();
430
	inline II cpi();
431
	inline II cpdr();
432
	inline II cpir();
433
434
	inline II BLOCK_LD(int increase, bool repeat);
435
	inline II ldd();
436
	inline II ldi();
437
	inline II lddr();
438
	inline II ldir();
439
440
	inline II BLOCK_IN(int increase, bool repeat);
441
	inline II ind();
442
	inline II ini();
443
	inline II indr();
444
	inline II inir();
445
446
	inline II BLOCK_OUT(int increase, bool repeat);
447
	inline II outd();
448
	inline II outi();
449
	inline II otdr();
450
	inline II otir();
451
452
	template<int EE = 0> inline II nop();
453
	inline II ccf();
454
	inline II cpl();
455
	inline II daa();
456
	inline II neg();
457
	inline II scf();
458
	inline II ex_af_af();
459
	inline II ex_de_hl();
460
	inline II exx();
461
	inline II di();
462
	inline II ei();
463
	inline II halt();
464
	template<unsigned N> inline II im_N();
465
466
	template<Reg8 REG> inline II ld_a_IR();
467
	inline II ld_r_a();
468
	inline II ld_i_a();
469
470
	template<Reg8 REG> inline II mulub_a_R();
471
	template<Reg16 REG> inline II muluw_hl_SS();
472
473
	friend class MSXCPU;
474
	friend class Z80TYPE;
475
	friend class R800TYPE;
476
};
477
478
class Z80TYPE;
479
class R800TYPE;
480
SERIALIZE_CLASS_VERSION(CPUCore<Z80TYPE>,  5);
481
SERIALIZE_CLASS_VERSION(CPUCore<R800TYPE>, 5); // keep these two the same
482
483
} // namespace openmsx
484
485
#endif